diff options
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx/codec-jz4760.c')
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/codec-jz4760.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/codec-jz4760.c b/firmware/target/mips/ingenic_jz47xx/codec-jz4760.c new file mode 100644 index 0000000000..f25dc70eb4 --- /dev/null +++ b/firmware/target/mips/ingenic_jz47xx/codec-jz4760.c | |||
@@ -0,0 +1,293 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2016 by Roman Stolyarov | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #include "config.h" | ||
22 | #include "audio.h" | ||
23 | #include "sound.h" | ||
24 | #include "cpu.h" | ||
25 | #include "system.h" | ||
26 | #include "pcm_sw_volume.h" | ||
27 | #include "cs4398.h" | ||
28 | #include "kernel.h" | ||
29 | |||
30 | #define PIN_CS_RST (32*1+10) | ||
31 | #define PIN_CODEC_PWRON (32*1+13) | ||
32 | #define PIN_AP_MUTE (32*1+14) | ||
33 | #define PIN_JD_CON (32*1+16) | ||
34 | |||
35 | static void pop_ctrl(const int val) | ||
36 | { | ||
37 | if(val) | ||
38 | __gpio_clear_pin(PIN_JD_CON); | ||
39 | else | ||
40 | __gpio_set_pin(PIN_JD_CON); | ||
41 | } | ||
42 | |||
43 | static void amp_enable(const int val) | ||
44 | { | ||
45 | if(val) | ||
46 | __gpio_set_pin(PIN_CODEC_PWRON); | ||
47 | else | ||
48 | __gpio_clear_pin(PIN_CODEC_PWRON); | ||
49 | } | ||
50 | |||
51 | static void dac_enable(const int val) | ||
52 | { | ||
53 | if(val) | ||
54 | __gpio_set_pin(PIN_CS_RST); | ||
55 | else | ||
56 | __gpio_clear_pin(PIN_CS_RST); | ||
57 | } | ||
58 | |||
59 | static void ap_mute(bool mute) | ||
60 | { | ||
61 | if(mute) | ||
62 | __gpio_clear_pin(PIN_AP_MUTE); | ||
63 | else | ||
64 | __gpio_set_pin(PIN_AP_MUTE); | ||
65 | } | ||
66 | |||
67 | static void audiohw_mute(bool mute) | ||
68 | { | ||
69 | if(mute) | ||
70 | cs4398_write_reg(CS4398_REG_MUTE, cs4398_read_reg(CS4398_REG_MUTE) | CS4398_MUTE_A | CS4398_MUTE_B); | ||
71 | else | ||
72 | cs4398_write_reg(CS4398_REG_MUTE, cs4398_read_reg(CS4398_REG_MUTE) & ~(CS4398_MUTE_A | CS4398_MUTE_B)); | ||
73 | } | ||
74 | |||
75 | void audiohw_preinit(void) | ||
76 | { | ||
77 | cs4398_write_reg(CS4398_REG_MISC, CS4398_CPEN | CS4398_PDN); | ||
78 | cs4398_write_reg(CS4398_REG_MODECTL, CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST); | ||
79 | cs4398_write_reg(CS4398_REG_VOLMIX, CS4398_ATAPI_A_L | CS4398_ATAPI_B_R); | ||
80 | cs4398_write_reg(CS4398_REG_MUTE, CS4398_MUTEP_LOW); | ||
81 | cs4398_write_reg(CS4398_REG_VOL_A, 0xff); | ||
82 | cs4398_write_reg(CS4398_REG_VOL_B, 0xff); | ||
83 | cs4398_write_reg(CS4398_REG_RAMPFILT, CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); | ||
84 | cs4398_write_reg(CS4398_REG_MISC, CS4398_CPEN); | ||
85 | } | ||
86 | |||
87 | void audiohw_init(void) | ||
88 | { | ||
89 | __gpio_as_func1(3*32+12); // BCK | ||
90 | __gpio_as_func0(3*32+13); // LRCK | ||
91 | __gpio_as_func2(4*32+5); // MCLK | ||
92 | __gpio_as_func0(4*32+7); // DO | ||
93 | |||
94 | pop_ctrl(0); | ||
95 | ap_mute(true); | ||
96 | amp_enable(0); | ||
97 | dac_enable(0); | ||
98 | |||
99 | __gpio_as_output(PIN_JD_CON); | ||
100 | __gpio_as_output(PIN_AP_MUTE); | ||
101 | __gpio_as_output(PIN_CODEC_PWRON); | ||
102 | __gpio_as_output(PIN_CS_RST); | ||
103 | |||
104 | mdelay(100); | ||
105 | amp_enable(1); | ||
106 | |||
107 | /* set AIC clk PLL1 */ | ||
108 | __cpm_select_i2sclk_pll(); | ||
109 | __cpm_select_i2sclk_pll1(); | ||
110 | |||
111 | __cpm_enable_pll_change(); | ||
112 | __cpm_set_i2sdiv(43-1); | ||
113 | |||
114 | __cpm_start_aic(); | ||
115 | |||
116 | /* Init AIC */ | ||
117 | __i2s_enable_sclk(); | ||
118 | __i2s_external_codec(); | ||
119 | __i2s_select_msbjustified(); | ||
120 | __i2s_as_master(); | ||
121 | __i2s_enable_transmit_dma(); | ||
122 | __i2s_set_transmit_trigger(24); | ||
123 | __i2s_set_oss_sample_size(16); | ||
124 | __i2s_enable(); | ||
125 | |||
126 | /* Init DAC */ | ||
127 | dac_enable(1); | ||
128 | udelay(1); | ||
129 | audiohw_preinit(); | ||
130 | } | ||
131 | |||
132 | static int vol_tenthdb2hw(const int tdb) | ||
133 | { | ||
134 | if (tdb < CS4398_VOLUME_MIN) { | ||
135 | return 0xff; | ||
136 | } else if (tdb > CS4398_VOLUME_MAX) { | ||
137 | return 0x00; | ||
138 | } else { | ||
139 | return (-tdb/5); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | void audiohw_set_volume(int vol_l, int vol_r) | ||
144 | { | ||
145 | cs4398_write_reg(CS4398_REG_VOL_A, vol_tenthdb2hw(vol_l)); | ||
146 | cs4398_write_reg(CS4398_REG_VOL_B, vol_tenthdb2hw(vol_r)); | ||
147 | } | ||
148 | |||
149 | void audiohw_set_lineout_volume(int vol_l, int vol_r) | ||
150 | { | ||
151 | #if 0 /* unused */ | ||
152 | cs4398_write_reg(CS4398_REG_VOL_A, vol_tenthdb2hw(vol_l)); | ||
153 | cs4398_write_reg(CS4398_REG_VOL_B, vol_tenthdb2hw(vol_r)); | ||
154 | #else | ||
155 | (void)vol_l; | ||
156 | (void)vol_r; | ||
157 | #endif | ||
158 | } | ||
159 | |||
160 | void audiohw_set_filter_roll_off(int value) | ||
161 | { | ||
162 | /* 0 = fast (sharp); | ||
163 | 1 = slow */ | ||
164 | if (value == 0) { | ||
165 | cs4398_write_reg(CS4398_REG_RAMPFILT, cs4398_read_reg(CS4398_REG_RAMPFILT) & ~CS4398_FILT_SEL); | ||
166 | } else { | ||
167 | cs4398_write_reg(CS4398_REG_RAMPFILT, cs4398_read_reg(CS4398_REG_RAMPFILT) | CS4398_FILT_SEL); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | void pll1_init(unsigned int freq); | ||
172 | void audiohw_set_frequency(int fsel) | ||
173 | { | ||
174 | unsigned int pll1_speed; | ||
175 | unsigned char mclk_div, bclk_div, func_mode; | ||
176 | |||
177 | switch(fsel) | ||
178 | { | ||
179 | case HW_FREQ_8: | ||
180 | pll1_speed = 426000000; | ||
181 | mclk_div = 52; | ||
182 | bclk_div = 16; | ||
183 | func_mode = 0; | ||
184 | break; | ||
185 | case HW_FREQ_11: | ||
186 | pll1_speed = 508000000; | ||
187 | mclk_div = 45; | ||
188 | bclk_div = 16; | ||
189 | func_mode = 0; | ||
190 | break; | ||
191 | case HW_FREQ_12: | ||
192 | pll1_speed = 516000000; | ||
193 | mclk_div = 42; | ||
194 | bclk_div = 16; | ||
195 | func_mode = 0; | ||
196 | break; | ||
197 | case HW_FREQ_16: | ||
198 | pll1_speed = 426000000; | ||
199 | mclk_div = 52; | ||
200 | bclk_div = 8; | ||
201 | func_mode = 0; | ||
202 | break; | ||
203 | case HW_FREQ_22: | ||
204 | pll1_speed = 508000000; | ||
205 | mclk_div = 45; | ||
206 | bclk_div = 8; | ||
207 | func_mode = 0; | ||
208 | break; | ||
209 | case HW_FREQ_24: | ||
210 | pll1_speed = 516000000; | ||
211 | mclk_div = 42; | ||
212 | bclk_div = 8; | ||
213 | func_mode = 0; | ||
214 | break; | ||
215 | case HW_FREQ_32: | ||
216 | pll1_speed = 426000000; | ||
217 | mclk_div = 52; | ||
218 | bclk_div = 4; | ||
219 | func_mode = 0; | ||
220 | break; | ||
221 | case HW_FREQ_44: | ||
222 | pll1_speed = 508000000; | ||
223 | mclk_div = 45; | ||
224 | bclk_div = 4; | ||
225 | func_mode = 0; | ||
226 | break; | ||
227 | case HW_FREQ_48: | ||
228 | pll1_speed = 516000000; | ||
229 | mclk_div = 42; | ||
230 | bclk_div = 4; | ||
231 | func_mode = 0; | ||
232 | break; | ||
233 | case HW_FREQ_64: | ||
234 | pll1_speed = 426000000; | ||
235 | mclk_div = 52; | ||
236 | bclk_div = 2; | ||
237 | func_mode = 1; | ||
238 | break; | ||
239 | case HW_FREQ_88: | ||
240 | pll1_speed = 508000000; | ||
241 | mclk_div = 45; | ||
242 | bclk_div = 2; | ||
243 | func_mode = 1; | ||
244 | break; | ||
245 | case HW_FREQ_96: | ||
246 | pll1_speed = 516000000; | ||
247 | mclk_div = 42; | ||
248 | bclk_div = 2; | ||
249 | func_mode = 1; | ||
250 | break; | ||
251 | default: | ||
252 | return; | ||
253 | } | ||
254 | |||
255 | __i2s_stop_bitclk(); | ||
256 | |||
257 | /* 0 = Single-Speed Mode (<50KHz); | ||
258 | 1 = Double-Speed Mode (50-100KHz); | ||
259 | 2 = Quad-Speed Mode; (100-200KHz) */ | ||
260 | cs4398_write_reg(CS4398_REG_MODECTL, (cs4398_read_reg(CS4398_REG_MODECTL) & ~CS4398_FM_MASK) | func_mode); | ||
261 | if (func_mode == 2) | ||
262 | cs4398_write_reg(CS4398_REG_MISC, cs4398_read_reg(CS4398_REG_MISC) | CS4398_MCLKDIV2); | ||
263 | else | ||
264 | cs4398_write_reg(CS4398_REG_MISC, cs4398_read_reg(CS4398_REG_MISC) & ~CS4398_MCLKDIV2); | ||
265 | |||
266 | pll1_init(pll1_speed); | ||
267 | __cpm_enable_pll_change(); | ||
268 | __cpm_set_i2sdiv(mclk_div-1); | ||
269 | __i2s_set_i2sdiv(bclk_div-1); | ||
270 | __i2s_start_bitclk(); | ||
271 | } | ||
272 | |||
273 | void audiohw_postinit(void) | ||
274 | { | ||
275 | sleep(HZ); | ||
276 | audiohw_mute(false); | ||
277 | ap_mute(false); | ||
278 | pop_ctrl(1); | ||
279 | } | ||
280 | |||
281 | void audiohw_close(void) | ||
282 | { | ||
283 | pop_ctrl(0); | ||
284 | sleep(HZ/10); | ||
285 | ap_mute(true); | ||
286 | audiohw_mute(true); | ||
287 | amp_enable(0); | ||
288 | dac_enable(0); | ||
289 | __i2s_disable(); | ||
290 | __cpm_stop_aic(); | ||
291 | sleep(HZ); | ||
292 | pop_ctrl(1); | ||
293 | } | ||