Move c/h files implementing/defining standard library stuff into a new libc directory...
[kugel-rb.git] / firmware / sound.c
blob4f95b6ed503aa229a930b4205c156121f98a8a4f
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 #ifdef SIMULATOR
47 extern void audiohw_set_volume(int value);
48 /* dummy for sim */
49 const struct sound_settings_info audiohw_settings[] = {
50 [SOUND_VOLUME] = {"dB", 0, 1, VOLUME_MIN / 10, VOLUME_MAX / 10, -25},
51 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
52 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
53 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
54 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
55 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
56 #if defined(HAVE_RECORDING)
57 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
58 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
59 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
60 #endif
61 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
62 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
63 #endif
64 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
65 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
66 #endif
67 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
68 [SOUND_LOUDNESS] = {"dB", 0, 1, 0, 17, 0},
69 [SOUND_AVC] = {"", 0, 1, -1, 4, 0},
70 [SOUND_MDB_STRENGTH] = {"dB", 0, 1, 0, 127, 48},
71 [SOUND_MDB_HARMONICS] = {"%", 0, 1, 0, 100, 50},
72 [SOUND_MDB_CENTER] = {"Hz", 0, 10, 20, 300, 60},
73 [SOUND_MDB_SHAPE] = {"Hz", 0, 10, 50, 300, 90},
74 [SOUND_MDB_ENABLE] = {"", 0, 1, 0, 1, 0},
75 [SOUND_SUPERBASS] = {"", 0, 1, 0, 1, 0},
76 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
78 #endif
80 const char *sound_unit(int setting)
82 return audiohw_settings[setting].unit;
85 int sound_numdecimals(int setting)
87 return audiohw_settings[setting].numdecimals;
90 int sound_steps(int setting)
92 return audiohw_settings[setting].steps;
95 int sound_min(int setting)
97 return audiohw_settings[setting].minval;
100 int sound_max(int setting)
102 return audiohw_settings[setting].maxval;
105 int sound_default(int setting)
107 return audiohw_settings[setting].defaultval;
110 static sound_set_type * const sound_set_fns[] =
112 [0 ... SOUND_LAST_SETTING-1] = NULL,
113 [SOUND_VOLUME] = sound_set_volume,
114 [SOUND_BASS] = sound_set_bass,
115 [SOUND_TREBLE] = sound_set_treble,
116 [SOUND_BALANCE] = sound_set_balance,
117 [SOUND_CHANNELS] = sound_set_channels,
118 [SOUND_STEREO_WIDTH] = sound_set_stereo_width,
119 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
120 [SOUND_LOUDNESS] = sound_set_loudness,
121 [SOUND_AVC] = sound_set_avc,
122 [SOUND_MDB_STRENGTH] = sound_set_mdb_strength,
123 [SOUND_MDB_HARMONICS] = sound_set_mdb_harmonics,
124 [SOUND_MDB_CENTER] = sound_set_mdb_center,
125 [SOUND_MDB_SHAPE] = sound_set_mdb_shape,
126 [SOUND_MDB_ENABLE] = sound_set_mdb_enable,
127 [SOUND_SUPERBASS] = sound_set_superbass,
128 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
129 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
130 [SOUND_BASS_CUTOFF] = sound_set_bass_cutoff,
131 #endif
132 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
133 [SOUND_TREBLE_CUTOFF] = sound_set_treble_cutoff,
134 #endif
137 sound_set_type* sound_get_fn(int setting)
139 return ((unsigned)setting >= ARRAYLEN(sound_set_fns)?
140 NULL : sound_set_fns[setting]);
143 #if CONFIG_CODEC == SWCODEC
144 static int (*dsp_callback)(int, intptr_t) = NULL;
146 void sound_set_dsp_callback(int (*func)(int, intptr_t))
148 dsp_callback = func;
150 #endif
152 #if (CONFIG_CODEC == MAS3507D) && !defined(SIMULATOR)
153 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
154 static int tenthdb2reg(int db)
156 if (db < -540) /* 3 dB steps */
157 return (db + 780) / 30;
158 else /* 1.5 dB steps */
159 return (db + 660) / 15;
161 #endif
164 #if !defined(AUDIOHW_HAVE_CLIPPING)
166 * The prescaler compensates for any kind of boosts, to prevent clipping.
168 * It's basically just a measure to make sure that audio does not clip during
169 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
170 * the audio amplitude by -12 dB before processing, then increase master gain
171 * by 12 dB after processing.
174 /* all values in tenth of dB MAS3507D UDA1380 */
175 int current_volume = 0; /* -780..+180 -840.. 0 */
176 int current_balance = 0; /* -960..+960 -840..+840 */
177 int current_treble = 0; /* -150..+150 0.. +60 */
178 int current_bass = 0; /* -150..+150 0..+240 */
180 static void set_prescaled_volume(void)
182 int prescale = 0;
183 int l, r;
185 /* The codecs listed use HW tone controls but don't have suitable prescaler
186 * functionality, so we let the prescaler stay at 0 for these, unless
187 * SW tone controls are in use. This is to avoid needing the SW DSP just for
188 * the prescaling.
190 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
191 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
192 || defined(HAVE_WM8751) || defined(HAVE_WM8758) || defined(HAVE_WM8985) \
193 || defined(HAVE_UDA1341))
195 prescale = MAX(current_bass, current_treble);
196 if (prescale < 0)
197 prescale = 0; /* no need to prescale if we don't boost
198 bass or treble */
200 /* Gain up the analog volume to compensate the prescale gain reduction,
201 * but if this would push the volume over the top, reduce prescaling
202 * instead (might cause clipping). */
203 if (current_volume + prescale > VOLUME_MAX)
204 prescale = VOLUME_MAX - current_volume;
205 #endif
207 #if defined(AUDIOHW_HAVE_PRESCALER)
208 audiohw_set_prescaler(prescale);
209 #else
210 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
211 #endif
213 if (current_volume == VOLUME_MIN)
214 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
216 l = r = current_volume + prescale;
218 /* Balance the channels scaled by the current volume and min volume. */
219 /* Subtract a dB from VOLUME_MIN to get it to a mute level */
220 if (current_balance > 0)
222 l -= ((l - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
224 else if (current_balance < 0)
226 r += ((r - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
229 #ifdef HAVE_SW_VOLUME_CONTROL
230 dsp_callback(DSP_CALLBACK_SET_SW_VOLUME, 0);
231 #endif
233 #ifndef SIMULATOR
234 #if CONFIG_CODEC == MAS3507D
235 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
236 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
237 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
238 || defined(HAVE_WM8750) || defined(HAVE_WM8751) || defined(HAVE_AS3514) \
239 || defined(HAVE_TSC2100) || defined(HAVE_AK4537) || defined(HAVE_UDA1341)
240 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
241 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
242 || defined(HAVE_WM8750) || (defined(HAVE_WM8751) && !defined(MROBE_100)) \
243 || defined(HAVE_WM8985)
244 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
245 #endif
247 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
248 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
249 #elif defined(HAVE_JZ4740_CODEC)
250 audiohw_set_volume(current_volume);
251 #endif
252 #else /* SIMULATOR */
253 audiohw_set_volume(current_volume);
254 #endif /* !SIMULATOR */
256 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
259 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
260 unsigned long mdb_shape_shadow = 0;
261 unsigned long loudness_shadow = 0;
262 #endif
264 void sound_set_volume(int value)
266 if(!audio_is_initialized)
267 return;
269 #if defined(AUDIOHW_HAVE_CLIPPING)
270 audiohw_set_volume(value);
271 #elif CONFIG_CPU == PNX0101
272 int tmp = (60 - value * 4) & 0xff;
273 CODECVOL = tmp | (tmp << 8);
274 #else
275 current_volume = value * 10; /* tenth of dB */
276 set_prescaled_volume();
277 #endif
280 void sound_set_balance(int value)
282 if(!audio_is_initialized)
283 return;
285 #ifdef AUDIOHW_HAVE_BALANCE
286 audiohw_set_balance(value);
287 #else
288 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
289 set_prescaled_volume();
290 #endif
293 void sound_set_bass(int value)
295 if(!audio_is_initialized)
296 return;
298 #if !defined(AUDIOHW_HAVE_CLIPPING)
299 #if defined(HAVE_WM8750) || defined(HAVE_WM8751)
300 current_bass = value;
301 #else
302 current_bass = value * 10;
303 #endif
304 #endif
306 #if defined(AUDIOHW_HAVE_BASS)
307 audiohw_set_bass(value);
308 #else
309 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
310 #endif
312 #if !defined(AUDIOHW_HAVE_CLIPPING)
313 set_prescaled_volume();
314 #endif
317 void sound_set_treble(int value)
319 if(!audio_is_initialized)
320 return;
322 #if !defined(AUDIOHW_HAVE_CLIPPING)
323 #if defined(HAVE_WM8750) || defined(HAVE_WM8751)
324 current_treble = value;
325 #else
326 current_treble = value * 10;
327 #endif
328 #endif
330 #if defined(AUDIOHW_HAVE_TREBLE)
331 audiohw_set_treble(value);
332 #else
333 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
334 #endif
336 #if !defined(AUDIOHW_HAVE_CLIPPING)
337 set_prescaled_volume();
338 #endif
341 void sound_set_channels(int value)
343 if(!audio_is_initialized)
344 return;
346 #if CONFIG_CODEC == SWCODEC
347 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
348 #else
349 audiohw_set_channel(value);
350 #endif
353 void sound_set_stereo_width(int value)
355 if(!audio_is_initialized)
356 return;
358 #if CONFIG_CODEC == SWCODEC
359 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
360 #else
361 audiohw_set_stereo_width(value);
362 #endif
365 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
366 void sound_set_bass_cutoff(int value)
368 if(!audio_is_initialized)
369 return;
371 audiohw_set_bass_cutoff(value);
373 #endif
375 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
376 void sound_set_treble_cutoff(int value)
378 if(!audio_is_initialized)
379 return;
381 audiohw_set_treble_cutoff(value);
383 #endif
385 #if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F))
386 void sound_set_loudness(int value)
388 if(!audio_is_initialized)
389 return;
390 loudness_shadow = (loudness_shadow & 0x04) |
391 (MAX(MIN(value * 4, 0x44), 0) << 8);
392 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
395 void sound_set_avc(int value)
397 if(!audio_is_initialized)
398 return;
399 int tmp;
401 static const uint16_t avc_vals[] =
403 (0x1 << 8) | (0x8 << 12), /* 20ms */
404 (0x2 << 8) | (0x8 << 12), /* 2s */
405 (0x4 << 8) | (0x8 << 12), /* 4s */
406 (0x8 << 8) | (0x8 << 12), /* 8s */
408 switch (value) {
409 case 1:
410 case 2:
411 case 3:
412 case 4:
413 tmp = avc_vals[value -1];
414 break;
415 case -1: /* turn off and then turn on again to decay quickly */
416 tmp = mas_codec_readreg(MAS_REG_KAVC);
417 mas_codec_writereg(MAS_REG_KAVC, 0);
418 break;
419 default: /* off */
420 tmp = 0;
421 break;
423 mas_codec_writereg(MAS_REG_KAVC, tmp);
426 void sound_set_mdb_strength(int value)
428 if(!audio_is_initialized)
429 return;
430 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
433 void sound_set_mdb_harmonics(int value)
435 if(!audio_is_initialized)
436 return;
437 int tmp = value * 127 / 100;
438 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
441 void sound_set_mdb_center(int value)
443 if(!audio_is_initialized)
444 return;
445 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
448 void sound_set_mdb_shape(int value)
450 if(!audio_is_initialized)
451 return;
452 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
453 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
456 void sound_set_mdb_enable(int value)
458 if(!audio_is_initialized)
459 return;
460 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
461 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
464 void sound_set_superbass(int value)
466 if(!audio_is_initialized)
467 return;
468 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
469 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
471 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
473 void sound_set(int setting, int value)
475 sound_set_type* sound_set_val = sound_get_fn(setting);
476 if (sound_set_val)
477 sound_set_val(value);
480 #if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
481 && !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
482 && !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
483 && !defined (HAVE_WM8731) && !defined (HAVE_WM8978) \
484 && !defined(HAVE_AK4537)) || defined(SIMULATOR)
485 int sound_val2phys(int setting, int value)
487 #if CONFIG_CODEC == MAS3587F
488 int result = 0;
490 switch(setting)
492 case SOUND_LEFT_GAIN:
493 case SOUND_RIGHT_GAIN:
494 result = (value - 2) * 15;
495 break;
497 case SOUND_MIC_GAIN:
498 result = value * 15 + 210;
499 break;
501 default:
502 result = value;
503 break;
505 return result;
506 #elif defined(HAVE_UDA1380)
507 int result = 0;
509 switch(setting)
511 #ifdef HAVE_RECORDING
512 case SOUND_LEFT_GAIN:
513 case SOUND_RIGHT_GAIN:
514 case SOUND_MIC_GAIN:
515 result = value * 5; /* (1/2) * 10 */
516 break;
517 #endif
518 default:
519 result = value;
520 break;
522 return result;
523 #elif defined(HAVE_TLV320) || defined(HAVE_WM8711) \
524 || defined(HAVE_WM8721) || defined(HAVE_WM8731)
525 int result = 0;
527 switch(setting)
529 #ifdef HAVE_RECORDING
530 case SOUND_LEFT_GAIN:
531 case SOUND_RIGHT_GAIN:
532 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
533 break;
535 case SOUND_MIC_GAIN:
536 result = value * 200; /* 0 or 20 dB */
537 break;
538 #endif
539 default:
540 result = value;
541 break;
543 return result;
544 #elif defined(HAVE_AS3514)
545 /* This is here for the sim only and the audio driver has its own */
546 int result;
548 switch(setting)
550 #ifdef HAVE_RECORDING
551 case SOUND_LEFT_GAIN:
552 case SOUND_RIGHT_GAIN:
553 case SOUND_MIC_GAIN:
554 result = (value - 23) * 15;
555 break;
556 #endif
557 default:
558 result = value;
559 break;
562 return result;
563 #elif defined(HAVE_WM8978)
564 int result;
566 switch (setting)
568 #ifdef HAVE_RECORDING
569 case SOUND_LEFT_GAIN:
570 case SOUND_RIGHT_GAIN:
571 case SOUND_MIC_GAIN:
572 result = value * 5;
573 break;
574 #endif
576 default:
577 result = value;
580 return result;
581 #else
582 (void)setting;
583 return value;
584 #endif
586 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
588 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
589 /* This function works by telling the decoder that we have another
590 crystal frequency than we actually have. It will adjust its internal
591 parameters and the result is that the audio is played at another pitch.
593 The pitch value precision is based on PITCH_SPEED_PRECISION (in dsp.h)
596 #ifdef SIMULATOR
597 static
598 #else
599 extern
600 #endif
601 unsigned long shadow_io_control_main;
602 static int last_pitch = PITCH_SPEED_100;
604 void sound_set_pitch(int32_t pitch)
606 unsigned long val;
608 if (pitch != last_pitch)
610 /* Calculate the new (bogus) frequency */
611 val = 18432 * PITCH_SPEED_100 / pitch;
613 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
615 /* We must tell the MAS that the frequency has changed.
616 * This will unfortunately cause a short silence. */
617 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
619 last_pitch = pitch;
623 int32_t sound_get_pitch(void)
625 return last_pitch;
627 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */