summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/audio/wm8978.c122
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
38const struct sound_settings_info audiohw_settings[] = 38const 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
63static uint16_t wmc_regs[WMC_NUM_REGISTERS] = 71static 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
132static void wmc_write(unsigned int reg, unsigned int val) 150static 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. */
403void 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. */
412void 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. */
423void 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. */
434void 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 */
447void 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
370void audiohw_close(void) 460void audiohw_close(void)
371{ 461{
372 /* 1. Mute all analogue outputs */ 462 /* 1. Mute all analogue outputs */