diff options
author | Rafaël Carré <rafael.carre@gmail.com> | 2008-12-04 22:27:48 +0000 |
---|---|---|
committer | Rafaël Carré <rafael.carre@gmail.com> | 2008-12-04 22:27:48 +0000 |
commit | 6aa807d32170eb463ede46397cb43c1c4088cbe9 (patch) | |
tree | bad103ff445aa938ca8e579ab72ccf513122749c /firmware/target/arm/as3525/pcm-as3525.c | |
parent | 8ea82ff4a8b03141c7bc0491dda351dc0645ccd8 (diff) | |
download | rockbox-6aa807d32170eb463ede46397cb43c1c4088cbe9.tar.gz rockbox-6aa807d32170eb463ede46397cb43c1c4088cbe9.zip |
Sansa AMS: PCM driver (FS#9592)
Note that on low memory targets (Clip/m200v4 tested) you will encounter
random crashes. Applying FS#9332 seems to help a lot.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19342 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/as3525/pcm-as3525.c')
-rw-r--r-- | firmware/target/arm/as3525/pcm-as3525.c | 102 |
1 files changed, 92 insertions, 10 deletions
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c index d91450c9cf..0386cc3336 100644 --- a/firmware/target/arm/as3525/pcm-as3525.c +++ b/firmware/target/arm/as3525/pcm-as3525.c | |||
@@ -21,58 +21,140 @@ | |||
21 | #include "system.h" | 21 | #include "system.h" |
22 | #include "audio.h" | 22 | #include "audio.h" |
23 | #include "string.h" | 23 | #include "string.h" |
24 | 24 | #include "as3525.h" | |
25 | /* TODO */ | 25 | #include "pl081.h" |
26 | 26 | #include "dma-target.h" | |
27 | #include "clock-target.h" | ||
28 | #include "panic.h" | ||
29 | #include "as3514.h" | ||
30 | #include "audiohw.h" | ||
31 | |||
32 | #define MAX_TRANSFER (4*((1<<11)-1)) /* maximum data we can transfer via DMA | ||
33 | * i.e. 32 bits at once (size of I2SO_DATA) | ||
34 | * and the number of 32bits words has to | ||
35 | * fit in 11 bits of DMA register */ | ||
36 | |||
37 | static unsigned char *dma_start_addr; | ||
38 | static size_t dma_size; /* in 4*32 bits */ | ||
39 | static void dma_callback(void); | ||
40 | static int locked = 0; | ||
41 | |||
42 | /* Mask the DMA interrupt */ | ||
27 | void pcm_play_lock(void) | 43 | void pcm_play_lock(void) |
28 | { | 44 | { |
45 | if(++locked == 1) | ||
46 | VIC_INT_EN_CLEAR |= INTERRUPT_DMAC; | ||
29 | } | 47 | } |
30 | 48 | ||
49 | /* Unmask the DMA interrupt if enabled */ | ||
31 | void pcm_play_unlock(void) | 50 | void pcm_play_unlock(void) |
32 | { | 51 | { |
52 | if(--locked == 0) | ||
53 | VIC_INT_ENABLE |= INTERRUPT_DMAC; | ||
33 | } | 54 | } |
34 | 55 | ||
35 | void pcm_play_dma_start(const void *addr, size_t size) | 56 | static void play_start_pcm(void) |
36 | { | 57 | { |
58 | const unsigned char* addr = dma_start_addr; | ||
59 | size_t size = dma_size; | ||
60 | if(size > MAX_TRANSFER) | ||
61 | size = MAX_TRANSFER; | ||
62 | |||
63 | if((unsigned int)dma_start_addr & 3) | ||
64 | panicf("unaligned pointer!"); | ||
65 | |||
66 | dma_size -= size; | ||
67 | dma_start_addr += size; | ||
68 | |||
69 | dma_enable_channel(1, (void*)addr, (void*)I2SOUT_DATA, DMA_PERI_I2SOUT, | ||
70 | DMAC_FLOWCTRL_DMAC_MEM_TO_PERI, true, false, size >> 2, DMA_S1, | ||
71 | dma_callback); | ||
37 | } | 72 | } |
38 | 73 | ||
39 | void pcm_play_dma_stop(void) | 74 | static void dma_callback(void) |
40 | { | 75 | { |
76 | if(!dma_size) | ||
77 | { | ||
78 | register pcm_more_callback_type get_more = pcm_callback_for_more; | ||
79 | if(get_more) | ||
80 | get_more(&dma_start_addr, &dma_size); | ||
81 | } | ||
82 | |||
83 | if(!dma_size) | ||
84 | pcm_play_dma_stop(); | ||
85 | else | ||
86 | play_start_pcm(); | ||
41 | } | 87 | } |
42 | 88 | ||
43 | void pcm_play_dma_pause(bool pause) | 89 | void pcm_play_dma_start(const void *addr, size_t size) |
44 | { | 90 | { |
91 | dma_size = size; | ||
92 | dma_start_addr = (unsigned char*)addr; | ||
93 | |||
94 | play_start_pcm(); | ||
45 | } | 95 | } |
46 | 96 | ||
47 | unsigned long physical_address(void *p) | 97 | void pcm_play_dma_stop(void) |
98 | { | ||
99 | dma_disable_channel(1); | ||
100 | dma_size = 0; | ||
101 | } | ||
102 | |||
103 | void pcm_play_dma_pause(bool pause) | ||
48 | { | 104 | { |
49 | return 0; | 105 | if(pause) |
106 | dma_disable_channel(1); | ||
107 | else | ||
108 | play_start_pcm(); | ||
50 | } | 109 | } |
51 | 110 | ||
52 | void pcm_play_dma_init(void) | 111 | void pcm_play_dma_init(void) |
53 | { | 112 | { |
113 | CGU_PERI |= CGU_I2SOUT_APB_CLOCK_ENABLE; | ||
114 | |||
115 | /* enable I2SO_MCLK, clock source PLLA, minimal frequency */ | ||
116 | CGU_AUDIO |= (1<<11) | (511<<2) | (1<<0); | ||
117 | |||
118 | I2SOUT_CONTROL |= (1<<6) ; /* enable dma */ | ||
119 | I2SOUT_CONTROL |= (1<<3) ; /* stereo */ | ||
120 | I2SOUT_CONTROL &= ~(1<<2); /* 16 bit samples */ | ||
121 | |||
122 | audiohw_preinit(); | ||
54 | } | 123 | } |
55 | 124 | ||
56 | void pcm_postinit(void) | 125 | void pcm_postinit(void) |
57 | { | 126 | { |
127 | audiohw_postinit(); | ||
128 | pcm_apply_settings(); | ||
58 | } | 129 | } |
59 | 130 | ||
60 | void pcm_set_frequency(unsigned int frequency) | 131 | void pcm_set_frequency(unsigned int frequency) |
61 | { | 132 | { |
133 | const int divider = (((AS3525_PLLA_FREQ/128) + (frequency/2)) / frequency) - 1; | ||
134 | if(divider < 0 || divider > 511) | ||
135 | panicf("unsupported frequency %d", frequency); | ||
136 | |||
137 | CGU_AUDIO &= ~(((511 ^ divider) << 2) /* I2SOUT */ | ||
138 | /*| ((511 ^ divider) << 14) */ /* I2SIN */ | ||
139 | ); | ||
140 | |||
141 | pcm_curr_sampr = frequency; | ||
62 | } | 142 | } |
63 | 143 | ||
64 | void pcm_apply_settings(void) | 144 | void pcm_apply_settings(void) |
65 | { | 145 | { |
146 | pcm_set_frequency(HW_SAMPR_DEFAULT); | ||
66 | } | 147 | } |
67 | 148 | ||
68 | size_t pcm_get_bytes_waiting(void) | 149 | size_t pcm_get_bytes_waiting(void) |
69 | { | 150 | { |
70 | return 0; | 151 | return dma_size; |
71 | } | 152 | } |
72 | 153 | ||
73 | const void * pcm_play_dma_get_peak_buffer(int *count) | 154 | const void * pcm_play_dma_get_peak_buffer(int *count) |
74 | { | 155 | { |
75 | return NULL; | 156 | *count = dma_size >> 2; |
157 | return (const void*)dma_start_addr; | ||
76 | } | 158 | } |
77 | 159 | ||
78 | 160 | ||