summaryrefslogtreecommitdiff
path: root/firmware/target/mips/ingenic_jz47xx/codec-jz4760.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx/codec-jz4760.c')
-rw-r--r--firmware/target/mips/ingenic_jz47xx/codec-jz4760.c293
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
35static 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
43static 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
51static 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
59static 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
67static 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
75void 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
87void 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
132static 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
143void 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
149void 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
160void 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
171void pll1_init(unsigned int freq);
172void 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
273void audiohw_postinit(void)
274{
275 sleep(HZ);
276 audiohw_mute(false);
277 ap_mute(false);
278 pop_ctrl(1);
279}
280
281void 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}