Add myself to the manual credits
[maemo-rb.git] / firmware / sound.c
blobc602a414670d243460f8c4a42545769cbdf4afaa
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)) \
261 || defined(HAVE_TSC2100) || defined(HAVE_WM8985)
262 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
263 #endif
265 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
266 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
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(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 case SOUND_LEFT_GAIN:
617 case SOUND_RIGHT_GAIN:
618 case SOUND_MIC_GAIN:
619 result = value * 5; /* (1/2) * 10 */
620 break;
622 default:
623 result = value;
624 break;
626 return result;
627 #elif defined(HAVE_TLV320) || defined(HAVE_WM8711) \
628 || defined(HAVE_WM8721) || defined(HAVE_WM8731)
629 int result = 0;
631 switch(setting)
633 #ifdef HAVE_RECORDING
634 case SOUND_LEFT_GAIN:
635 case SOUND_RIGHT_GAIN:
636 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
637 break;
639 case SOUND_MIC_GAIN:
640 result = value * 200; /* 0 or 20 dB */
641 break;
642 #endif
643 default:
644 result = value;
645 break;
647 return result;
648 #elif defined(HAVE_AS3514)
649 /* This is here for the sim only and the audio driver has its own */
650 int result;
652 switch(setting)
654 #ifdef HAVE_RECORDING
655 case SOUND_LEFT_GAIN:
656 case SOUND_RIGHT_GAIN:
657 case SOUND_MIC_GAIN:
658 result = (value - 23) * 15;
659 break;
660 #endif
661 default:
662 result = value;
663 break;
666 return result;
667 #elif defined(HAVE_WM8978)
668 int result;
670 switch (setting)
672 #ifdef HAVE_RECORDING
673 case SOUND_LEFT_GAIN:
674 case SOUND_RIGHT_GAIN:
675 case SOUND_MIC_GAIN:
676 result = value * 5;
677 break;
678 #endif
680 default:
681 result = value;
684 return result;
685 #else
686 (void)setting;
687 return value;
688 #endif
690 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
692 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
693 #ifndef SIMULATOR
694 /* This function works by telling the decoder that we have another
695 crystal frequency than we actually have. It will adjust its internal
696 parameters and the result is that the audio is played at another pitch.
698 The pitch value is in tenths of percent.
700 static int last_pitch = 1000;
702 void sound_set_pitch(int pitch)
704 unsigned long val;
706 if (pitch != last_pitch)
708 /* Calculate the new (bogus) frequency */
709 val = 18432 * 1000 / pitch;
711 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
713 /* We must tell the MAS that the frequency has changed.
714 * This will unfortunately cause a short silence. */
715 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
717 last_pitch = pitch;
721 int sound_get_pitch(void)
723 return last_pitch;
725 #else /* SIMULATOR */
726 void sound_set_pitch(int pitch)
728 (void)pitch;
731 int sound_get_pitch(void)
733 return 1000;
735 #endif /* SIMULATOR */
736 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */