diff --git a/firmware/drivers/audio/eros_qn_codec.c b/firmware/drivers/audio/eros_qn_codec.c index 21347f5fca..fdf21d2f9d 100644 --- a/firmware/drivers/audio/eros_qn_codec.c +++ b/firmware/drivers/audio/eros_qn_codec.c @@ -26,10 +26,14 @@ #include "audiohw.h" #include "settings.h" #include "pcm_sw_volume.h" +#include "gpio-x1000.h" static long int vol_l_hw = 0; static long int vol_r_hw = 0; +/* internal: mute the headphone amp. 0 - unmuted, 1 - muted */ +void audiohw_mute_hp(int mute); + void pcm5102_set_outputs(void) { audiohw_set_volume(vol_l_hw, vol_r_hw); @@ -53,13 +57,33 @@ void audiohw_set_volume(int vol_l, int vol_r) if (lineout_inserted() && !headphones_inserted()) { l = r = global_settings.volume_limit * 10; + + /* mute the headphone amp if not plugged in */ + audiohw_mute_hp(1); } else { + /* unmute the headphone amp when plugged in */ + audiohw_mute_hp(0); l = vol_l; r = vol_r; } #endif + l = l <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : l; + r = r <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : r; + pcm_set_master_volume(l, r); } + +void audiohw_mute_hp(int mute) +{ + if (mute == 0) + { + gpio_set_level(GPIO_MAX97220_SHDN, 1); + } + else + { + gpio_set_level(GPIO_MAX97220_SHDN, 0); + } +} diff --git a/firmware/export/eros_qn_codec.h b/firmware/export/eros_qn_codec.h index 15c745c04b..9c900186a8 100644 --- a/firmware/export/eros_qn_codec.h +++ b/firmware/export/eros_qn_codec.h @@ -26,6 +26,9 @@ #define PCM5102A_VOLUME_MIN -740 #define PCM5102A_VOLUME_MAX 0 +/* a small DC offset appears to prevent play/pause clicking */ +#define PCM_DC_OFFSET_VALUE -1 + AUDIOHW_SETTING(VOLUME, "dB", 0, 1, PCM5102A_VOLUME_MIN/10, PCM5102A_VOLUME_MAX/10, 0) /* this just calls audiohw_set_volume() with the last (locally) known volume, diff --git a/firmware/pcm_sw_volume.c b/firmware/pcm_sw_volume.c index 7322269f44..3593c684af 100644 --- a/firmware/pcm_sw_volume.c +++ b/firmware/pcm_sw_volume.c @@ -54,7 +54,11 @@ static typeof (memcpy) *pcm_scaling_fn = NULL; /* Scale sample by PCM factor */ static inline int32_t pcm_scale_sample(PCM_F_T f, int32_t s) { +#if defined(PCM_DC_OFFSET_VALUE) + return (f * s + PCM_DC_OFFSET_VALUE) >> PCM_SW_VOLUME_FRACBITS; +#else return (f * s) >> PCM_SW_VOLUME_FRACBITS; +#endif } /* Both UNITY, use direct copy */