summaryrefslogtreecommitdiff
path: root/arch/arm/cpu/armv7
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/cpu/armv7')
-rw-r--r--arch/arm/cpu/armv7/exynos/clock.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c
index a042423..40a8c71 100644
--- a/arch/arm/cpu/armv7/exynos/clock.c
+++ b/arch/arm/cpu/armv7/exynos/clock.c
@@ -26,6 +26,17 @@
#include <asm/arch/clock.h>
#include <asm/arch/clk.h>
+/* Epll Clock division values to achive different frequency output */
+static struct set_epll_con_val exynos5_epll_div[] = {
+ { 192000000, 0, 48, 3, 1, 0 },
+ { 180000000, 0, 45, 3, 1, 0 },
+ { 73728000, 1, 73, 3, 3, 47710 },
+ { 67737600, 1, 90, 4, 3, 20762 },
+ { 49152000, 0, 49, 3, 3, 9961 },
+ { 45158400, 0, 45, 3, 3, 10381 },
+ { 180633600, 0, 45, 3, 1, 10381 }
+};
+
/* exynos: return pll clock frequency */
static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k)
{
@@ -706,6 +717,93 @@ static unsigned long exynos5_get_i2c_clk(void)
return aclk_66;
}
+int exynos5_set_epll_clk(unsigned long rate)
+{
+ unsigned int epll_con, epll_con_k;
+ unsigned int i;
+ unsigned int lockcnt;
+ unsigned int start;
+ struct exynos5_clock *clk =
+ (struct exynos5_clock *)samsung_get_base_clock();
+
+ epll_con = readl(&clk->epll_con0);
+ epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
+ EPLL_CON0_LOCK_DET_EN_SHIFT) |
+ EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT |
+ EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT |
+ EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT);
+
+ for (i = 0; i < ARRAY_SIZE(exynos5_epll_div); i++) {
+ if (exynos5_epll_div[i].freq_out == rate)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(exynos5_epll_div))
+ return -1;
+
+ epll_con_k = exynos5_epll_div[i].k_dsm << 0;
+ epll_con |= exynos5_epll_div[i].en_lock_det <<
+ EPLL_CON0_LOCK_DET_EN_SHIFT;
+ epll_con |= exynos5_epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
+ epll_con |= exynos5_epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
+ epll_con |= exynos5_epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT;
+
+ /*
+ * Required period ( in cycles) to genarate a stable clock output.
+ * The maximum clock time can be up to 3000 * PDIV cycles of PLLs
+ * frequency input (as per spec)
+ */
+ lockcnt = 3000 * exynos5_epll_div[i].p_div;
+
+ writel(lockcnt, &clk->epll_lock);
+ writel(epll_con, &clk->epll_con0);
+ writel(epll_con_k, &clk->epll_con1);
+
+ start = get_timer(0);
+
+ while (!(readl(&clk->epll_con0) &
+ (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
+ if (get_timer(start) > TIMEOUT_EPLL_LOCK) {
+ debug("%s: Timeout waiting for EPLL lock\n", __func__);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void exynos5_set_i2s_clk_source(void)
+{
+ struct exynos5_clock *clk =
+ (struct exynos5_clock *)samsung_get_base_clock();
+
+ clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
+ (CLK_SRC_SCLK_EPLL));
+}
+
+int exynos5_set_i2s_clk_prescaler(unsigned int src_frq,
+ unsigned int dst_frq)
+{
+ struct exynos5_clock *clk =
+ (struct exynos5_clock *)samsung_get_base_clock();
+ unsigned int div;
+
+ if ((dst_frq == 0) || (src_frq == 0)) {
+ debug("%s: Invalid requency input for prescaler\n", __func__);
+ debug("src frq = %d des frq = %d ", src_frq, dst_frq);
+ return -1;
+ }
+
+ div = (src_frq / dst_frq);
+ if (div > AUDIO_1_RATIO_MASK) {
+ debug("%s: Frequency ratio is out of range\n", __func__);
+ debug("src frq = %d des frq = %d ", src_frq, dst_frq);
+ return -1;
+ }
+ clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
+ (div & AUDIO_1_RATIO_MASK));
+ return 0;
+}
+
unsigned long get_pll_clk(int pllreg)
{
if (cpu_is_exynos5())
@@ -777,3 +875,26 @@ void set_mipi_clk(void)
if (cpu_is_exynos4())
exynos4_set_mipi_clk();
}
+
+int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
+{
+
+ if (cpu_is_exynos5())
+ return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq);
+ else
+ return 0;
+}
+
+void set_i2s_clk_source(void)
+{
+ if (cpu_is_exynos5())
+ exynos5_set_i2s_clk_source();
+}
+
+int set_epll_clk(unsigned long rate)
+{
+ if (cpu_is_exynos5())
+ return exynos5_set_epll_clk(rate);
+ else
+ return 0;
+}