ce6d889885ae4fb67119aafc64b37540485289b4
[kugel-rb.git] / firmware / target / mips / ingenic_jz47xx / codec-jz4740.c
blobce6d889885ae4fb67119aafc64b37540485289b4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 by Maurus Cuelenaere
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "config.h"
23 #include "audio.h"
24 #include "audiohw.h"
25 #include "jz4740.h"
26 #include "system.h"
28 /* TODO */
29 const struct sound_settings_info audiohw_settings[] = {
30 #ifdef HAVE_SW_VOLUME_CONTROL
31 [SOUND_VOLUME] = {"dB", 0, 1, SW_VOLUME_MIN, 6, 0},
32 #else
33 [SOUND_VOLUME] = {"dB", 0, 1, 0, 6, 0},
34 #endif
35 /* HAVE_SW_TONE_CONTROLS */
36 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
37 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
38 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
39 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
40 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
41 #ifdef HAVE_RECORDING
42 [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23},
43 [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23},
44 [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 1, 1},
45 #endif
48 #if 0
49 static unsigned short codec_volume;
50 static unsigned short codec_base_gain;
51 static unsigned short codec_mic_gain;
52 static int HP_register_value;
53 #endif
54 static bool HP_on_off_flag;
56 static void i2s_codec_reset(void)
58 REG_ICDC_CDCCR1 = (ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_PDVR | ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_VRCGL |
59 ICDC_CDCCR1_VRCGH | ICDC_CDCCR1_HPOV0 | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP |
60 ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST);
61 udelay(10);
62 REG_ICDC_CDCCR1 = (ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_PDVR | ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_VRCGL |
63 ICDC_CDCCR1_VRCGH | ICDC_CDCCR1_HPOV0 | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP );
66 static void i2s_codec_init(void)
68 __cpm_start_aic1();
69 __cpm_start_aic2();
71 __aic_enable();
73 __i2s_internal_codec();
74 __i2s_as_slave();
75 __i2s_select_i2s();
76 __aic_select_i2s();
78 __aic_disable_byteswap();
79 __aic_disable_unsignadj();
80 __aic_disable_mono2stereo();
82 i2s_codec_reset();
84 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST);
86 REG_ICDC_CDCCR2 = ( ICDC_CDCCR2_AINVOL(23) | ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_44)
87 | ICDC_CDCCR2_HPVOL(ICDC_CDCCR2_HPVOL_0));
89 mdelay(15);
90 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVR | ICDC_CDCCR1_VRCGL | ICDC_CDCCR1_VRCGH);
91 REG_ICDC_CDCCR1 |= (ICDC_CDCCR1_EDAC | ICDC_CDCCR1_HPCG);
93 mdelay(600);
94 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_HPCG | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP);
96 mdelay(2);
98 /* CDCCR1.ELININ=0, CDCCR1.EMIC=0, CDCCR1.EADC=0, CDCCR1.SW1ON=0, CDCCR1.EDAC=1, CDCCR1.SW2ON=1, CDCCR1.HPMUTE=0 */
99 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_ELININ | ICDC_CDCCR1_EMIC | ICDC_CDCCR1_EADC |
100 ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_HPMUTE)) | (ICDC_CDCCR1_EDAC
101 | ICDC_CDCCR1_SW2ON);
103 HP_on_off_flag = 1; /* HP is on */
106 #if 0
107 static void i2s_codec_set_mic(unsigned short v) /* 0 <= v <= 100 */
109 v &= 0xff;
111 if(v > 100)
112 v = 100;
113 codec_mic_gain = 31 * v/100;
115 REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (codec_mic_gain << 16));
118 static void i2s_codec_set_base(unsigned short v) /* 0 <= v <= 100 */
120 v &= 0xff;
122 if(v > 100)
123 v = 100;
125 if(v < 25)
126 codec_base_gain = 0;
127 if(v >= 25 && v < 50)
128 codec_base_gain = 1;
129 if(v >= 50 && v < 75)
130 codec_base_gain = 2;
131 if(v >= 75 && v <= 100)
132 codec_base_gain = 3;
134 REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3 << 4)) | (codec_base_gain << 4));
137 static void i2s_codec_set_volume(unsigned short v) /* 0 <= v <= 100 */
139 v &= 0xff;
141 if(v > 100)
142 v = 100;
144 if(v < 25)
145 codec_volume = 0;
146 if(v >= 25 && v < 50)
147 codec_volume = 1;
148 if(v >= 50 && v < 75)
149 codec_volume = 2;
150 if(v >= 75 && v <= 100)
151 codec_volume = 3;
153 REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3)) | codec_volume);
156 static unsigned short i2s_codec_get_bass(void)
158 unsigned short val;
159 int ret;
161 if(codec_base_gain == 0)
162 val = 0;
163 if(codec_base_gain == 1)
164 val = 25;
165 if(codec_base_gain == 2)
166 val = 50;
167 if(codec_base_gain == 3)
168 val = 75;
170 ret = val << 8;
171 val |= ret;
173 return val;
176 static unsigned short i2s_codec_get_mic(void)
178 unsigned short val;
179 int ret;
180 val = 100 * codec_mic_gain / 31;
181 ret = val << 8;
182 val |= ret;
184 return val;
187 static unsigned short i2s_codec_get_volume(void)
189 unsigned short val;
190 int ret;
192 if(codec_volume == 0)
193 val = 0;
194 if(codec_volume == 1)
195 val = 25;
196 if(codec_volume == 2)
197 val = 50;
198 if(codec_volume == 3)
199 val = 75;
201 ret = val << 8;
202 val |= ret;
204 return val;
207 static unsigned long HP_register_value;
208 static void HP_turn_on(void)
210 //see 1.3.4.1
212 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST); //set suspend 0
214 mdelay(15);
215 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVR | ICDC_CDCCR1_VRCGL | ICDC_CDCCR1_VRCGH);
216 REG_ICDC_CDCCR1 |= (ICDC_CDCCR1_EDAC | ICDC_CDCCR1_HPCG);
218 mdelay(600);
219 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_HPCG | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP);
221 mdelay(2);
222 HP_register_value = REG_ICDC_CDCCR1;
224 //see 1.3.4.2
225 /*REG_ICDC_CDCCR1 &= 0xfffffffc;
226 mdelay(7);
227 REG_ICDC_CDCCR1 |= 0x00040400;
228 mdelay(15);
229 REG_ICDC_CDCCR1 &= 0xfffbfbff;
230 udelay(500);
231 REG_ICDC_CDCCR1 &= 0xffe5fcff;
232 REG_ICDC_CDCCR1 |= 0x01000000;
233 mdelay(400);
234 REG_ICDC_CDCCR1 &= 0xfffeffff;
235 mdelay(7);
236 HP_register_value = REG_ICDC_CDCCR1;*/
238 //see 1.3.4.3
242 static void HP_turn_off(void)
244 //see 1.3.4.1
245 mdelay(2);
246 REG_ICDC_CDCCR1 = HP_register_value;
247 REG_ICDC_CDCCR1 |= 0x001b0300;
248 REG_ICDC_CDCCR1 &= 0xfeffffff;
250 mdelay(15);
251 REG_ICDC_CDCCR1 |= 0x00000002;//set suspend 1
253 //see 1.3.4.2
254 /*mdelay(4);
255 REG_ICDC_CDCCR1 = HP_register_value;
256 REG_ICDC_CDCCR1 |= 0x001b0300;
257 REG_ICDC_CDCCR1 &= 0xfeffffff;
258 mdelay(4);
259 REG_ICDC_CDCCR1 |= 0x00000400;
260 mdelay(15);
261 REG_ICDC_CDCCR1 &= 0xfffffdff;
262 mdelay(7);
263 REG_ICDC_CDCCR1 |= 0x00000002;*/
265 //see 1.3.4.3
267 #endif
269 static void audiohw_mute(bool mute)
271 if(mute)
272 REG_ICDC_CDCCR1 |= ICDC_CDCCR1_HPMUTE;
273 else
274 REG_ICDC_CDCCR1 &= ~ICDC_CDCCR1_HPMUTE;
277 void audiohw_preinit(void)
281 void audiohw_postinit(void)
283 audiohw_mute(false);
284 //HP_turn_on();
287 void audiohw_init(void)
289 i2s_codec_init();
292 void audiohw_set_volume(int v)
294 if(v >= 0)
296 /* 0 <= v <= 60 */
297 unsigned int codec_volume = ICDC_CDCCR2_HPVOL(v / 20);
299 if((REG_ICDC_CDCCR2 & ICDC_CDCCR2_HPVOL(0x3)) != codec_volume)
300 REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 & ~ICDC_CDCCR2_HPVOL(0x3)) | codec_volume;
304 void audiohw_set_frequency(int freq)
306 unsigned int speed;
308 switch(freq)
310 case 8000:
311 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_8);
312 break;
313 case 11025:
314 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_11);
315 break;
316 case 12000:
317 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_12);
318 break;
319 case 16000:
320 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_16);
321 break;
322 case 22050:
323 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_22);
324 break;
325 case 24000:
326 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_24);
327 break;
328 case 32000:
329 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_32);
330 break;
331 case 44100:
332 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_44);
333 break;
334 case 48000:
335 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_48);
336 break;
337 default:
338 return;
341 if((REG_ICDC_CDCCR2 & ICDC_CDCCR2_SMPR(0xF)) != speed)
342 REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 & ~ICDC_CDCCR2_SMPR(0xF)) | speed;
345 int audio_channels = 2;
346 int audio_output_source = AUDIO_SRC_PLAYBACK;
348 void audio_set_output_source(int source)
350 if((unsigned)source >= AUDIO_NUM_SOURCES)
351 source = AUDIO_SRC_PLAYBACK;
353 audio_output_source = source;
354 } /* audio_set_output_source */
356 void audio_input_mux(int source, unsigned flags)
358 static int last_source = AUDIO_SRC_PLAYBACK;
359 static bool last_recording = false;
360 bool recording = flags & SRCF_RECORDING;
362 switch (source)
364 default: /* playback - no recording */
365 source = AUDIO_SRC_PLAYBACK;
366 case AUDIO_SRC_PLAYBACK:
367 audio_channels = 2;
368 if(source != last_source)
369 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_ELININ | ICDC_CDCCR1_EMIC | ICDC_CDCCR1_EADC | ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_HPMUTE))
370 | (ICDC_CDCCR1_EDAC | ICDC_CDCCR1_SW2ON);
371 break;
373 #if INPUT_SRC_CAPS & SRC_CAP_MIC
374 case AUDIO_SRC_MIC: /* recording only */
375 audio_channels = 1;
376 if(source != last_source)
377 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_ELININ | ICDC_CDCCR1_EDAC | ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_HPMUTE))
378 | (ICDC_CDCCR1_EADC | ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_EMIC);
379 break;
380 #endif
382 #if INPUT_SRC_CAPS & SRC_CAP_FMRADIO
383 case AUDIO_SRC_FMRADIO: /* recording and playback */
384 audio_channels = 2;
386 if(source == last_source && recording == last_recording)
387 break;
389 last_recording = recording;
391 if(recording)
392 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_EMIC | ICDC_CDCCR1_EDAC | ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_HPMUTE))
393 | (ICDC_CDCCR1_EADC | ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_ELININ);
394 else
395 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_EMIC | ICDC_CDCCR1_EDAC | ICDC_CDCCR1_EADC |
396 ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_HPMUTE)) | (ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_ELININ);
397 break;
398 #endif
399 } /* end switch */
401 last_source = source;
402 } /* audio_input_mux */