Telechips NAND: split out a couple of small functions to help readability, and add...
[kugel-rb.git] / firmware / sound.c
blob95c67a1a3c43df580cf846809cd0ef65aa9e40fb
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_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) \
260 || defined(HAVE_WM8758) || defined(HAVE_WM8985)) || defined(HAVE_TSC2100)
262 prescale = MAX(current_bass, current_treble);
263 if (prescale < 0)
264 prescale = 0; /* no need to prescale if we don't boost
265 bass or treble */
267 /* Gain up the analog volume to compensate the prescale gain reduction,
268 * but if this would push the volume over the top, reduce prescaling
269 * instead (might cause clipping). */
270 if (current_volume + prescale > VOLUME_MAX)
271 prescale = VOLUME_MAX - current_volume;
272 #endif
274 #if defined(AUDIOHW_HAVE_PRESCALER)
275 audiohw_set_prescaler(prescale);
276 #else
277 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
278 #endif
280 if (current_volume == VOLUME_MIN)
281 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
283 l = r = current_volume + prescale;
285 if (current_balance > 0)
287 l -= current_balance;
288 if (l < VOLUME_MIN)
289 l = VOLUME_MIN;
291 if (current_balance < 0)
293 r += current_balance;
294 if (r < VOLUME_MIN)
295 r = VOLUME_MIN;
298 #if CONFIG_CODEC == MAS3507D
299 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
300 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
301 || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) \
302 || defined(HAVE_AS3514) || defined(HAVE_TSC2100)
303 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
304 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
305 || (defined(HAVE_WM8751) && !defined(MROBE_100)) \
306 || defined(HAVE_TSC2100) || defined(HAVE_WM8985)
307 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
308 #endif
310 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
311 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
312 #endif
314 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
315 #endif /* !SIMULATOR */
318 #ifndef SIMULATOR
320 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
321 unsigned long mdb_shape_shadow = 0;
322 unsigned long loudness_shadow = 0;
323 #endif
325 void sound_set_volume(int value)
327 if(!audio_is_initialized)
328 return;
330 #if defined(AUDIOHW_HAVE_CLIPPING)
331 audiohw_set_volume(value);
332 #elif CONFIG_CPU == PNX0101
333 int tmp = (60 - value * 4) & 0xff;
334 CODECVOL = tmp | (tmp << 8);
335 #else
336 current_volume = value * 10; /* tenth of dB */
337 set_prescaled_volume();
338 #endif
341 void sound_set_balance(int value)
343 if(!audio_is_initialized)
344 return;
346 #ifdef AUDIOHW_HAVE_BALANCE
347 audiohw_set_balance(value);
348 #else
349 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
350 set_prescaled_volume();
351 #endif
354 void sound_set_bass(int value)
356 if(!audio_is_initialized)
357 return;
359 #if !defined(AUDIOHW_HAVE_CLIPPING)
360 #if defined(HAVE_WM8751)
361 current_bass = value;
362 #else
363 current_bass = value * 10;
364 #endif
365 #endif
367 #if defined(AUDIOHW_HAVE_BASS)
368 audiohw_set_bass(value);
369 #else
370 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
371 #endif
373 #if !defined(AUDIOHW_HAVE_CLIPPING)
374 set_prescaled_volume();
375 #endif
378 void sound_set_treble(int value)
380 if(!audio_is_initialized)
381 return;
383 #if !defined(AUDIOHW_HAVE_CLIPPING)
384 #if defined(HAVE_WM8751)
385 current_treble = value;
386 #else
387 current_treble = value * 10;
388 #endif
389 #endif
391 #if defined(AUDIOHW_HAVE_TREBLE)
392 audiohw_set_treble(value);
393 #else
394 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
395 #endif
397 #if !defined(AUDIOHW_HAVE_CLIPPING)
398 set_prescaled_volume();
399 #endif
402 void sound_set_channels(int value)
404 if(!audio_is_initialized)
405 return;
407 #if CONFIG_CODEC == SWCODEC
408 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
409 #else
410 audiohw_set_channel(value);
411 #endif
414 void sound_set_stereo_width(int value)
416 if(!audio_is_initialized)
417 return;
419 #if CONFIG_CODEC == SWCODEC
420 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
421 #else
422 audiohw_set_stereo_width(value);
423 #endif
426 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
427 void sound_set_bass_cutoff(int value)
429 if(!audio_is_initialized)
430 return;
432 audiohw_set_bass_cutoff(value);
434 #endif
436 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
437 void sound_set_treble_cutoff(int value)
439 if(!audio_is_initialized)
440 return;
442 audiohw_set_treble_cutoff(value);
444 #endif
446 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
447 void sound_set_loudness(int value)
449 if(!audio_is_initialized)
450 return;
451 loudness_shadow = (loudness_shadow & 0x04) |
452 (MAX(MIN(value * 4, 0x44), 0) << 8);
453 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
456 void sound_set_avc(int value)
458 if(!audio_is_initialized)
459 return;
460 int tmp;
461 switch (value) {
462 case 1: /* 20ms */
463 tmp = (0x1 << 8) | (0x8 << 12);
464 break;
465 case 2: /* 2s */
466 tmp = (0x2 << 8) | (0x8 << 12);
467 break;
468 case 3: /* 4s */
469 tmp = (0x4 << 8) | (0x8 << 12);
470 break;
471 case 4: /* 8s */
472 tmp = (0x8 << 8) | (0x8 << 12);
473 break;
474 case -1: /* turn off and then turn on again to decay quickly */
475 tmp = mas_codec_readreg(MAS_REG_KAVC);
476 mas_codec_writereg(MAS_REG_KAVC, 0);
477 break;
478 default: /* off */
479 tmp = 0;
480 break;
482 mas_codec_writereg(MAS_REG_KAVC, tmp);
485 void sound_set_mdb_strength(int value)
487 if(!audio_is_initialized)
488 return;
489 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
492 void sound_set_mdb_harmonics(int value)
494 if(!audio_is_initialized)
495 return;
496 int tmp = value * 127 / 100;
497 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
500 void sound_set_mdb_center(int value)
502 if(!audio_is_initialized)
503 return;
504 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
507 void sound_set_mdb_shape(int value)
509 if(!audio_is_initialized)
510 return;
511 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
512 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
515 void sound_set_mdb_enable(int value)
517 if(!audio_is_initialized)
518 return;
519 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
520 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
523 void sound_set_superbass(int value)
525 if(!audio_is_initialized)
526 return;
527 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
528 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
530 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
532 #else /* SIMULATOR */
533 int sim_volume;
534 void sound_set_volume(int value)
536 /* 128 is SDL_MIX_MAXVOLUME */
537 sim_volume = 128 * (value - VOLUME_MIN / 10) / (VOLUME_RANGE / 10);
540 void sound_set_balance(int value)
542 (void)value;
545 void sound_set_bass(int value)
547 (void)value;
550 void sound_set_treble(int value)
552 (void)value;
555 void sound_set_channels(int value)
557 (void)value;
560 void sound_set_stereo_width(int value)
562 (void)value;
565 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
566 void sound_set_loudness(int value)
568 (void)value;
571 void sound_set_avc(int value)
573 (void)value;
576 void sound_set_mdb_strength(int value)
578 (void)value;
581 void sound_set_mdb_harmonics(int value)
583 (void)value;
586 void sound_set_mdb_center(int value)
588 (void)value;
591 void sound_set_mdb_shape(int value)
593 (void)value;
596 void sound_set_mdb_enable(int value)
598 (void)value;
601 void sound_set_superbass(int value)
603 (void)value;
605 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
607 #if defined(HAVE_WM8758) || defined(HAVE_WM8985)
608 void sound_set_bass_cutoff(int value)
610 (void) value;
613 void sound_set_treble_cutoff(int value)
615 (void) value;
617 #endif /* HAVE_WM8758 */
619 #endif /* SIMULATOR */
621 void sound_set(int setting, int value)
623 sound_set_type* sound_set_val = sound_get_fn(setting);
624 if (sound_set_val)
625 sound_set_val(value);
628 #if (!defined(HAVE_AS3514) && !defined (HAVE_WM8731) && !defined(HAVE_TSC2100)) \
629 || defined(SIMULATOR)
630 int sound_val2phys(int setting, int value)
632 #if CONFIG_CODEC == MAS3587F
633 int result = 0;
635 switch(setting)
637 case SOUND_LEFT_GAIN:
638 case SOUND_RIGHT_GAIN:
639 result = (value - 2) * 15;
640 break;
642 case SOUND_MIC_GAIN:
643 result = value * 15 + 210;
644 break;
646 default:
647 result = value;
648 break;
650 return result;
651 #elif defined(HAVE_UDA1380)
652 int result = 0;
654 switch(setting)
656 case SOUND_LEFT_GAIN:
657 case SOUND_RIGHT_GAIN:
658 case SOUND_MIC_GAIN:
659 result = value * 5; /* (1/2) * 10 */
660 break;
662 default:
663 result = value;
664 break;
666 return result;
667 #elif defined(HAVE_TLV320) || defined(HAVE_WM8731)
668 int result = 0;
670 switch(setting)
672 #ifdef HAVE_RECORDING
673 case SOUND_LEFT_GAIN:
674 case SOUND_RIGHT_GAIN:
675 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
676 break;
678 case SOUND_MIC_GAIN:
679 result = value * 200; /* 0 or 20 dB */
680 break;
681 #endif
682 default:
683 result = value;
684 break;
686 return result;
687 #elif defined(HAVE_AS3514)
688 /* This is here for the sim only and the audio driver has its own */
689 int result;
691 switch(setting)
693 case SOUND_LEFT_GAIN:
694 case SOUND_RIGHT_GAIN:
695 case SOUND_MIC_GAIN:
696 result = (value - 23) * 15;
697 break;
699 default:
700 result = value;
701 break;
704 return result;
705 #else
706 (void)setting;
707 return value;
708 #endif
710 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
712 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
713 #ifndef SIMULATOR
714 /* This function works by telling the decoder that we have another
715 crystal frequency than we actually have. It will adjust its internal
716 parameters and the result is that the audio is played at another pitch.
718 The pitch value is in tenths of percent.
720 static int last_pitch = 1000;
722 void sound_set_pitch(int pitch)
724 unsigned long val;
726 if (pitch != last_pitch)
728 /* Calculate the new (bogus) frequency */
729 val = 18432 * 1000 / pitch;
731 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
733 /* We must tell the MAS that the frequency has changed.
734 * This will unfortunately cause a short silence. */
735 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
737 last_pitch = pitch;
741 int sound_get_pitch(void)
743 return last_pitch;
745 #else /* SIMULATOR */
746 void sound_set_pitch(int pitch)
748 (void)pitch;
751 int sound_get_pitch(void)
753 return 1000;
755 #endif /* SIMULATOR */
756 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */