msm: clock: Move out pll code from clock-local.c to clock-pll.c

The new clock-pll driver is designed to control
PLL clocks including shared, locally controlled
and voteable PLLs. Move PLL code from clock-local.c
into this new driver.

Change-Id: I58fc0c7e4816e52d25dd2521a70baff52d8a74b2
Signed-off-by: Vikram Mulukutla <markivx@codeaurora.org>
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d233c91..14bae2d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -168,7 +168,7 @@
 obj-$(CONFIG_ARCH_QSD8X50) += devices-qsd8x50.o clock-pcom-lookup.o
 obj-$(CONFIG_MACH_QSD8X50_SURF) += board-qsd8x50.o
 obj-$(CONFIG_MACH_QSD8X50_FFA) += board-qsd8x50.o
-obj-$(CONFIG_ARCH_MSM8X60) += devices-msm8x60.o clock-local.o clock-8x60.o acpuclock-8x60.o
+obj-$(CONFIG_ARCH_MSM8X60) += devices-msm8x60.o clock-local.o clock-8x60.o acpuclock-8x60.o clock-pll.o
 obj-$(CONFIG_ARCH_MSM8X60) += clock-rpm.o
 obj-$(CONFIG_ARCH_MSM8X60) += saw-regulator.o
 obj-$(CONFIG_ARCH_MSM8X60) += footswitch-8x60.o
@@ -240,10 +240,10 @@
 obj-$(CONFIG_MACH_MSM8625_EVB) +=  board-qrd7627a.o board-7627a-all.o
 obj-$(CONFIG_MACH_MSM8625_QRD7) +=  board-qrd7627a.o board-7627a-all.o
 obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o memory_topology.o
-obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o clock-7x30.o acpuclock-7x30.o
+obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o clock-7x30.o acpuclock-7x30.o clock-pll.o
 obj-$(CONFIG_MACH_MSM7X25_SURF) += board-msm7x27.o devices-msm7x25.o
 obj-$(CONFIG_MACH_MSM7X25_FFA) += board-msm7x27.o devices-msm7x25.o
-obj-$(CONFIG_ARCH_MSM8960) += clock-local.o clock-dss-8960.o clock-8960.o clock-rpm.o
+obj-$(CONFIG_ARCH_MSM8960) += clock-local.o clock-dss-8960.o clock-8960.o clock-rpm.o clock-pll.o
 obj-$(CONFIG_ARCH_MSM8960) += footswitch-8x60.o
 obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o
 obj-$(CONFIG_ARCH_MSM8960) += memory_topology.o
@@ -270,7 +270,7 @@
 obj-$(CONFIG_MACH_MPQ8064_HRD) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_MPQ8064_DTV) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
-obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o
+obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
 obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o board-copper-regulator.o board-copper-gpiomux.o
 obj-$(CONFIG_ARCH_MSMCOPPER) += acpuclock-krait.o acpuclock-copper.o
 
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index f9d8dbe..5951734 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -31,6 +31,7 @@
 #include "clock-pcom.h"
 #include "clock-voter.h"
 #include "proc_comm.h"
+#include "clock-pll.h"
 
 #define REG_BASE(off) (MSM_CLK_CTL_BASE + (off))
 #define REG(off) (MSM_CLK_CTL_SH2_BASE + (off))
@@ -268,6 +269,7 @@
 	.en_reg = PLL_ENA_REG,
 	.en_mask = BIT(1),
 	.status_reg = PLL1_STATUS_BASE_REG,
