woops... fix the header and bump the plugin API
[kugel-rb.git] / firmware / sound.c
blob5125782308651acaeddcd95680a1266311e56f21
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 #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 sound_set_type* sound_get_fn(int setting)
129 sound_set_type* result = NULL;
131 switch (setting) {
132 case SOUND_VOLUME:
133 result = sound_set_volume;
134 break;
136 case SOUND_BASS:
137 result = sound_set_bass;
138 break;
140 case SOUND_TREBLE:
141 result = sound_set_treble;
142 break;
144 case SOUND_BALANCE:
145 result = sound_set_balance;
146 break;
148 case SOUND_CHANNELS:
149 result = sound_set_channels;
150 break;
152 case SOUND_STEREO_WIDTH:
153 result = sound_set_stereo_width;
154 break;
156 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
157 case SOUND_BASS_CUTOFF:
158 result = sound_set_bass_cutoff;
159 break;
160 #endif
162 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
163 case SOUND_TREBLE_CUTOFF:
164 result = sound_set_treble_cutoff;
165 break;
166 #endif
168 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
169 case SOUND_LOUDNESS:
170 result = sound_set_loudness;
171 break;
173 case SOUND_AVC:
174 result = sound_set_avc;
175 break;
177 case SOUND_MDB_STRENGTH:
178 result = sound_set_mdb_strength;
179 break;
181 case SOUND_MDB_HARMONICS:
182 result = sound_set_mdb_harmonics;
183 break;
185 case SOUND_MDB_CENTER:
186 result = sound_set_mdb_center;
187 break;
189 case SOUND_MDB_SHAPE:
190 result = sound_set_mdb_shape;
191 break;
193 case SOUND_MDB_ENABLE:
194 result = sound_set_mdb_enable;
195 break;
197 case SOUND_SUPERBASS:
198 result = sound_set_superbass;
199 break;
200 #endif
203 return result;
206 #if CONFIG_CODEC == SWCODEC
207 /* Copied from dsp.h, nasty nasty, but we don't want to include dsp.h */
208 enum {
209 DSP_CALLBACK_SET_PRESCALE = 0,
210 DSP_CALLBACK_SET_BASS,
211 DSP_CALLBACK_SET_TREBLE,
212 DSP_CALLBACK_SET_CHANNEL_CONFIG,
213 DSP_CALLBACK_SET_STEREO_WIDTH
216 static int (*dsp_callback)(int, intptr_t) = NULL;
218 void sound_set_dsp_callback(int (*func)(int, intptr_t))
220 dsp_callback = func;
222 #endif
224 #ifndef SIMULATOR
225 #if CONFIG_CODEC == MAS3507D
226 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
227 static int tenthdb2reg(int db)
229 if (db < -540) /* 3 dB steps */
230 return (db + 780) / 30;
231 else /* 1.5 dB steps */
232 return (db + 660) / 15;
234 #endif
237 #if !defined(AUDIOHW_HAVE_CLIPPING)
239 * The prescaler compensates for any kind of boosts, to prevent clipping.
241 * It's basically just a measure to make sure that audio does not clip during
242 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
243 * the audio amplitude by -12 dB before processing, then increase master gain
244 * by 12 dB after processing.
247 /* all values in tenth of dB MAS3507D UDA1380 */
248 int current_volume = 0; /* -780..+180 -840.. 0 */
249 int current_balance = 0; /* -960..+960 -840..+840 */
250 int current_treble = 0; /* -150..+150 0.. +60 */
251 int current_bass = 0; /* -150..+150 0..+240 */
253 static void set_prescaled_volume(void)
255 int prescale = 0;
256 int l, r;
258 /* The WM codecs listed don't have suitable prescaler functionality, so we let
259 * the prescaler stay at 0 for these unless SW tone controls are in use */
260 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
261 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
262 || defined(HAVE_WM8751) || defined(HAVE_WM8758) || defined(HAVE_WM8985)) \
263 || defined(HAVE_TSC2100)
265 prescale = MAX(current_bass, current_treble);
266 if (prescale < 0)
267 prescale = 0; /* no need to prescale if we don't boost
268 bass or treble */
270 /* Gain up the analog volume to compensate the prescale gain reduction,
271 * but if this would push the volume over the top, reduce prescaling
272 * instead (might cause clipping). */
273 if (current_volume + prescale > VOLUME_MAX)
274 prescale = VOLUME_MAX - current_volume;
275 #endif
277 #if defined(AUDIOHW_HAVE_PRESCALER)
278 audiohw_set_prescaler(prescale);
279 #else
280 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
281 #endif
283 if (current_volume == VOLUME_MIN)
284 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
286 l = r = current_volume + prescale;
288 /* Balance the channels scaled by the current volume and min volume. */
289 /* Subtract a dB from VOLUME_MIN to get it to a mute level */
290 if (current_balance > 0)
292 l -= ((l - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
294 else if (current_balance < 0)
296 r += ((r - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
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) && !defined (HAVE_WM8978)) \
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 #elif defined(HAVE_WM8978)
712 int result;
714 switch (setting)
716 #ifdef HAVE_RECORDING
717 case SOUND_LEFT_GAIN:
718 case SOUND_RIGHT_GAIN:
719 case SOUND_MIC_GAIN:
720 result = value * 5;
721 break;
722 #endif
724 default:
725 result = value;
728 return result;
729 #else
730 (void)setting;
731 return value;
732 #endif
734 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
736 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
737 #ifndef SIMULATOR
738 /* This function works by telling the decoder that we have another
739 crystal frequency than we actually have. It will adjust its internal
740 parameters and the result is that the audio is played at another pitch.
742 The pitch value is in tenths of percent.
744 static int last_pitch = 1000;
746 void sound_set_pitch(int pitch)
748 unsigned long val;
750 if (pitch != last_pitch)
752 /* Calculate the new (bogus) frequency */
753 val = 18432 * 1000 / pitch;
755 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
757 /* We must tell the MAS that the frequency has changed.
758 * This will unfortunately cause a short silence. */
759 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
761 last_pitch = pitch;
765 int sound_get_pitch(void)
767 return last_pitch;
769 #else /* SIMULATOR */
770 void sound_set_pitch(int pitch)
772 (void)pitch;
775 int sound_get_pitch(void)
777 return 1000;
779 #endif /* SIMULATOR */
780 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */