[alsa-devel] [PATCH] ASoC: rt286: fix headphone click/crack noise on Dell XPS 9343 I2S mode
Kai-Heng Feng
kai.heng.feng at canonical.com
Thu Feb 16 08:15:45 CET 2017
On Thu, Feb 16, 2017 at 2:53 PM, Bard Liao <bardliao at realtek.com> wrote:
>> -----Original Message-----
>> From: Kai-Heng Feng [mailto:kai.heng.feng at canonical.com]
>> Sent: Monday, January 23, 2017 1:35 PM
>> To: Bard Liao
>> Cc: Oder Chiou; lgirdwood at gmail.com; broonie at kernel.org;
>> alsa-devel at alsa-project.org; Kai-Heng Feng
>> Subject: [PATCH] ASoC: rt286: fix headphone click/crack noise on Dell XPS 9343
>> I2S mode
>>
>> HDA mode does not have these issues because necessary workarounds in
>> linux/sound/pci/hda/patch_realtek.c are already applied. So we can
>> leverage these workaournds into rt286.
>>
>> When jack is plugged, it rapidly generates I2C interrupts, which
>> triggers rt286_irq() and rt286_jack_detect(), which causes the noise.
>> alc_fixup_dell_xps13() in patch_realtek.c sets up a pin that can stop
>> the frantic interrupts, hence fixes the click noise.
>>
>> When rt286 is under powersaving state, play a sound with headphone or
>> plug a headphone in will produce a loud crack sound.
>> alc_shutup_dell_xps13() patch_realtek.c mutes the headphone at plugging.
>> Apply the same workaround to LDO2 power event can make the loud crack
>> sound to a more tolerable pop sound. I found that unconditionally apply
>> the workaround to all related power event can help a little further.
>>
>> Link: https://bugzilla.kernel.org/show_bug.cgi?id=112611
>> Link: https://bugzilla.redhat.com/show_bug.cgi?id=1313434
>> Signed-off-by: Kai-Heng Feng <kai.heng.feng at canonical.com>
>> ---
>> sound/soc/codecs/rt286.c | 67
>> +++++++++++++++++++++++++++++++++++++++++++++---
>> 1 file changed, 63 insertions(+), 4 deletions(-)
>>
>> diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
>> index 74c0e4e..d041937 100644
>> --- a/sound/soc/codecs/rt286.c
>> +++ b/sound/soc/codecs/rt286.c
>> @@ -36,6 +36,8 @@
>> #define RT286_VENDOR_ID 0x10ec0286
>> #define RT288_VENDOR_ID 0x10ec0288
>>
>> +#define AMP_OUT_MUTE 0xb080
>> +
>> struct rt286_priv {
>> struct reg_default *index_cache;
>> int index_cache_size;
>> @@ -47,6 +49,7 @@ struct rt286_priv {
>> struct delayed_work jack_detect_work;
>> int sys_clk;
>> int clk_id;
>> + void (*mute_hpo_func)(struct snd_soc_codec *codec);
>> };
>>
>> static const struct reg_default rt286_index_def[] = {
>> @@ -472,10 +475,51 @@ static int rt286_set_dmic1_event(struct
>> snd_soc_dapm_widget *w,
>> return 0;
>> }
>>
>> +/* Add HV, VREF and LDO1 event functions to workaround headphone crack
>> noise */
>> +static int rt286_hv_event(struct snd_soc_dapm_widget *w,
>> + struct snd_kcontrol *kcontrol, int event)
>> +{
>> + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
>> + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
>> +
>> + if (rt286->mute_hpo_func)
>> + rt286->mute_hpo_func(codec);
>> +
>> + return 0;
>> +}
>> +
>> +static int rt286_vref_event(struct snd_soc_dapm_widget *w,
>> + struct snd_kcontrol *kcontrol, int event)
>> +{
>> + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
>> + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
>> +
>> + if (rt286->mute_hpo_func)
>> + rt286->mute_hpo_func(codec);
>> +
>> + return 0;
>> +}
>> +
>> +static int rt286_ldo1_event(struct snd_soc_dapm_widget *w,
>> + struct snd_kcontrol *kcontrol, int event)
>> +{
>> + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
>> + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
>> +
>> + if (rt286->mute_hpo_func)
>> + rt286->mute_hpo_func(codec);
>> +
>> + return 0;
>> +}
>> +
>> static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
>> struct snd_kcontrol *kcontrol, int event)
>> {
>> struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
>> + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
>> +
>> + if (rt286->mute_hpo_func)
>> + rt286->mute_hpo_func(codec);
>>
>> switch (event) {
>> case SND_SOC_DAPM_POST_PMU:
>> @@ -516,16 +560,24 @@ static int rt286_mic1_event(struct
>> snd_soc_dapm_widget *w,
>> return 0;
>> }
>>
>> +static void dell_dino_mute_hpo(struct snd_soc_codec *codec)
>> +{
>> + snd_soc_write(codec, RT286_SET_AMP_GAIN_HPO, AMP_OUT_MUTE);
>> +}
>> +
>
> I didn't see where will headphone be unmute. There is already a
> headphone mute control on the driver. See
> SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0,
> &hpol_enable_control),
> SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0,
> &hpor_enable_control),
This is a direct mirror to function alc_shutup_dell_xps13() in
sound/pci/hda/patch_realtek.c.
I'll try to use what you suggest here.
>
>
>> SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1,
>> 13, 1, rt286_ldo2_event, SND_SOC_DAPM_PRE_PMD |
>> - SND_SOC_DAPM_POST_PMU),
>> + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
>
> Is POST_PMU really what you want?
I found that mute output before any power event has better result than
mute after.
>
>> @@ -1190,6 +1242,11 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
>> regmap_update_bits(rt286->regmap,
>> RT286_CBJ_CTRL1, 0xf000, 0xb000);
>> } else {
>> + /* Fix headphone click noise */
>> + if (dmi_check_system(dmi_dell_dino))
>> + regmap_write(rt286->regmap,
>> + RT286_MIC1_DET_CTRL, 0x0020);
>> +
>
> I need to figure out how 0x0020 works.
It's from commit 3e1b0c4a9d563d7fc6e22dc92613cd3237bb5ce0
>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
More information about the Alsa-devel
mailing list