+	.status_mask = BIT(16),
 	.parent = &tcxo_clk.c,
 	.c = {
 		.dbg_name = "pll1_clk",
@@ -282,6 +284,7 @@
 	.en_reg = PLL_ENA_REG,
 	.en_mask = BIT(2),
 	.status_reg = PLL2_STATUS_BASE_REG,
+	.status_mask = BIT(16),
 	.parent = &tcxo_clk.c,
 	.c = {
 		.dbg_name = "pll2_clk",
@@ -296,6 +299,7 @@
 	.en_reg = PLL_ENA_REG,
 	.en_mask = BIT(3),
 	.status_reg = PLL3_STATUS_BASE_REG,
+	.status_mask = BIT(16),
 	.parent = &lpxo_clk.c,
 	.c = {
 		.dbg_name = "pll3_clk",
@@ -309,6 +313,7 @@
 	.en_reg = PLL_ENA_REG,
 	.en_mask = BIT(4),
 	.status_reg = PLL4_STATUS_BASE_REG,
+	.status_mask = BIT(16),
 	.parent = &lpxo_clk.c,
 	.c = {
 		.dbg_name = "pll4_clk",
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 89cde6d..ca5a63d 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -33,6 +33,7 @@
 #include "clock-voter.h"
 #include "clock-dss-8960.h"
 #include "devices.h"
+#include "clock-pll.h"
 
 #define REG(off)	(MSM_CLK_CTL_BASE + (off))
 #define REG_MM(off)	(MSM_MMSS_CLK_CTL_BASE + (off))
@@ -478,7 +479,7 @@
 	.c = {
 		.dbg_name = "pll2_clk",
 		.rate = 800000000,
-		.ops = &clk_ops_pll,
+		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll2_clk.c),
 		.warned = true,
 	},
@@ -490,7 +491,7 @@
 	.c = {
 		.dbg_name = "pll3_clk",
 		.rate = 1200000000,
-		.ops = &clk_ops_pll,
+		.ops = &clk_ops_local_pll,
 		.vdd_class = &vdd_sr2_pll,
 		.fmax[VDD_SR2_PLL_ON] = ULONG_MAX,
 		CLK_INIT(pll3_clk.c),
@@ -502,6 +503,7 @@
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(4),
 	.status_reg = LCC_PLL0_STATUS_REG,
+	.status_mask = BIT(16),
 	.parent = &pxo_clk.c,
 	.c = {
 		.dbg_name = "pll4_clk",
@@ -516,6 +518,7 @@
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(8),
 	.status_reg = BB_PLL8_STATUS_REG,
+	.status_mask = BIT(16),
 	.parent = &pxo_clk.c,
 	.c = {
 		.dbg_name = "pll8_clk",
@@ -530,6 +533,7 @@
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(14),
 	.status_reg = BB_PLL14_STATUS_REG,
+	.status_mask = BIT(16),
 	.parent = &pxo_clk.c,
 	.c = {
 		.dbg_name = "pll14_clk",
@@ -546,7 +550,7 @@
 	.c = {
 		.dbg_name = "pll15_clk",
 		.rate = 975000000,
-		.ops = &clk_ops_pll,
+		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll15_clk.c),
 		.warned = true,
 	},
@@ -6032,7 +6036,7 @@
 
 	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
 
-	clk_ops_pll.enable = sr_pll_clk_enable;
+	clk_ops_local_pll.enable = sr_pll_clk_enable;
 
 	/* Initialize clock registers. */
 	reg_init();
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 5031887..6c23c50 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -31,6 +31,7 @@
 #include "clock-local.h"
 #include "clock-rpm.h"
 #include "clock-voter.h"
+#include "clock-pll.h"
 
 #ifdef CONFIG_MSM_SECURE_IO
 #undef readl_relaxed
@@ -304,6 +305,7 @@
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(8),
 	.status_reg = BB_PLL8_STATUS_REG,
+	.status_mask = BIT(16),
 	.parent = &pxo_clk.c,
 	.c = {
 		.dbg_name = "pll8_clk",
@@ -320,7 +322,7 @@
 	.c = {
 		.dbg_name = "pll2_clk",
 		.rate = 800000000,
-		.ops = &clk_ops_pll,
+		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll2_clk.c),
 		.warned = true,
 	},
@@ -332,7 +334,7 @@
 	.c = {
 		.dbg_name = "pll3_clk",
 		.rate = 0, /* TODO: Detect rate dynamically */
-		.ops = &clk_ops_pll,
+		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll3_clk.c),
 		.warned = true,
 	},
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 411e615..b145278 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -32,6 +32,7 @@
 #include "clock-voter.h"
 #include "clock-rpm.h"
 #include "devices.h"
+#include "clock-pll.h"
 
 #define REG(off)	(MSM_CLK_CTL_BASE + (off))
 #define REG_LPA(off)	(MSM_LPASS_CLK_CTL_BASE + (off))
@@ -259,6 +260,7 @@
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(0),
 	.status_reg = BB_PLL0_STATUS_REG,
+	.status_mask = BIT(16),
 	.parent = &cxo_clk.c,
 	.soft_vote = &soft_vote_pll0,
 	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
@@ -275,6 +277,7 @@
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(0),
 	.status_reg = BB_PLL0_STATUS_REG,
+	.status_mask = BIT(16),
 	.soft_vote = &soft_vote_pll0,
 	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
 	.c = {
@@ -290,6 +293,7 @@
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(4),
 	.status_reg = LCC_PLL0_STATUS_REG,
+	.status_mask = BIT(16),
 	.parent = &cxo_clk.c,
 	.c = {
 		.dbg_name = "pll4_clk",
@@ -306,6 +310,7 @@
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(8),
 	.status_reg = BB_PLL8_STATUS_REG,
+	.status_mask = BIT(16),
 	.parent = &cxo_clk.c,
 	.soft_vote = &soft_vote_pll8,
 	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
@@ -322,6 +327,7 @@
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(8),
 	.status_reg = BB_PLL8_STATUS_REG,
+	.status_mask = BIT(16),
 	.soft_vote = &soft_vote_pll8,
 	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
 	.c = {
@@ -338,7 +344,7 @@
 	.c = {
 		.dbg_name = "pll9_acpu_clk",
 		.rate = 440000000,
-		.ops = &clk_ops_pll,
+		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll9_acpu_clk.c),
 		.warned = true,
 	},
@@ -348,6 +354,7 @@
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(11),
 	.status_reg = BB_PLL14_STATUS_REG,
+	.status_mask = BIT(16),
 	.parent = &cxo_clk.c,
 	.c = {
 		.dbg_name = "pll14_clk",
@@ -1742,7 +1749,7 @@
 
 	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
 
-	clk_ops_pll.enable = sr_pll_clk_enable;
+	clk_ops_local_pll.enable = sr_pll_clk_enable;
 
 	/* Enable PDM CXO source. */
 	regval = readl_relaxed(PDM_CLK_NS_REG);
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 84aa086..d414e44 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -627,158 +627,6 @@
 	return HANDOFF_ENABLED_CLK;
 }
 
-int pll_vote_clk_enable(struct clk *clk)
-{
-	u32 ena;
-	unsigned long flags;
-	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
-
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
-	ena = readl_relaxed(pll->en_reg);
-	ena |= pll->en_mask;
-	writel_relaxed(ena, pll->en_reg);
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
-	/* Wait until PLL is enabled */
-	while ((readl_relaxed(pll->status_reg) & BIT(16)) == 0)
-		cpu_relax();
-
-	return 0;
-}
-
-void pll_vote_clk_disable(struct clk *clk)
-{
-	u32 ena;
-	unsigned long flags;
-	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
-
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
-	ena = readl_relaxed(pll->en_reg);
-	ena &= ~(pll->en_mask);
-	writel_relaxed(ena, pll->en_reg);
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-}
-
-struct clk *pll_vote_clk_get_parent(struct clk *clk)
-{
-	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
-	return pll->parent;
-}
-
-int pll_vote_clk_is_enabled(struct clk *clk)
-{
-	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
-	return !!(readl_relaxed(pll->status_reg) & BIT(16));
-}
-
-struct clk_ops clk_ops_pll_vote = {
-	.enable = pll_vote_clk_enable,
-	.disable = pll_vote_clk_disable,
-	.auto_off = pll_vote_clk_disable,
-	.is_enabled = pll_vote_clk_is_enabled,
-	.get_parent = pll_vote_clk_get_parent,
-};
-
-static int pll_clk_enable(struct clk *clk)
-{
-	u32 mode;
-	unsigned long flags;
-	struct pll_clk *pll = to_pll_clk(clk);
-
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
-	mode = readl_relaxed(pll->mode_reg);
-	/* Disable PLL bypass mode. */
-	mode |= BIT(1);
-	writel_relaxed(mode, pll->mode_reg);
-
-	/*
-	 * H/W requires a 5us delay between disabling the bypass and
-	 * de-asserting the reset. Delay 10us just to be safe.
-	 */
-	mb();
-	udelay(10);
-
-	/* De-assert active-low PLL reset. */
-	mode |= BIT(2);
-	writel_relaxed(mode, pll->mode_reg);
-
-	/* Wait until PLL is locked. */
-	mb();
-	udelay(50);
-
-	/* Enable PLL output. */
-	mode |= BIT(0);
-	writel_relaxed(mode, pll->mode_reg);
-
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-	return 0;
-}
-
-static void pll_clk_disable(struct clk *clk)
-{
-	u32 mode;
-	unsigned long flags;
-	struct pll_clk *pll = to_pll_clk(clk);
-
-	/*
-	 * Disable the PLL output, disable test mode, enable
-	 * the bypass mode, and assert the reset.
-	 */
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
-	mode = readl_relaxed(pll->mode_reg);
-	mode &= ~BM(3, 0);
-	writel_relaxed(mode, pll->mode_reg);
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-}
-
-static struct clk *pll_clk_get_parent(struct clk *clk)
-{
-	struct pll_clk *pll = to_pll_clk(clk);
-	return pll->parent;
-}
-
-int sr_pll_clk_enable(struct clk *clk)
-{
-	u32 mode;
-	unsigned long flags;
-	struct pll_clk *pll = to_pll_clk(clk);
-
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
-	mode = readl_relaxed(pll->mode_reg);
-	/* De-assert active-low PLL reset. */
-	mode |= BIT(2);
-	writel_relaxed(mode, pll->mode_reg);
-
-	/*
-	 * H/W requires a 5us delay between disabling the bypass and
-	 * de-asserting the reset. Delay 10us just to be safe.
-	 */
-	mb();
-	udelay(10);
-
-	/* Disable PLL bypass mode. */
-	mode |= BIT(1);
-	writel_relaxed(mode, pll->mode_reg);
-
-	/* Wait until PLL is locked. */
-	mb();
-	udelay(60);
-
-	/* Enable PLL output. */
-	mode |= BIT(0);
-	writel_relaxed(mode, pll->mode_reg);
-
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-	return 0;
-}
-
-struct clk_ops clk_ops_pll = {
-	.enable = pll_clk_enable,
-	.disable = pll_clk_disable,
-	.auto_off = pll_clk_disable,
-	.get_parent = pll_clk_get_parent,
-};
-
 struct clk_ops clk_ops_gnd = {
 };
 
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 3dd849a..0419ede 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -17,12 +17,6 @@
 #include <linux/spinlock.h>
 #include "clock.h"
 
-/*
- * Bit manipulation macros
- */
-#define BM(msb, lsb)	(((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
-#define BVAL(msb, lsb, val)	(((val) << lsb) & BM(msb, lsb))
-
 #define MN_MODE_DUAL_EDGE 0x2
 
 /* MD Registers */
@@ -257,57 +251,6 @@
 };
 
 /**
- * struct pll_vote_clk - phase locked loop (HW voteable)
- * @soft_vote: soft voting variable for multiple PLL software instances
- * @soft_vote_mask: soft voting mask for multiple PLL software instances
- * @en_reg: enable register
- * @en_mask: ORed with @en_reg to enable the clock
- * @status_reg: status register
- * @parent: clock source
- * @c: clk
- */
-struct pll_vote_clk {
-	u32 *soft_vote;
-	const u32 soft_vote_mask;
-	void __iomem *const en_reg;
-	const u32 en_mask;
-
-	void __iomem *const status_reg;
-
-	struct clk *parent;
-	struct clk c;
-};
-
-extern struct clk_ops clk_ops_pll_vote;
-
-static inline struct pll_vote_clk *to_pll_vote_clk(struct clk *clk)
-{
-	return container_of(clk, struct pll_vote_clk, c);
-}
-
-/**
- * struct pll_clk - phase locked loop
- * @mode_reg: enable register
- * @parent: clock source
- * @c: clk
- */
-struct pll_clk {
-	void __iomem *const mode_reg;
-
-	struct clk *parent;
-	struct clk c;
-};
-
-extern struct clk_ops clk_ops_pll;
-
-static inline struct pll_clk *to_pll_clk(struct clk *clk)
-{
-	return container_of(clk, struct pll_clk, c);
-}
-
-int sr_pll_clk_enable(struct clk *clk);
-
-/**
  * struct branch_clk - branch
  * @enabled: true if clock is on, false otherwise
  * @b: branch
@@ -365,14 +308,6 @@
 extern struct fixed_clk		gnd_clk;
 
 /*
- * PLL vote clock APIs
- */
-int pll_vote_clk_enable(struct clk *clk);
-void pll_vote_clk_disable(struct clk *clk);
-struct clk *pll_vote_clk_get_parent(struct clk *clk);
-int pll_vote_clk_is_enabled(struct clk *clk);
-
-/*
  * Generic set-rate implementations
  */
 void set_rate_mnd(struct rcg_clk *clk, struct clk_freq_tbl *nf);
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index 68c390a..eb980e8 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -17,13 +17,194 @@
 #include <linux/err.h>
 #include <linux/remote_spinlock.h>
 
-#include <mach/socinfo.h>
+#include <mach/scm-io.h>
 #include <mach/msm_iomap.h>
 
 #include "clock.h"
 #include "clock-pll.h"
 #include "smd_private.h"
 
+#ifdef CONFIG_MSM_SECURE_IO
+#undef readl_relaxed
+#undef writel_relaxed
+#define readl_relaxed secure_readl
+#define writel_relaxed secure_writel
+#endif
+
+#define PLL_OUTCTRL BIT(0)
+#define PLL_BYPASSNL BIT(1)
+#define PLL_RESET_N BIT(2)
+#define PLL_MODE_MASK BM(3, 0)
+
+static DEFINE_SPINLOCK(pll_reg_lock);
+
+int pll_vote_clk_enable(struct clk *clk)
+{
+	u32 ena;
+	unsigned long flags;
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	ena = readl_relaxed(pll->en_reg);
+	ena |= pll->en_mask;
+	writel_relaxed(ena, pll->en_reg);
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+
+	/* Wait until PLL is enabled */
+	while ((readl_relaxed(pll->status_reg) & pll->status_mask) == 0)
+		cpu_relax();
+
+	return 0;
+}
+
+void pll_vote_clk_disable(struct clk *clk)
+{
+	u32 ena;
+	unsigned long flags;
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	ena = readl_relaxed(pll->en_reg);
+	ena &= ~(pll->en_mask);
+	writel_relaxed(ena, pll->en_reg);
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+}
+
+struct clk *pll_vote_clk_get_parent(struct clk *clk)
+{
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+	return pll->parent;
+}
+
+int pll_vote_clk_is_enabled(struct clk *clk)
+{
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+	return !!(readl_relaxed(pll->status_reg) & pll->status_mask);
+}
+
+struct clk_ops clk_ops_pll_vote = {
+	.enable = pll_vote_clk_enable,
+	.disable = pll_vote_clk_disable,
+	.auto_off = pll_vote_clk_disable,
+	.is_enabled = pll_vote_clk_is_enabled,
+	.get_parent = pll_vote_clk_get_parent,
+};
+
+static void __pll_clk_enable_reg(void __iomem *mode_reg)
+{
+	u32 mode = readl_relaxed(mode_reg);
+	/* Disable PLL bypass mode. */
+	mode |= PLL_BYPASSNL;
+	writel_relaxed(mode, mode_reg);
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	udelay(10);
+
+	/* De-assert active-low PLL reset. */
+	mode |= PLL_RESET_N;
+	writel_relaxed(mode, mode_reg);
+
+	/* Wait until PLL is locked. */
+	mb();
+	udelay(50);
+
+	/* Enable PLL output. */
+	mode |= PLL_OUTCTRL;
+	writel_relaxed(mode, mode_reg);
+
+	/* Ensure that the write above goes through before returning. */
+	mb();
+}
+
+static int local_pll_clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	struct pll_clk *pll = to_pll_clk(clk);
+
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	__pll_clk_enable_reg(pll->mode_reg);
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+
+	return 0;
+}
+
+static void __pll_clk_disable_reg(void __iomem *mode_reg)
+{
+	u32 mode = readl_relaxed(mode_reg);
+	mode &= ~PLL_MODE_MASK;
+	writel_relaxed(mode, mode_reg);
+}
+
+static void local_pll_clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+	struct pll_clk *pll = to_pll_clk(clk);
+
+	/*
+	 * Disable the PLL output, disable test mode, enable
+	 * the bypass mode, and assert the reset.
+	 */
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	__pll_clk_disable_reg(pll->mode_reg);
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+}
+
+static struct clk *local_pll_clk_get_parent(struct clk *clk)
+{
+	struct pll_clk *pll = to_pll_clk(clk);
+	return pll->parent;
+}
+
+int sr_pll_clk_enable(struct clk *clk)
+{
+	u32 mode;
+	unsigned long flags;
+	struct pll_clk *pll = to_pll_clk(clk);
+
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	mode = readl_relaxed(pll->mode_reg);
+	/* De-assert active-low PLL reset. */
+	mode |= PLL_RESET_N;
+	writel_relaxed(mode, pll->mode_reg);
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	udelay(10);
+
+	/* Disable PLL bypass mode. */
+	mode |= PLL_BYPASSNL;
+	writel_relaxed(mode, pll->mode_reg);
+
+	/* Wait until PLL is locked. */
+	mb();
+	udelay(60);
+
+	/* Enable PLL output. */
+	mode |= PLL_OUTCTRL;
+	writel_relaxed(mode, pll->mode_reg);
+
+	/* Ensure that the write above goes through before returning. */
+	mb();
+
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+
+	return 0;
+}
+
+struct clk_ops clk_ops_local_pll = {
+	.enable = local_pll_clk_enable,
+	.disable = local_pll_clk_disable,
+	.auto_off = local_pll_clk_disable,
+	.get_parent = local_pll_clk_get_parent,
+};
+
 struct pll_rate {
 	unsigned int lvalue;
 	unsigned long rate;
@@ -95,21 +276,6 @@
 
 }
 
-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);
@@ -119,7 +285,7 @@
 
 	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_clk_enable_reg(pll->mode_reg);
 		pll_control->pll[PLL_BASE + pll_id].on = 1;
 	}
 
@@ -137,7 +303,7 @@
 	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_clk_disable_reg(pll->mode_reg);
 		pll_control->pll[PLL_BASE + pll_id].on = 0;
 	}
 
@@ -151,11 +317,6 @@
 	return readl_relaxed(pll->mode_reg) & BIT(0);
 }
 
