1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 by Michael Sevakis
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
30 /* PCM interrupt routine lockout */
41 #define FIFO_COUNT ((IISFCON >> 6) & 0x3F)
43 /* Setup for the DMA controller */
44 #define DMA_CONTROL_SETUP ((1<<31) | (1<<29) | (1<<23) | (1<<22) | (1<<20))
47 /* for PCLK = 50 MHz, frame size = 32 */
48 /* [prescaler, master clock rate] */
49 static const unsigned char pcm_freq_parms
[HW_NUM_FREQ
][2] =
51 [HW_FREQ_44
] = { 2, IISMOD_MASTER_CLOCK_384FS
},
52 [HW_FREQ_22
] = { 8, IISMOD_MASTER_CLOCK_256FS
},
53 [HW_FREQ_11
] = { 17, IISMOD_MASTER_CLOCK_256FS
},
57 /* DMA count has hit zero - no more data */
58 /* Get more data from the callback and top off the FIFO */
59 void fiq_handler(void) __attribute__((interrupt ("FIQ")));
61 /* Mask the DMA interrupt */
62 void pcm_play_lock(void)
64 if (++dma_play_lock
.locked
== 1)
65 s3c_regset32(&INTMSK
, DMA2_MASK
);
68 /* Unmask the DMA interrupt if enabled */
69 void pcm_play_unlock(void)
71 if (--dma_play_lock
.locked
== 0)
72 s3c_regclr32(&INTMSK
, dma_play_lock
.state
);
75 void pcm_play_dma_init(void)
77 /* There seem to be problems when changing the IIS interface configuration
78 * when a clock is not present.
80 s3c_regset32(&CLKCON
, 1<<17);
83 /* master, transmit mode, 16 bit samples, BCLK 32fs, PCLK */
84 IISMOD
= IISMOD_MASTER_CLOCK_PCLK
| IISMOD_MASTER_MODE
| IISMOD_TRANSMIT_MODE
85 | IISMOD_16_BIT
| IISMOD_MASTER_CLOCK_256FS
| IISMOD_BIT_CLOCK_32FS
;
87 /* TX idle, enable prescaler */
88 IISCON
|= IISCON_TX_IDLE
| IISCON_IIS_PRESCALER_ENABLE
;
90 /* slave, transmit mode, 16 bit samples - MCLK 384fs - use 16.9344Mhz -
92 IISMOD
= (1<<9) | (1<<8) | (2<<6) | (1<<3) | (1<<2) | (1<<0);
95 IISCON
|= (1<<3) | (1<<2);
98 s3c_regclr32(&CLKCON
, 1<<17);
104 /* GPCCON = (GPCCON & ~(3<<14)) | (1<<14); */
105 S3C244_GPIO_CONFIG (GPCCON
, 7, GPIO_OUTPUT
);
109 /* GPE4=I2SDO, GPE3=I2SDI, GPE2=CDCLK, GPE1=I2SSCLK, GPE0=I2SLRCK */
110 GPECON
= (GPECON
& ~0x3ff) | 0x2aa;
112 /* Do not service DMA requests, yet */
114 /* clear any pending int and mask it */
115 s3c_regset32(&INTMSK
, DMA2_MASK
);
119 s3c_regset32(&INTMOD
, DMA2_MASK
);
122 void pcm_postinit(void)
127 void pcm_dma_apply_settings(void)
130 unsigned int reg_val
;
131 /* set prescaler and master clock rate according to freq */
132 reg_val
= (pcm_freq_parms
[pcm_fsel
][0] << 5) | pcm_freq_parms
[pcm_fsel
][0];
134 IISMOD
= (IISMOD
& ~IISMOD_MASTER_CLOCK_384FS
) | pcm_freq_parms
[pcm_fsel
][1] ;
138 audiohw_set_frequency(pcm_fsel
);
141 /* Connect the DMA and start filling the FIFO */
142 static void play_start_pcm(void)
144 /* clear pending DMA interrupt */
147 /* Flush any pending writes */
148 clean_dcache_range((char*)DISRC2
-0x30000000, (DCON2
& 0xFFFFF) * 2);
150 /* unmask DMA interrupt when unlocking */
151 dma_play_lock
.state
= DMA2_MASK
;
153 /* turn on the request */
156 /* Activate the channel */
159 /* turn off the idle */
163 IISMOD
= (IISMOD
& ~IISMOD_MASTER_CLOCK_384FS
) | pcm_freq_parms
[pcm_fsel
][1] ;
164 IISPSR
= (pcm_freq_parms
[pcm_fsel
][0] << 5) | pcm_freq_parms
[pcm_fsel
][0];
171 /* Disconnect the DMA and wait for the FIFO to clear */
172 static void play_stop_pcm(void)
174 /* Mask DMA interrupt */
175 s3c_regset32(&INTMSK
, DMA2_MASK
);
177 /* De-Activate the DMA channel */
180 /* are we playing? wait for the chunk to finish */
181 if (dma_play_lock
.state
!= 0)
183 /* wait for the FIFO to empty and DMA to stop */
184 while ((IISCON
& (1<<7)) || (DMASKTRIG2
& 0x2));
187 /* Keep interrupt masked when unlocking */
188 dma_play_lock
.state
= 0;
190 /* turn off the request */
193 /* turn on the idle */
200 void pcm_play_dma_start(const void *addr
, size_t size
)
202 /* Enable the IIS clock */
203 s3c_regset32(&CLKCON
, 1<<17);
205 /* stop any DMA in progress - idle IIS */
208 /* connect DMA to the FIFO and enable the FIFO */
209 IISFCON
= (1<<15) | (1<<13);
212 DIDST2
= (unsigned int)&IISFIFO
;
214 /* IIS is on the APB bus, INT when TC reaches 0, fixed dest addr */
217 /* set DMA source and options */
218 DISRC2
= (unsigned int)addr
+ 0x30000000;
219 /* How many transfers to make - we transfer half-word at a time = 2 bytes */
220 /* DMA control: CURR_TC int, single service mode, I2SSDO int, HW trig */
221 /* no auto-reload, half-word (16bit) */
222 DCON2
= DMA_CONTROL_SETUP
| (size
/ 2);
223 DISRCC2
= 0x00; /* memory is on AHB bus, increment addresses */
228 /* Promptly stop DMA transfers and stop IIS */
229 void pcm_play_dma_stop(void)
233 /* Disconnect the IIS clock */
234 s3c_regclr32(&CLKCON
, 1<<17);
237 void pcm_play_dma_pause(bool pause
)
241 /* pause playback on current buffer */
246 /* restart playback on current buffer */
247 /* make sure we're aligned on left channel - skip any right
248 channel sample left waiting */
249 DISRC2
= (DCSRC2
+ 2) & ~0x3;
250 DCON2
= DMA_CONTROL_SETUP
| (DSTAT2
& 0xFFFFE);
255 void fiq_handler(void)
260 /* clear any pending interrupt */
263 /* Buffer empty. Try to get more. */
264 pcm_play_get_more_callback(&start
, &size
);
269 /* Flush any pending cache writes */
270 clean_dcache_range(start
, size
);
272 /* set the new DMA values */
273 DCON2
= DMA_CONTROL_SETUP
| (size
>> 1);
274 DISRC2
= (unsigned int)start
+ 0x30000000;
276 /* Re-Activate the channel */
280 size_t pcm_get_bytes_waiting(void)
282 /* lie a little and only return full pairs */
283 return (DSTAT2
& 0xFFFFE) * 2;
286 const void * pcm_play_dma_get_peak_buffer(int *count
)
288 unsigned long addr
= DCSRC2
;
290 *count
= (cnt
& 0xFFFFF) >> 1;
291 return (void *)((addr
+ 2) & ~3);