Packard Bell Vibe 500: change a not so lucky keymap for the bookmark delete.
[kugel-rb.git] / firmware / sound.c
blobca8b79e4d939babc4b6fe9395d7dbb14f18dbd4d
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 * const 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 static int (*dsp_callback)(int, intptr_t) = NULL;
163 void sound_set_dsp_callback(int (*func)(int, intptr_t))
165 dsp_callback = func;
167 #endif
169 #ifndef SIMULATOR
170 #if CONFIG_CODEC == MAS3507D
171 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
172 static int tenthdb2reg(int db)
174 if (db < -540) /* 3 dB steps */
175 return (db + 780) / 30;
176 else /* 1.5 dB steps */
177 return (db + 660) / 15;
179 #endif
182 #if !defined(AUDIOHW_HAVE_CLIPPING)
184 * The prescaler compensates for any kind of boosts, to prevent clipping.
186 * It's basically just a measure to make sure that audio does not clip during
187 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
188 * the audio amplitude by -12 dB before processing, then increase master gain
189 * by 12 dB after processing.
192 /* all values in tenth of dB MAS3507D UDA1380 */
193 int current_volume = 0; /* -780..+180 -840.. 0 */
194 int current_balance = 0; /* -960..+960 -840..+840 */
195 int current_treble = 0; /* -150..+150 0.. +60 */
196 int current_bass = 0; /* -150..+150 0..+240 */
198 static void set_prescaled_volume(void)
200 int prescale = 0;
201 int l, r;
203 /* The codecs listed use HW tone controls but don't have suitable prescaler
204 * functionality, so we let the prescaler stay at 0 for these, unless
205 * SW tone controls are in use. This is to avoid needing the SW DSP just for
206 * the prescaling.
208 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
209 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
210 || defined(HAVE_WM8751) || defined(HAVE_WM8758) || defined(HAVE_WM8985) \
211 || defined(HAVE_UDA1341))
213 prescale = MAX(current_bass, current_treble);
214 if (prescale < 0)
215 prescale = 0; /* no need to prescale if we don't boost
216 bass or treble */
218 /* Gain up the analog volume to compensate the prescale gain reduction,
219 * but if this would push the volume over the top, reduce prescaling
220 * instead (might cause clipping). */
221 if (current_volume + prescale > VOLUME_MAX)
222 prescale = VOLUME_MAX - current_volume;
223 #endif
225 #if defined(AUDIOHW_HAVE_PRESCALER)
226 audiohw_set_prescaler(prescale);
227 #else
228 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
229 #endif
231 if (current_volume == VOLUME_MIN)
232 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
234 l = r = current_volume + prescale;
236 /* Balance the channels scaled by the current volume and min volume. */
237 /* Subtract a dB from VOLUME_MIN to get it to a mute level */
238 if (current_balance > 0)
240 l -= ((l - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
242 else if (current_balance < 0)
244 r += ((r - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
247 #ifdef HAVE_SW_VOLUME_CONTROL
248 dsp_callback(DSP_CALLBACK_SET_SW_VOLUME, 0);
249 #endif
251 #if CONFIG_CODEC == MAS3507D
252 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
253 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
254 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
255 || defined(HAVE_WM8751) || defined(HAVE_AS3514) || defined(HAVE_TSC2100) \
256 || defined(HAVE_AK4537) || defined(HAVE_UDA1341)
257 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
258 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
259 || (defined(HAVE_WM8751) && !defined(MROBE_100)) || defined(HAVE_WM8985)
260 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
261 #endif
263 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
264 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
265 #elif defined(HAVE_JZ4740_CODEC)
266 audiohw_set_volume(current_volume);
267 #endif
269 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
270 #endif /* !SIMULATOR */
273 #ifndef SIMULATOR
275 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
276 unsigned long mdb_shape_shadow = 0;
277 unsigned long loudness_shadow = 0;
278 #endif
280 void sound_set_volume(int value)
282 if(!audio_is_initialized)
283 return;
285 #if defined(AUDIOHW_HAVE_CLIPPING)
286 audiohw_set_volume(value);
287 #elif CONFIG_CPU == PNX0101
288 int tmp = (60 - value * 4) & 0xff;
289 CODECVOL = tmp | (tmp << 8);
290 #else
291 current_volume = value * 10; /* tenth of dB */
292 set_prescaled_volume();
293 #endif
296 void sound_set_balance(int value)
298 if(!audio_is_initialized)
299 return;
301 #ifdef AUDIOHW_HAVE_BALANCE
302 audiohw_set_balance(value);
303 #else
304 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
305 set_prescaled_volume();
306 #endif
309 void sound_set_bass(int value)
311 if(!audio_is_initialized)
312 return;
314 #if !defined(AUDIOHW_HAVE_CLIPPING)
315 #if defined(HAVE_WM8751)
316 current_bass = value;
317 #else
318 current_bass = value * 10;
319 #endif
320 #endif
322 #if defined(AUDIOHW_HAVE_BASS)
323 audiohw_set_bass(value);
324 #else
325 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
326 #endif
328 #if !defined(AUDIOHW_HAVE_CLIPPING)
329 set_prescaled_volume();
330 #endif
333 void sound_set_treble(int value)
335 if(!audio_is_initialized)
336 return;
338 #if !defined(AUDIOHW_HAVE_CLIPPING)
339 #if defined(HAVE_WM8751)
340 current_treble = value;
341 #else
342 current_treble = value * 10;
343 #endif
344 #endif
346 #if defined(AUDIOHW_HAVE_TREBLE)
347 audiohw_set_treble(value);
348 #else
349 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
350 #endif
352 #if !defined(AUDIOHW_HAVE_CLIPPING)
353 set_prescaled_volume();
354 #endif
357 void sound_set_channels(int value)
359 if(!audio_is_initialized)
360 return;
362 #if CONFIG_CODEC == SWCODEC
363 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
364 #else
365 audiohw_set_channel(value);
366 #endif
369 void sound_set_stereo_width(int value)
371 if(!audio_is_initialized)
372 return;
374 #if CONFIG_CODEC == SWCODEC
375 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
376 #else
377 audiohw_set_stereo_width(value);
378 #endif
381 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
382 void sound_set_bass_cutoff(int value)
384 if(!audio_is_initialized)
385 return;
387 audiohw_set_bass_cutoff(value);
389 #endif
391 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
392 void sound_set_treble_cutoff(int value)
394 if(!audio_is_initialized)
395 return;
397 audiohw_set_treble_cutoff(value);
399 #endif
401 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
402 void sound_set_loudness(int value)
404 if(!audio_is_initialized)
405 return;
406 loudness_shadow = (loudness_shadow & 0x04) |
407 (MAX(MIN(value * 4, 0x44), 0) << 8);
408 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
411 void sound_set_avc(int value)
413 if(!audio_is_initialized)
414 return;
415 int tmp;
417 static const uint16_t avc_vals[] =
419 (0x1 << 8) | (0x8 << 12), /* 20ms */
420 (0x2 << 8) | (0x8 << 12), /* 2s */
421 (0x4 << 8) | (0x8 << 12), /* 4s */
422 (0x8 << 8) | (0x8 << 12), /* 8s */
424 switch (value) {
425 case 1:
426 case 2:
427 case 3:
428 case 4:
429 tmp = avc_vals[value -1];
430 break;
431 case -1: /* turn off and then turn on again to decay quickly */
432 tmp = mas_codec_readreg(MAS_REG_KAVC);
433 mas_codec_writereg(MAS_REG_KAVC, 0);
434 break;
435 default: /* off */
436 tmp = 0;
437 break;
439 mas_codec_writereg(MAS_REG_KAVC, tmp);
442 void sound_set_mdb_strength(int value)
444 if(!audio_is_initialized)
445 return;
446 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
449 void sound_set_mdb_harmonics(int value)
451 if(!audio_is_initialized)
452 return;
453 int tmp = value * 127 / 100;
454 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
457 void sound_set_mdb_center(int value)
459 if(!audio_is_initialized)
460 return;
461 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
464 void sound_set_mdb_shape(int value)
466 if(!audio_is_initialized)
467 return;
468 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
469 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
472 void sound_set_mdb_enable(int value)
474 if(!audio_is_initialized)
475 return;
476 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
477 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
480 void sound_set_superbass(int value)
482 if(!audio_is_initialized)
483 return;
484 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
485 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
487 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
489 #else /* SIMULATOR */
490 int sim_volume;
491 void sound_set_volume(int value)
493 /* 128 is SDL_MIX_MAXVOLUME */
494 sim_volume = 128 * (value - VOLUME_MIN / 10) / (VOLUME_RANGE / 10);
497 void sound_set_balance(int value)
499 (void)value;
502 void sound_set_bass(int value)
504 (void)value;
507 void sound_set_treble(int value)
509 (void)value;
512 void sound_set_channels(int value)
514 (void)value;
517 void sound_set_stereo_width(int value)
519 (void)value;
522 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
523 void sound_set_loudness(int value)
525 (void)value;
528 void sound_set_avc(int value)
530 (void)value;
533 void sound_set_mdb_strength(int value)
535 (void)value;
538 void sound_set_mdb_harmonics(int value)
540 (void)value;
543 void sound_set_mdb_center(int value)
545 (void)value;
548 void sound_set_mdb_shape(int value)
550 (void)value;
553 void sound_set_mdb_enable(int value)
555 (void)value;
558 void sound_set_superbass(int value)
560 (void)value;
562 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
564 #if defined(HAVE_WM8758) || defined(HAVE_WM8985)
565 void sound_set_bass_cutoff(int value)
567 (void) value;
570 void sound_set_treble_cutoff(int value)
572 (void) value;
574 #endif /* HAVE_WM8758 */
576 #endif /* SIMULATOR */
578 void sound_set(int setting, int value)
580 sound_set_type* sound_set_val = sound_get_fn(setting);
581 if (sound_set_val)
582 sound_set_val(value);
585 #if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
586 && !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
587 && !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
588 && !defined (HAVE_WM8731) && !defined (HAVE_WM8978) \
589 && !defined(HAVE_AK4537)) || defined(SIMULATOR)
590 int sound_val2phys(int setting, int value)
592 #if CONFIG_CODEC == MAS3587F
593 int result = 0;
595 switch(setting)
597 case SOUND_LEFT_GAIN:
598 case SOUND_RIGHT_GAIN:
599 result = (value - 2) * 15;
600 break;
602 case SOUND_MIC_GAIN:
603 result = value * 15 + 210;
604 break;
606 default:
607 result = value;
608 break;
610 return result;
611 #elif defined(HAVE_UDA1380)
612 int result = 0;
614 switch(setting)
616 #ifdef HAVE_RECORDING
617 case SOUND_LEFT_GAIN:
618 case SOUND_RIGHT_GAIN:
619 case SOUND_MIC_GAIN:
620 result = value * 5; /* (1/2) * 10 */
621 break;
622 #endif
623 default:
624 result = value;
625 break;
627 return result;
628 #elif defined(HAVE_TLV320) || defined(HAVE_WM8711) \
629 || defined(HAVE_WM8721) || defined(HAVE_WM8731)
630 int result = 0;
632 switch(setting)
634 #ifdef HAVE_RECORDING
635 case SOUND_LEFT_GAIN:
636 case SOUND_RIGHT_GAIN:
637 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
638 break;
640 case SOUND_MIC_GAIN:
641 result = value * 200; /* 0 or 20 dB */
642 break;
643 #endif
644 default:
645 result = value;
646 break;
648 return result;
649 #elif defined(HAVE_AS3514)
650 /* This is here for the sim only and the audio driver has its own */
651 int result;
653 switch(setting)
655 #ifdef HAVE_RECORDING
656 case SOUND_LEFT_GAIN:
657 case SOUND_RIGHT_GAIN:
658 case SOUND_MIC_GAIN:
659 result = (value - 23) * 15;
660 break;
661 #endif
662 default:
663 result = value;
664 break;
667 return result;
668 #elif defined(HAVE_WM8978)
669 int result;
671 switch (setting)
673 #ifdef HAVE_RECORDING
674 case SOUND_LEFT_GAIN:
675 case SOUND_RIGHT_GAIN:
676 case SOUND_MIC_GAIN:
677 result = value * 5;
678 break;
679 #endif
681 default:
682 result = value;
685 return result;
686 #else
687 (void)setting;
688 return value;
689 #endif
691 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
693 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
694 #ifndef SIMULATOR
695 /* This function works by telling the decoder that we have another
696 crystal frequency than we actually have. It will adjust its internal
697 parameters and the result is that the audio is played at another pitch.
699 The pitch value precision is based on PITCH_SPEED_PRECISION (in dsp.h)
701 static int last_pitch = PITCH_SPEED_100;
703 void sound_set_pitch(int32_t pitch)
705 unsigned long val;
707 if (pitch != last_pitch)
709 /* Calculate the new (bogus) frequency */
710 val = 18432 * PITCH_SPEED_100 / pitch;
712 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
714 /* We must tell the MAS that the frequency has changed.
715 * This will unfortunately cause a short silence. */
716 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
718 last_pitch = pitch;
722 int32_t sound_get_pitch(void)
724 return last_pitch;
726 #else /* SIMULATOR */
727 void sound_set_pitch(int32_t pitch)
729 (void)pitch;
732 int32_t sound_get_pitch(void)
734 return PITCH_SPEED_100;
736 #endif /* SIMULATOR */
737 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */