From 280aa323a7c7b464588197f490d86acf9ecc8c27 Mon Sep 17 00:00:00 2001
From: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
Date: Tue, 21 Jun 2011 14:06:22 +0530
Subject: [RFC][PATCH] ARM: Samsung: organize duplicated EPLL code

The S5PV210/C110,C100,6450/6440 and EXYNOS4 defines custom
EPLL set_rate function. The same can be reorganized on the basis
of the PLL used.
Eg: PLL90XX. PLL46XX, PLL45XX and PLL65XX.

Also, Adds the epll ops for EXYNOS4.
Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
---
 arch/arm/mach-exynos4/Kconfig                   |    2 +
 arch/arm/mach-exynos4/clock.c                   |    7 +
 arch/arm/mach-s5p64x0/Kconfig                   |    5 +
 arch/arm/mach-s5p64x0/clock-s5p6440.c           |   56 +--------
 arch/arm/mach-s5p64x0/clock-s5p6450.c           |   48 +-------
 arch/arm/mach-s5p64x0/include/mach/regs-clock.h |    1 +
 arch/arm/mach-s5pc100/Kconfig                   |    1 +
 arch/arm/mach-s5pc100/clock.c                   |   60 +---------
 arch/arm/mach-s5pv210/Kconfig                   |    2 +
 arch/arm/mach-s5pv210/clock.c                   |   73 +-----------
 arch/arm/plat-s5p/Kconfig                       |   21 +++
 arch/arm/plat-s5p/Makefile                      |    6 +
 arch/arm/plat-s5p/include/plat/pll.h            |  153 +++--------------------
 arch/arm/plat-s5p/pll_45xx.c                    |   50 ++++++++
 arch/arm/plat-s5p/pll_46xx.c                    |  138 ++++++++++++++++++++
 arch/arm/plat-s5p/pll_65xx.c                    |  102 +++++++++++++++
 arch/arm/plat-s5p/pll_90xx.c                    |  115 +++++++++++++++++
 17 files changed, 474 insertions(+), 366 deletions(-)
 create mode 100644 arch/arm/plat-s5p/pll_45xx.c
 create mode 100644 arch/arm/plat-s5p/pll_46xx.c
 create mode 100644 arch/arm/plat-s5p/pll_65xx.c
 create mode 100644 arch/arm/plat-s5p/pll_90xx.c

diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig
index 1435fc3..a36c198 100644
--- a/arch/arm/mach-exynos4/Kconfig
+++ b/arch/arm/mach-exynos4/Kconfig
@@ -12,6 +12,8 @@ if ARCH_EXYNOS4
 config CPU_EXYNOS4210
 	bool
 	select S3C_PL330_DMA
+	select PLL_45XX
+	select PLL_46XX
 	help
 	  Enable EXYNOS4210 CPU support
 
diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c
index feeb27e..778501f 100644
--- a/arch/arm/mach-exynos4/clock.c
+++ b/arch/arm/mach-exynos4/clock.c
@@ -1243,6 +1243,11 @@ static struct clksrc_clk *sysclks[] = {
 	&clk_sclk_spdif,
 };
 
+static struct clk_ops exynos4_epll_ops = {
+	.set_rate = pll46xx_epll_set_rate,
+	.get_rate = s5p_epll_get_rate,
+};
+
 static int xtal_rate;
 
 static unsigned long exynos4_fout_apll_get_rate(struct clk *clk)
@@ -1321,6 +1326,8 @@ void __init_or_cpufreq exynos4_setup_clocks(void)
 	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
 		s3c_set_clksrc(&clksrcs[ptr], true);
 
+	clk_fout_epll.ops = &exynos4_epll_ops;
+
 	clk_audiocdclk0.rate = PCM_EXTCLK0;
 	clk_set_parent(&clk_sclk_audio0.clk, &clk_audiocdclk0);
 }
diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig
index 017af4c..221a3a0 100644
--- a/arch/arm/mach-s5p64x0/Kconfig
+++ b/arch/arm/mach-s5p64x0/Kconfig
@@ -10,6 +10,8 @@ if ARCH_S5P64X0
 config CPU_S5P6440
 	bool
 	select S3C_PL330_DMA
+	select PLL_45XX
+	select PLL_90XX
 	select S5P_HRT
 	help
 	  Enable S5P6440 CPU support
@@ -18,6 +20,9 @@ config CPU_S5P6450
 	bool
 	select S3C_PL330_DMA
 	select S5P_HRT
+	select PLL_45XX
+	select PLL_46XX
+	select PLL_90XX
 	help
 	  Enable S5P6450 CPU support
 
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c
index 0e9cd30..713e612 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6440.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c
@@ -33,63 +33,9 @@
 #include <plat/clock-clksrc.h>
 #include <plat/s5p6440.h>
 
-static u32 epll_div[][5] = {
-	{ 36000000,	0,	48, 1, 4 },
-	{ 48000000,	0,	32, 1, 3 },
-	{ 60000000,	0,	40, 1, 3 },
-	{ 72000000,	0,	48, 1, 3 },
-	{ 84000000,	0,	28, 1, 2 },
-	{ 96000000,	0,	32, 1, 2 },
-	{ 32768000,	45264,	43, 1, 4 },
-	{ 45158000,	6903,	30, 1, 3 },
-	{ 49152000,	50332,	32, 1, 3 },
-	{ 67738000,	10398,	45, 1, 3 },
-	{ 73728000,	9961,	49, 1, 3 }
-};
-
-static int s5p6440_epll_set_rate(struct clk *clk, unsigned long rate)
-{
-	unsigned int epll_con, epll_con_k;
-	unsigned int i;
-
-	if (clk->rate == rate)	/* Return if nothing changed */
-		return 0;
-
-	epll_con = __raw_readl(S5P64X0_EPLL_CON);
-	epll_con_k = __raw_readl(S5P64X0_EPLL_CON_K);
-
-	epll_con_k &= ~(PLL90XX_KDIV_MASK);
-	epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
-
-	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
-		 if (epll_div[i][0] == rate) {
-			epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT);
-			epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
-				    (epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
-				    (epll_div[i][4] << PLL90XX_SDIV_SHIFT);
-			break;
-		}
-	}
-
-	if (i == ARRAY_SIZE(epll_div)) {
-		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
-		return -EINVAL;
-	}
-
-	__raw_writel(epll_con, S5P64X0_EPLL_CON);
-	__raw_writel(epll_con_k, S5P64X0_EPLL_CON_K);
-
-	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
-			clk->rate, rate);
-
-	clk->rate = rate;
-
-	return 0;
-}
-
 static struct clk_ops s5p6440_epll_ops = {
 	.get_rate = s5p_epll_get_rate,
-	.set_rate = s5p6440_epll_set_rate,
+	.set_rate = pll90xx_epll_set_rate,
 };
 
 static struct clksrc_clk clk_hclk = {
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c
index d9dc16c..00841ca 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6450.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c
@@ -41,55 +41,9 @@ static struct clksrc_clk clk_mout_dpll = {
 	.reg_src	= { .reg = S5P64X0_CLK_SRC0, .shift = 5, .size = 1 },
 };
 
-static u32 epll_div[][5] = {
-	{ 133000000,	27307,	55, 2, 2 },
-	{ 100000000,	43691,	41, 2, 2 },
-	{ 480000000,	0,	80, 2, 0 },
-};
-
-static int s5p6450_epll_set_rate(struct clk *clk, unsigned long rate)
-{
-	unsigned int epll_con, epll_con_k;
-	unsigned int i;
-
-	if (clk->rate == rate)	/* Return if nothing changed */
-		return 0;
-
-	epll_con = __raw_readl(S5P64X0_EPLL_CON);
-	epll_con_k = __raw_readl(S5P64X0_EPLL_CON_K);
-
-	epll_con_k &= ~(PLL90XX_KDIV_MASK);
-	epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
-
-	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
-		 if (epll_div[i][0] == rate) {
-			epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT);
-			epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
-				    (epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
-				    (epll_div[i][4] << PLL90XX_SDIV_SHIFT);
-			break;
-		}
-	}
-
-	if (i == ARRAY_SIZE(epll_div)) {
-		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
-		return -EINVAL;
-	}
-
-	__raw_writel(epll_con, S5P64X0_EPLL_CON);
-	__raw_writel(epll_con_k, S5P64X0_EPLL_CON_K);
-
-	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
-			clk->rate, rate);
-
-	clk->rate = rate;
-
-	return 0;
-}
-
 static struct clk_ops s5p6450_epll_ops = {
 	.get_rate = s5p_epll_get_rate,
-	.set_rate = s5p6450_epll_set_rate,
+	.set_rate = pll90xx_epll_set_rate,
 };
 
 static struct clksrc_clk clk_dout_epll = {
diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
index a133f22..38ddad0 100644
--- a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
@@ -61,5 +61,6 @@
 #define ARM_DIV_MASK			(0xF << ARM_DIV_RATIO_SHIFT)
 
 #define S5P_EPLL_CON			S5P64X0_EPLL_CON
+#define S5P_EPLL_CON1			S5P64X0_EPLL_CON_K
 
 #endif /* __ASM_ARCH_REGS_CLOCK_H */
diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig
index 608722f..7bdb9d5 100644
--- a/arch/arm/mach-s5pc100/Kconfig
+++ b/arch/arm/mach-s5pc100/Kconfig
@@ -11,6 +11,7 @@ config CPU_S5PC100
 	bool
 	select S5P_EXT_INT
 	select S3C_PL330_DMA
+	select PLL_65XX
 	help
 	  Enable S5PC100 CPU support
 
diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c
index ff5cbb3..d3a87c2 100644
--- a/arch/arm/mach-s5pc100/clock.c
+++ b/arch/arm/mach-s5pc100/clock.c
@@ -251,67 +251,9 @@ static struct clksrc_clk clk_div_hdmi = {
 	.reg_div = { .reg = S5P_CLK_DIV3, .shift = 28, .size = 4 },
 };
 
-static u32 epll_div[][4] = {
-	{ 32750000,	131, 3, 4 },
-	{ 32768000,	131, 3, 4 },
-	{ 36000000,	72,  3, 3 },
-	{ 45000000,	90,  3, 3 },
-	{ 45158000,	90,  3, 3 },
-	{ 45158400,	90,  3, 3 },
-	{ 48000000,	96,  3, 3 },
-	{ 49125000,	131, 4, 3 },
-	{ 49152000,	131, 4, 3 },
-	{ 60000000,	120, 3, 3 },
-	{ 67737600,	226, 5, 3 },
-	{ 67738000,	226, 5, 3 },
-	{ 73800000,	246, 5, 3 },
-	{ 73728000,	246, 5, 3 },
-	{ 72000000,	144, 3, 3 },
-	{ 84000000,	168, 3, 3 },
-	{ 96000000,	96,  3, 2 },
-	{ 144000000,	144, 3, 2 },
-	{ 192000000,	96,  3, 1 }
-};
-
-static int s5pc100_epll_set_rate(struct clk *clk, unsigned long rate)
-{
-	unsigned int epll_con;
-	unsigned int i;
-
-	if (clk->rate == rate)	/* Return if nothing changed */
-		return 0;
-
-	epll_con = __raw_readl(S5P_EPLL_CON);
-
-	epll_con &= ~(PLL65XX_MDIV_MASK | PLL65XX_PDIV_MASK | PLL65XX_SDIV_MASK);
-
-	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
-		if (epll_div[i][0] == rate) {
-			epll_con |= (epll_div[i][1] << PLL65XX_MDIV_SHIFT) |
-				    (epll_div[i][2] << PLL65XX_PDIV_SHIFT) |
-				    (epll_div[i][3] << PLL65XX_SDIV_SHIFT);
-			break;
-		}
-	}
-
-	if (i == ARRAY_SIZE(epll_div)) {
-		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
-		return -EINVAL;
-	}
-
-	__raw_writel(epll_con, S5P_EPLL_CON);
-
-	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
-			clk->rate, rate);
-
-	clk->rate = rate;
-
-	return 0;
-}
-
 static struct clk_ops s5pc100_epll_ops = {
 	.get_rate = s5p_epll_get_rate,
-	.set_rate = s5pc100_epll_set_rate,
+	.set_rate = pll65xx_epll_set_rate,
 };
 
 static int s5pc100_d0_0_ctrl(struct clk *clk, int enable)
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 37b5a97..523ddc9 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -15,6 +15,8 @@ config CPU_S5PV210
 	select S5P_EXT_INT
 	select S5P_HRT
 	select S5PV210_PM if PM
+	select PLL_45XX
+	select PLL_46XX
 	help
 	  Enable S5PV210 CPU support
 
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index ae72f87..a1ba857 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -979,79 +979,8 @@ static struct clksrc_clk *sysclks[] = {
 	&clk_sclk_spdif,
 };
 
-static u32 epll_div[][6] = {
-	{  48000000, 0, 48, 3, 3, 0 },
-	{  96000000, 0, 48, 3, 2, 0 },
-	{ 144000000, 1, 72, 3, 2, 0 },
-	{ 192000000, 0, 48, 3, 1, 0 },
-	{ 288000000, 1, 72, 3, 1, 0 },
-	{  32750000, 1, 65, 3, 4, 35127 },
-	{  32768000, 1, 65, 3, 4, 35127 },
-	{  45158400, 0, 45, 3, 3, 10355 },
-	{  45000000, 0, 45, 3, 3, 10355 },
-	{  45158000, 0, 45, 3, 3, 10355 },
-	{  49125000, 0, 49, 3, 3, 9961 },
-	{  49152000, 0, 49, 3, 3, 9961 },
-	{  67737600, 1, 67, 3, 3, 48366 },
-	{  67738000, 1, 67, 3, 3, 48366 },
-	{  73800000, 1, 73, 3, 3, 47710 },
-	{  73728000, 1, 73, 3, 3, 47710 },
-	{  36000000, 1, 32, 3, 4, 0 },
-	{  60000000, 1, 60, 3, 3, 0 },
-	{  72000000, 1, 72, 3, 3, 0 },
-	{  80000000, 1, 80, 3, 3, 0 },
-	{  84000000, 0, 42, 3, 2, 0 },
-	{  50000000, 0, 50, 3, 3, 0 },
-};
-
-static int s5pv210_epll_set_rate(struct clk *clk, unsigned long rate)
-{
-	unsigned int epll_con, epll_con_k;
-	unsigned int i;
-
-	/* Return if nothing changed */
-	if (clk->rate == rate)
-		return 0;
-
-	epll_con = __raw_readl(S5P_EPLL_CON);
-	epll_con_k = __raw_readl(S5P_EPLL_CON1);
-
-	epll_con_k &= ~PLL46XX_KDIV_MASK;
-	epll_con &= ~(1 << 27 |
-			PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT |
-			PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT |
-			PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
-
-	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
-		if (epll_div[i][0] == rate) {
-			epll_con_k |= epll_div[i][5] << 0;
-			epll_con |= (epll_div[i][1] << 27 |
-					epll_div[i][2] << PLL46XX_MDIV_SHIFT |
-					epll_div[i][3] << PLL46XX_PDIV_SHIFT |
-					epll_div[i][4] << PLL46XX_SDIV_SHIFT);
-			break;
-		}
-	}
-
-	if (i == ARRAY_SIZE(epll_div)) {
-		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n",
-				__func__);
-		return -EINVAL;
-	}
-
-	__raw_writel(epll_con, S5P_EPLL_CON);
-	__raw_writel(epll_con_k, S5P_EPLL_CON1);
-
-	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
-			clk->rate, rate);
-
-	clk->rate = rate;
-
-	return 0;
-}
-
 static struct clk_ops s5pv210_epll_ops = {
-	.set_rate = s5pv210_epll_set_rate,
+	.set_rate = pll46xx_epll_set_rate,
 	.get_rate = s5p_epll_get_rate,
 };
 
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 7f9ff2a..a5cd0fc 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -95,3 +95,24 @@ config S5P_SETUP_MIPIPHY
 	bool
 	help
 	  Compile in common setup code for MIPI-CSIS and MIPI-DSIM devices
