Merge branch 'master' into sim-target-tree
[kugel-rb.git] / firmware / sound.c
blobf852e848ed17d65382b0743a2bff2832d4435eef
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 const char *sound_unit(int setting)
48 return audiohw_settings[setting].unit;
51 int sound_numdecimals(int setting)
53 return audiohw_settings[setting].numdecimals;
56 int sound_steps(int setting)
58 return audiohw_settings[setting].steps;
61 int sound_min(int setting)
63 return audiohw_settings[setting].minval;
66 int sound_max(int setting)
68 return audiohw_settings[setting].maxval;
71 int sound_default(int setting)
73 return audiohw_settings[setting].defaultval;
76 static sound_set_type * const sound_set_fns[] =
78 [0 ... SOUND_LAST_SETTING-1] = NULL,
79 [SOUND_VOLUME] = sound_set_volume,
80 [SOUND_BASS] = sound_set_bass,
81 [SOUND_TREBLE] = sound_set_treble,
82 [SOUND_BALANCE] = sound_set_balance,
83 [SOUND_CHANNELS] = sound_set_channels,
84 [SOUND_STEREO_WIDTH] = sound_set_stereo_width,
85 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
86 [SOUND_LOUDNESS] = sound_set_loudness,
87 [SOUND_AVC] = sound_set_avc,
88 [SOUND_MDB_STRENGTH] = sound_set_mdb_strength,
89 [SOUND_MDB_HARMONICS] = sound_set_mdb_harmonics,
90 [SOUND_MDB_CENTER] = sound_set_mdb_center,
91 [SOUND_MDB_SHAPE] = sound_set_mdb_shape,
92 [SOUND_MDB_ENABLE] = sound_set_mdb_enable,
93 [SOUND_SUPERBASS] = sound_set_superbass,
94 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
95 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
96 [SOUND_BASS_CUTOFF] = sound_set_bass_cutoff,
97 #endif
98 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
99 [SOUND_TREBLE_CUTOFF] = sound_set_treble_cutoff,
100 #endif
103 sound_set_type* sound_get_fn(int setting)
105 return ((unsigned)setting >= ARRAYLEN(sound_set_fns)?
106 NULL : sound_set_fns[setting]);
109 #if CONFIG_CODEC == SWCODEC
110 static int (*dsp_callback)(int, intptr_t) = NULL;
112 void sound_set_dsp_callback(int (*func)(int, intptr_t))
114 dsp_callback = func;
116 #endif
118 #if (CONFIG_CODEC == MAS3507D) && !defined(SIMULATOR)
119 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
120 static int tenthdb2reg(int db)
122 if (db < -540) /* 3 dB steps */
123 return (db + 780) / 30;
124 else /* 1.5 dB steps */
125 return (db + 660) / 15;
127 #endif
130 #if !defined(AUDIOHW_HAVE_CLIPPING)
132 * The prescaler compensates for any kind of boosts, to prevent clipping.
134 * It's basically just a measure to make sure that audio does not clip during
135 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
136 * the audio amplitude by -12 dB before processing, then increase master gain
137 * by 12 dB after processing.
140 /* all values in tenth of dB MAS3507D UDA1380 */
141 int current_volume = 0; /* -780..+180 -840.. 0 */
142 int current_balance = 0; /* -960..+960 -840..+840 */
143 int current_treble = 0; /* -150..+150 0.. +60 */
144 int current_bass = 0; /* -150..+150 0..+240 */
146 static void set_prescaled_volume(void)
148 int prescale = 0;
149 int l, r;
151 /* The codecs listed use HW tone controls but don't have suitable prescaler
152 * functionality, so we let the prescaler stay at 0 for these, unless
153 * SW tone controls are in use. This is to avoid needing the SW DSP just for
154 * the prescaling.
156 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
157 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
158 || defined(HAVE_WM8758) || defined(HAVE_WM8985) || defined(HAVE_UDA1341))
160 prescale = MAX(current_bass, current_treble);
161 if (prescale < 0)
162 prescale = 0; /* no need to prescale if we don't boost
163 bass or treble */
165 /* Gain up the analog volume to compensate the prescale gain reduction,
166 * but if this would push the volume over the top, reduce prescaling
167 * instead (might cause clipping). */
168 if (current_volume + prescale > VOLUME_MAX)
169 prescale = VOLUME_MAX - current_volume;
170 #endif
172 #if defined(AUDIOHW_HAVE_PRESCALER)
173 audiohw_set_prescaler(prescale);
174 #else
175 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
176 #endif
178 if (current_volume == VOLUME_MIN)
179 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
181 l = r = current_volume + prescale;
183 /* Balance the channels scaled by the current volume and min volume. */
184 /* Subtract a dB from VOLUME_MIN to get it to a mute level */
185 if (current_balance > 0)
187 l -= ((l - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
189 else if (current_balance < 0)
191 r += ((r - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
194 #ifdef HAVE_SW_VOLUME_CONTROL
195 dsp_callback(DSP_CALLBACK_SET_SW_VOLUME, 0);
196 #endif
198 #ifndef SIMULATOR
199 #if CONFIG_CODEC == MAS3507D
200 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
201 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
202 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
203 || defined(HAVE_WM8750) || defined(HAVE_WM8751) || defined(HAVE_AS3514) \
204 || defined(HAVE_TSC2100) || defined(HAVE_AK4537) || defined(HAVE_UDA1341)
205 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
206 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
207 || defined(HAVE_WM8750) || (defined(HAVE_WM8751) && !defined(MROBE_100)) \
208 || defined(HAVE_WM8985)
209 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
210 #endif
212 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
213 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
214 #elif defined(HAVE_JZ4740_CODEC) || defined(HAVE_SDL_AUDIO)
215 audiohw_set_volume(current_volume);
216 #endif
217 #else /* SIMULATOR */
218 audiohw_set_volume(current_volume);
219 #endif /* !SIMULATOR */
221 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
224 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
225 unsigned long mdb_shape_shadow = 0;
226 unsigned long loudness_shadow = 0;
227 #endif
229 void sound_set_volume(int value)
231 if(!audio_is_initialized)
232 return;
234 #if defined(AUDIOHW_HAVE_CLIPPING)
235 audiohw_set_volume(value);
236 #elif CONFIG_CPU == PNX0101
237 int tmp = (60 - value * 4) & 0xff;
238 CODECVOL = tmp | (tmp << 8);
239 #else
240 current_volume = value * 10; /* tenth of dB */
241 set_prescaled_volume();
242 #endif
245 void sound_set_balance(int value)
247 if(!audio_is_initialized)
248 return;
250 #ifdef AUDIOHW_HAVE_BALANCE
251 audiohw_set_balance(value);
252 #else
253 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
254 set_prescaled_volume();
255 #endif
258 void sound_set_bass(int value)
260 if(!audio_is_initialized)
261 return;
263 #if !defined(AUDIOHW_HAVE_CLIPPING)
264 #if defined(HAVE_WM8750) || defined(HAVE_WM8751)
265 current_bass = value;
266 #else
267 current_bass = value * 10;
268 #endif
269 #endif
271 #if defined(AUDIOHW_HAVE_BASS)
272 audiohw_set_bass(value);
273 #else
274 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
275 #endif
277 #if !defined(AUDIOHW_HAVE_CLIPPING)
278 set_prescaled_volume();
279 #endif
282 void sound_set_treble(int value)
284 if(!audio_is_initialized)
285 return;
287 #if !defined(AUDIOHW_HAVE_CLIPPING)
288 #if defined(HAVE_WM8750) || defined(HAVE_WM8751)
289 current_treble = value;
290 #else
291 current_treble = value * 10;
292 #endif
293 #endif
295 #if defined(AUDIOHW_HAVE_TREBLE)
296 audiohw_set_treble(value);
297 #else
298 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
299 #endif
301 #if !defined(AUDIOHW_HAVE_CLIPPING)
302 set_prescaled_volume();
303 #endif
306 void sound_set_channels(int value)
308 if(!audio_is_initialized)
309 return;
311 #if CONFIG_CODEC == SWCODEC
312 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
313 #else
314 audiohw_set_channel(value);
315 #endif
318 void sound_set_stereo_width(int value)
320 if(!audio_is_initialized)
321 return;
323 #if CONFIG_CODEC == SWCODEC
324 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
325 #else
326 audiohw_set_stereo_width(value);
327 #endif
330 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
331 void sound_set_bass_cutoff(int value)
333 if(!audio_is_initialized)
334 return;
336 audiohw_set_bass_cutoff(value);
338 #endif
340 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
341 void sound_set_treble_cutoff(int value)
343 if(!audio_is_initialized)
344 return;
346 audiohw_set_treble_cutoff(value);
348 #endif
350 #if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F))
351 void sound_set_loudness(int value)
353 if(!audio_is_initialized)
354 return;
355 loudness_shadow = (loudness_shadow & 0x04) |
356 (MAX(MIN(value * 4, 0x44), 0) << 8);
357 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
360 void sound_set_avc(int value)
362 if(!audio_is_initialized)
363 return;
364 int tmp;
366 static const uint16_t avc_vals[] =
368 (0x1 << 8) | (0x8 << 12), /* 20ms */
369 (0x2 << 8) | (0x8 << 12), /* 2s */
370 (0x4 << 8) | (0x8 << 12), /* 4s */
371 (0x8 << 8) | (0x8 << 12), /* 8s */
373 switch (value) {
374 case 1:
375 case 2:
376 case 3:
377 case 4:
378 tmp = avc_vals[value -1];
379 break;
380 case -1: /* turn off and then turn on again to decay quickly */
381 tmp = mas_codec_readreg(MAS_REG_KAVC);
382 mas_codec_writereg(MAS_REG_KAVC, 0);
383 break;
384 default: /* off */
385 tmp = 0;
386 break;
388 mas_codec_writereg(MAS_REG_KAVC, tmp);
391 void sound_set_mdb_strength(int value)
393 if(!audio_is_initialized)
394 return;
395 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
398 void sound_set_mdb_harmonics(int value)
400 if(!audio_is_initialized)
401 return;
402 int tmp = value * 127 / 100;
403 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
406 void sound_set_mdb_center(int value)
408 if(!audio_is_initialized)
409 return;
410 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
413 void sound_set_mdb_shape(int value)
415 if(!audio_is_initialized)
416 return;
417 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
418 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
421 void sound_set_mdb_enable(int value)
423 if(!audio_is_initialized)
424 return;
425 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
426 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
429 void sound_set_superbass(int value)
431 if(!audio_is_initialized)
432 return;
433 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
434 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
436 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
438 void sound_set(int setting, int value)
440 sound_set_type* sound_set_val = sound_get_fn(setting);
441 if (sound_set_val)
442 sound_set_val(value);
445 #if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
446 && !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
447 && !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
448 && !defined (HAVE_WM8731) && !defined (HAVE_WM8978) \
449 && !defined(HAVE_AK4537)) || defined(SIMULATOR)
450 int sound_val2phys(int setting, int value)
452 #if CONFIG_CODEC == MAS3587F
453 int result = 0;
455 switch(setting)
457 case SOUND_LEFT_GAIN:
458 case SOUND_RIGHT_GAIN:
459 result = (value - 2) * 15;
460 break;
462 case SOUND_MIC_GAIN:
463 result = value * 15 + 210;
464 break;
466 default:
467 result = value;
468 break;
470 return result;
471 #elif defined(HAVE_UDA1380)
472 int result = 0;
474 switch(setting)
476 #ifdef HAVE_RECORDING
477 case SOUND_LEFT_GAIN:
478 case SOUND_RIGHT_GAIN:
479 case SOUND_MIC_GAIN:
480 result = value * 5; /* (1/2) * 10 */
481 break;
482 #endif
483 default:
484 result = value;
485 break;
487 return result;
488 #elif defined(HAVE_TLV320) || defined(HAVE_WM8711) \
489 || defined(HAVE_WM8721) || defined(HAVE_WM8731)
490 int result = 0;
492 switch(setting)
494 #ifdef HAVE_RECORDING
495 case SOUND_LEFT_GAIN:
496 case SOUND_RIGHT_GAIN:
497 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
498 break;
500 case SOUND_MIC_GAIN:
501 result = value * 200; /* 0 or 20 dB */
502 break;
503 #endif
504 default:
505 result = value;
506 break;
508 return result;
509 #elif defined(HAVE_AS3514)
510 /* This is here for the sim only and the audio driver has its own */
511 int result;
513 switch(setting)
515 #ifdef HAVE_RECORDING
516 case SOUND_LEFT_GAIN:
517 case SOUND_RIGHT_GAIN:
518 case SOUND_MIC_GAIN:
519 result = (value - 23) * 15;
520 break;
521 #endif
522 default:
523 result = value;
524 break;
527 return result;
528 #elif defined(HAVE_WM8978)
529 int result;
531 switch (setting)
533 #ifdef HAVE_RECORDING
534 case SOUND_LEFT_GAIN:
535 case SOUND_RIGHT_GAIN:
536 case SOUND_MIC_GAIN:
537 result = value * 5;
538 break;
539 #endif
541 default:
542 result = value;
545 return result;
546 #else
547 (void)setting;
548 return value;
549 #endif
551 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
553 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
554 /* This function works by telling the decoder that we have another
555 crystal frequency than we actually have. It will adjust its internal
556 parameters and the result is that the audio is played at another pitch.
558 The pitch value precision is based on PITCH_SPEED_PRECISION (in dsp.h)
561 #ifdef SIMULATOR
562 static
563 #else
564 extern
565 #endif
566 unsigned long shadow_io_control_main;
567 static int last_pitch = PITCH_SPEED_100;
569 void sound_set_pitch(int32_t pitch)
571 unsigned long val;
573 if (pitch != last_pitch)
575 /* Calculate the new (bogus) frequency */
576 val = 18432 * PITCH_SPEED_100 / pitch;
578 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
580 /* We must tell the MAS that the frequency has changed.
581 * This will unfortunately cause a short silence. */
582 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
584 last_pitch = pitch;
588 int32_t sound_get_pitch(void)
590 return last_pitch;
592 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */