
On 22 August 2012 12:14, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds clock support for I2S
Signed-off-by: R. Chandrasekar rcsekar@samsung.com Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Changes in V2:
- None
arch/arm/cpu/armv7/exynos/clock.c | 119 ++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/clk.h | 3 + arch/arm/include/asm/arch-exynos/clock.h | 29 +++++++ 3 files changed, 151 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 44dff2b..691f6d4 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -26,6 +26,16 @@ #include <asm/arch/clock.h> #include <asm/arch/clk.h>
+/* Epll Clock division values to achive different frequency output */ +static struct st_epll_con_val 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 }
+};
Are these division values common to Exynos or only for exynos-5.
/* exynos4: return pll clock frequency */ static unsigned long exynos4_get_pll_clk(int pllreg) { @@ -848,6 +858,92 @@ static int exynos5_spi_set_clock_rate(enum periph_id periph_id, return 0; }
+int exynos5_clock_epll_set_rate(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(epll_div); i++) {
if (epll_div[i].freq_out == rate)
break;
}
if (i == ARRAY_SIZE(epll_div))
return -1;
epll_con_k = epll_div[i].k_dsm << 0;
epll_con |= epll_div[i].en_lock_det << EPLL_CON0_LOCK_DET_EN_SHIFT;
epll_con |= epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
epll_con |= epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
epll_con |= 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 * 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_clock_select_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_clock_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()) @@ -927,3 +1023,26 @@ int spi_set_clock_rate(enum periph_id periph_id, unsigned int rate) else return 0; }
+int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq) +{
if (cpu_is_exynos5())
return exynos5_clock_set_i2s_clk_prescaler(src_frq, dst_frq);
else
return 0;
+}
+void clock_select_i2s_clk_source(void) +{
if (cpu_is_exynos5())
exynos5_clock_select_i2s_clk_source();
+}
+int clock_epll_set_rate(unsigned long rate) +{
if (cpu_is_exynos5())
return exynos5_clock_epll_set_rate(rate);
else
return 0;
+} diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 4e51402..f32c634 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -41,4 +41,7 @@ unsigned long get_lcd_clk(void); void set_lcd_clk(void); void set_mipi_clk(void); int spi_set_clock_rate(enum periph_id periph_id, unsigned int rate); +void clock_select_i2s_clk_source(void); +int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); +int clock_epll_set_rate(unsigned long rate); #endif diff --git a/arch/arm/include/asm/arch-exynos/clock.h b/arch/arm/include/asm/arch-exynos/clock.h index fce38ef..1df49a9 100644 --- a/arch/arm/include/asm/arch-exynos/clock.h +++ b/arch/arm/include/asm/arch-exynos/clock.h @@ -595,9 +595,38 @@ struct exynos5_clock { unsigned int pll_div2_sel; unsigned char res123[0xf5d8]; };
+/* structure for epll configuration used in audio clock configuration */ +struct st_epll_con_val {
unsigned int freq_out; /* frequency out */
unsigned int en_lock_det; /* enable lock detect */
unsigned int m_div; /* m divider value */
unsigned int p_div; /* p divider value */
unsigned int s_div; /* s divider value */
unsigned int k_dsm; /* k value of delta signal modulator */
+}; #endif
#define MPLL_FOUT_SEL_SHIFT 4 +#define EXYNOS5_EPLLCON0_LOCKED_SHIFT 29 /* EPLL Locked bit position*/ +#define TIMEOUT_EPLL_LOCK 1000
+#define AUDIO_0_RATIO_MASK 0x0f +#define AUDIO_1_RATIO_MASK 0x0f
+#define AUDIO1_SEL_MASK 0xf +#define CLK_SRC_SCLK_EPLL 0x7
+/* CON0 bit-fields */ +#define EPLL_CON0_MDIV_MASK 0x1ff +#define EPLL_CON0_PDIV_MASK 0x3f +#define EPLL_CON0_SDIV_MASK 0x7 +#define EPLL_CON0_MDIV_SHIFT 16 +#define EPLL_CON0_PDIV_SHIFT 8 +#define EPLL_CON0_SDIV_SHIFT 0 +#define EPLL_CON0_LOCK_DET_EN_SHIFT 28 +#define EPLL_CON0_LOCK_DET_EN_MASK 1
#define MPLL_FOUT_SEL_MASK 0x1 #define BPLL_FOUT_SEL_SHIFT 0
#define BPLL_FOUT_SEL_MASK 0x1
1.7.4.4