-static bool pll_clk_is_local(struct clk *clk)
-{
-	return true;
-}
-
 static enum handoff pll_clk_handoff(struct clk *clk)
 {
 	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
@@ -191,6 +352,5 @@
 	.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
index ae0ca17..7de81c9 100644
--- a/arch/arm/mach-msm/clock-pll.h
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -12,6 +12,9 @@
  *
  */
 
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_PLL_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_PLL_H
+
 /**
  * enum - For PLL IDs
  */
@@ -50,3 +53,65 @@
  * msm_shared_pll_control_init() - Initialize shared pll control structure
  */
 void msm_shared_pll_control_init(void);
+
+/**
+ * struct pll_vote_clk - phase locked loop (HW voteable)
+ * @soft_vote: soft voting variable for multiple PLL software instances
+ * @soft_vote_mask: soft voting mask for multiple PLL software instances
+ * @en_reg: enable register
+ * @en_mask: ORed with @en_reg to enable the clock
+ * @status_mask: ANDed with @status_reg to determine if PLL is active.
+ * @status_reg: status register
+ * @parent: clock source
+ * @c: clk
+ */
+struct pll_vote_clk {
+	u32 *soft_vote;
+	const u32 soft_vote_mask;
+	void __iomem *const en_reg;
+	const u32 en_mask;
+	void __iomem *const status_reg;
+	const u32 status_mask;
+
+	struct clk *parent;
+	struct clk c;
+};
+
+extern struct clk_ops clk_ops_pll_vote;
+
+static inline struct pll_vote_clk *to_pll_vote_clk(struct clk *clk)
+{
+	return container_of(clk, struct pll_vote_clk, c);
+}
+
+/**
+ * struct pll_clk - phase locked loop
+ * @mode_reg: enable register
+ * @parent: clock source
+ * @c: clk
+ */
+struct pll_clk {
+	void __iomem *const mode_reg;
+
+	struct clk *parent;
+	struct clk c;
+};
+
+extern struct clk_ops clk_ops_local_pll;
+
+static inline struct pll_clk *to_pll_clk(struct clk *clk)
+{
+	return container_of(clk, struct pll_clk, c);
+}
+
+int sr_pll_clk_enable(struct clk *clk);
+
+/*
+ * PLL vote clock APIs
+ */
+int pll_vote_clk_enable(struct clk *clk);
+void pll_vote_clk_disable(struct clk *clk);
+struct clk *pll_vote_clk_get_parent(struct clk *clk);
+int pll_vote_clk_is_enabled(struct clk *clk);
+
+#endif
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 60be654..fda7175 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -37,6 +37,12 @@
 #define CLKFLAG_MIN			0x00000400
 #define CLKFLAG_MAX			0x00000800
 
+/*
+ * Bit manipulation macros
+ */
+#define BM(msb, lsb)	(((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
+#define BVAL(msb, lsb, val)	(((val) << lsb) & BM(msb, lsb))
+
 #define MAX_VDD_LEVELS			4
 
 /**