merge 19488 back from the 3.1 branch
[kugel-rb.git] / firmware / sound.c
blobfb377f6f6d810d412d63b62321cd36ab38723417
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 #ifndef SIMULATOR
28 #include "i2c.h"
29 #include "mas.h"
30 #if CONFIG_CPU == PNX0101
31 #include "pnx0101.h"
32 #endif
33 #include "dac.h"
34 #include "system.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 #if !defined(VOLUME_MIN) && !defined(VOLUME_MAX)
45 #warning define for VOLUME_MIN and VOLUME_MAX is missing
46 #define VOLUME_MIN -700
47 #define VOLUME_MAX 0
48 #endif
50 /* volume/balance/treble/bass interdependency main part */
51 #define VOLUME_RANGE (VOLUME_MAX - VOLUME_MIN)
53 #ifndef SIMULATOR
54 extern bool audio_is_initialized;
56 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
57 extern unsigned long shadow_io_control_main;
58 extern unsigned shadow_codec_reg0;
59 #endif
60 #endif /* SIMULATOR */
62 #ifdef SIMULATOR
63 /* dummy for sim */
64 const struct sound_settings_info audiohw_settings[] = {
65 [SOUND_VOLUME] = {"dB", 0, 1, VOLUME_MIN / 10, VOLUME_MAX / 10, -25},
66 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
67 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
68 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
69 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
70 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
71 #if defined(HAVE_RECORDING)
72 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
73 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
74 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
75 #endif
76 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
77 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
78 #endif
79 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
80 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
81 #endif
82 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
83 [SOUND_LOUDNESS] = {"dB", 0, 1, 0, 17, 0},
84 [SOUND_AVC] = {"", 0, 1, -1, 4, 0},
85 [SOUND_MDB_STRENGTH] = {"dB", 0, 1, 0, 127, 48},
86 [SOUND_MDB_HARMONICS] = {"%", 0, 1, 0, 100, 50},
87 [SOUND_MDB_CENTER] = {"Hz", 0, 10, 20, 300, 60},
88 [SOUND_MDB_SHAPE] = {"Hz", 0, 10, 50, 300, 90},
89 [SOUND_MDB_ENABLE] = {"", 0, 1, 0, 1, 0},
90 [SOUND_SUPERBASS] = {"", 0, 1, 0, 1, 0},
91 #endif
93 #endif
95 const char *sound_unit(int setting)
97 return audiohw_settings[setting].unit;
100 int sound_numdecimals(int setting)
102 return audiohw_settings[setting].numdecimals;
105 int sound_steps(int setting)
107 return audiohw_settings[setting].steps;
110 int sound_min(int setting)
112 return audiohw_settings[setting].minval;
115 int sound_max(int setting)
117 return audiohw_settings[setting].maxval;
120 int sound_default(int setting)
122 return audiohw_settings[setting].defaultval;
125 sound_set_type* sound_get_fn(int setting)
127 sound_set_type* result = NULL;
129 switch (setting) {
130 case SOUND_VOLUME:
131 result = sound_set_volume;
132 break;
134 case SOUND_BASS:
135 result = sound_set_bass;
136 break;
138 case SOUND_TREBLE:
139 result = sound_set_treble;
140 break;
142 case SOUND_BALANCE:
143 result = sound_set_balance;
144 break;
146 case SOUND_CHANNELS:
147 result = sound_set_channels;
148 break;
150 case SOUND_STEREO_WIDTH:
151 result = sound_set_stereo_width;
152 break;
154 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
155 case SOUND_BASS_CUTOFF:
156 result = sound_set_bass_cutoff;
157 break;
158 #endif
160 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
161 case SOUND_TREBLE_CUTOFF:
162 result = sound_set_treble_cutoff;
163 break;
164 #endif
166 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
167 case SOUND_LOUDNESS:
168 result = sound_set_loudness;
169 break;
171 case SOUND_AVC:
172 result = sound_set_avc;
173 break;
175 case SOUND_MDB_STRENGTH:
176 result = sound_set_mdb_strength;
177 break;
179 case SOUND_MDB_HARMONICS:
180 result = sound_set_mdb_harmonics;
181 break;
183 case SOUND_MDB_CENTER:
184 result = sound_set_mdb_center;
185 break;
187 case SOUND_MDB_SHAPE:
188 result = sound_set_mdb_shape;
189 break;
191 case SOUND_MDB_ENABLE:
192 result = sound_set_mdb_enable;
193 break;
195 case SOUND_SUPERBASS:
196 result = sound_set_superbass;
197 break;
198 #endif
201 return result;
204 #if CONFIG_CODEC == SWCODEC
205 /* Copied from dsp.h, nasty nasty, but we don't want to include dsp.h */
206 enum {
207 DSP_CALLBACK_SET_PRESCALE = 0,
208 DSP_CALLBACK_SET_BASS,
209 DSP_CALLBACK_SET_TREBLE,
210 DSP_CALLBACK_SET_CHANNEL_CONFIG,
211 DSP_CALLBACK_SET_STEREO_WIDTH
214 static int (*dsp_callback)(int, intptr_t) = NULL;
216 void sound_set_dsp_callback(int (*func)(int, intptr_t))
218 dsp_callback = func;
220 #endif
222 #ifndef SIMULATOR
223 #if CONFIG_CODEC == MAS3507D
224 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
225 static int tenthdb2reg(int db)
227 if (db < -540) /* 3 dB steps */
228 return (db + 780) / 30;
229 else /* 1.5 dB steps */
230 return (db + 660) / 15;
232 #endif
235 #if !defined(AUDIOHW_HAVE_CLIPPING)
237 * The prescaler compensates for any kind of boosts, to prevent clipping.
239 * It's basically just a measure to make sure that audio does not clip during
240 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
241 * the audio amplitude by -12 dB before processing, then increase master gain
242 * by 12 dB after processing.
245 /* all values in tenth of dB MAS3507D UDA1380 */
246 int current_volume = 0; /* -780..+180 -840.. 0 */
247 int current_balance = 0; /* -960..+960 -840..+840 */
248 int current_treble = 0; /* -150..+150 0.. +60 */
249 int current_bass = 0; /* -150..+150 0..+240 */
251 static void set_prescaled_volume(void)
253 int prescale = 0;
254 int l, r;
256 /* The WM codecs listed don't have suitable prescaler functionality, so we let
257 * the prescaler stay at 0 for these unless SW tone controls are in use */
258 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
259 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
260 || defined(HAVE_WM8751) || defined(HAVE_WM8758) || defined(HAVE_WM8985)) \
261 || defined(HAVE_TSC2100)
263 prescale = MAX(current_bass, current_treble);
264 if (prescale < 0)
265 prescale = 0; /* no need to prescale if we don't boost
266 bass or treble */
268 /* Gain up the analog volume to compensate the prescale gain reduction,
269 * but if this would push the volume over the top, reduce prescaling
270 * instead (might cause clipping). */
271 if (current_volume + prescale > VOLUME_MAX)
272 prescale = VOLUME_MAX - current_volume;
273 #endif
275 #if defined(AUDIOHW_HAVE_PRESCALER)
276 audiohw_set_prescaler(prescale);
277 #else
278 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
279 #endif
281 if (current_volume == VOLUME_MIN)
282 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
284 l = r = current_volume + prescale;
286 if (current_balance > 0)
288 l -= current_balance;
289 if (l < VOLUME_MIN)
290 l = VOLUME_MIN;
292 if (current_balance < 0)
294 r += current_balance;
295 if (r < VOLUME_MIN)
296 r = VOLUME_MIN;
299 #if CONFIG_CODEC == MAS3507D
300 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
301 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
302 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
303 || defined(HAVE_WM8751) || defined(HAVE_AS3514) || defined(HAVE_TSC2100)
304 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
305 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
306 || (defined(HAVE_WM8751) && !defined(MROBE_100)) \
307 || defined(HAVE_TSC2100) || defined(HAVE_WM8985)
308 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
309 #endif
311 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
312 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
313 #endif
315 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
316 #endif /* !SIMULATOR */
319 #ifndef SIMULATOR
321 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
322 unsigned long mdb_shape_shadow = 0;
323 unsigned long loudness_shadow = 0;
324 #endif
326 void sound_set_volume(int value)
328 if(!audio_is_initialized)
329 return;
331 #if defined(AUDIOHW_HAVE_CLIPPING)
332 audiohw_set_volume(value);
333 #elif CONFIG_CPU == PNX0101
334 int tmp = (60 - value * 4) & 0xff;
335 CODECVOL = tmp | (tmp << 8);
336 #else
337 current_volume = value * 10; /* tenth of dB */
338 set_prescaled_volume();
339 #endif
342 void sound_set_balance(int value)
344 if(!audio_is_initialized)
345 return;
347 #ifdef AUDIOHW_HAVE_BALANCE
348 audiohw_set_balance(value);
349 #else
350 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
351 set_prescaled_volume();
352 #endif
355 void sound_set_bass(int value)
357 if(!audio_is_initialized)
358 return;
360 #if !defined(AUDIOHW_HAVE_CLIPPING)
361 #if defined(HAVE_WM8751)
362 current_bass = value;
363 #else
364 current_bass = value * 10;
365 #endif
366 #endif
368 #if defined(AUDIOHW_HAVE_BASS)
369 audiohw_set_bass(value);
370 #else
371 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
372 #endif
374 #if !defined(AUDIOHW_HAVE_CLIPPING)
375 set_prescaled_volume();
376 #endif
379 void sound_set_treble(int value)
381 if(!audio_is_initialized)
382 return;
384 #if !defined(AUDIOHW_HAVE_CLIPPING)
385 #if defined(HAVE_WM8751)
386 current_treble = value;
387 #else
388 current_treble = value * 10;
389 #endif
390 #endif
392 #if defined(AUDIOHW_HAVE_TREBLE)
393 audiohw_set_treble(value);
394 #else
395 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
396 #endif
398 #if !defined(AUDIOHW_HAVE_CLIPPING)
399 set_prescaled_volume();
400 #endif
403 void sound_set_channels(int value)
405 if(!audio_is_initialized)
406 return;
408 #if CONFIG_CODEC == SWCODEC
409 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
410 #else
411 audiohw_set_channel(value);
412 #endif
415 void sound_set_stereo_width(int value)
417 if(!audio_is_initialized)
418 return;
420 #if CONFIG_CODEC == SWCODEC
421 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
422 #else
423 audiohw_set_stereo_width(value);
424 #endif
427 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
428 void sound_set_bass_cutoff(int value)
430 if(!audio_is_initialized)
431 return;
433 audiohw_set_bass_cutoff(value);
435 #endif
437 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
438 void sound_set_treble_cutoff(int value)
440 if(!audio_is_initialized)
441 return;
443 audiohw_set_treble_cutoff(value);
445 #endif
447 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
448 void sound_set_loudness(int value)
450 if(!audio_is_initialized)
451 return;
452 loudness_shadow = (loudness_shadow & 0x04) |
453 (MAX(MIN(value * 4, 0x44), 0) << 8);
454 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
457 void sound_set_avc(int value)
459 if(!audio_is_initialized)
460 return;
461 int tmp;
462 switch (value) {
463 case 1: /* 20ms */
464 tmp = (0x1 << 8) | (0x8 << 12);
465 break;
466 case 2: /* 2s */
467 tmp = (0x2 << 8) | (0x8 << 12);
468 break;
469 case 3: /* 4s */
470 tmp = (0x4 << 8) | (0x8 << 12);
471 break;
472 case 4: /* 8s */
473 tmp = (0x8 << 8) | (0x8 << 12);
474 break;
475 case -1: /* turn off and then turn on again to decay quickly */
476 tmp = mas_codec_readreg(MAS_REG_KAVC);
477 mas_codec_writereg(MAS_REG_KAVC, 0);
478 break;
479 default: /* off */
480 tmp = 0;
481 break;
483 mas_codec_writereg(MAS_REG_KAVC, tmp);
486 void sound_set_mdb_strength(int value)
488 if(!audio_is_initialized)
489 return;
490 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
493 void sound_set_mdb_harmonics(int value)
495 if(!audio_is_initialized)
496 return;
497 int tmp = value * 127 / 100;
498 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
501 void sound_set_mdb_center(int value)
503 if(!audio_is_initialized)
504 return;
505 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
508 void sound_set_mdb_shape(int value)
510 if(!audio_is_initialized)
511 return;
512 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
513 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
516 void sound_set_mdb_enable(int value)
518 if(!audio_is_initialized)
519 return;
520 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
521 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
524 void sound_set_superbass(int value)
526 if(!audio_is_initialized)
527 return;
528 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
529 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
531 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
533 #else /* SIMULATOR */
534 int sim_volume;
535 void sound_set_volume(int value)
537 /* 128 is SDL_MIX_MAXVOLUME */
538 sim_volume = 128 * (value - VOLUME_MIN / 10) / (VOLUME_RANGE / 10);
541 void sound_set_balance(int value)
543 (void)value;
546 void sound_set_bass(int value)
548 (void)value;
551 void sound_set_treble(int value)
553 (void)value;
556 void sound_set_channels(int value)
558 (void)value;
561 void sound_set_stereo_width(int value)
563 (void)value;
566 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
567 void sound_set_loudness(int value)
569 (void)value;
572 void sound_set_avc(int value)
574 (void)value;
577 void sound_set_mdb_strength(int value)
579 (void)value;
582 void sound_set_mdb_harmonics(int value)
584 (void)value;
587 void sound_set_mdb_center(int value)
589 (void)value;
592 void sound_set_mdb_shape(int value)
594 (void)value;
597 void sound_set_mdb_enable(int value)
599 (void)value;
602 void sound_set_superbass(int value)
604 (void)value;
606 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
608 #if defined(HAVE_WM8758) || defined(HAVE_WM8985)
609 void sound_set_bass_cutoff(int value)
611 (void) value;
614 void sound_set_treble_cutoff(int value)
616 (void) value;
618 #endif /* HAVE_WM8758 */
620 #endif /* SIMULATOR */
622 void sound_set(int setting, int value)
624 sound_set_type* sound_set_val = sound_get_fn(setting);
625 if (sound_set_val)
626 sound_set_val(value);
629 #if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
630 && !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
631 && !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
632 && !defined (HAVE_WM8731)) \
633 || defined(SIMULATOR)
634 int sound_val2phys(int setting, int value)
636 #if CONFIG_CODEC == MAS3587F
637 int result = 0;
639 switch(setting)
641 case SOUND_LEFT_GAIN:
642 case SOUND_RIGHT_GAIN:
643 result = (value - 2) * 15;
644 break;
646 case SOUND_MIC_GAIN:
647 result = value * 15 + 210;
648 break;
650 default:
651 result = value;
652 break;
654 return result;
655 #elif defined(HAVE_UDA1380)
656 int result = 0;
658 switch(setting)
660 case SOUND_LEFT_GAIN:
661 case SOUND_RIGHT_GAIN:
662 case SOUND_MIC_GAIN:
663 result = value * 5; /* (1/2) * 10 */
664 break;
666 default:
667 result = value;
668 break;
670 return result;
671 #elif defined(HAVE_TLV320) || defined(HAVE_WM8711) \
672 || defined(HAVE_WM8721) || defined(HAVE_WM8731)
673 int result = 0;
675 switch(setting)
677 #ifdef HAVE_RECORDING
678 case SOUND_LEFT_GAIN:
679 case SOUND_RIGHT_GAIN:
680 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
681 break;
683 case SOUND_MIC_GAIN:
684 result = value * 200; /* 0 or 20 dB */
685 break;
686 #endif
687 default:
688 result = value;
689 break;
691 return result;
692 #elif defined(HAVE_AS3514)
693 /* This is here for the sim only and the audio driver has its own */
694 int result;
696 switch(setting)
698 #ifdef HAVE_RECORDING
699 case SOUND_LEFT_GAIN:
700 case SOUND_RIGHT_GAIN:
701 case SOUND_MIC_GAIN:
702 result = (value - 23) * 15;
703 break;
704 #endif
705 default:
706 result = value;
707 break;
710 return result;
711 #else
712 (void)setting;
713 return value;
714 #endif
716 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
718 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
719 #ifndef SIMULATOR
720 /* This function works by telling the decoder that we have another
721 crystal frequency than we actually have. It will adjust its internal
722 parameters and the result is that the audio is played at another pitch.
724 The pitch value is in tenths of percent.
726 static int last_pitch = 1000;
728 void sound_set_pitch(int pitch)
730 unsigned long val;
732 if (pitch != last_pitch)
734 /* Calculate the new (bogus) frequency */
735 val = 18432 * 1000 / pitch;
737 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
739 /* We must tell the MAS that the frequency has changed.
740 * This will unfortunately cause a short silence. */
741 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
743 last_pitch = pitch;
747 int sound_get_pitch(void)
749 return last_pitch;
751 #else /* SIMULATOR */
752 void sound_set_pitch(int pitch)
754 (void)pitch;
757 int sound_get_pitch(void)
759 return 1000;
761 #endif /* SIMULATOR */
762 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */