Hopefully finish off the red from r26051.
[kugel-rb.git] / firmware / target / mips / ingenic_jz47xx / codec-jz4740.c
blobab9efc91b092cadd3a33e271b470de885b9fd279
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 "sound.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 #ifdef AUDIOHW_HAVE_BASS
37 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
38 #endif
39 #ifdef AUDIOHW_HAVE_TREBLE
40 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
41 #endif
42 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
43 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
44 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
45 #ifdef HAVE_RECORDING
46 [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23},
47 [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23},
48 [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 1, 1},
49 #endif
52 #if 0
53 static unsigned short codec_volume;
54 static unsigned short codec_base_gain;
55 static unsigned short codec_mic_gain;
56 static int HP_register_value;
57 #endif
58 static bool HP_on_off_flag;
60 static void i2s_codec_reset(void)
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 |
64 ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST);
65 udelay(10);
66 REG_ICDC_CDCCR1 = (ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_PDVR | ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_VRCGL |
67 ICDC_CDCCR1_VRCGH | ICDC_CDCCR1_HPOV0 | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP );
70 static void i2s_codec_init(void)
72 __cpm_start_aic1();
73 __cpm_start_aic2();
75 __aic_enable();
77 __i2s_internal_codec();
78 __i2s_as_slave();
79 __i2s_select_i2s();
80 __aic_select_i2s();
82 __aic_disable_byteswap();
83 __aic_disable_unsignadj();
84 __aic_disable_mono2stereo();
86 i2s_codec_reset();
88 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST);
90 REG_ICDC_CDCCR2 = ( ICDC_CDCCR2_AINVOL(23) | ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_44)
91 | ICDC_CDCCR2_HPVOL(ICDC_CDCCR2_HPVOL_0));
93 mdelay(15);
94 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVR | ICDC_CDCCR1_VRCGL | ICDC_CDCCR1_VRCGH);
95 REG_ICDC_CDCCR1 |= (ICDC_CDCCR1_EDAC | ICDC_CDCCR1_HPCG);
97 mdelay(600);
98 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_HPCG | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP);
100 mdelay(2);
102 /* CDCCR1.ELININ=0, CDCCR1.EMIC=0, CDCCR1.EADC=0, CDCCR1.SW1ON=0, CDCCR1.EDAC=1, CDCCR1.SW2ON=1, CDCCR1.HPMUTE=0 */
103 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_ELININ | ICDC_CDCCR1_EMIC | ICDC_CDCCR1_EADC |
104 ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_HPMUTE)) | (ICDC_CDCCR1_EDAC
105 | ICDC_CDCCR1_SW2ON);
107 HP_on_off_flag = 1; /* HP is on */
110 #if 0
111 static void i2s_codec_set_mic(unsigned short v) /* 0 <= v <= 100 */
113 v &= 0xff;
115 if(v > 100)
116 v = 100;
117 codec_mic_gain = 31 * v/100;
119 REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (codec_mic_gain << 16));
122 static void i2s_codec_set_base(unsigned short v) /* 0 <= v <= 100 */
124 v &= 0xff;
126 if(v > 100)
127 v = 100;
129 if(v < 25)
130 codec_base_gain = 0;
131 if(v >= 25 && v < 50)
132 codec_base_gain = 1;
133 if(v >= 50 && v < 75)
134 codec_base_gain = 2;
135 if(v >= 75 && v <= 100)
136 codec_base_gain = 3;
138 REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3 << 4)) | (codec_base_gain << 4));
141 static void i2s_codec_set_volume(unsigned short v) /* 0 <= v <= 100 */
143 v &= 0xff;
145 if(v > 100)
146 v = 100;
148 if(v < 25)
149 codec_volume = 0;
150 if(v >= 25 && v < 50)
151 codec_volume = 1;
152 if(v >= 50 && v < 75)
153 codec_volume = 2;
154 if(v >= 75 && v <= 100)
155 codec_volume = 3;
157 REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3)) | codec_volume);
160 static unsigned short i2s_codec_get_bass(void)
162 unsigned short val;
163 int ret;
165 if(codec_base_gain == 0)
166 val = 0;
167 if(codec_base_gain == 1)
168 val = 25;
169 if(codec_base_gain == 2)
170 val = 50;
171 if(codec_base_gain == 3)
172 val = 75;
174 ret = val << 8;
175 val |= ret;
177 return val;
180 static unsigned short i2s_codec_get_mic(void)
182 unsigned short val;
183 int ret;
184 val = 100 * codec_mic_gain / 31;
185 ret = val << 8;
186 val |= ret;
188 return val;
191 static unsigned short i2s_codec_get_volume(void)
193 unsigned short val;
194 int ret;
196 if(codec_volume == 0)
197 val = 0;
198 if(codec_volume == 1)
199 val = 25;
200 if(codec_volume == 2)
201 val = 50;
202 if(codec_volume == 3)
203 val = 75;
205 ret = val << 8;
206 val |= ret;
208 return val;
211 static unsigned long HP_register_value;
212 static void HP_turn_on(void)
214 //see 1.3.4.1
216 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST); //set suspend 0
218 mdelay(15);
219 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVR | ICDC_CDCCR1_VRCGL | ICDC_CDCCR1_VRCGH);
220 REG_ICDC_CDCCR1 |= (ICDC_CDCCR1_EDAC | ICDC_CDCCR1_HPCG);
222 mdelay(600);
223 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_HPCG | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP);
225 mdelay(2);
226 HP_register_value = REG_ICDC_CDCCR1;
228 //see 1.3.4.2
229 /*REG_ICDC_CDCCR1 &= 0xfffffffc;
230 mdelay(7);
231 REG_ICDC_CDCCR1 |= 0x00040400;
232 mdelay(15);
233 REG_ICDC_CDCCR1 &= 0xfffbfbff;
234 udelay(500);
235 REG_ICDC_CDCCR1 &= 0xffe5fcff;
236 REG_ICDC_CDCCR1 |= 0x01000000;
237 mdelay(400);
238 REG_ICDC_CDCCR1 &= 0xfffeffff;
239 mdelay(7);
240 HP_register_value = REG_ICDC_CDCCR1;*/
242 //see 1.3.4.3
246 static void HP_turn_off(void)
248 //see 1.3.4.1
249 mdelay(2);
250 REG_ICDC_CDCCR1 = HP_register_value;
251 REG_ICDC_CDCCR1 |= 0x001b0300;
252 REG_ICDC_CDCCR1 &= 0xfeffffff;
254 mdelay(15);
255 REG_ICDC_CDCCR1 |= 0x00000002;//set suspend 1
257 //see 1.3.4.2
258 /*mdelay(4);
259 REG_ICDC_CDCCR1 = HP_register_value;
260 REG_ICDC_CDCCR1 |= 0x001b0300;
261 REG_ICDC_CDCCR1 &= 0xfeffffff;
262 mdelay(4);
263 REG_ICDC_CDCCR1 |= 0x00000400;
264 mdelay(15);
265 REG_ICDC_CDCCR1 &= 0xfffffdff;
266 mdelay(7);
267 REG_ICDC_CDCCR1 |= 0x00000002;*/
269 //see 1.3.4.3
271 #endif
273 static void audiohw_mute(bool mute)
275 if(mute)
276 REG_ICDC_CDCCR1 |= ICDC_CDCCR1_HPMUTE;
277 else
278 REG_ICDC_CDCCR1 &= ~ICDC_CDCCR1_HPMUTE;
281 void audiohw_preinit(void)
285 void audiohw_postinit(void)
287 audiohw_mute(false);
288 //HP_turn_on();
291 void audiohw_init(void)
293 i2s_codec_init();
296 void audiohw_set_volume(int v)
298 if(v >= 0)
300 /* 0 <= v <= 60 */
301 unsigned int codec_volume = ICDC_CDCCR2_HPVOL(v / 20);
303 if((REG_ICDC_CDCCR2 & ICDC_CDCCR2_HPVOL(0x3)) != codec_volume)
304 REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 & ~ICDC_CDCCR2_HPVOL(0x3)) | codec_volume;
308 void audiohw_set_frequency(int freq)
310 unsigned int speed;
312 switch(freq)
314 case 8000:
315 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_8);
316 break;
317 case 11025:
318 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_11);
319 break;
320 case 12000:
321 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_12);
322 break;
323 case 16000:
324 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_16);
325 break;
326 case 22050:
327 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_22);
328 break;
329 case 24000:
330 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_24);
331 break;
332 case 32000:
333 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_32);
334 break;
335 case 44100:
336 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_44);
337 break;
338 case 48000:
339 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_48);
340 break;
341 default:
342 return;
345 if((REG_ICDC_CDCCR2 & ICDC_CDCCR2_SMPR(0xF)) != speed)
346 REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 & ~ICDC_CDCCR2_SMPR(0xF)) | speed;
349 int audio_channels = 2;
350 int audio_output_source = AUDIO_SRC_PLAYBACK;
352 void audio_set_output_source(int source)
354 if((unsigned)source >= AUDIO_NUM_SOURCES)
355 source = AUDIO_SRC_PLAYBACK;
357 audio_output_source = source;
358 } /* audio_set_output_source */
360 void audio_input_mux(int source, unsigned flags)
362 static int last_source = AUDIO_SRC_PLAYBACK;
363 static bool last_recording = false;
364 bool recording = flags & SRCF_RECORDING;
366 switch (source)
368 default: /* playback - no recording */
369 source = AUDIO_SRC_PLAYBACK;
370 case AUDIO_SRC_PLAYBACK:
371 audio_channels = 2;
372 if(source != last_source)
373 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_ELININ | ICDC_CDCCR1_EMIC | ICDC_CDCCR1_EADC | ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_HPMUTE))
374 | (ICDC_CDCCR1_EDAC | ICDC_CDCCR1_SW2ON);
375 break;
377 #if INPUT_SRC_CAPS & SRC_CAP_MIC
378 case AUDIO_SRC_MIC: /* recording only */
379 audio_channels = 1;
380 if(source != last_source)
381 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_ELININ | ICDC_CDCCR1_EDAC | ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_HPMUTE))
382 | (ICDC_CDCCR1_EADC | ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_EMIC);
383 break;
384 #endif
386 #if INPUT_SRC_CAPS & SRC_CAP_FMRADIO
387 case AUDIO_SRC_FMRADIO: /* recording and playback */
388 audio_channels = 2;
390 if(source == last_source && recording == last_recording)
391 break;
393 last_recording = recording;
395 if(recording)
396 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_EMIC | ICDC_CDCCR1_EDAC | ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_HPMUTE))
397 | (ICDC_CDCCR1_EADC | ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_ELININ);
398 else
399 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_EMIC | ICDC_CDCCR1_EDAC | ICDC_CDCCR1_EADC |
400 ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_HPMUTE)) | (ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_ELININ);
401 break;
402 #endif
403 } /* end switch */
405 last_source = source;
406 } /* audio_input_mux */