Create system-sdl.c in the target tree and move early initialization into a system_in...
[kugel-rb.git] / firmware / sound.c
blob47f64accd6d293503b6f6c620ce1dc3d060e2c50
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Linus Nielsen Feltzing
11 * Copyright (C) 2007 by Christian Gmeiner
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include "config.h"
25 #include "sound.h"
26 #include "logf.h"
27 #include "system.h"
28 #include "i2c.h"
29 #include "mas.h"
30 #ifndef SIMULATOR
31 #if CONFIG_CPU == PNX0101
32 #include "pnx0101.h"
33 #endif
34 #include "dac.h"
35 #if CONFIG_CODEC == SWCODEC
36 #include "pcm.h"
37 #endif
38 #endif
40 /* TODO
41 * find a nice way to handle 1.5db steps -> see wm8751 ifdef in sound_set_bass/treble
44 extern bool audio_is_initialized;
46 const char *sound_unit(int setting)
48 return audiohw_settings[setting].unit;
51 int sound_numdecimals(int setting)
53 return audiohw_settings[setting].numdecimals;
56 int sound_steps(int setting)
58 return audiohw_settings[setting].steps;
61 int sound_min(int setting)
63 return audiohw_settings[setting].minval;
66 int sound_max(int setting)
68 return audiohw_settings[setting].maxval;
71 int sound_default(int setting)
73 return audiohw_settings[setting].defaultval;
76 static sound_set_type * const sound_set_fns[] =
78 [0 ... SOUND_LAST_SETTING-1] = NULL,
79 [SOUND_VOLUME] = sound_set_volume,
80 [SOUND_BASS] = sound_set_bass,
81 [SOUND_TREBLE] = sound_set_treble,
82 [SOUND_BALANCE] = sound_set_balance,
83 [SOUND_CHANNELS] = sound_set_channels,
84 [SOUND_STEREO_WIDTH] = sound_set_stereo_width,
85 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
86 [SOUND_LOUDNESS] = sound_set_loudness,
87 [SOUND_AVC] = sound_set_avc,
88 [SOUND_MDB_STRENGTH] = sound_set_mdb_strength,
89 [SOUND_MDB_HARMONICS] = sound_set_mdb_harmonics,
90 [SOUND_MDB_CENTER] = sound_set_mdb_center,
91 [SOUND_MDB_SHAPE] = sound_set_mdb_shape,
92 [SOUND_MDB_ENABLE] = sound_set_mdb_enable,
93 [SOUND_SUPERBASS] = sound_set_superbass,
94 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
95 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
96 [SOUND_BASS_CUTOFF] = sound_set_bass_cutoff,
97 #endif
98 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
99 [SOUND_TREBLE_CUTOFF] = sound_set_treble_cutoff,
100 #endif
103 sound_set_type* sound_get_fn(int setting)
105 return ((unsigned)setting >= ARRAYLEN(sound_set_fns)?
106 NULL : sound_set_fns[setting]);
109 #if CONFIG_CODEC == SWCODEC
110 static int (*dsp_callback)(int, intptr_t) = NULL;
112 void sound_set_dsp_callback(int (*func)(int, intptr_t))
114 dsp_callback = func;
116 #endif
118 #if (CONFIG_CODEC == MAS3507D) && !defined(SIMULATOR)
119 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
120 static int tenthdb2reg(int db)
122 if (db < -540) /* 3 dB steps */
123 return (db + 780) / 30;
124 else /* 1.5 dB steps */
125 return (db + 660) / 15;
127 #endif
130 #if !defined(AUDIOHW_HAVE_CLIPPING)
132 * The prescaler compensates for any kind of boosts, to prevent clipping.
134 * It's basically just a measure to make sure that audio does not clip during
135 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
136 * the audio amplitude by -12 dB before processing, then increase master gain
137 * by 12 dB after processing.
140 /* all values in tenth of dB MAS3507D UDA1380 */
141 int current_volume = 0; /* -780..+180 -840.. 0 */
142 int current_balance = 0; /* -960..+960 -840..+840 */
143 int current_treble = 0; /* -150..+150 0.. +60 */
144 int current_bass = 0; /* -150..+150 0..+240 */
146 static void set_prescaled_volume(void)
148 int prescale = 0;
149 int l, r;
151 /* The codecs listed use HW tone controls but don't have suitable prescaler
152 * functionality, so we let the prescaler stay at 0 for these, unless
153 * SW tone controls are in use. This is to avoid needing the SW DSP just for
154 * the prescaling.
156 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
157 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
158 || defined(HAVE_WM8751) || defined(HAVE_WM8758) || defined(HAVE_WM8985) \
159 || defined(HAVE_UDA1341))
161 prescale = MAX(current_bass, current_treble);
162 if (prescale < 0)
163 prescale = 0; /* no need to prescale if we don't boost
164 bass or treble */
166 /* Gain up the analog volume to compensate the prescale gain reduction,
167 * but if this would push the volume over the top, reduce prescaling
168 * instead (might cause clipping). */
169 if (current_volume + prescale > VOLUME_MAX)
170 prescale = VOLUME_MAX - current_volume;
171 #endif
173 #if defined(AUDIOHW_HAVE_PRESCALER)
174 audiohw_set_prescaler(prescale);
175 #else
176 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
177 #endif
179 if (current_volume == VOLUME_MIN)
180 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
182 l = r = current_volume + prescale;
184 /* Balance the channels scaled by the current volume and min volume. */
185 /* Subtract a dB from VOLUME_MIN to get it to a mute level */
186 if (current_balance > 0)
188 l -= ((l - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
190 else if (current_balance < 0)
192 r += ((r - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
195 #ifdef HAVE_SW_VOLUME_CONTROL
196 dsp_callback(DSP_CALLBACK_SET_SW_VOLUME, 0);
197 #endif
199 #ifndef SIMULATOR
200 #if CONFIG_CODEC == MAS3507D
201 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
202 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
203 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
204 || defined(HAVE_WM8750) || defined(HAVE_WM8751) || defined(HAVE_AS3514) \
205 || defined(HAVE_TSC2100) || defined(HAVE_AK4537) || defined(HAVE_UDA1341)
206 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
207 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
208 || defined(HAVE_WM8750) || (defined(HAVE_WM8751) && !defined(MROBE_100)) \
209 || defined(HAVE_WM8985)
210 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
211 #endif
213 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
214 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
215 #elif defined(HAVE_JZ4740_CODEC) || defined(HAVE_SDL_AUDIO)
216 audiohw_set_volume(current_volume);
217 #endif
218 #else /* SIMULATOR */
219 audiohw_set_volume(current_volume);
220 #endif /* !SIMULATOR */
222 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
225 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
226 unsigned long mdb_shape_shadow = 0;
227 unsigned long loudness_shadow = 0;
228 #endif
230 void sound_set_volume(int value)
232 if(!audio_is_initialized)
233 return;
235 #if defined(AUDIOHW_HAVE_CLIPPING)
236 audiohw_set_volume(value);
237 #elif CONFIG_CPU == PNX0101
238 int tmp = (60 - value * 4) & 0xff;
239 CODECVOL = tmp | (tmp << 8);
240 #else
241 current_volume = value * 10; /* tenth of dB */
242 set_prescaled_volume();
243 #endif
246 void sound_set_balance(int value)
248 if(!audio_is_initialized)
249 return;
251 #ifdef AUDIOHW_HAVE_BALANCE
252 audiohw_set_balance(value);
253 #else
254 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
255 set_prescaled_volume();
256 #endif
259 void sound_set_bass(int value)
261 if(!audio_is_initialized)
262 return;
264 #if !defined(AUDIOHW_HAVE_CLIPPING)
265 #if defined(HAVE_WM8750) || defined(HAVE_WM8751)
266 current_bass = value;
267 #else
268 current_bass = value * 10;
269 #endif
270 #endif
272 #if defined(AUDIOHW_HAVE_BASS)
273 audiohw_set_bass(value);
274 #else
275 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
276 #endif
278 #if !defined(AUDIOHW_HAVE_CLIPPING)
279 set_prescaled_volume();
280 #endif
283 void sound_set_treble(int value)
285 if(!audio_is_initialized)
286 return;
288 #if !defined(AUDIOHW_HAVE_CLIPPING)
289 #if defined(HAVE_WM8750) || defined(HAVE_WM8751)
290 current_treble = value;
291 #else
292 current_treble = value * 10;
293 #endif
294 #endif
296 #if defined(AUDIOHW_HAVE_TREBLE)
297 audiohw_set_treble(value);
298 #else
299 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
300 #endif
302 #if !defined(AUDIOHW_HAVE_CLIPPING)
303 set_prescaled_volume();
304 #endif
307 void sound_set_channels(int value)
309 if(!audio_is_initialized)
310 return;
312 #if CONFIG_CODEC == SWCODEC
313 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
314 #else
315 audiohw_set_channel(value);
316 #endif
319 void sound_set_stereo_width(int value)
321 if(!audio_is_initialized)
322 return;
324 #if CONFIG_CODEC == SWCODEC
325 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
326 #else
327 audiohw_set_stereo_width(value);
328 #endif
331 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
332 void sound_set_bass_cutoff(int value)
334 if(!audio_is_initialized)
335 return;
337 audiohw_set_bass_cutoff(value);
339 #endif
341 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
342 void sound_set_treble_cutoff(int value)
344 if(!audio_is_initialized)
345 return;
347 audiohw_set_treble_cutoff(value);
349 #endif
351 #if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F))
352 void sound_set_loudness(int value)
354 if(!audio_is_initialized)
355 return;
356 loudness_shadow = (loudness_shadow & 0x04) |
357 (MAX(MIN(value * 4, 0x44), 0) << 8);
358 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
361 void sound_set_avc(int value)
363 if(!audio_is_initialized)
364 return;
365 int tmp;
367 static const uint16_t avc_vals[] =
369 (0x1 << 8) | (0x8 << 12), /* 20ms */
370 (0x2 << 8) | (0x8 << 12), /* 2s */
371 (0x4 << 8) | (0x8 << 12), /* 4s */
372 (0x8 << 8) | (0x8 << 12), /* 8s */
374 switch (value) {
375 case 1:
376 case 2:
377 case 3:
378 case 4:
379 tmp = avc_vals[value -1];
380 break;
381 case -1: /* turn off and then turn on again to decay quickly */
382 tmp = mas_codec_readreg(MAS_REG_KAVC);
383 mas_codec_writereg(MAS_REG_KAVC, 0);
384 break;
385 default: /* off */
386 tmp = 0;
387 break;
389 mas_codec_writereg(MAS_REG_KAVC, tmp);
392 void sound_set_mdb_strength(int value)
394 if(!audio_is_initialized)
395 return;
396 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
399 void sound_set_mdb_harmonics(int value)
401 if(!audio_is_initialized)
402 return;
403 int tmp = value * 127 / 100;
404 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
407 void sound_set_mdb_center(int value)
409 if(!audio_is_initialized)
410 return;
411 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
414 void sound_set_mdb_shape(int value)
416 if(!audio_is_initialized)
417 return;
418 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
419 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
422 void sound_set_mdb_enable(int value)
424 if(!audio_is_initialized)
425 return;
426 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
427 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
430 void sound_set_superbass(int value)
432 if(!audio_is_initialized)
433 return;
434 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
435 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
437 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
439 void sound_set(int setting, int value)
441 sound_set_type* sound_set_val = sound_get_fn(setting);
442 if (sound_set_val)
443 sound_set_val(value);
446 #if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
447 && !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
448 && !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
449 && !defined (HAVE_WM8731) && !defined (HAVE_WM8978) \
450 && !defined(HAVE_AK4537)) || defined(SIMULATOR)
451 int sound_val2phys(int setting, int value)
453 #if CONFIG_CODEC == MAS3587F
454 int result = 0;
456 switch(setting)
458 case SOUND_LEFT_GAIN:
459 case SOUND_RIGHT_GAIN:
460 result = (value - 2) * 15;
461 break;
463 case SOUND_MIC_GAIN:
464 result = value * 15 + 210;
465 break;
467 default:
468 result = value;
469 break;
471 return result;
472 #elif defined(HAVE_UDA1380)
473 int result = 0;
475 switch(setting)
477 #ifdef HAVE_RECORDING
478 case SOUND_LEFT_GAIN:
479 case SOUND_RIGHT_GAIN:
480 case SOUND_MIC_GAIN:
481 result = value * 5; /* (1/2) * 10 */
482 break;
483 #endif
484 default:
485 result = value;
486 break;
488 return result;
489 #elif defined(HAVE_TLV320) || defined(HAVE_WM8711) \
490 || defined(HAVE_WM8721) || defined(HAVE_WM8731)
491 int result = 0;
493 switch(setting)
495 #ifdef HAVE_RECORDING
496 case SOUND_LEFT_GAIN:
497 case SOUND_RIGHT_GAIN:
498 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
499 break;
501 case SOUND_MIC_GAIN:
502 result = value * 200; /* 0 or 20 dB */
503 break;
504 #endif
505 default:
506 result = value;
507 break;
509 return result;
510 #elif defined(HAVE_AS3514)
511 /* This is here for the sim only and the audio driver has its own */
512 int result;
514 switch(setting)
516 #ifdef HAVE_RECORDING
517 case SOUND_LEFT_GAIN:
518 case SOUND_RIGHT_GAIN:
519 case SOUND_MIC_GAIN:
520 result = (value - 23) * 15;
521 break;
522 #endif
523 default:
524 result = value;
525 break;
528 return result;
529 #elif defined(HAVE_WM8978)
530 int result;
532 switch (setting)
534 #ifdef HAVE_RECORDING
535 case SOUND_LEFT_GAIN:
536 case SOUND_RIGHT_GAIN:
537 case SOUND_MIC_GAIN:
538 result = value * 5;
539 break;
540 #endif
542 default:
543 result = value;
546 return result;
547 #else
548 (void)setting;
549 return value;
550 #endif
552 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
554 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
555 /* This function works by telling the decoder that we have another
556 crystal frequency than we actually have. It will adjust its internal
557 parameters and the result is that the audio is played at another pitch.
559 The pitch value precision is based on PITCH_SPEED_PRECISION (in dsp.h)
562 #ifdef SIMULATOR
563 static
564 #else
565 extern
566 #endif
567 unsigned long shadow_io_control_main;
568 static int last_pitch = PITCH_SPEED_100;
570 void sound_set_pitch(int32_t pitch)
572 unsigned long val;
574 if (pitch != last_pitch)
576 /* Calculate the new (bogus) frequency */
577 val = 18432 * PITCH_SPEED_100 / pitch;
579 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
581 /* We must tell the MAS that the frequency has changed.
582 * This will unfortunately cause a short silence. */
583 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
585 last_pitch = pitch;
589 int32_t sound_get_pitch(void)
591 return last_pitch;
593 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */