diff options
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/audio/wm8978.c | 122 |
1 files changed, 106 insertions, 16 deletions
diff --git a/firmware/drivers/audio/wm8978.c b/firmware/drivers/audio/wm8978.c index a2dbf5a8fb..2d57ce3f10 100644 --- a/firmware/drivers/audio/wm8978.c +++ b/firmware/drivers/audio/wm8978.c | |||
@@ -37,27 +37,35 @@ extern void audiohw_enable_headphone_jack(bool enable); | |||
37 | 37 | ||
38 | const struct sound_settings_info audiohw_settings[] = | 38 | const struct sound_settings_info audiohw_settings[] = |
39 | { | 39 | { |
40 | [SOUND_VOLUME] = {"dB", 0, 1, -90, 6, -25}, | 40 | [SOUND_VOLUME] = {"dB", 0, 1, -90, 6, -25}, |
41 | [SOUND_BASS] = {"dB", 0, 1, -12, 12, 0}, | 41 | [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, |
42 | [SOUND_TREBLE] = {"dB", 0, 1, -12, 12, 0}, | 42 | [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, |
43 | [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, | 43 | [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100}, |
44 | [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, | 44 | [SOUND_EQ_BAND1_GAIN] = {"dB", 0, 1, -12, 12, 0}, |
45 | [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100}, | 45 | [SOUND_EQ_BAND2_GAIN] = {"dB", 0, 1, -12, 12, 0}, |
46 | [SOUND_EQ_BAND3_GAIN] = {"dB", 0, 1, -12, 12, 0}, | ||
47 | [SOUND_EQ_BAND4_GAIN] = {"dB", 0, 1, -12, 12, 0}, | ||
48 | [SOUND_EQ_BAND5_GAIN] = {"dB", 0, 1, -12, 12, 0}, | ||
49 | [SOUND_EQ_BAND1_FREQUENCY] = {"", 0, 1, 0, 3, 0}, | ||
50 | [SOUND_EQ_BAND2_FREQUENCY] = {"", 0, 1, 0, 3, 0}, | ||
51 | [SOUND_EQ_BAND3_FREQUENCY] = {"", 0, 1, 0, 3, 0}, | ||
52 | [SOUND_EQ_BAND4_FREQUENCY] = {"", 0, 1, 0, 3, 0}, | ||
53 | [SOUND_EQ_BAND5_FREQUENCY] = {"", 0, 1, 0, 3, 0}, | ||
54 | [SOUND_EQ_BAND2_WIDTH] = {"", 0, 1, 0, 1, 0}, | ||
55 | [SOUND_EQ_BAND3_WIDTH] = {"", 0, 1, 0, 1, 0}, | ||
56 | [SOUND_EQ_BAND4_WIDTH] = {"", 0, 1, 0, 1, 0}, | ||
57 | [SOUND_DEPTH_3D] = {"%", 0, 1, 0, 15, 0}, | ||
46 | #ifdef HAVE_RECORDING | 58 | #ifdef HAVE_RECORDING |
47 | /* Digital: -119.0dB to +8.0dB in 0.5dB increments | 59 | /* Digital: -119.0dB to +8.0dB in 0.5dB increments |
48 | * Analog: Relegated to volume control | 60 | * Analog: Relegated to volume control |
49 | * Circumstances unfortunately do not allow a great deal of positive | 61 | * Circumstances unfortunately do not allow a great deal of positive |
50 | * gain. */ | 62 | * gain. */ |
51 | [SOUND_LEFT_GAIN] = {"dB", 1, 1,-238, 16, 0}, | 63 | [SOUND_LEFT_GAIN] = {"dB", 1, 1,-238, 16, 0}, |
52 | [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-238, 16, 0}, | 64 | [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-238, 16, 0}, |
53 | #if 0 | 65 | #if 0 |
54 | [SOUND_MIC_GAIN] = {"dB", 1, 1,-238, 16, 0}, | 66 | [SOUND_MIC_GAIN] = {"dB", 1, 1,-238, 16, 0}, |
55 | #endif | 67 | #endif |
56 | #endif | 68 | #endif |
57 | #if 0 | ||
58 | [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1}, | ||
59 | [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1}, | ||
60 | #endif | ||
61 | }; | 69 | }; |
62 | 70 | ||
63 | static uint16_t wmc_regs[WMC_NUM_REGISTERS] = | 71 | static uint16_t wmc_regs[WMC_NUM_REGISTERS] = |
@@ -123,10 +131,20 @@ struct | |||
123 | { | 131 | { |
124 | int vol_l; | 132 | int vol_l; |
125 | int vol_r; | 133 | int vol_r; |
134 | int dac_l; | ||
135 | int dac_r; | ||
126 | bool ahw_mute; | 136 | bool ahw_mute; |
137 | int prescaler; | ||
138 | int enhance_3d_prescaler; | ||
127 | } wmc_vol = | 139 | } wmc_vol = |
128 | { | 140 | { |
129 | 0, 0, false | 141 | .vol_l = 0, |
142 | .vol_r = 0, | ||
143 | .dac_l = 0, | ||
144 | .dac_r = 0, | ||
145 | .ahw_mute = false, | ||
146 | .prescaler = 0, | ||
147 | .enhance_3d_prescaler = 0, | ||
130 | }; | 148 | }; |
131 | 149 | ||
132 | static void wmc_write(unsigned int reg, unsigned int val) | 150 | static void wmc_write(unsigned int reg, unsigned int val) |
@@ -191,6 +209,10 @@ int sound_val2phys(int setting, int value) | |||
191 | break; | 209 | break; |
192 | #endif | 210 | #endif |
193 | 211 | ||
212 | case SOUND_DEPTH_3D: | ||
213 | result = (100 * value + 8) / 15; | ||
214 | break; | ||
215 | |||
194 | default: | 216 | default: |
195 | result = value; | 217 | result = value; |
196 | } | 218 | } |
@@ -216,8 +238,12 @@ void audiohw_preinit(void) | |||
216 | wmc_set(WMC_OUT4_MONO_MIXER_CTRL, WMC_MUTE); | 238 | wmc_set(WMC_OUT4_MONO_MIXER_CTRL, WMC_MUTE); |
217 | 239 | ||
218 | /* 3. Set L/RMIXEN = 1 and DACENL/R = 1 in register R3. */ | 240 | /* 3. Set L/RMIXEN = 1 and DACENL/R = 1 in register R3. */ |
219 | wmc_write(WMC_POWER_MANAGEMENT3, | 241 | wmc_write(WMC_POWER_MANAGEMENT3, WMC_RMIXEN | WMC_LMIXEN); |
220 | WMC_RMIXEN | WMC_LMIXEN | WMC_DACENR | WMC_DACENL); | 242 | |
243 | /* EQ and 3D applied to DAC (Set before DAC enable!) */ | ||
244 | wmc_set(WMC_EQ1_LOW_SHELF, WMC_EQ3DMODE); | ||
245 | |||
246 | wmc_set(WMC_POWER_MANAGEMENT3, WMC_DACENR | WMC_DACENL); | ||
221 | 247 | ||
222 | /* 4. Set BUFIOEN = 1 and VMIDSEL[1:0] to required value in register | 248 | /* 4. Set BUFIOEN = 1 and VMIDSEL[1:0] to required value in register |
223 | * R1. Wait for VMID supply to settle */ | 249 | * R1. Wait for VMID supply to settle */ |
@@ -305,6 +331,12 @@ void audiohw_set_headphone_vol(int vol_l, int vol_r) | |||
305 | get_headphone_levels(vol_l, &dac_l, &hp_l, &mix_l, &boost_l); | 331 | get_headphone_levels(vol_l, &dac_l, &hp_l, &mix_l, &boost_l); |
306 | get_headphone_levels(vol_r, &dac_r, &hp_r, &mix_r, &boost_r); | 332 | get_headphone_levels(vol_r, &dac_r, &hp_r, &mix_r, &boost_r); |
307 | 333 | ||
334 | wmc_vol.dac_l = dac_l; | ||
335 | wmc_vol.dac_r = dac_r; | ||
336 | |||
337 | dac_l -= wmc_vol.prescaler + wmc_vol.enhance_3d_prescaler; | ||
338 | dac_r -= wmc_vol.prescaler + wmc_vol.enhance_3d_prescaler; | ||
339 | |||
308 | wmc_write_masked(WMC_LEFT_MIXER_CTRL, mix_l << WMC_BYPLMIXVOL_POS, | 340 | wmc_write_masked(WMC_LEFT_MIXER_CTRL, mix_l << WMC_BYPLMIXVOL_POS, |
309 | WMC_BYPLMIXVOL); | 341 | WMC_BYPLMIXVOL); |
310 | wmc_write_masked(WMC_LEFT_ADC_BOOST_CTRL, | 342 | wmc_write_masked(WMC_LEFT_ADC_BOOST_CTRL, |
@@ -367,6 +399,64 @@ static void audiohw_mute(bool mute) | |||
367 | } | 399 | } |
368 | } | 400 | } |
369 | 401 | ||
402 | /* Equalizer - set the eq band level -12 to +12 dB. */ | ||
403 | void audiohw_set_eq_band_gain(unsigned int band, int val) | ||
404 | { | ||
405 | if (band > 4) | ||
406 | return; | ||
407 | |||
408 | wmc_write_masked(band + WMC_EQ1_LOW_SHELF, 12 - val, WMC_EQG); | ||
409 | } | ||
410 | |||
411 | /* Equalizer - set the eq band frequency index. */ | ||
412 | void audiohw_set_eq_band_frequency(unsigned int band, int val) | ||
413 | { | ||
414 | if (band > 4) | ||
415 | return; | ||
416 | |||
417 | wmc_write_masked(band + WMC_EQ1_LOW_SHELF, | ||
418 | val << WMC_EQC_POS, WMC_EQC); | ||
419 | } | ||
420 | |||
421 | /* Equalizer - set bandwidth for peaking filters to wide (!= 0) or | ||
422 | * narrow (0); only valid for peaking filter bands 1-3. */ | ||
423 | void audiohw_set_eq_band_width(unsigned int band, int val) | ||
424 | { | ||
425 | if (band < 1 || band > 3) | ||
426 | return; | ||
427 | |||
428 | wmc_write_masked(band + WMC_EQ1_LOW_SHELF, | ||
429 | (val == 0) ? 0 : WMC_EQBW, WMC_EQBW); | ||
430 | } | ||
431 | |||
432 | /* Set prescaler to prevent clipping the output amp when applying positive | ||
433 | * gain to EQ bands. */ | ||
434 | void audiohw_set_prescaler(int val) | ||
435 | { | ||
436 | val *= 2; | ||
437 | wmc_vol.prescaler = val; | ||
438 | val += wmc_vol.enhance_3d_prescaler; /* Combine with 3D attenuation */ | ||
439 | |||
440 | wmc_write_masked(WMC_LEFT_DAC_DIGITAL_VOL, wmc_vol.dac_l - val, | ||
441 | WMC_DVOL); | ||
442 | wmc_write_masked(WMC_RIGHT_DAC_DIGITAL_VOL, wmc_vol.dac_r - val, | ||
443 | WMC_DVOL); | ||
444 | } | ||
445 | |||
446 | /* Set the depth of the 3D effect */ | ||
447 | void audiohw_set_depth_3d(int val) | ||
448 | { | ||
449 | int att = 10*val / 15; /* -5 dB @ full setting */ | ||
450 | wmc_vol.enhance_3d_prescaler = att; | ||
451 | att += wmc_vol.prescaler; /* Combine with prescaler attenuation */ | ||
452 | |||
453 | wmc_write_masked(WMC_LEFT_DAC_DIGITAL_VOL, wmc_vol.dac_l - att, | ||
454 | WMC_DVOL); | ||
455 | wmc_write_masked(WMC_RIGHT_DAC_DIGITAL_VOL, wmc_vol.dac_r - att, | ||
456 | WMC_DVOL); | ||
457 | wmc_write_masked(WMC_3D_CONTROL, val, WMC_DEPTH3D); | ||
458 | } | ||
459 | |||
370 | void audiohw_close(void) | 460 | void audiohw_close(void) |
371 | { | 461 | { |
372 | /* 1. Mute all analogue outputs */ | 462 | /* 1. Mute all analogue outputs */ |