+
+config PLL_45XX
+	bool
+	help
+	  Compile in definitions for 45XX series PLL's
+
+config PLL_46XX
+	bool
+	help
+	  Compile in definitions for 46XX series PLL's
+
+config PLL_65XX
+	bool
+	help
+	  Compile in definitions for 65XX series PLL's
+
+config PLL_90XX
+	bool
+	help
+	  Compile in definitions for 90XX series PLL's
+
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index e234cc4..f50ada8 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -35,3 +35,9 @@ obj-$(CONFIG_S5P_DEV_CSIS0)	+= dev-csis0.o
 obj-$(CONFIG_S5P_DEV_CSIS1)	+= dev-csis1.o
 obj-$(CONFIG_S5P_DEV_USB_EHCI)	+= dev-ehci.o
 obj-$(CONFIG_S5P_SETUP_MIPIPHY)	+= setup-mipiphy.o
+
+# PLL Drivers
+obj-$(CONFIG_PLL_45XX)		+= pll_45xx.o
+obj-$(CONFIG_PLL_46XX)		+= pll_46xx.o
+obj-$(CONFIG_PLL_65XX)		+= pll_65xx.o
+obj-$(CONFIG_PLL_90XX)		+= pll_90xx.o
diff --git a/arch/arm/plat-s5p/include/plat/pll.h b/arch/arm/plat-s5p/include/plat/pll.h
index bf28fad..517c4b4 100644
--- a/arch/arm/plat-s5p/include/plat/pll.h
+++ b/arch/arm/plat-s5p/include/plat/pll.h
@@ -1,25 +1,15 @@
 /* arch/arm/plat-s5p/include/plat/pll.h
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
+ * Copyright (C) 2011 Samsung Electronics Co.Ltd
  *
- * S5P PLL code
- *
- * Based on arch/arm/plat-s3c64xx/include/plat/pll.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#define PLL45XX_MDIV_MASK	(0x3FF)
-#define PLL45XX_PDIV_MASK	(0x3F)
-#define PLL45XX_SDIV_MASK	(0x7)
-#define PLL45XX_MDIV_SHIFT	(16)
-#define PLL45XX_PDIV_SHIFT	(8)
-#define PLL45XX_SDIV_SHIFT	(0)
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
 
-#include <asm/div64.h>
+#ifndef __PLAT_S5P_PLL_H
+#define __PLAT_S5P_PLL_H
 
 enum pll45xx_type_t {
 	pll_4500,
@@ -27,127 +17,24 @@ enum pll45xx_type_t {
 	pll_4508
 };
 
-static inline unsigned long s5p_get_pll45xx(unsigned long baseclk, u32 pll_con,
-					    enum pll45xx_type_t pll_type)
-{
-	u32 mdiv, pdiv, sdiv;
-	u64 fvco = baseclk;
-
-	mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
-	pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
-	sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
-
-	if (pll_type == pll_4508)
-		sdiv = sdiv - 1;
-
-	fvco *= mdiv;
-	do_div(fvco, (pdiv << sdiv));
-
-	return (unsigned long)fvco;
-}
-
-#define PLL46XX_KDIV_MASK	(0xFFFF)
-#define PLL4650C_KDIV_MASK	(0xFFF)
-#define PLL46XX_MDIV_MASK	(0x1FF)
-#define PLL46XX_PDIV_MASK	(0x3F)
-#define PLL46XX_SDIV_MASK	(0x7)
-#define PLL46XX_MDIV_SHIFT	(16)
-#define PLL46XX_PDIV_SHIFT	(8)
-#define PLL46XX_SDIV_SHIFT	(0)
-
 enum pll46xx_type_t {
 	pll_4600,
 	pll_4650,
 	pll_4650c,
 };
 
-static inline unsigned long s5p_get_pll46xx(unsigned long baseclk,
-					    u32 pll_con0, u32 pll_con1,
-					    enum pll46xx_type_t pll_type)
-{
-	unsigned long result;
-	u32 mdiv, pdiv, sdiv, kdiv;
-	u64 tmp;
-
-	mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
-	pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
-	sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
-	kdiv = pll_con1 & PLL46XX_KDIV_MASK;
-
-	if (pll_type == pll_4650c)
-		kdiv = pll_con1 & PLL4650C_KDIV_MASK;
-	else
-		kdiv = pll_con1 & PLL46XX_KDIV_MASK;
-
-	tmp = baseclk;
-
-	if (pll_type == pll_4600) {
-		tmp *= (mdiv << 16) + kdiv;
-		do_div(tmp, (pdiv << sdiv));
-		result = tmp >> 16;
-	} else {
-		tmp *= (mdiv << 10) + kdiv;
-		do_div(tmp, (pdiv << sdiv));
-		result = tmp >> 10;
-	}
-
-	return result;
-}
-
-#define PLL90XX_MDIV_MASK	(0xFF)
-#define PLL90XX_PDIV_MASK	(0x3F)
-#define PLL90XX_SDIV_MASK	(0x7)
-#define PLL90XX_KDIV_MASK	(0xffff)
-#define PLL90XX_MDIV_SHIFT	(16)
-#define PLL90XX_PDIV_SHIFT	(8)
-#define PLL90XX_SDIV_SHIFT	(0)
-#define PLL90XX_KDIV_SHIFT	(0)
-
-static inline unsigned long s5p_get_pll90xx(unsigned long baseclk,
-					    u32 pll_con, u32 pll_conk)
-{
-	unsigned long result;
-	u32 mdiv, pdiv, sdiv, kdiv;
-	u64 tmp;
-
-	mdiv = (pll_con >> PLL90XX_MDIV_SHIFT) & PLL90XX_MDIV_MASK;
-	pdiv = (pll_con >> PLL90XX_PDIV_SHIFT) & PLL90XX_PDIV_MASK;
-	sdiv = (pll_con >> PLL90XX_SDIV_SHIFT) & PLL90XX_SDIV_MASK;
-	kdiv = pll_conk & PLL90XX_KDIV_MASK;
-
-	/* We need to multiple baseclk by mdiv (the integer part) and kdiv
-	 * which is in 2^16ths, so shift mdiv up (does not overflow) and
-	 * add kdiv before multiplying. The use of tmp is to avoid any
-	 * overflows before shifting bac down into result when multipling
-	 * by the mdiv and kdiv pair.
-	 */
-
-	tmp = baseclk;
-	tmp *= (mdiv << 16) + kdiv;
-	do_div(tmp, (pdiv << sdiv));
-	result = tmp >> 16;
-
-	return result;
-}
-
-#define PLL65XX_MDIV_MASK	(0x3FF)
-#define PLL65XX_PDIV_MASK	(0x3F)
-#define PLL65XX_SDIV_MASK	(0x7)
-#define PLL65XX_MDIV_SHIFT	(16)
-#define PLL65XX_PDIV_SHIFT	(8)
-#define PLL65XX_SDIV_SHIFT	(0)
-
-static inline unsigned long s5p_get_pll65xx(unsigned long baseclk, u32 pll_con)
-{
-	u32 mdiv, pdiv, sdiv;
-	u64 fvco = baseclk;
+extern unsigned long s5p_get_pll90xx(unsigned long baseclk, u32 pll_con,
+				     u32 pll_conk);
+extern int pll90xx_epll_set_rate(struct clk *clk, unsigned long rate);
 
-	mdiv = (pll_con >> PLL65XX_MDIV_SHIFT) & PLL65XX_MDIV_MASK;
-	pdiv = (pll_con >> PLL65XX_PDIV_SHIFT) & PLL65XX_PDIV_MASK;
-	sdiv = (pll_con >> PLL65XX_SDIV_SHIFT) & PLL65XX_SDIV_MASK;
+extern unsigned long s5p_get_pll46xx(unsigned long baseclk,
+				     u32 pll_con0, u32 pll_con1,
+				     enum pll46xx_type_t pll_type);
+extern int pll46xx_epll_set_rate(struct clk *clk, unsigned long rate);
 
-	fvco *= mdiv;
-	do_div(fvco, (pdiv << sdiv));
+extern unsigned long s5p_get_pll45xx(unsigned long baseclk, u32 pll_con,
+				     enum pll45xx_type_t pll_type);
+extern int pll65xx_epll_set_rate(struct clk *clk, unsigned long rate);
+extern unsigned long s5p_get_pll65xx(unsigned long baseclk, u32 pll_con);
 
-	return (unsigned long)fvco;
-}
+#endif /* __PLAT_S5P_PLL_H */
diff --git a/arch/arm/plat-s5p/pll_45xx.c b/arch/arm/plat-s5p/pll_45xx.c
new file mode 100644
index 0000000..4f4243b
--- /dev/null
+++ b/arch/arm/plat-s5p/pll_45xx.c
@@ -0,0 +1,50 @@
+/* arch/arm/plat-s5p/pll_45xx.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5P PLL45XX code
+ *
+ * splitting arch/arm/plat-s5p/include/plat/pll.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/s5p-clock.h>
+#include <plat/pll.h>
+
+#define PLL45XX_MDIV_MASK	(0x3FF)
+#define PLL45XX_PDIV_MASK	(0x3F)
+#define PLL45XX_SDIV_MASK	(0x7)
+#define PLL45XX_MDIV_SHIFT	(16)
+#define PLL45XX_PDIV_SHIFT	(8)
+#define PLL45XX_SDIV_SHIFT	(0)
+
+#include <asm/div64.h>
+
+unsigned long s5p_get_pll45xx(unsigned long baseclk, u32 pll_con,
+			      enum pll45xx_type_t pll_type)
+{
+	u32 mdiv, pdiv, sdiv;
+	u64 fvco = baseclk;
+
+	mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
+	pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
+	sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
+
+	if (pll_type == pll_4508)
+		sdiv = sdiv - 1;
+
+	fvco *= mdiv;
+	do_div(fvco, (pdiv << sdiv));
+
+	return (unsigned long)fvco;
+}
diff --git a/arch/arm/plat-s5p/pll_46xx.c b/arch/arm/plat-s5p/pll_46xx.c
new file mode 100644
index 0000000..e956d05
--- /dev/null
+++ b/arch/arm/plat-s5p/pll_46xx.c
@@ -0,0 +1,138 @@
+/* arch/arm/plat-s5p/pll_46xx.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5P PLL46XX code
+ *
+ * splitting arch/arm/plat-s5p/include/plat/pll.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/s5p-clock.h>
+#include <plat/pll.h>
+
+#define PLL46XX_KDIV_MASK	(0xFFFF)
+#define PLL4650C_KDIV_MASK	(0xFFF)
+#define PLL46XX_MDIV_MASK	(0x1FF)
+#define PLL46XX_PDIV_MASK	(0x3F)
+#define PLL46XX_SDIV_MASK	(0x7)
+#define PLL46XX_VSEL_EN		(1)
+#define PLL46XX_VSEL_SHFIT	(27)
+#define PLL46XX_MDIV_SHIFT	(16)
+#define PLL46XX_PDIV_SHIFT	(8)
+#define PLL46XX_SDIV_SHIFT	(0)
+#define PLL46XX_KDIV_SHIFT	(0)
+
+static u32 epll_div[][6] = {
+	{  48000000, 0, 48, 3, 3, 0 },
+	{  96000000, 0, 48, 3, 2, 0 },
+	{ 144000000, 1, 72, 3, 2, 0 },
+	{ 192000000, 0, 48, 3, 1, 0 },
+	{ 288000000, 1, 72, 3, 1, 0 },
+	{  32750000, 1, 65, 3, 4, 35127 },
+	{  32768000, 1, 65, 3, 4, 35127 },
+	{  45158400, 0, 45, 3, 3, 10355 },
+	{  45000000, 0, 45, 3, 3, 10355 },
+	{  45158000, 0, 45, 3, 3, 10355 },
+	{  49125000, 0, 49, 3, 3, 9961 },
+	{  49152000, 0, 49, 3, 3, 9961 },
+	{  67737600, 1, 67, 3, 3, 48366 },
+	{  67738000, 1, 67, 3, 3, 48366 },
+	{  73800000, 1, 73, 3, 3, 47710 },
+	{  73728000, 1, 73, 3, 3, 47710 },
+	{  36000000, 1, 32, 3, 4, 0 },
+	{  60000000, 1, 60, 3, 3, 0 },
+	{  72000000, 1, 72, 3, 3, 0 },
+	{  80000000, 1, 80, 3, 3, 0 },
+	{  84000000, 0, 42, 3, 2, 0 },
+	{  50000000, 0, 50, 3, 3, 0 },
+};
+
+int pll46xx_epll_set_rate(struct clk *clk, unsigned long rate)
+{
+	int i;
+	unsigned int con0, con1;
+
+	/* Return if nothing changed */
+	if (clk->rate == rate)
+		return 0;
+
+	con0 = __raw_readl(S5P_EPLL_CON);
+	con1 = __raw_readl(S5P_EPLL_CON1);
+
+	con0 &= ~(PLL46XX_VSEL_EN << PLL46XX_VSEL_SHFIT |
+		  PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT |
+		  PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT |
+		  PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
+	con1 &= ~PLL46XX_KDIV_MASK;
+
+	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
+		if (epll_div[i][0] == rate) {
+			con1 |= epll_div[i][5] << PLL46XX_KDIV_SHIFT;
+			con0 |= (epll_div[i][1] << PLL46XX_VSEL_SHFIT |
+				 epll_div[i][2] << PLL46XX_MDIV_SHIFT |
+				 epll_div[i][3] << PLL46XX_PDIV_SHIFT |
+				 epll_div[i][4] << PLL46XX_SDIV_SHIFT);
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(epll_div)) {
+		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
+		return -EINVAL;
+	}
+
+	__raw_writel(con0, S5P_EPLL_CON);
+	__raw_writel(con1, S5P_EPLL_CON1);
+
+	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
+			clk->rate, rate);
+
+	clk->rate = rate;
+
+	return 0;
+}
+
+unsigned long s5p_get_pll46xx(unsigned long baseclk,
+			      u32 pll_con0, u32 pll_con1,
+			      enum pll46xx_type_t pll_type)
+{
+	unsigned long result;
+	u32 mdiv, pdiv, sdiv, kdiv;
+	u64 tmp;
+
+	mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
+	pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
+	sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
+	kdiv = pll_con1 & PLL46XX_KDIV_MASK;
+
+	if (pll_type == pll_4650c)
+		kdiv = pll_con1 & PLL4650C_KDIV_MASK;
+	else
+		kdiv = pll_con1 & PLL46XX_KDIV_MASK;
+
+	tmp = baseclk;
+
+	if (pll_type == pll_4600) {
+		tmp *= (mdiv << 16) + kdiv;
+		do_div(tmp, (pdiv << sdiv));
+		result = tmp >> 16;
+	} else {
+		tmp *= (mdiv << 10) + kdiv;
+		do_div(tmp, (pdiv << sdiv));
+		result = tmp >> 10;
+	}
+
+	return result;
+}
+
diff --git a/arch/arm/plat-s5p/pll_65xx.c b/arch/arm/plat-s5p/pll_65xx.c
new file mode 100644
index 0000000..480ca4b
--- /dev/null
+++ b/arch/arm/plat-s5p/pll_65xx.c
@@ -0,0 +1,102 @@
+/* arch/arm/plat-s5p/pll_65xx.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5P PLL65XX code
+ *
+ * splitting arch/arm/plat-s5p/include/plat/pll.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/s5p-clock.h>
+#include <plat/pll.h>
+
+#define PLL65XX_MDIV_MASK	(0x3FF)
+#define PLL65XX_PDIV_MASK	(0x3F)
+#define PLL65XX_SDIV_MASK	(0x7)
+#define PLL65XX_MDIV_SHIFT	(16)
+#define PLL65XX_PDIV_SHIFT	(8)
+#define PLL65XX_SDIV_SHIFT	(0)
+
+static u32 epll_div[][4] = {
+	{ 32750000,	131, 3, 4 },
+	{ 32768000,	131, 3, 4 },
+	{ 36000000,	72,  3, 3 },
+	{ 45000000,	90,  3, 3 },
+	{ 45158000,	90,  3, 3 },
+	{ 45158400,	90,  3, 3 },
+	{ 48000000,	96,  3, 3 },
+	{ 49125000,	131, 4, 3 },
+	{ 49152000,	131, 4, 3 },
+	{ 60000000,	120, 3, 3 },
+	{ 67737600,	226, 5, 3 },
+	{ 67738000,	226, 5, 3 },
+	{ 73800000,	246, 5, 3 },
+	{ 73728000,	246, 5, 3 },
+	{ 72000000,	144, 3, 3 },
+	{ 84000000,	168, 3, 3 },
+	{ 96000000,	96,  3, 2 },
+	{ 144000000,	144, 3, 2 },
+	{ 192000000,	96,  3, 1 }
+};
+
+int pll65xx_epll_set_rate(struct clk *clk, unsigned long rate)
+{
+	int i;
+	unsigned int con;
+
+	if (clk->rate == rate)	/* Return if nothing changed */
+		return 0;
+
+	con = __raw_readl(S5P_EPLL_CON);
+
+	con &= ~(PLL65XX_MDIV_MASK | PLL65XX_PDIV_MASK | PLL65XX_SDIV_MASK);
+
+	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
+		if (epll_div[i][0] == rate) {
+			con |= (epll_div[i][1] << PLL65XX_MDIV_SHIFT) |
+			       (epll_div[i][2] << PLL65XX_PDIV_SHIFT) |
+			       (epll_div[i][3] << PLL65XX_SDIV_SHIFT);
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(pll65xx_epll_div)) {
+		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
+		return -EINVAL;
+	}
+
+	__raw_writel(con, S5P_EPLL_CON);
+
+	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
+			clk->rate, rate);
+
+	clk->rate = rate;
+
+	return 0;
+}
+
+unsigned long s5p_get_pll65xx(unsigned long baseclk, u32 pll_con)
+{
+	u32 mdiv, pdiv, sdiv;
+	u64 fvco = baseclk;
+
+	mdiv = (pll_con >> PLL65XX_MDIV_SHIFT) & PLL65XX_MDIV_MASK;
+	pdiv = (pll_con >> PLL65XX_PDIV_SHIFT) & PLL65XX_PDIV_MASK;
+	sdiv = (pll_con >> PLL65XX_SDIV_SHIFT) & PLL65XX_SDIV_MASK;
+
+	fvco *= mdiv;
+	do_div(fvco, (pdiv << sdiv));
+
+	return (unsigned long)fvco;
+}
diff --git a/arch/arm/plat-s5p/pll_90xx.c b/arch/arm/plat-s5p/pll_90xx.c
new file mode 100644
index 0000000..e0e2cac
--- /dev/null
+++ b/arch/arm/plat-s5p/pll_90xx.c
@@ -0,0 +1,115 @@
+/* arch/arm/plat-s5p/pll_90xx.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5P PLL90XX code
+ *
+ * splitting arch/arm/plat-s5p/include/plat/pll.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/s5p-clock.h>
+#include <plat/pll.h>
+
+#define PLL90XX_MDIV_MASK	(0xFF)
+#define PLL90XX_PDIV_MASK	(0x3F)
+#define PLL90XX_SDIV_MASK	(0x7)
+#define PLL90XX_KDIV_MASK	(0xffff)
+#define PLL90XX_MDIV_SHIFT	(16)
+#define PLL90XX_PDIV_SHIFT	(8)
+#define PLL90XX_SDIV_SHIFT	(0)
+#define PLL90XX_KDIV_SHIFT	(0)
+
+static u32 epll_div[][5] = {
+	{ 36000000,	0,	48, 1, 4 },
+	{ 48000000,	0,	32, 1, 3 },
+	{ 60000000,	0,	40, 1, 3 },
+	{ 72000000,	0,	48, 1, 3 },
+	{ 84000000,	0,	28, 1, 2 },
+	{ 96000000,	0,	32, 1, 2 },
+	{ 32768000,	45264,	43, 1, 4 },
+	{ 45158000,	6903,	30, 1, 3 },
+	{ 49152000,	50332,	32, 1, 3 },
+	{ 67738000,	10398,	45, 1, 3 },
+	{ 73728000,	9961,	49, 1, 3 },
+	{ 100000000,	43691,	41, 2, 2 },
+	{ 133000000,	27307,	55, 2, 2 },
+	{ 480000000,	0,	80, 2, 0 },
+};
+
+int pll90xx_epll_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned int con, con_k;
+	int i;
+
+	if (clk->rate == rate)	/* Return if nothing changed */
+		return 0;
+
+	con = __raw_readl(S5P_EPLL_CON);
+	con_k = __raw_readl(S5P_EPLL_CON1);
+
+	con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
+	con_k &= ~(PLL90XX_KDIV_MASK);
+
+	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
+		if (epll_div[i][0] == rate) {
+			con_k |= epll_div[i][1] << PLL90XX_KDIV_SHIFT;
+			con |=	(epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
+				(epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
+				(epll_div[i][4] << PLL90XX_SDIV_SHIFT);
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(epll_div)) {
+		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
+		return -EINVAL;
+	}
+
+	__raw_writel(con, S5P_EPLL_CON);
+	__raw_writel(con_k, S5P_EPLL_CON1);
+
+	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
+			clk->rate, rate);
+
+	clk->rate = rate;
+
+	return 0;
+}
+
+unsigned long s5p_get_pll90xx(unsigned long baseclk, u32 pll_con,
+			      u32 pll_conk)
+{
+	unsigned long result;
+	u32 mdiv, pdiv, sdiv, kdiv;
+	u64 tmp;
+
+	mdiv = (pll_con >> PLL90XX_MDIV_SHIFT) & PLL90XX_MDIV_MASK;
+	pdiv = (pll_con >> PLL90XX_PDIV_SHIFT) & PLL90XX_PDIV_MASK;
+	sdiv = (pll_con >> PLL90XX_SDIV_SHIFT) & PLL90XX_SDIV_MASK;
+	kdiv = pll_conk & PLL90XX_KDIV_MASK;
+
+	/* We need to multiple baseclk by mdiv (the integer part) and kdiv
+	 * which is in 2^16ths, so shift mdiv up (does not overflow) and
+	 * add kdiv before multiplying. The use of tmp is to avoid any
+	 * overflows before shifting bac down into result when multipling
+	 * by the mdiv and kdiv pair.
+	 */
+
+	tmp = baseclk;
+	tmp *= (mdiv << 16) + kdiv;
+	do_div(tmp, (pdiv << sdiv));
+	result = tmp >> 16;
+
+	return result;
+}
-- 
1.7.2.3

