summaryrefslogtreecommitdiff
path: root/firmware/target/coldfire/pcm-coldfire.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/coldfire/pcm-coldfire.c')
-rw-r--r--firmware/target/coldfire/pcm-coldfire.c738
1 files changed, 738 insertions, 0 deletions
diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c
new file mode 100644
index 0000000000..6b92f9cc14
--- /dev/null
+++ b/firmware/target/coldfire/pcm-coldfire.c
@@ -0,0 +1,738 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Michael Sevakis
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include <stdlib.h>
20#include "system.h"
21#include "kernel.h"
22#include "logf.h"
23#include "audio.h"
24#if defined(HAVE_UDA1380)
25#include "uda1380.h"
26#elif defined(HAVE_TLV320)
27#include "tlv320.h"
28#endif
29
30/* Avoid further #ifdef's for some codec functions */
31#if defined(HAVE_UDA1380)
32#define ac_init uda1380_init
33#define ac_mute uda1380_mute
34#define ac_set_frequency uda1380_set_frequency
35#elif defined(HAVE_TLV320)
36#define ac_init tlv320_init
37#define ac_mute tlv320_mute
38#define ac_set_frequency tlv320_set_frequency
39#endif
40
41/** Semi-private shared symbols **/
42
43/* the registered callback function to ask for more pcm data */
44extern pcm_more_callback_type pcm_callback_for_more;
45extern bool pcm_playing;
46extern bool pcm_paused;
47
48/* the registered callback function for when more data is available */
49extern pcm_more_callback_type pcm_callback_more_ready;
50extern bool pcm_recording;
51
52/* peaks */
53static int play_peak_left, play_peak_right;
54static unsigned long *rec_peak_addr;
55static int rec_peak_left, rec_peak_right;
56
57#define IIS_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
58 (pcm_txsrc_select[pcm_monitor+1] << 8) | \
59 (4 << 2) ) /* 64 bit clocks / word clock */
60#define IIS_RESET 0x800
61
62#ifdef IAUDIO_X5
63#define SET_IIS_CONFIG(x) IIS1CONFIG = (x);
64#define IIS_CONFIG IIS1CONFIG
65#define PLLCR_SET_AUDIO_BITS_DEFPARM \
66 ((freq_ent[FPARM_CLSEL] << 28) | (1 << 22))
67#else
68#define SET_IIS_CONFIG(x) IIS2CONFIG = (x);
69#define IIS_CONFIG IIS2CONFIG
70#define PLLCR_SET_AUDIO_BITS_DEFPARM \
71 ((freq_ent[FPARM_CLSEL] << 28) | (3 << 22))
72
73#ifdef HAVE_SPDIF_OUT
74#define EBU_DEFPARM ((7 << 12) | (3 << 8) | (1 << 5) | (5 << 2))
75#endif
76#endif
77
78/** Sample rates **/
79#define FPARM_CLOCKSEL 0
80#define FPARM_CLSEL 1
81#define FPARM_FSEL 2
82#if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380)
83static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
84{
85 [HW_FREQ_88] = { 0x0c, 0x01, 0x03 },
86 [HW_FREQ_44] = { 0x06, 0x01, 0x02 },
87 [HW_FREQ_22] = { 0x04, 0x02, 0x01 },
88 [HW_FREQ_11] = { 0x02, 0x02, 0x00 },
89};
90#endif
91
92#if CONFIG_CPU == MCF5250 && defined(HAVE_TLV320)
93static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
94{
95 [HW_FREQ_88] = { 0x0c, 0x01, 0x02 },
96 [HW_FREQ_44] = { 0x06, 0x01, 0x01 },
97 [HW_FREQ_22] = { 0x04, 0x01, 0x00 },
98 [HW_FREQ_11] = { 0x02, 0x02, 0x00 },
99};
100#endif
101
102static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */
103static const unsigned char *freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT];
104
105/* set frequency used by the audio hardware */
106void pcm_set_frequency(unsigned int frequency)
107{
108 int index;
109
110 switch(frequency)
111 {
112 case SAMPR_11:
113 index = HW_FREQ_11;
114 break;
115 case SAMPR_22:
116 index = HW_FREQ_22;
117 break;
118 default:
119 case SAMPR_44:
120 index = HW_FREQ_44;
121 break;
122 case SAMPR_88:
123 index = HW_FREQ_88;
124 break;
125 }
126
127 /* remember table entry and rate */
128 freq_ent = pcm_freq_parms[index];
129 pcm_freq = hw_freq_sampr[index];
130} /* pcm_set_frequency */
131
132/** monitoring/source selection **/
133static int pcm_monitor = AUDIO_SRC_PLAYBACK;
134
135static const unsigned char pcm_txsrc_select[AUDIO_NUM_SOURCES+1] =
136{
137 [AUDIO_SRC_PLAYBACK+1] = 3, /* PDOR3 */
138 [AUDIO_SRC_MIC+1] = 4, /* IIS1 RcvData */
139 [AUDIO_SRC_LINEIN+1] = 4, /* IIS1 RcvData */
140#ifdef HAVE_FMRADIO_IN
141 [AUDIO_SRC_FMRADIO+1] = 4, /* IIS1 RcvData */
142#endif
143#ifdef HAVE_SPDIF_IN
144 [AUDIO_SRC_SPDIF+1] = 7, /* EBU1 RcvData */
145#endif
146};
147
148static const unsigned short pcm_dataincontrol[AUDIO_NUM_SOURCES+1] =
149{
150 [AUDIO_SRC_PLAYBACK+1] = 0x0200, /* Reset PDIR2 data flow */
151 [AUDIO_SRC_MIC+1] = 0xc020, /* Int. when 6 samples in FIFO,
152 PDIR2 src = ebu1RcvData */
153 [AUDIO_SRC_LINEIN+1] = 0xc020, /* Int. when 6 samples in FIFO,
154 PDIR2 src = ebu1RcvData */
155#ifdef HAVE_FMRADIO_IN
156 [AUDIO_SRC_FMRADIO+1] = 0xc020, /* Int. when 6 samples in FIFO,
157 PDIR2 src = ebu1RcvData */
158#endif
159#ifdef HAVE_SPDIF_IN
160 [AUDIO_SRC_SPDIF+1] = 0xc038, /* Int. when 6 samples in FIFO,
161 PDIR2 src = ebu1RcvData */
162#endif
163};
164
165static int pcm_rec_src = AUDIO_SRC_PLAYBACK;
166
167void pcm_set_monitor(int monitor)
168{
169 if ((unsigned)monitor >= AUDIO_NUM_SOURCES)
170 monitor = AUDIO_SRC_PLAYBACK;
171 pcm_monitor = monitor;
172} /* pcm_set_monitor */
173
174void pcm_set_rec_source(int source)
175{
176 if ((unsigned)source >= AUDIO_NUM_SOURCES)
177 source = AUDIO_SRC_PLAYBACK;
178 pcm_rec_src = source;
179} /* pcm_set_rec_source */
180
181/* apply audio settings */
182void pcm_apply_settings(bool reset)
183{
184 static int last_pcm_freq = HW_SAMPR_DEFAULT;
185#if 0
186 static int last_pcm_monitor = AUDIO_SRC_PLAYBACK;
187#endif
188 static int last_pcm_rec_src = AUDIO_SRC_PLAYBACK;
189
190 /* Playback must prevent pops and record monitoring won't work at all
191 adding IIS_RESET when setting IIS_CONFIG. Use a different method for
192 each. */
193 if (reset && (pcm_monitor != AUDIO_SRC_PLAYBACK))
194 {
195 /* Not playback - reset first */
196 SET_IIS_CONFIG(IIS_RESET);
197 reset = false;
198 }
199
200 if (pcm_rec_src != last_pcm_rec_src)
201 {
202 last_pcm_rec_src = pcm_rec_src;
203 DATAINCONTROL = pcm_dataincontrol[pcm_rec_src+1];
204 }
205
206 if (pcm_freq != last_pcm_freq)
207 {
208 last_pcm_freq = pcm_freq;
209 ac_set_frequency(freq_ent[FPARM_FSEL]);
210 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
211 }
212
213 SET_IIS_CONFIG(IIS_DEFPARM | (reset ? IIS_RESET : 0));
214} /* pcm_apply_settings */
215
216/** DMA **/
217
218/****************************************************************************
219 ** Playback DMA transfer
220 **/
221
222/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
223void pcm_play_dma_start(const void *addr, size_t size)
224{
225 logf("pcm_play_dma_start");
226
227 addr = (void *)((unsigned long)addr & ~3); /* Align data */
228 size &= ~3; /* Size must be multiple of 4 */
229
230 pcm_playing = true;
231
232 /* Reset the audio FIFO */
233#ifdef HAVE_SPDIF_OUT
234 EBU1CONFIG = IIS_RESET | EBU_DEFPARM;
235#endif
236
237 /* Set up DMA transfer */
238 SAR0 = (unsigned long)addr; /* Source address */
239 DAR0 = (unsigned long)&PDOR3; /* Destination address */
240 BCR0 = size; /* Bytes to transfer */
241
242 /* Enable the FIFO and force one write to it */
243 pcm_apply_settings(false);
244
245 /* Also send the audio to S/PDIF */
246#ifdef HAVE_SPDIF_OUT
247 EBU1CONFIG = EBU_DEFPARM;
248#endif
249
250 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA |
251 DMA_SINC | DMA_SSIZE(3) | DMA_START;
252} /* pcm_play_dma_start */
253
254/* Stops the DMA transfer and interrupt */
255void pcm_play_dma_stop(void)
256{
257 logf("pcm_play_dma_stop");
258
259 pcm_playing = false;
260
261 DCR0 = 0;
262 DSR0 = 1;
263
264 /* Reset the FIFO */
265 pcm_apply_settings(false);
266
267#ifdef HAVE_SPDIF_OUT
268 EBU1CONFIG = IIS_RESET | EBU_DEFPARM;
269#endif
270} /* pcm_play_dma_stop */
271
272void pcm_init(void)
273{
274 logf("pcm_init");
275
276 pcm_playing = false;
277 pcm_paused = false;
278 pcm_callback_for_more = NULL;
279
280 MPARK = 0x81; /* PARK[1,0]=10 + BCR24BIT */
281 DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
282 DMAROUTE = (DMAROUTE & 0xffffff00) | DMA0_REQ_AUDIO_1;
283 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
284
285 /* Reset the audio FIFO */
286 SET_IIS_CONFIG(IIS_RESET);
287
288 pcm_set_frequency(-1);
289 pcm_set_monitor(-1);
290
291 /* Prevent pops (resets DAC to zero point) */
292 SET_IIS_CONFIG(IIS_DEFPARM | IIS_RESET);
293
294 /* Initialize default register values. */
295 ac_init();
296
297#if defined(HAVE_UDA1380)
298 /* Sleep a while so the power can stabilize (especially a long
299 delay is needed for the line out connector). */
300 sleep(HZ);
301 /* Power on FSDAC and HP amp. */
302 uda1380_enable_output(true);
303#elif defined(HAVE_TLV320)
304 sleep(HZ/4);
305#endif
306
307 /* UDA1380: Unmute the master channel
308 (DAC should be at zero point now). */
309 ac_mute(false);
310
311 /* Call pcm_play_dma_stop to initialize everything. */
312 pcm_play_dma_stop();
313
314 /* Enable interrupt at level 7, priority 0 */
315 ICR6 = (7 << 2);
316 IMR &= ~(1 << 14); /* bit 14 is DMA0 */
317} /* pcm_init */
318
319size_t pcm_get_bytes_waiting(void)
320{
321 return BCR0 & 0xffffff;
322} /* pcm_get_bytes_waiting */
323
324/* DMA0 Interrupt is called when the DMA has finished transfering a chunk
325 from the caller's buffer */
326void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
327void DMA0(void)
328{
329 int res = DSR0;
330
331 DSR0 = 1; /* Clear interrupt */
332 DCR0 &= ~DMA_EEXT;
333
334 /* Stop on error */
335 if ((res & 0x70) == 0)
336 {
337 pcm_more_callback_type get_more = pcm_callback_for_more;
338 unsigned char *next_start;
339 size_t next_size = 0;
340
341 if (get_more)
342 get_more(&next_start, &next_size);
343
344 if (next_size > 0)
345 {
346 SAR0 = (unsigned long)next_start; /* Source address */
347 BCR0 = next_size; /* Bytes to transfer */
348 DCR0 |= DMA_EEXT;
349 return;
350 }
351 else
352 {
353 /* Finished playing */
354#if 0
355 /* int. logfs can trash the display */
356 logf("DMA0 No Data:0x%04x", res);
357#endif
358 }
359 }
360 else
361 {
362 logf("DMA Error:0x%04x", res);
363 }
364
365 pcm_play_dma_stop();
366} /* DMA0 */
367
368/****************************************************************************
369 ** Recording DMA transfer
370 **/
371void pcm_rec_dma_start(const void *addr, size_t size)
372{
373 logf("pcm_rec_dma_start");
374
375 addr = (void *)((unsigned long)addr & ~3); /* Align data */
376 size &= ~3; /* Size must be multiple of 4 */
377
378 pcm_recording = true;
379
380 DAR1 = (unsigned long)addr; /* Destination address */
381 SAR1 = (unsigned long)&PDIR2; /* Source address */
382 BCR1 = size; /* Bytes to transfer */
383
384 rec_peak_addr = (unsigned long *)addr;
385
386 pcm_apply_settings(false);
387
388 /* Start the DMA transfer.. */
389#ifdef HAVE_SPDIF_IN
390 INTERRUPTCLEAR = 0x03c00000;
391#endif
392
393 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC |
394 DMA_DSIZE(3) | DMA_START;
395} /* pcm_dma_start */
396
397void pcm_rec_dma_stop(void)
398{
399 logf("pcm_rec_dma_stop");
400
401 pcm_recording = false;
402
403 DCR1 = 0;
404 DSR1 = 1; /* Clear interrupt */
405} /* pcm_dma_stop */
406
407void pcm_init_recording(void)
408{
409 logf("pcm_init_recording");
410
411 pcm_recording = false;
412 pcm_callback_more_ready = NULL;
413
414 AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */
415
416 DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */
417 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
418 DMAROUTE = (DMAROUTE & 0xffff00ff) | DMA1_REQ_AUDIO_2;
419
420#ifdef HAVE_SPDIF_IN
421 /* PHASECONFIG setup: gain = 3*2^13, source = EBUIN */
422 PHASECONFIG = (6 << 3) | (4 << 0);
423#endif
424
425 pcm_rec_dma_stop();
426
427 ICR7 = (7 << 2); /* Enable interrupt at level 7, priority 0 */
428 IMR &= ~(1 << 15); /* bit 15 is DMA1 */
429} /* pcm_init_recording */
430
431void pcm_close_recording(void)
432{
433 logf("pcm_close_recording");
434
435 pcm_rec_dma_stop();
436
437 DMAROUTE &= 0xffff00ff;
438 ICR7 = 0x00; /* Disable interrupt */
439 IMR |= (1 << 15); /* bit 15 is DMA1 */
440} /* pcm_close_recording */
441
442/* DMA1 Interrupt is called when the DMA has finished transfering a chunk
443 into the caller's buffer */
444void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
445void DMA1(void)
446{
447 int res = DSR1;
448 pcm_more_callback_type more_ready;
449 unsigned char *next_start;
450 ssize_t next_size = 0; /* passing <> 0 is indicates
451 an error condition */
452
453 DSR1 = 1; /* Clear interrupt */
454 DCR1 &= ~DMA_EEXT;
455
456 if (res & 0x70)
457 {
458 next_size = DMA_REC_ERROR_DMA;
459 logf("DMA1 err: 0x%x", res);
460 }
461#ifdef HAVE_SPDIF_IN
462 else if (pcm_rec_src == AUDIO_SRC_SPDIF &&
463 (INTERRUPTSTAT & 0x01c00000)) /* valnogood, symbolerr, parityerr */
464 {
465 INTERRUPTCLEAR = 0x03c00000;
466 next_size = DMA_REC_ERROR_SPDIF;
467 logf("spdif err");
468 }
469#endif
470
471 more_ready = pcm_callback_more_ready;
472
473 if (more_ready)
474 more_ready(&next_start, &next_size);
475
476 if (next_size > 0)
477 {
478 /* Start peaking at dest */
479 rec_peak_addr = (unsigned long *)next_start;
480 DAR1 = (unsigned long)next_start; /* Destination address */
481 BCR1 = (unsigned long)next_size; /* Bytes to transfer */
482 DCR1 |= DMA_EEXT;
483 return;
484 }
485 else
486 {
487#if 0
488 /* int. logfs can trash the display */
489 logf("DMA1 No Data:0x%04x", res);
490#endif
491 }
492
493 /* Finished recording */
494 pcm_rec_dma_stop();
495} /* DMA1 */
496
497void pcm_mute(bool mute)
498{
499 ac_mute(mute);
500 if (mute)
501 sleep(HZ/16);
502} /* pcm_mute */
503
504void pcm_play_pause_pause(void)
505{
506 /* Disable DMA peripheral request. */
507 DCR0 &= ~DMA_EEXT;
508 pcm_apply_settings(true);
509#ifdef HAVE_SPDIF_OUT
510 EBU1CONFIG = EBU_DEFPARM;
511#endif
512} /* pcm_play_pause_pause */
513
514void pcm_play_pause_unpause(void)
515{
516 /* Enable the FIFO and force one write to it */
517 pcm_apply_settings(false);
518#ifdef HAVE_SPDIF_OUT
519 EBU1CONFIG = EBU_DEFPARM;
520#endif
521 DCR0 |= DMA_EEXT | DMA_START;
522} /* pcm_play_pause_unpause */
523
524/**
525 * Return playback peaks - Peaks ahead in the DMA buffer based upon the
526 * calling period to attempt to compensate for
527 * delay.
528 */
529void pcm_calculate_peaks(int *left, int *right)
530{
531 unsigned long samples;
532 unsigned long *addr, *end;
533 long peak_p, peak_n;
534 int level;
535
536 static unsigned long last_peak_tick = 0;
537 static unsigned long frame_period = 0;
538
539 /* Throttled peak ahead based on calling period */
540 unsigned long period = current_tick - last_peak_tick;
541
542 /* Keep reasonable limits on period */
543 if (period < 1)
544 period = 1;
545 else if (period > HZ/5)
546 period = HZ/5;
547
548 frame_period = (3*frame_period + period) >> 2;
549
550 last_peak_tick = current_tick;
551
552 if (!pcm_playing || pcm_paused)
553 {
554 play_peak_left = play_peak_right = 0;
555 goto peak_done;
556 }
557
558 /* prevent interrupt from setting up next transfer and
559 be sure SAR0 and BCR0 refer to current transfer */
560 level = set_irq_level(HIGHEST_IRQ_LEVEL);
561
562 addr = (long *)(SAR0 & ~3);
563 samples = (BCR0 & 0xffffff) >> 2;
564
565 set_irq_level(level);
566
567 samples = MIN(frame_period*pcm_freq/HZ, samples);
568 end = addr + samples;
569 peak_p = peak_n = 0;
570
571 if (left && right)
572 {
573 if (samples > 0)
574 {
575 long peak_rp = 0, peak_rn = 0;
576
577 do
578 {
579 long value = *addr;
580 long ch;
581
582 ch = value >> 16;
583 if (ch > peak_p) peak_p = ch;
584 else if (ch < peak_n) peak_n = ch;
585
586 ch = (short)value;
587 if (ch > peak_rp) peak_rp = ch;
588 else if (ch < peak_rn) peak_rn = ch;
589
590 addr += 4;
591 }
592 while (addr < end);
593
594 play_peak_left = MAX(peak_p, -peak_n);
595 play_peak_right = MAX(peak_rp, -peak_rn);
596 }
597 }
598 else if (left || right)
599 {
600 if (samples > 0)
601 {
602 if (left)
603 {
604 /* Put left channel in low word */
605 addr = (long *)((short *)addr - 1);
606 end = (long *)((short *)end - 1);
607 }
608
609 do
610 {
611 long value = *(short *)addr;
612
613 if (value > peak_p) peak_p = value;
614 else if (value < peak_n) peak_n = value;
615
616 addr += 4;
617 }
618 while (addr < end);
619
620 if (left)
621 play_peak_left = MAX(peak_p, -peak_n);
622 else
623 play_peak_right = MAX(peak_p, -peak_n);
624 }
625 }
626
627peak_done:
628 if (left)
629 *left = play_peak_left;
630
631 if (right)
632 *right = play_peak_right;
633} /* pcm_calculate_peaks */
634
635/**
636 * Return recording peaks - Looks at every 4th sample from last peak up to
637 * current write position.
638 */
639void pcm_calculate_rec_peaks(int *left, int *right)
640{
641 unsigned long *pkaddr, *addr, *end;
642 long peak_lp, peak_ln; /* L +,- */
643 long peak_rp, peak_rn; /* R +,- */
644 int level;
645
646 if (!pcm_recording)
647 {
648 rec_peak_left = rec_peak_right = 0;
649 goto peak_done;
650 }
651
652 /* read these atomically or each value may not refer to the
653 same data transfer */
654 level = set_irq_level(HIGHEST_IRQ_LEVEL);
655
656 pkaddr = rec_peak_addr;
657 addr = pkaddr;
658 end = (unsigned long *)(DAR1 & ~3);
659
660 set_irq_level(level);
661
662 if (addr < end)
663 {
664 peak_lp = peak_ln =
665 peak_rp = peak_rn = 0;
666
667 /* peak one sample per line */
668 do
669 {
670 long value = *addr;
671 long ch;
672
673 ch = value >> 16;
674 if (ch < peak_ln)
675 peak_ln = ch;
676 else if (ch > peak_lp)
677 peak_lp = ch;
678
679 ch = (short)value;
680 if (ch > peak_rp)
681 peak_rp = ch;
682 else if (ch < peak_rn)
683 peak_rn = ch;
684
685 addr += 4;
686 }
687 while (addr < end);
688
689 /* only update rec_peak_addr if a DMA interrupt hasn't already
690 done so */
691 level = set_irq_level(HIGHEST_IRQ_LEVEL);
692
693 if (pkaddr == rec_peak_addr)
694 rec_peak_addr = end;
695
696 set_irq_level(level);
697
698 /* save peaks */
699 rec_peak_left = MAX(peak_lp, -peak_ln);
700 rec_peak_right = MAX(peak_rp, -peak_rn);
701 }
702
703peak_done:
704 if (left)
705 *left = rec_peak_left;
706
707 if (right)
708 *right = rec_peak_right;
709} /* pcm_calculate_rec_peaks */
710
711/**
712 * Select VINL & VINR source: 0=Line-in, 1=FM Radio
713 */
714/* All use GPIO */
715#if defined(IAUDIO_X5)
716 #define REC_MUX_BIT (1 << 29)
717 #define REC_MUX_SET_LINE() or_l(REC_MUX_BIT, &GPIO_OUT)
718 #define REC_MUX_SET_FM() and_l(~REC_MUX_BIT, &GPIO_OUT)
719#else
720#if defined(IRIVER_H100_SERIES)
721 #define REC_MUX_BIT (1 << 23)
722#elif defined(IRIVER_H300_SERIES)
723 #define REC_MUX_BIT (1 << 30)
724#endif
725 #define REC_MUX_SET_LINE() and_l(~REC_MUX_BIT, &GPIO_OUT)
726 #define REC_MUX_SET_FM() or_l(REC_MUX_BIT, &GPIO_OUT)
727#endif
728
729void pcm_rec_mux(int source)
730{
731 if (source == 0)
732 REC_MUX_SET_LINE(); /* Line In */
733 else
734 REC_MUX_SET_FM(); /* FM radio */
735
736 or_l(REC_MUX_BIT, &GPIO_ENABLE);
737 or_l(REC_MUX_BIT, &GPIO_FUNCTION);
738} /* pcm_rec_mux */