summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/pcm-as3525.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/as3525/pcm-as3525.c')
-rw-r--r--firmware/target/arm/as3525/pcm-as3525.c102
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
37static unsigned char *dma_start_addr;
38static size_t dma_size; /* in 4*32 bits */
39static void dma_callback(void);
40static int locked = 0;
41
42/* Mask the DMA interrupt */
27void pcm_play_lock(void) 43void 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 */
31void pcm_play_unlock(void) 50void pcm_play_unlock(void)
32{ 51{
52 if(--locked == 0)
53 VIC_INT_ENABLE |= INTERRUPT_DMAC;
33} 54}
34 55
35void pcm_play_dma_start(const void *addr, size_t size) 56static 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
39void pcm_play_dma_stop(void) 74static 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
43void pcm_play_dma_pause(bool pause) 89void 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
47unsigned long physical_address(void *p) 97void pcm_play_dma_stop(void)
98{
99 dma_disable_channel(1);
100 dma_size = 0;
101}
102
103void 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
52void pcm_play_dma_init(void) 111void 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
56void pcm_postinit(void) 125void pcm_postinit(void)
57{ 126{
127 audiohw_postinit();
128 pcm_apply_settings();
58} 129}
59 130
60void pcm_set_frequency(unsigned int frequency) 131void 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
64void pcm_apply_settings(void) 144void pcm_apply_settings(void)
65{ 145{
146 pcm_set_frequency(HW_SAMPR_DEFAULT);
66} 147}
67 148
68size_t pcm_get_bytes_waiting(void) 149size_t pcm_get_bytes_waiting(void)
69{ 150{
70 return 0; 151 return dma_size;
71} 152}
72 153
73const void * pcm_play_dma_get_peak_buffer(int *count) 154const 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