summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2010-05-15 13:09:45 +0000
committerMichael Sevakis <jethead71@rockbox.org>2010-05-15 13:09:45 +0000
commit80d0d15ca9b253f8a446f50cf25d3d4b850bcfd1 (patch)
tree2598d3a019c33d6f9ea76010fd6d3a8301ef87a0 /firmware/drivers
parent0f77db73469920f0b0006f696ddb36029338c378 (diff)
downloadrockbox-80d0d15ca9b253f8a446f50cf25d3d4b850bcfd1.tar.gz
rockbox-80d0d15ca9b253f8a446f50cf25d3d4b850bcfd1.zip
Gigabeat S: Fully enable access to hardware tone controls and 3-D effect feature. Under the hood, it's designated a hardware equalizer since it is one. Implement code framework for hardware EQ in general. Menu aspect is well abstracted and so the UI and strings can be changed around if taste doesn't quite suit. So far the emphasis is distinction of the UI labelling from the software EQ so that it's clear the settings are for a different thing.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26051 a1c6a512-1295-4272-9138-f99709370657
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 */