forked from len0rd/rockbox
as3543: fix audio gap when switching from dac to line-in/recording
Also clarity parts of the code. The old code suffered from two defects: - it was very unclear because it made changes to whole registers (using as3514_write) instead of fields (using as3514_set/clear/write_masked). Also the routing code was spread accross several functions which made it hard to follow. - it did not properly reroute audio on monitor changes. In particular, the following could happen: when switching from DAC to radio, the code would fail to clear SUM_off, resulting in a weird situation where the main mixer was off (SUM_off) but the headphone where using the main mixer as input. Incredibly this worked anyway (at least on AMSv2 and YP-R0) but resulted in strange volume gaps between DAC and radio mode. Change-Id: I7826835fdb59c21f6483b223883ca9289e85caca
This commit is contained in:
parent
cbcc8f368f
commit
afe7f1b915
1 changed files with 51 additions and 30 deletions
|
|
@ -78,6 +78,8 @@
|
||||||
|
|
||||||
/* Shadow registers */
|
/* Shadow registers */
|
||||||
static uint8_t as3514_regs[AS3514_NUM_AUDIO_REGS]; /* 8-bit registers */
|
static uint8_t as3514_regs[AS3514_NUM_AUDIO_REGS]; /* 8-bit registers */
|
||||||
|
/* Keep track of volume */
|
||||||
|
static int current_vol_l, current_vol_r;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* little helper method to set register values.
|
* little helper method to set register values.
|
||||||
|
|
@ -264,6 +266,10 @@ void audiohw_set_volume(int vol_l, int vol_r)
|
||||||
unsigned int hph_r, hph_l;
|
unsigned int hph_r, hph_l;
|
||||||
unsigned int mix_l, mix_r;
|
unsigned int mix_l, mix_r;
|
||||||
|
|
||||||
|
/* remember volume */
|
||||||
|
current_vol_l = vol_l;
|
||||||
|
current_vol_r = vol_r;
|
||||||
|
|
||||||
vol_l = vol_tenthdb2hw(vol_l);
|
vol_l = vol_tenthdb2hw(vol_l);
|
||||||
vol_r = vol_tenthdb2hw(vol_r);
|
vol_r = vol_tenthdb2hw(vol_r);
|
||||||
|
|
||||||
|
|
@ -273,13 +279,13 @@ void audiohw_set_volume(int vol_l, int vol_r)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We combine the mixer/DAC channel volume range with the headphone volume
|
/* We combine the mixer/DAC channel volume range with the headphone volume
|
||||||
range - keep first stage as loud as possible */
|
* range. We want to keep the mixers volume as high as possible and the
|
||||||
|
* headphone volume as low as possible. */
|
||||||
|
|
||||||
/*AS3543 mixer can go a little louder then the as3514, although
|
/* AS3543 mixer can go a little louder then the as3514, although
|
||||||
* it might be possible to go louder on the as3514 as well */
|
* it might be possible to go louder on the as3514 as well */
|
||||||
|
|
||||||
#ifdef HAVE_AS3543
|
#ifdef HAVE_AS3543
|
||||||
#define MIXER_MAX_VOLUME 0x1b
|
#define MIXER_MAX_VOLUME 0x1b /* IMPORTANT corresponds to a volume of 0dB (see below) */
|
||||||
#else /* lets leave the AS3514 alone until its better tested*/
|
#else /* lets leave the AS3514 alone until its better tested*/
|
||||||
#define MIXER_MAX_VOLUME 0x16
|
#define MIXER_MAX_VOLUME 0x16
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -301,17 +307,28 @@ void audiohw_set_volume(int vol_l, int vol_r)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_AS3543
|
#ifdef HAVE_AS3543
|
||||||
/*if not radio or recording*/
|
bool dac_only = !(as3514_regs[AS3514_AUDIOSET1] & (AUDIOSET1_ADC_on | AUDIOSET1_LIN1_on));
|
||||||
if (!(as3514_regs[AS3514_AUDIOSET1] & (AUDIOSET1_ADC_on | AUDIOSET1_LIN1_on))) {
|
if(dac_only && hph_l != 0 && hph_r != 0)
|
||||||
if (!hph_l || !hph_r) { /*if volume higher, disable the mixer to slightly improve noise*/
|
{
|
||||||
as3514_write(AS3514_AUDIOSET1, AUDIOSET1_DAC_on | AUDIOSET1_DAC_GAIN_on);
|
/* In DAC only mode, if both left and right volume are higher than
|
||||||
as3514_write(AS3514_AUDIOSET2, AUDIOSET2_AGC_off | AUDIOSET2_HPH_QUALITY_LOW_POWER);
|
* MIXER_MAX_VOLUME, we disable and bypass the DAC mixer to slightly
|
||||||
as3514_write_masked(AS3514_HPH_OUT_R, HPH_OUT_R_HP_OUT_SUM, HPH_OUT_R_HP_OUT_MASK);
|
* improve noise.
|
||||||
} else {
|
*
|
||||||
as3514_write(AS3514_AUDIOSET1, AUDIOSET1_DAC_on);
|
* WARNING this works because MIXER_MAX_VOLUME corresponds to a DAC mixer
|
||||||
as3514_write(AS3514_AUDIOSET2, AUDIOSET2_SUM_off | AUDIOSET2_AGC_off | AUDIOSET2_HPH_QUALITY_LOW_POWER);
|
* volume of 0dB, thus it's the same to bypass the mixer or set its
|
||||||
as3514_write_masked(AS3514_HPH_OUT_R, HPH_OUT_R_HP_OUT_DAC, HPH_OUT_R_HP_OUT_MASK);
|
* level to MIXER_MAX_VOLUME, except that bypassing is less noisy */
|
||||||
}
|
as3514_clear(AS3514_AUDIOSET1, AUDIOSET1_DAC_GAIN_on);
|
||||||
|
as3514_set(AS3514_AUDIOSET2, AUDIOSET2_SUM_off);
|
||||||
|
as3514_write_masked(AS3514_HPH_OUT_R, HPH_OUT_R_HP_OUT_DAC, HPH_OUT_R_HP_OUT_MASK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* In all other cases, we have no choice but to go through the main mixer
|
||||||
|
* (aka SUM) to get the volume we want or to properly route audio from
|
||||||
|
* line-in/microphone. */
|
||||||
|
as3514_set(AS3514_AUDIOSET1, AUDIOSET1_DAC_GAIN_on);
|
||||||
|
as3514_clear(AS3514_AUDIOSET2, AUDIOSET2_SUM_off);
|
||||||
|
as3514_write_masked(AS3514_HPH_OUT_R, HPH_OUT_R_HP_OUT_SUM, HPH_OUT_R_HP_OUT_MASK);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -485,28 +502,32 @@ void audiohw_set_recvol(int left, int right, int type)
|
||||||
*/
|
*/
|
||||||
void audiohw_set_monitor(bool enable)
|
void audiohw_set_monitor(bool enable)
|
||||||
{
|
{
|
||||||
|
/* On AS3543 we play with DAC mixer bypass to decrease noise. This means that
|
||||||
|
* even in DAC mode, the headphone mux might be set to HPH_OUT_R_HP_OUT_SUM or
|
||||||
|
* HPH_OUT_R_HP_OUT_DAC depending on the volume. Care must be taken when
|
||||||
|
* changing monitor.
|
||||||
|
*
|
||||||
|
* The only safe procedure is to first change the Audioset1 register to enable/disable
|
||||||
|
* monitor, then call audiohw_set_volume to recompute the audio routing, then
|
||||||
|
* mute/unmute lines-in. */
|
||||||
if (enable) {
|
if (enable) {
|
||||||
#ifdef HAVE_AS3543
|
/* select either LIN1 or LIN2 but keep them muted for now */
|
||||||
as3514_write_masked(AS3514_HPH_OUT_R, HPH_OUT_R_HP_OUT_SUM, HPH_OUT_R_HP_OUT_MASK);
|
|
||||||
#endif
|
|
||||||
/* select either LIN1 or LIN2 */
|
|
||||||
as3514_write_masked(AS3514_AUDIOSET1, AUDIOSET1_LIN_on,
|
as3514_write_masked(AS3514_AUDIOSET1, AUDIOSET1_LIN_on,
|
||||||
AUDIOSET1_LIN1_on | AUDIOSET1_LIN2_on);
|
AUDIOSET1_LIN1_on | AUDIOSET1_LIN2_on);
|
||||||
|
/* change audio routing */
|
||||||
|
audiohw_set_volume(current_vol_l, current_vol_r);
|
||||||
|
/* finally unmute line-in */
|
||||||
as3514_set(AS3514_LINE_IN_R, LINE_IN1_R_LI1R_MUTE_off);
|
as3514_set(AS3514_LINE_IN_R, LINE_IN1_R_LI1R_MUTE_off);
|
||||||
as3514_set(AS3514_LINE_IN_L, LINE_IN1_L_LI1L_MUTE_off);
|
as3514_set(AS3514_LINE_IN_L, LINE_IN1_L_LI1L_MUTE_off);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#ifdef HAVE_AS3543
|
/* mute line-in */
|
||||||
as3514_write_masked(AS3514_HPH_OUT_R, HPH_OUT_R_HP_OUT_DAC, HPH_OUT_R_HP_OUT_MASK);
|
as3514_clear(AS3514_LINE_IN_R, LINE_IN1_R_LI1R_MUTE_off);
|
||||||
#endif
|
as3514_clear(AS3514_LINE_IN_L, LINE_IN1_L_LI1L_MUTE_off);
|
||||||
/* turn off both LIN1 and LIN2 (if present) */
|
/* disable line-in */
|
||||||
as3514_clear(AS3514_LINE_IN1_R, LINE_IN1_R_LI1R_MUTE_off);
|
|
||||||
as3514_clear(AS3514_LINE_IN1_L, LINE_IN1_L_LI1L_MUTE_off);
|
|
||||||
#ifndef HAVE_AS3543
|
|
||||||
as3514_clear(AS3514_LINE_IN2_R, LINE_IN2_R_LI2R_MUTE_off);
|
|
||||||
as3514_clear(AS3514_LINE_IN2_L, LINE_IN2_L_LI2L_MUTE_off);
|
|
||||||
#endif
|
|
||||||
as3514_clear(AS3514_AUDIOSET1, AUDIOSET1_LIN1_on | AUDIOSET1_LIN2_on);
|
as3514_clear(AS3514_AUDIOSET1, AUDIOSET1_LIN1_on | AUDIOSET1_LIN2_on);
|
||||||
|
/* change audio routing */
|
||||||
|
audiohw_set_volume(current_vol_l, current_vol_r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* HAVE_RECORDING || HAVE_FMRADIO_IN */
|
#endif /* HAVE_RECORDING || HAVE_FMRADIO_IN */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue