Forgot to add Eric Clayton to the CREDITS file for FS #10234.
[kugel-rb.git] / firmware / sound.c
blob5e5a5963747654e142938b6d6bab53832e7f0d13
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 #ifndef SIMULATOR
29 #include "i2c.h"
30 #include "mas.h"
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 #define ONE_DB 10
46 #if !defined(VOLUME_MIN) && !defined(VOLUME_MAX)
47 #warning define for VOLUME_MIN and VOLUME_MAX is missing
48 #define VOLUME_MIN -700
49 #define VOLUME_MAX 0
50 #endif
52 /* volume/balance/treble/bass interdependency main part */
53 #define VOLUME_RANGE (VOLUME_MAX - VOLUME_MIN)
55 #ifndef SIMULATOR
56 extern bool audio_is_initialized;
58 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
59 extern unsigned long shadow_io_control_main;
60 extern unsigned shadow_codec_reg0;
61 #endif
62 #endif /* SIMULATOR */
64 #ifdef SIMULATOR
65 /* dummy for sim */
66 const struct sound_settings_info audiohw_settings[] = {
67 [SOUND_VOLUME] = {"dB", 0, 1, VOLUME_MIN / 10, VOLUME_MAX / 10, -25},
68 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
69 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
70 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
71 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
72 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
73 #if defined(HAVE_RECORDING)
74 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
75 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
76 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
77 #endif
78 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
79 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
80 #endif
81 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
82 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
83 #endif
84 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
85 [SOUND_LOUDNESS] = {"dB", 0, 1, 0, 17, 0},
86 [SOUND_AVC] = {"", 0, 1, -1, 4, 0},
87 [SOUND_MDB_STRENGTH] = {"dB", 0, 1, 0, 127, 48},
88 [SOUND_MDB_HARMONICS] = {"%", 0, 1, 0, 100, 50},
89 [SOUND_MDB_CENTER] = {"Hz", 0, 10, 20, 300, 60},
90 [SOUND_MDB_SHAPE] = {"Hz", 0, 10, 50, 300, 90},
91 [SOUND_MDB_ENABLE] = {"", 0, 1, 0, 1, 0},
92 [SOUND_SUPERBASS] = {"", 0, 1, 0, 1, 0},
93 #endif
95 #endif
97 const char *sound_unit(int setting)
99 return audiohw_settings[setting].unit;
102 int sound_numdecimals(int setting)
104 return audiohw_settings[setting].numdecimals;
107 int sound_steps(int setting)
109 return audiohw_settings[setting].steps;
112 int sound_min(int setting)
114 return audiohw_settings[setting].minval;
117 int sound_max(int setting)
119 return audiohw_settings[setting].maxval;
122 int sound_default(int setting)
124 return audiohw_settings[setting].defaultval;
127 static sound_set_type *sound_set_fns[] =
129 [0 ... SOUND_LAST_SETTING-1] = NULL,
130 [SOUND_VOLUME] = sound_set_volume,
131 [SOUND_BASS] = sound_set_bass,
132 [SOUND_TREBLE] = sound_set_treble,
133 [SOUND_BALANCE] = sound_set_balance,
134 [SOUND_CHANNELS] = sound_set_channels,
135 [SOUND_STEREO_WIDTH] = sound_set_stereo_width,
136 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
137 [SOUND_LOUDNESS] = sound_set_loudness,
138 [SOUND_AVC] = sound_set_avc,
139 [SOUND_MDB_STRENGTH] = sound_set_mdb_strength,
140 [SOUND_MDB_HARMONICS] = sound_set_mdb_harmonics,
141 [SOUND_MDB_CENTER] = sound_set_mdb_center,
142 [SOUND_MDB_SHAPE] = sound_set_mdb_shape,
143 [SOUND_MDB_ENABLE] = sound_set_mdb_enable,
144 [SOUND_SUPERBASS] = sound_set_superbass,
145 #endif
146 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
147 [SOUND_BASS_CUTOFF] = sound_set_bass_cutoff,
148 #endif
149 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
150 [SOUND_TREBLE_CUTOFF] = sound_set_treble_cutoff,
151 #endif
154 sound_set_type* sound_get_fn(int setting)
156 return ((unsigned)setting >= ARRAYLEN(sound_set_fns)?
157 NULL : sound_set_fns[setting]);
160 #if CONFIG_CODEC == SWCODEC
161 /* Copied from dsp.h, nasty nasty, but we don't want to include dsp.h */
162 enum {
163 DSP_CALLBACK_SET_PRESCALE = 0,
164 DSP_CALLBACK_SET_BASS,
165 DSP_CALLBACK_SET_TREBLE,
166 DSP_CALLBACK_SET_CHANNEL_CONFIG,
167 DSP_CALLBACK_SET_STEREO_WIDTH
170 static int (*dsp_callback)(int, intptr_t) = NULL;
172 void sound_set_dsp_callback(int (*func)(int, intptr_t))
174 dsp_callback = func;
176 #endif
178 #ifndef SIMULATOR
179 #if CONFIG_CODEC == MAS3507D
180 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
181 static int tenthdb2reg(int db)
183 if (db < -540) /* 3 dB steps */
184 return (db + 780) / 30;
185 else /* 1.5 dB steps */
186 return (db + 660) / 15;
188 #endif
191 #if !defined(AUDIOHW_HAVE_CLIPPING)
193 * The prescaler compensates for any kind of boosts, to prevent clipping.
195 * It's basically just a measure to make sure that audio does not clip during
196 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
197 * the audio amplitude by -12 dB before processing, then increase master gain
198 * by 12 dB after processing.
201 /* all values in tenth of dB MAS3507D UDA1380 */
202 int current_volume = 0; /* -780..+180 -840.. 0 */
203 int current_balance = 0; /* -960..+960 -840..+840 */
204 int current_treble = 0; /* -150..+150 0.. +60 */
205 int current_bass = 0; /* -150..+150 0..+240 */
207 static void set_prescaled_volume(void)
209 int prescale = 0;
210 int l, r;
212 /* The WM codecs listed don't have suitable prescaler functionality, so we let
213 * the prescaler stay at 0 for these unless SW tone controls are in use */
214 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
215 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
216 || defined(HAVE_WM8751) || defined(HAVE_WM8758) || defined(HAVE_WM8985)) \
217 || defined(HAVE_TSC2100)
219 prescale = MAX(current_bass, current_treble);
220 if (prescale < 0)
221 prescale = 0; /* no need to prescale if we don't boost
222 bass or treble */
224 /* Gain up the analog volume to compensate the prescale gain reduction,
225 * but if this would push the volume over the top, reduce prescaling
226 * instead (might cause clipping). */
227 if (current_volume + prescale > VOLUME_MAX)
228 prescale = VOLUME_MAX - current_volume;
229 #endif
231 #if defined(AUDIOHW_HAVE_PRESCALER)
232 audiohw_set_prescaler(prescale);
233 #else
234 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
235 #endif
237 if (current_volume == VOLUME_MIN)
238 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
240 l = r = current_volume + prescale;
242 /* Balance the channels scaled by the current volume and min volume. */
243 /* Subtract a dB from VOLUME_MIN to get it to a mute level */
244 if (current_balance > 0)
246 l -= ((l - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
248 else if (current_balance < 0)
250 r += ((r - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
253 #if CONFIG_CODEC == MAS3507D
254 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
255 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
256 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
257 || defined(HAVE_WM8751) || defined(HAVE_AS3514) || defined(HAVE_TSC2100)
258 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
259 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
260 || (defined(HAVE_WM8751) && !defined(MROBE_100)) || defined(HAVE_WM8985)
261 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
262 #endif
264 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
265 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
266 #endif
268 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
269 #endif /* !SIMULATOR */
272 #ifndef SIMULATOR
274 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
275 unsigned long mdb_shape_shadow = 0;
276 unsigned long loudness_shadow = 0;
277 #endif
279 void sound_set_volume(int value)
281 if(!audio_is_initialized)
282 return;
284 #if defined(AUDIOHW_HAVE_CLIPPING)
285 audiohw_set_volume(value);
286 #elif CONFIG_CPU == PNX0101
287 int tmp = (60 - value * 4) & 0xff;
288 CODECVOL = tmp | (tmp << 8);
289 #else
290 current_volume = value * 10; /* tenth of dB */
291 set_prescaled_volume();
292 #endif
295 void sound_set_balance(int value)
297 if(!audio_is_initialized)
298 return;
300 #ifdef AUDIOHW_HAVE_BALANCE
301 audiohw_set_balance(value);
302 #else
303 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
304 set_prescaled_volume();
305 #endif
308 void sound_set_bass(int value)
310 if(!audio_is_initialized)
311 return;
313 #if !defined(AUDIOHW_HAVE_CLIPPING)
314 #if defined(HAVE_WM8751)
315 current_bass = value;
316 #else
317 current_bass = value * 10;
318 #endif
319 #endif
321 #if defined(AUDIOHW_HAVE_BASS)
322 audiohw_set_bass(value);
323 #else
324 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
325 #endif
327 #if !defined(AUDIOHW_HAVE_CLIPPING)
328 set_prescaled_volume();
329 #endif
332 void sound_set_treble(int value)
334 if(!audio_is_initialized)
335 return;
337 #if !defined(AUDIOHW_HAVE_CLIPPING)
338 #if defined(HAVE_WM8751)
339 current_treble = value;
340 #else
341 current_treble = value * 10;
342 #endif
343 #endif
345 #if defined(AUDIOHW_HAVE_TREBLE)
346 audiohw_set_treble(value);
347 #else
348 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
349 #endif
351 #if !defined(AUDIOHW_HAVE_CLIPPING)
352 set_prescaled_volume();
353 #endif
356 void sound_set_channels(int value)
358 if(!audio_is_initialized)
359 return;
361 #if CONFIG_CODEC == SWCODEC
362 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
363 #else
364 audiohw_set_channel(value);
365 #endif
368 void sound_set_stereo_width(int value)
370 if(!audio_is_initialized)
371 return;
373 #if CONFIG_CODEC == SWCODEC
374 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
375 #else
376 audiohw_set_stereo_width(value);
377 #endif
380 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
381 void sound_set_bass_cutoff(int value)
383 if(!audio_is_initialized)
384 return;
386 audiohw_set_bass_cutoff(value);
388 #endif
390 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
391 void sound_set_treble_cutoff(int value)
393 if(!audio_is_initialized)
394 return;
396 audiohw_set_treble_cutoff(value);
398 #endif
400 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
401 void sound_set_loudness(int value)
403 if(!audio_is_initialized)
404 return;
405 loudness_shadow = (loudness_shadow & 0x04) |
406 (MAX(MIN(value * 4, 0x44), 0) << 8);
407 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
410 void sound_set_avc(int value)
412 if(!audio_is_initialized)
413 return;
414 int tmp;
416 static const uint16_t avc_vals[] =
418 (0x1 << 8) | (0x8 << 12), /* 20ms */
419 (0x2 << 8) | (0x8 << 12), /* 2s */
420 (0x4 << 8) | (0x8 << 12), /* 4s */
421 (0x8 << 8) | (0x8 << 12), /* 8s */
423 switch (value) {
424 case 1:
425 case 2:
426 case 3:
427 case 4:
428 tmp = avc_vals[value -1];
429 break;
430 case -1: /* turn off and then turn on again to decay quickly */
431 tmp = mas_codec_readreg(MAS_REG_KAVC);
432 mas_codec_writereg(MAS_REG_KAVC, 0);
433 break;
434 default: /* off */
435 tmp = 0;
436 break;
438 mas_codec_writereg(MAS_REG_KAVC, tmp);
441 void sound_set_mdb_strength(int value)
443 if(!audio_is_initialized)
444 return;
445 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
448 void sound_set_mdb_harmonics(int value)
450 if(!audio_is_initialized)
451 return;
452 int tmp = value * 127 / 100;
453 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
456 void sound_set_mdb_center(int value)
458 if(!audio_is_initialized)
459 return;
460 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
463 void sound_set_mdb_shape(int value)
465 if(!audio_is_initialized)
466 return;
467 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
468 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
471 void sound_set_mdb_enable(int value)
473 if(!audio_is_initialized)
474 return;
475 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
476 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
479 void sound_set_superbass(int value)
481 if(!audio_is_initialized)
482 return;
483 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
484 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
486 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
488 #else /* SIMULATOR */
489 int sim_volume;
490 void sound_set_volume(int value)
492 /* 128 is SDL_MIX_MAXVOLUME */
493 sim_volume = 128 * (value - VOLUME_MIN / 10) / (VOLUME_RANGE / 10);
496 void sound_set_balance(int value)
498 (void)value;
501 void sound_set_bass(int value)
503 (void)value;
506 void sound_set_treble(int value)
508 (void)value;
511 void sound_set_channels(int value)
513 (void)value;
516 void sound_set_stereo_width(int value)
518 (void)value;
521 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
522 void sound_set_loudness(int value)
524 (void)value;
527 void sound_set_avc(int value)
529 (void)value;
532 void sound_set_mdb_strength(int value)
534 (void)value;
537 void sound_set_mdb_harmonics(int value)
539 (void)value;
542 void sound_set_mdb_center(int value)
544 (void)value;
547 void sound_set_mdb_shape(int value)
549 (void)value;
552 void sound_set_mdb_enable(int value)
554 (void)value;
557 void sound_set_superbass(int value)
559 (void)value;
561 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
563 #if defined(HAVE_WM8758) || defined(HAVE_WM8985)
564 void sound_set_bass_cutoff(int value)
566 (void) value;
569 void sound_set_treble_cutoff(int value)
571 (void) value;
573 #endif /* HAVE_WM8758 */
575 #endif /* SIMULATOR */
577 void sound_set(int setting, int value)
579 sound_set_type* sound_set_val = sound_get_fn(setting);
580 if (sound_set_val)
581 sound_set_val(value);
584 #if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
585 && !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
586 && !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
587 && !defined (HAVE_WM8731) && !defined (HAVE_WM8978)) \
588 || defined(SIMULATOR)
589 int sound_val2phys(int setting, int value)
591 #if CONFIG_CODEC == MAS3587F
592 int result = 0;
594 switch(setting)
596 case SOUND_LEFT_GAIN:
597 case SOUND_RIGHT_GAIN:
598 result = (value - 2) * 15;
599 break;
601 case SOUND_MIC_GAIN:
602 result = value * 15 + 210;
603 break;
605 default:
606 result = value;
607 break;
609 return result;
610 #elif defined(HAVE_UDA1380)
611 int result = 0;
613 switch(setting)
615 case SOUND_LEFT_GAIN:
616 case SOUND_RIGHT_GAIN:
617 case SOUND_MIC_GAIN:
618 result = value * 5; /* (1/2) * 10 */
619 break;
621 default:
622 result = value;
623 break;
625 return result;
626 #elif defined(HAVE_TLV320) || defined(HAVE_WM8711) \
627 || defined(HAVE_WM8721) || defined(HAVE_WM8731)
628 int result = 0;
630 switch(setting)
632 #ifdef HAVE_RECORDING
633 case SOUND_LEFT_GAIN:
634 case SOUND_RIGHT_GAIN:
635 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
636 break;
638 case SOUND_MIC_GAIN:
639 result = value * 200; /* 0 or 20 dB */
640 break;
641 #endif
642 default:
643 result = value;
644 break;
646 return result;
647 #elif defined(HAVE_AS3514)
648 /* This is here for the sim only and the audio driver has its own */
649 int result;
651 switch(setting)
653 #ifdef HAVE_RECORDING
654 case SOUND_LEFT_GAIN:
655 case SOUND_RIGHT_GAIN:
656 case SOUND_MIC_GAIN:
657 result = (value - 23) * 15;
658 break;
659 #endif
660 default:
661 result = value;
662 break;
665 return result;
666 #elif defined(HAVE_WM8978)
667 int result;
669 switch (setting)
671 #ifdef HAVE_RECORDING
672 case SOUND_LEFT_GAIN:
673 case SOUND_RIGHT_GAIN:
674 case SOUND_MIC_GAIN:
675 result = value * 5;
676 break;
677 #endif
679 default:
680 result = value;
683 return result;
684 #else
685 (void)setting;
686 return value;
687 #endif
689 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
691 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
692 #ifndef SIMULATOR
693 /* This function works by telling the decoder that we have another
694 crystal frequency than we actually have. It will adjust its internal
695 parameters and the result is that the audio is played at another pitch.
697 The pitch value is in tenths of percent.
699 static int last_pitch = 1000;
701 void sound_set_pitch(int pitch)
703 unsigned long val;
705 if (pitch != last_pitch)
707 /* Calculate the new (bogus) frequency */
708 val = 18432 * 1000 / pitch;
710 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
712 /* We must tell the MAS that the frequency has changed.
713 * This will unfortunately cause a short silence. */
714 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
716 last_pitch = pitch;
720 int sound_get_pitch(void)
722 return last_pitch;
724 #else /* SIMULATOR */
725 void sound_set_pitch(int pitch)
727 (void)pitch;
730 int sound_get_pitch(void)
732 return 1000;
734 #endif /* SIMULATOR */
735 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */