diff options
Diffstat (limited to 'firmware/target')
3 files changed, 172 insertions, 100 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/i2s-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/i2s-gigabeat-s.c index 6291a9cf18..723999c15e 100644 --- a/firmware/target/arm/imx31/gigabeat-s/i2s-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/i2s-gigabeat-s.c | |||
@@ -20,6 +20,8 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "config.h" | 21 | #include "config.h" |
22 | #include "system.h" | 22 | #include "system.h" |
23 | #include "ccm-imx31.h" | ||
24 | #include "sdma-imx31.h" | ||
23 | #include "i2s.h" | 25 | #include "i2s.h" |
24 | 26 | ||
25 | void i2s_reset(void) | 27 | void i2s_reset(void) |
@@ -42,4 +44,95 @@ void i2s_reset(void) | |||
42 | ((64-1) << CCM_PDR1_SSI2_PODF_POS), | 44 | ((64-1) << CCM_PDR1_SSI2_PODF_POS), |
43 | CCM_PDR1_SSI1_PODF | CCM_PDR1_SSI2_PODF | | 45 | CCM_PDR1_SSI1_PODF | CCM_PDR1_SSI2_PODF | |
44 | CCM_PDR1_SSI1_PRE_PODF | CCM_PDR1_SSI2_PRE_PODF); | 46 | CCM_PDR1_SSI1_PRE_PODF | CCM_PDR1_SSI2_PRE_PODF); |
47 | |||
48 | ccm_module_clock_gating(CG_SSI1, CGM_ON_RUN_WAIT); | ||
49 | ccm_module_clock_gating(CG_SSI2, CGM_ON_RUN_WAIT); | ||
50 | |||
51 | /* Reset & disable SSIs */ | ||
52 | SSI_SCR1 &= ~SSI_SCR_SSIEN; | ||
53 | SSI_SCR2 &= ~SSI_SCR_SSIEN; | ||
54 | |||
55 | SSI_SIER1 = 0; | ||
56 | SSI_SIER2 = 0; | ||
57 | |||
58 | /* Set up audio mux */ | ||
59 | |||
60 | /* Port 2 (internally connected to SSI2) | ||
61 | * All clocking is output sourced from port 4 */ | ||
62 | AUDMUX_PTCR2 = AUDMUX_PTCR_TFS_DIR | AUDMUX_PTCR_TFSEL_PORT4 | | ||
63 | AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT4 | | ||
64 | AUDMUX_PTCR_SYN; | ||
65 | |||
66 | /* Receive data from port 4 */ | ||
67 | AUDMUX_PDCR2 = AUDMUX_PDCR_RXDSEL_PORT4; | ||
68 | /* All clock lines are inputs sourced from the master mode codec and | ||
69 | * sent back to SSI2 through port 2 */ | ||
70 | AUDMUX_PTCR4 = AUDMUX_PTCR_SYN; | ||
71 | |||
72 | /* Receive data from port 2 */ | ||
73 | AUDMUX_PDCR4 = AUDMUX_PDCR_RXDSEL_PORT2; | ||
74 | |||
75 | /* PORT1 (internally connected to SSI1) routes clocking to PORT5 to | ||
76 | * provide MCLK to the codec */ | ||
77 | /* TX clocks are inputs taken from SSI2 */ | ||
78 | /* RX clocks are outputs taken from PORT4 */ | ||
79 | AUDMUX_PTCR1 = AUDMUX_PTCR_RFS_DIR | AUDMUX_PTCR_RFSSEL_PORT4 | | ||
80 | AUDMUX_PTCR_RCLKDIR | AUDMUX_PTCR_RCSEL_PORT4; | ||
81 | /* RX data taken from PORT4 */ | ||
82 | AUDMUX_PDCR1 = AUDMUX_PDCR_RXDSEL_PORT4; | ||
83 | |||
84 | /* PORT5 outputs TCLK sourced from PORT1 (SSI1) */ | ||
85 | AUDMUX_PTCR5 = AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT1; | ||
86 | AUDMUX_PDCR5 = 0; | ||
87 | |||
88 | /* Setup SSIs */ | ||
89 | |||
90 | /* SSI2 - SoC software interface for all I2S data out */ | ||
91 | SSI_SCR2 = SSI_SCR_SYN | SSI_SCR_I2S_MODE_SLAVE; | ||
92 | SSI_STCR2 = SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSI | | ||
93 | SSI_STCR_TEFS | SSI_STCR_TFEN0; | ||
94 | |||
95 | /* 16 bits per word, 2 words per frame */ | ||
96 | SSI_STCCR2 = SSI_STRCCR_WL16 | ((2-1) << SSI_STRCCR_DC_POS) | | ||
97 | ((4-1) << SSI_STRCCR_PM_POS); | ||
98 | |||
99 | /* Transmit low watermark */ | ||
100 | SSI_SFCSR2 = (SSI_SFCSR2 & ~SSI_SFCSR_TFWM0) | | ||
101 | ((8-SDMA_SSI_TXFIFO_WML) << SSI_SFCSR_TFWM0_POS); | ||
102 | SSI_STMSK2 = 0; | ||
103 | |||
104 | /* SSI1 - provides MCLK to codec. Receives data from codec. */ | ||
105 | SSI_STCR1 = SSI_STCR_TXDIR; | ||
106 | |||
107 | /* f(INT_BIT_CLK) = | ||
108 | * f(SYS_CLK) / [(DIV2 + 1)*(7*PSR + 1)*(PM + 1)*2] = | ||
109 | * 677737600 / [(1 + 1)*(7*0 + 1)*(0 + 1)*2] = | ||
110 | * 677737600 / 4 = 169344000 Hz | ||
111 | * | ||
112 | * 45.4.2.2 DIV2, PSR, and PM Bit Description states: | ||
113 | * Bits DIV2, PSR, and PM should not be all set to zero at the same | ||
114 | * time. | ||
115 | * | ||
116 | * The hardware seems to force a divide by 4 even if all bits are | ||
117 | * zero but comply by setting DIV2 and the others to zero. | ||
118 | */ | ||
119 | SSI_STCCR1 = SSI_STRCCR_DIV2 | ((1-1) << SSI_STRCCR_PM_POS); | ||
120 | |||
121 | /* SSI1 - receive - asynchronous clocks */ | ||
122 | SSI_SCR1 = SSI_SCR_I2S_MODE_SLAVE; | ||
123 | |||
124 | SSI_SRCR1 = SSI_SRCR_RXBIT0 | SSI_SRCR_RSCKP | SSI_SRCR_RFSI | | ||
125 | SSI_SRCR_REFS; | ||
126 | |||
127 | /* 16 bits per word, 2 words per frame */ | ||
128 | SSI_SRCCR1 = SSI_STRCCR_WL16 | ((2-1) << SSI_STRCCR_DC_POS) | | ||
129 | ((4-1) << SSI_STRCCR_PM_POS); | ||
130 | |||
131 | /* Receive high watermark */ | ||
132 | SSI_SFCSR1 = (SSI_SFCSR1 & ~SSI_SFCSR_RFWM0) | | ||
133 | (SDMA_SSI_RXFIFO_WML << SSI_SFCSR_RFWM0_POS); | ||
134 | SSI_SRMSK1 = 0; | ||
135 | |||
136 | /* Enable SSI1 (codec clock) */ | ||
137 | SSI_SCR1 |= SSI_SCR_SSIEN; | ||
45 | } | 138 | } |
diff --git a/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c index 65571a4ee2..1c21415752 100644 --- a/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include "kernel.h" | 23 | #include "kernel.h" |
24 | #include "audio.h" | 24 | #include "audio.h" |
25 | #include "sound.h" | 25 | #include "sound.h" |
26 | #include "ccm-imx31.h" | 26 | //#include "ccm-imx31.h" |
27 | #include "sdma-imx31.h" | 27 | #include "sdma-imx31.h" |
28 | #include "mmu-imx31.h" | 28 | #include "mmu-imx31.h" |
29 | #include "pcm-internal.h" | 29 | #include "pcm-internal.h" |
@@ -149,101 +149,11 @@ void pcm_dma_apply_settings(void) | |||
149 | 149 | ||
150 | void pcm_play_dma_init(void) | 150 | void pcm_play_dma_init(void) |
151 | { | 151 | { |
152 | /* Init channel information */ | 152 | /* Init DMA channel information */ |
153 | sdma_channel_init(DMA_PLAY_CH_NUM, &dma_play_cd, &dma_play_bd); | 153 | sdma_channel_init(DMA_PLAY_CH_NUM, &dma_play_cd, &dma_play_bd); |
154 | sdma_channel_set_priority(DMA_PLAY_CH_NUM, DMA_PLAY_CH_PRIORITY); | 154 | sdma_channel_set_priority(DMA_PLAY_CH_NUM, DMA_PLAY_CH_PRIORITY); |
155 | 155 | ||
156 | ccm_module_clock_gating(CG_SSI1, CGM_ON_RUN_WAIT); | 156 | /* Init audio interfaces */ |
157 | ccm_module_clock_gating(CG_SSI2, CGM_ON_RUN_WAIT); | ||
158 | |||
159 | /* Reset & disable SSIs */ | ||
160 | SSI_SCR1 &= ~SSI_SCR_SSIEN; | ||
161 | SSI_SCR2 &= ~SSI_SCR_SSIEN; | ||
162 | |||
163 | SSI_SIER1 = 0; | ||
164 | SSI_SIER2 = 0; | ||
165 | |||
166 | /* Set up audio mux */ | ||
167 | |||
168 | /* Port 2 (internally connected to SSI2) | ||
169 | * All clocking is output sourced from port 4 */ | ||
170 | AUDMUX_PTCR2 = AUDMUX_PTCR_TFS_DIR | AUDMUX_PTCR_TFSEL_PORT4 | | ||
171 | AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT4 | | ||
172 | AUDMUX_PTCR_SYN; | ||
173 | |||
174 | /* Receive data from port 4 */ | ||
175 | AUDMUX_PDCR2 = AUDMUX_PDCR_RXDSEL_PORT4; | ||
176 | /* All clock lines are inputs sourced from the master mode codec and | ||
177 | * sent back to SSI2 through port 2 */ | ||
178 | AUDMUX_PTCR4 = AUDMUX_PTCR_SYN; | ||
179 | |||
180 | /* Receive data from port 2 */ | ||
181 | AUDMUX_PDCR4 = AUDMUX_PDCR_RXDSEL_PORT2; | ||
182 | |||
183 | /* PORT1 (internally connected to SSI1) routes clocking to PORT5 to | ||
184 | * provide MCLK to the codec */ | ||
185 | /* TX clocks are inputs taken from SSI2 */ | ||
186 | /* RX clocks are outputs taken from PORT4 */ | ||
187 | AUDMUX_PTCR1 = AUDMUX_PTCR_RFS_DIR | AUDMUX_PTCR_RFSSEL_PORT4 | | ||
188 | AUDMUX_PTCR_RCLKDIR | AUDMUX_PTCR_RCSEL_PORT4; | ||
189 | /* RX data taken from PORT4 */ | ||
190 | AUDMUX_PDCR1 = AUDMUX_PDCR_RXDSEL_PORT4; | ||
191 | |||
192 | /* PORT5 outputs TCLK sourced from PORT1 (SSI1) */ | ||
193 | AUDMUX_PTCR5 = AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT1; | ||
194 | AUDMUX_PDCR5 = 0; | ||
195 | |||
196 | /* Setup SSIs */ | ||
197 | |||
198 | /* SSI2 - SoC software interface for all I2S data out */ | ||
199 | SSI_SCR2 = SSI_SCR_SYN | SSI_SCR_I2S_MODE_SLAVE; | ||
200 | SSI_STCR2 = SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSI | | ||
201 | SSI_STCR_TEFS | SSI_STCR_TFEN0; | ||
202 | |||
203 | /* 16 bits per word, 2 words per frame */ | ||
204 | SSI_STCCR2 = SSI_STRCCR_WL16 | ((2-1) << SSI_STRCCR_DC_POS) | | ||
205 | ((4-1) << SSI_STRCCR_PM_POS); | ||
206 | |||
207 | /* Transmit low watermark */ | ||
208 | SSI_SFCSR2 = (SSI_SFCSR2 & ~SSI_SFCSR_TFWM0) | | ||
209 | ((8-SDMA_SSI_TXFIFO_WML) << SSI_SFCSR_TFWM0_POS); | ||
210 | SSI_STMSK2 = 0; | ||
211 | |||
212 | /* SSI1 - provides MCLK to codec. Receives data from codec. */ | ||
213 | SSI_STCR1 = SSI_STCR_TXDIR; | ||
214 | |||
215 | /* f(INT_BIT_CLK) = | ||
216 | * f(SYS_CLK) / [(DIV2 + 1)*(7*PSR + 1)*(PM + 1)*2] = | ||
217 | * 677737600 / [(1 + 1)*(7*0 + 1)*(0 + 1)*2] = | ||
218 | * 677737600 / 4 = 169344000 Hz | ||
219 | * | ||
220 | * 45.4.2.2 DIV2, PSR, and PM Bit Description states: | ||
221 | * Bits DIV2, PSR, and PM should not be all set to zero at the same | ||
222 | * time. | ||
223 | * | ||
224 | * The hardware seems to force a divide by 4 even if all bits are | ||
225 | * zero but comply by setting DIV2 and the others to zero. | ||
226 | */ | ||
227 | SSI_STCCR1 = SSI_STRCCR_DIV2 | ((1-1) << SSI_STRCCR_PM_POS); | ||
228 | |||
229 | /* SSI1 - receive - asynchronous clocks */ | ||
230 | SSI_SCR1 = SSI_SCR_I2S_MODE_SLAVE; | ||
231 | |||
232 | SSI_SRCR1 = SSI_SRCR_RXBIT0 | SSI_SRCR_RSCKP | SSI_SRCR_RFSI | | ||
233 | SSI_SRCR_REFS; | ||
234 | |||
235 | /* 16 bits per word, 2 words per frame */ | ||
236 | SSI_SRCCR1 = SSI_STRCCR_WL16 | ((2-1) << SSI_STRCCR_DC_POS) | | ||
237 | ((4-1) << SSI_STRCCR_PM_POS); | ||
238 | |||
239 | /* Receive high watermark */ | ||
240 | SSI_SFCSR1 = (SSI_SFCSR1 & ~SSI_SFCSR_RFWM0) | | ||
241 | (SDMA_SSI_RXFIFO_WML << SSI_SFCSR_RFWM0_POS); | ||
242 | SSI_SRMSK1 = 0; | ||
243 | |||
244 | /* Enable SSI1 (codec clock) */ | ||
245 | SSI_SCR1 |= SSI_SCR_SSIEN; | ||
246 | |||
247 | audiohw_init(); | 157 | audiohw_init(); |
248 | } | 158 | } |
249 | 159 | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/wmcodec-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/wmcodec-gigabeat-s.c index 36ab33a5dc..ca23aa4e56 100644 --- a/firmware/target/arm/imx31/gigabeat-s/wmcodec-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/wmcodec-gigabeat-s.c | |||
@@ -22,24 +22,93 @@ | |||
22 | ****************************************************************************/ | 22 | ****************************************************************************/ |
23 | #include "config.h" | 23 | #include "config.h" |
24 | #include "system.h" | 24 | #include "system.h" |
25 | #include "kernel.h" | 25 | #include "audiohw.h" |
26 | #include "sound.h" | ||
27 | #include "wmcodec.h" | 26 | #include "wmcodec.h" |
27 | #include "audio.h" | ||
28 | #include "i2s.h" | 28 | #include "i2s.h" |
29 | #include "i2c-imx31.h" | 29 | #include "i2c-imx31.h" |
30 | 30 | ||
31 | /* NOTE: Some port-specific bits will have to be moved away (node and GPIO | ||
32 | * writes) for cleanest implementation. */ | ||
33 | |||
34 | static struct i2c_node wm8978_i2c_node = | 31 | static struct i2c_node wm8978_i2c_node = |
35 | { | 32 | { |
36 | .num = I2C1_NUM, | 33 | .num = I2C1_NUM, |
37 | .ifdr = I2C_IFDR_DIV192, /* 66MHz/.4MHz = 165, closest = 192 = 343750Hz */ | 34 | .ifdr = I2C_IFDR_DIV192, /* 66MHz/.4MHz = 165, closest = 192 = 343750Hz */ |
38 | /* Just hard-code for now - scaling may require | ||
39 | * updating */ | ||
40 | .addr = WMC_I2C_ADDR, | 35 | .addr = WMC_I2C_ADDR, |
41 | }; | 36 | }; |
42 | 37 | ||
38 | /* For 16.9344MHz MCLK, codec as master. */ | ||
39 | const struct wmc_srctrl_entry wmc_srctrl_table[HW_NUM_FREQ] = | ||
40 | { | ||
41 | [HW_FREQ_8] = /* PLL = 65.536MHz */ | ||
42 | { | ||
43 | .plln = 7 | WMC_PLL_PRESCALE, | ||
44 | .pllk1 = 0x2f, /* 12414886 */ | ||
45 | .pllk2 = 0x0b7, | ||
46 | .pllk3 = 0x1a6, | ||
47 | .mclkdiv = WMC_MCLKDIV_8, /* 2.0480 MHz */ | ||
48 | .filter = WMC_SR_8KHZ, | ||
49 | }, | ||
50 | [HW_FREQ_11] = /* PLL = off */ | ||
51 | { | ||
52 | .mclkdiv = WMC_MCLKDIV_6, /* 2.8224 MHz */ | ||
53 | .filter = WMC_SR_12KHZ, | ||
54 | }, | ||
55 | [HW_FREQ_12] = /* PLL = 73.728 MHz */ | ||
56 | { | ||
57 | .plln = 8 | WMC_PLL_PRESCALE, | ||
58 | .pllk1 = 0x2d, /* 11869595 */ | ||
59 | .pllk2 = 0x08e, | ||
60 | .pllk3 = 0x19b, | ||
61 | .mclkdiv = WMC_MCLKDIV_6, /* 3.0720 MHz */ | ||
62 | .filter = WMC_SR_12KHZ, | ||
63 | }, | ||
64 | [HW_FREQ_16] = /* PLL = 65.536MHz */ | ||
65 | { | ||
66 | .plln = 7 | WMC_PLL_PRESCALE, | ||
67 | .pllk1 = 0x2f, /* 12414886 */ | ||
68 | .pllk2 = 0x0b7, | ||
69 | .pllk3 = 0x1a6, | ||
70 | .mclkdiv = WMC_MCLKDIV_4, /* 4.0960 MHz */ | ||
71 | .filter = WMC_SR_16KHZ, | ||
72 | }, | ||
73 | [HW_FREQ_22] = /* PLL = off */ | ||
74 | { | ||
75 | .mclkdiv = WMC_MCLKDIV_3, /* 5.6448 MHz */ | ||
76 | .filter = WMC_SR_24KHZ, | ||
77 | }, | ||
78 | [HW_FREQ_24] = /* PLL = 73.728 MHz */ | ||
79 | { | ||
80 | .plln = 8 | WMC_PLL_PRESCALE, | ||
81 | .pllk1 = 0x2d, /* 11869595 */ | ||
82 | .pllk2 = 0x08e, | ||
83 | .pllk3 = 0x19b, | ||
84 | .mclkdiv = WMC_MCLKDIV_3, /* 6.1440 MHz */ | ||
85 | .filter = WMC_SR_24KHZ, | ||
86 | }, | ||
87 | [HW_FREQ_32] = /* PLL = 65.536MHz */ | ||
88 | { | ||
89 | .plln = 7 | WMC_PLL_PRESCALE, | ||
90 | .pllk1 = 0x2f, /* 12414886 */ | ||
91 | .pllk2 = 0x0b7, | ||
92 | .pllk3 = 0x1a6, | ||
93 | .mclkdiv = WMC_MCLKDIV_2, /* 8.1920 MHz */ | ||
94 | .filter = WMC_SR_32KHZ, | ||
95 | }, | ||
96 | [HW_FREQ_44] = /* PLL = off */ | ||
97 | { | ||
98 | .mclkdiv = WMC_MCLKDIV_1_5, /* 11.2896 MHz */ | ||
99 | .filter = WMC_SR_48KHZ, | ||
100 | }, | ||
101 | [HW_FREQ_48] = /* PLL = 73.728 MHz */ | ||
102 | { | ||
103 | .plln = 8 | WMC_PLL_PRESCALE, | ||
104 | .pllk1 = 0x2d, /* 11869595 */ | ||
105 | .pllk2 = 0x08e, | ||
106 | .pllk3 = 0x19b, | ||
107 | .mclkdiv = WMC_MCLKDIV_1_5, /* 12.2880 MHz */ | ||
108 | .filter = WMC_SR_48KHZ, | ||
109 | }, | ||
110 | }; | ||
111 | |||
43 | void audiohw_init(void) | 112 | void audiohw_init(void) |
44 | { | 113 | { |
45 | i2s_reset(); | 114 | i2s_reset(); |