fuzev2: prevent button light flickering when accessing µSD
[kugel-rb.git] / firmware / sound.c
blobb56e610034bf3199c262dbcd5c5f3b2dec3245cb
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 #include "i2c.h"
29 #include "mas.h"
30 #ifndef SIMULATOR
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 extern bool audio_is_initialized;
46 #ifdef SIMULATOR
47 extern void audiohw_set_volume(int value);
48 /* dummy for sim */
49 const struct sound_settings_info audiohw_settings[] = {
50 [SOUND_VOLUME] = {"dB", 0, 1, VOLUME_MIN / 10, VOLUME_MAX / 10, -25},
51 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
52 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
53 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
54 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
55 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
56 #if defined(HAVE_RECORDING)
57 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
58 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
59 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
60 #endif
61 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
62 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
63 #endif
64 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
65 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
66 #endif
67 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
68 [SOUND_LOUDNESS] = {"dB", 0, 1, 0, 17, 0},
69 [SOUND_AVC] = {"", 0, 1, -1, 4, 0},
70 [SOUND_MDB_STRENGTH] = {"dB", 0, 1, 0, 127, 48},
71 [SOUND_MDB_HARMONICS] = {"%", 0, 1, 0, 100, 50},
72 [SOUND_MDB_CENTER] = {"Hz", 0, 10, 20, 300, 60},
73 [SOUND_MDB_SHAPE] = {"Hz", 0, 10, 50, 300, 90},
74 [SOUND_MDB_ENABLE] = {"", 0, 1, 0, 1, 0},
75 [SOUND_SUPERBASS] = {"", 0, 1, 0, 1, 0},
76 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
78 #endif
80 const char *sound_unit(int setting)
82 return audiohw_settings[setting].unit;
85 int sound_numdecimals(int setting)
87 return audiohw_settings[setting].numdecimals;
90 int sound_steps(int setting)
92 return audiohw_settings[setting].steps;
95 int sound_min(int setting)
97 return audiohw_settings[setting].minval;
100 int sound_max(int setting)
102 return audiohw_settings[setting].maxval;
105 int sound_default(int setting)
107 return audiohw_settings[setting].defaultval;
110 static sound_set_type * const sound_set_fns[] =
112 [0 ... SOUND_LAST_SETTING-1] = NULL,
113 [SOUND_VOLUME] = sound_set_volume,
114 [SOUND_BASS] = sound_set_bass,
115 [SOUND_TREBLE] = sound_set_treble,
116 [SOUND_BALANCE] = sound_set_balance,
117 [SOUND_CHANNELS] = sound_set_channels,
118 [SOUND_STEREO_WIDTH] = sound_set_stereo_width,
119 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
120 [SOUND_LOUDNESS] = sound_set_loudness,
121 [SOUND_AVC] = sound_set_avc,
122 [SOUND_MDB_STRENGTH] = sound_set_mdb_strength,
123 [SOUND_MDB_HARMONICS] = sound_set_mdb_harmonics,
124 [SOUND_MDB_CENTER] = sound_set_mdb_center,
125 [SOUND_MDB_SHAPE] = sound_set_mdb_shape,
126 [SOUND_MDB_ENABLE] = sound_set_mdb_enable,
127 [SOUND_SUPERBASS] = sound_set_superbass,
128 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
129 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
130 [SOUND_BASS_CUTOFF] = sound_set_bass_cutoff,
131 #endif
132 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
133 [SOUND_TREBLE_CUTOFF] = sound_set_treble_cutoff,
134 #endif
137 sound_set_type* sound_get_fn(int setting)
139 return ((unsigned)setting >= ARRAYLEN(sound_set_fns)?
140 NULL : sound_set_fns[setting]);
143 #if CONFIG_CODEC == SWCODEC
144 static int (*dsp_callback)(int, intptr_t) = NULL;
146 void sound_set_dsp_callback(int (*func)(int, intptr_t))
148 dsp_callback = func;
150 #endif
152 #if (CONFIG_CODEC == MAS3507D) && !defined(SIMULATOR)
153 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
154 static int tenthdb2reg(int db)
156 if (db < -540) /* 3 dB steps */
157 return (db + 780) / 30;
158 else /* 1.5 dB steps */
159 return (db + 660) / 15;
161 #endif
164 #if !defined(AUDIOHW_HAVE_CLIPPING)
166 * The prescaler compensates for any kind of boosts, to prevent clipping.
168 * It's basically just a measure to make sure that audio does not clip during
169 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
170 * the audio amplitude by -12 dB before processing, then increase master gain
171 * by 12 dB after processing.
174 /* all values in tenth of dB MAS3507D UDA1380 */
175 int current_volume = 0; /* -780..+180 -840.. 0 */
176 int current_balance = 0; /* -960..+960 -840..+840 */
177 int current_treble = 0; /* -150..+150 0.. +60 */
178 int current_bass = 0; /* -150..+150 0..+240 */
180 static void set_prescaled_volume(void)
182 int prescale = 0;
183 int l, r;
185 /* The codecs listed use HW tone controls but don't have suitable prescaler
186 * functionality, so we let the prescaler stay at 0 for these, unless
187 * SW tone controls are in use. This is to avoid needing the SW DSP just for
188 * the prescaling.
190 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
191 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
192 || defined(HAVE_WM8758) || defined(HAVE_WM8985) || defined(HAVE_UDA1341))
194 prescale = MAX(current_bass, current_treble);
195 if (prescale < 0)
196 prescale = 0; /* no need to prescale if we don't boost
197 bass or treble */
199 /* Gain up the analog volume to compensate the prescale gain reduction,
200 * but if this would push the volume over the top, reduce prescaling
201 * instead (might cause clipping). */
202 if (current_volume + prescale > VOLUME_MAX)
203 prescale = VOLUME_MAX - current_volume;
204 #endif
206 #if defined(AUDIOHW_HAVE_PRESCALER)
207 audiohw_set_prescaler(prescale);
208 #else
209 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
210 #endif
212 if (current_volume == VOLUME_MIN)
213 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
215 l = r = current_volume + prescale;
217 /* Balance the channels scaled by the current volume and min volume. */
218 /* Subtract a dB from VOLUME_MIN to get it to a mute level */
219 if (current_balance > 0)
221 l -= ((l - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
223 else if (current_balance < 0)
225 r += ((r - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
228 #ifdef HAVE_SW_VOLUME_CONTROL
229 dsp_callback(DSP_CALLBACK_SET_SW_VOLUME, 0);
230 #endif
232 #ifndef SIMULATOR
233 #if CONFIG_CODEC == MAS3507D
234 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
235 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
236 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
237 || defined(HAVE_WM8750) || defined(HAVE_WM8751) || defined(HAVE_AS3514) \
238 || defined(HAVE_TSC2100) || defined(HAVE_AK4537) || defined(HAVE_UDA1341)
239 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
240 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
241 || defined(HAVE_WM8750) || (defined(HAVE_WM8751) && !defined(MROBE_100)) \
242 || defined(HAVE_WM8985)
243 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
244 #endif
246 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
247 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
248 #elif defined(HAVE_JZ4740_CODEC)
249 audiohw_set_volume(current_volume);
250 #endif
251 #else /* SIMULATOR */
252 audiohw_set_volume(current_volume);
253 #endif /* !SIMULATOR */
255 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
258 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
259 unsigned long mdb_shape_shadow = 0;
260 unsigned long loudness_shadow = 0;
261 #endif
263 void sound_set_volume(int value)
265 if(!audio_is_initialized)
266 return;
268 #if defined(AUDIOHW_HAVE_CLIPPING)
269 audiohw_set_volume(value);
270 #elif CONFIG_CPU == PNX0101
271 int tmp = (60 - value * 4) & 0xff;
272 CODECVOL = tmp | (tmp << 8);
273 #else
274 current_volume = value * 10; /* tenth of dB */
275 set_prescaled_volume();
276 #endif
279 void sound_set_balance(int value)
281 if(!audio_is_initialized)
282 return;
284 #ifdef AUDIOHW_HAVE_BALANCE
285 audiohw_set_balance(value);
286 #else
287 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
288 set_prescaled_volume();
289 #endif
292 void sound_set_bass(int value)
294 if(!audio_is_initialized)
295 return;
297 #if !defined(AUDIOHW_HAVE_CLIPPING)
298 #if defined(HAVE_WM8750) || defined(HAVE_WM8751)
299 current_bass = value;
300 #else
301 current_bass = value * 10;
302 #endif
303 #endif
305 #if defined(AUDIOHW_HAVE_BASS)
306 audiohw_set_bass(value);
307 #else
308 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
309 #endif
311 #if !defined(AUDIOHW_HAVE_CLIPPING)
312 set_prescaled_volume();
313 #endif
316 void sound_set_treble(int value)
318 if(!audio_is_initialized)
319 return;
321 #if !defined(AUDIOHW_HAVE_CLIPPING)
322 #if defined(HAVE_WM8750) || defined(HAVE_WM8751)
323 current_treble = value;
324 #else
325 current_treble = value * 10;
326 #endif
327 #endif
329 #if defined(AUDIOHW_HAVE_TREBLE)
330 audiohw_set_treble(value);
331 #else
332 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
333 #endif
335 #if !defined(AUDIOHW_HAVE_CLIPPING)
336 set_prescaled_volume();
337 #endif
340 void sound_set_channels(int value)
342 if(!audio_is_initialized)
343 return;
345 #if CONFIG_CODEC == SWCODEC
346 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
347 #else
348 audiohw_set_channel(value);
349 #endif
352 void sound_set_stereo_width(int value)
354 if(!audio_is_initialized)
355 return;
357 #if CONFIG_CODEC == SWCODEC
358 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
359 #else
360 audiohw_set_stereo_width(value);
361 #endif
364 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
365 void sound_set_bass_cutoff(int value)
367 if(!audio_is_initialized)
368 return;
370 audiohw_set_bass_cutoff(value);
372 #endif
374 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
375 void sound_set_treble_cutoff(int value)
377 if(!audio_is_initialized)
378 return;
380 audiohw_set_treble_cutoff(value);
382 #endif
384 #if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F))
385 void sound_set_loudness(int value)
387 if(!audio_is_initialized)
388 return;
389 loudness_shadow = (loudness_shadow & 0x04) |
390 (MAX(MIN(value * 4, 0x44), 0) << 8);
391 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
394 void sound_set_avc(int value)
396 if(!audio_is_initialized)
397 return;
398 int tmp;
400 static const uint16_t avc_vals[] =
402 (0x1 << 8) | (0x8 << 12), /* 20ms */
403 (0x2 << 8) | (0x8 << 12), /* 2s */
404 (0x4 << 8) | (0x8 << 12), /* 4s */
405 (0x8 << 8) | (0x8 << 12), /* 8s */
407 switch (value) {
408 case 1:
409 case 2:
410 case 3:
411 case 4:
412 tmp = avc_vals[value -1];
413 break;
414 case -1: /* turn off and then turn on again to decay quickly */
415 tmp = mas_codec_readreg(MAS_REG_KAVC);
416 mas_codec_writereg(MAS_REG_KAVC, 0);
417 break;
418 default: /* off */
419 tmp = 0;
420 break;
422 mas_codec_writereg(MAS_REG_KAVC, tmp);
425 void sound_set_mdb_strength(int value)
427 if(!audio_is_initialized)
428 return;
429 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
432 void sound_set_mdb_harmonics(int value)
434 if(!audio_is_initialized)
435 return;
436 int tmp = value * 127 / 100;
437 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
440 void sound_set_mdb_center(int value)
442 if(!audio_is_initialized)
443 return;
444 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
447 void sound_set_mdb_shape(int value)
449 if(!audio_is_initialized)
450 return;
451 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
452 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
455 void sound_set_mdb_enable(int value)
457 if(!audio_is_initialized)
458 return;
459 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
460 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
463 void sound_set_superbass(int value)
465 if(!audio_is_initialized)
466 return;
467 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
468 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
470 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
472 void sound_set(int setting, int value)
474 sound_set_type* sound_set_val = sound_get_fn(setting);
475 if (sound_set_val)
476 sound_set_val(value);
479 #if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
480 && !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
481 && !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
482 && !defined (HAVE_WM8731) && !defined (HAVE_WM8978) \
483 && !defined(HAVE_AK4537)) || defined(SIMULATOR)
484 int sound_val2phys(int setting, int value)
486 #if CONFIG_CODEC == MAS3587F
487 int result = 0;
489 switch(setting)
491 case SOUND_LEFT_GAIN:
492 case SOUND_RIGHT_GAIN:
493 result = (value - 2) * 15;
494 break;
496 case SOUND_MIC_GAIN:
497 result = value * 15 + 210;
498 break;
500 default:
501 result = value;
502 break;
504 return result;
505 #elif defined(HAVE_UDA1380)
506 int result = 0;
508 switch(setting)
510 #ifdef HAVE_RECORDING
511 case SOUND_LEFT_GAIN:
512 case SOUND_RIGHT_GAIN:
513 case SOUND_MIC_GAIN:
514 result = value * 5; /* (1/2) * 10 */
515 break;
516 #endif
517 default:
518 result = value;
519 break;
521 return result;
522 #elif defined(HAVE_TLV320) || defined(HAVE_WM8711) \
523 || defined(HAVE_WM8721) || defined(HAVE_WM8731)
524 int result = 0;
526 switch(setting)
528 #ifdef HAVE_RECORDING
529 case SOUND_LEFT_GAIN:
530 case SOUND_RIGHT_GAIN:
531 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
532 break;
534 case SOUND_MIC_GAIN:
535 result = value * 200; /* 0 or 20 dB */
536 break;
537 #endif
538 default:
539 result = value;
540 break;
542 return result;
543 #elif defined(HAVE_AS3514)
544 /* This is here for the sim only and the audio driver has its own */
545 int result;
547 switch(setting)
549 #ifdef HAVE_RECORDING
550 case SOUND_LEFT_GAIN:
551 case SOUND_RIGHT_GAIN:
552 case SOUND_MIC_GAIN:
553 result = (value - 23) * 15;
554 break;
555 #endif
556 default:
557 result = value;
558 break;
561 return result;
562 #elif defined(HAVE_WM8978)
563 int result;
565 switch (setting)
567 #ifdef HAVE_RECORDING
568 case SOUND_LEFT_GAIN:
569 case SOUND_RIGHT_GAIN:
570 case SOUND_MIC_GAIN:
571 result = value * 5;
572 break;
573 #endif
575 default:
576 result = value;
579 return result;
580 #else
581 (void)setting;
582 return value;
583 #endif
585 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
587 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
588 /* This function works by telling the decoder that we have another
589 crystal frequency than we actually have. It will adjust its internal
590 parameters and the result is that the audio is played at another pitch.
592 The pitch value precision is based on PITCH_SPEED_PRECISION (in dsp.h)
595 #ifdef SIMULATOR
596 static
597 #else
598 extern
599 #endif
600 unsigned long shadow_io_control_main;
601 static int last_pitch = PITCH_SPEED_100;
603 void sound_set_pitch(int32_t pitch)
605 unsigned long val;
607 if (pitch != last_pitch)
609 /* Calculate the new (bogus) frequency */
610 val = 18432 * PITCH_SPEED_100 / pitch;
612 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
614 /* We must tell the MAS that the frequency has changed.
615 * This will unfortunately cause a short silence. */
616 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
618 last_pitch = pitch;
622 int32_t sound_get_pitch(void)
624 return last_pitch;
626 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */