summaryrefslogtreecommitdiff
path: root/firmware/target/arm/rk27xx/pcm-rk27xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/rk27xx/pcm-rk27xx.c')
-rw-r--r--firmware/target/arm/rk27xx/pcm-rk27xx.c62
1 files changed, 59 insertions, 3 deletions
diff --git a/firmware/target/arm/rk27xx/pcm-rk27xx.c b/firmware/target/arm/rk27xx/pcm-rk27xx.c
index b8ae56adaf..80a8d462ea 100644
--- a/firmware/target/arm/rk27xx/pcm-rk27xx.c
+++ b/firmware/target/arm/rk27xx/pcm-rk27xx.c
@@ -8,6 +8,7 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2011 Marcin Bukat 10 * Copyright (C) 2011 Marcin Bukat
11 * Copyright (C) 2011 Andrew Ryabinin
11 * 12 *
12 * This program is free software; you can redistribute it and/or 13 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 14 * modify it under the terms of the GNU General Public License
@@ -179,13 +180,65 @@ static void i2s_init(void)
179 (0<<2) | /* normal operation */ 180 (0<<2) | /* normal operation */
180#ifdef CODEC_SLAVE 181#ifdef CODEC_SLAVE
181 (1<<1) | /* start Tx (master mode) */ 182 (1<<1) | /* start Tx (master mode) */
182 (1<<0); /* start Rx (master mode) */ 183 (0<<0); /* do not start Rx (master mode) */
184 /* setting Rx bit to 1 result in choppy audio */
183#else 185#else
184 (0<<1) | /* not used in slave mode */ 186 (0<<1) | /* not used in slave mode */
185 (0<<0); /* not used in slave mode */ 187 (0<<0); /* not used in slave mode */
186#endif 188#endif
187} 189}
188 190
191#ifdef CODEC_SLAVE
192/* When codec is slave we need to setup i2s MCLK clock using codec pll.
193 * The MCLK frequency is 256*codec frequency as i2s setup is:
194 * LRCK/SCLK = 64 and MCLK/SCLK = 4 (see i2s_init() for reference)
195 *
196 * PLL output frequency:
197 * Fout = ((Fref / (CLKR+1)) * (CLKF+1)) / (CLKOD+1)
198 * Fref = 24 MHz
199 */
200static void set_codec_freq(unsigned int freq)
201{
202 long timeout;
203
204 /* {CLKR, CLKF, CLKOD, CODECPLL_DIV} */
205 static const unsigned int pcm_freq_params[HW_NUM_FREQ][4] =
206 {
207 [HW_FREQ_96] = {24, 255, 4, 1},
208 [HW_FREQ_48] = {24, 127, 4, 1},
209 [HW_FREQ_44] = {24, 293, 4, 4},
210 [HW_FREQ_32] = {24, 127, 4, 2},
211 [HW_FREQ_24] = {24, 127, 4, 3},
212 [HW_FREQ_22] = {24, 146, 4, 4},
213 [HW_FREQ_16] = {24, 127, 5, 4},
214 [HW_FREQ_12] = {24, 127, 4, 7},
215 [HW_FREQ_11] = {24, 146, 4, 9},
216 [HW_FREQ_8] = {24, 127, 5, 9},
217 };
218 /* select divider output from codec pll */
219 SCU_DIVCON1 &= ~((1<<9) | (0xF<<5));
220 SCU_DIVCON1 |= (pcm_freq_params[freq][3]<<5);
221
222 /* Codec PLL power up */
223 SCU_PLLCON3 &= ~(1<<22);
224
225 SCU_PLLCON3 = (1<<24) | /* Saturation behavior enable */
226 (1<<23) | /* Enable fast locking circuit */
227 (pcm_freq_params[freq][0]<<16) | /* CLKR factor */
228 (pcm_freq_params[freq][1]<<4) | /* CLKF factor */
229 (pcm_freq_params[freq][2]<<1) ; /* CLKOD factor */
230
231/* wait for CODEC PLL lock with 10 ms timeout
232 * datasheet states that pll lock should take approx. 0.3 ms
233 */
234 timeout = current_tick + (HZ/100);
235 while (!(SCU_STATUS & (1<<2)))
236 if (TIME_AFTER(current_tick, timeout))
237 break;
238
239}
240#endif
241
189void pcm_play_dma_init(void) 242void pcm_play_dma_init(void)
190{ 243{
191 /* unmask HDMA interrupt in INTC */ 244 /* unmask HDMA interrupt in INTC */
@@ -204,8 +257,11 @@ void pcm_play_dma_postinit(void)
204 257
205void pcm_dma_apply_settings(void) 258void pcm_dma_apply_settings(void)
206{ 259{
207 /* I2S module runs in slave mode */ 260#ifdef CODEC_SLAVE
208 return; 261 set_codec_freq(pcm_fsel);
262#endif
263
264 audiohw_set_frequency(pcm_fsel);
209} 265}
210 266
211size_t pcm_get_bytes_waiting(void) 267size_t pcm_get_bytes_waiting(void)