diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-4.19/950-0292-ASoC-pcm512x-Implement-the-digital_mute-interface.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-4.19/950-0292-ASoC-pcm512x-Implement-the-digital_mute-interface.patch | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-4.19/950-0292-ASoC-pcm512x-Implement-the-digital_mute-interface.patch b/target/linux/bcm27xx/patches-4.19/950-0292-ASoC-pcm512x-Implement-the-digital_mute-interface.patch new file mode 100644 index 0000000000..e68cf7b2f9 --- /dev/null +++ b/target/linux/bcm27xx/patches-4.19/950-0292-ASoC-pcm512x-Implement-the-digital_mute-interface.patch @@ -0,0 +1,196 @@ +From 4a15efde52bb79bf44e63b998cd84f896404d728 Mon Sep 17 00:00:00 2001 +From: Dimitris Papavasiliou <dpapavas@gmail.com> +Date: Sat, 24 Nov 2018 22:05:42 +0200 +Subject: [PATCH] ASoC: pcm512x: Implement the digital_mute interface + +[ Upstream commit 3500f1c589e92e0b6b1f8d31b4084fbde08d49cb ] + +Clicks and pops of various volumes can be produced while the device is +opened, closed, put into and taken out of standby, or reconfigured. +Fix this, by implementing the digital_mute interface, so that the +output is muted during such operations. + +Signed-off-by: Dimitris Papavasiliou <dpapavas@gmail.com> +Signed-off-by: Mark Brown <broonie@kernel.org> +--- + sound/soc/codecs/pcm512x.c | 121 ++++++++++++++++++++++++++++++++++++- + sound/soc/codecs/pcm512x.h | 2 + + 2 files changed, 121 insertions(+), 2 deletions(-) + +--- a/sound/soc/codecs/pcm512x.c ++++ b/sound/soc/codecs/pcm512x.c +@@ -53,6 +53,8 @@ struct pcm512x_priv { + unsigned long overclock_pll; + unsigned long overclock_dac; + unsigned long overclock_dsp; ++ int mute; ++ struct mutex mutex; + int lrclk_div; + }; + +@@ -385,6 +387,61 @@ static const struct soc_enum pcm512x_ved + SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, + pcm512x_ramp_step_text); + ++static int pcm512x_update_mute(struct pcm512x_priv *pcm512x) ++{ ++ return regmap_update_bits( ++ pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR, ++ (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT) ++ | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT)); ++} ++ ++static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); ++ ++ mutex_lock(&pcm512x->mutex); ++ ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4); ++ ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2); ++ mutex_unlock(&pcm512x->mutex); ++ ++ return 0; ++} ++ ++static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); ++ int ret, changed = 0; ++ ++ mutex_lock(&pcm512x->mutex); ++ ++ if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) { ++ pcm512x->mute ^= 0x4; ++ changed = 1; ++ } ++ if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) { ++ pcm512x->mute ^= 0x2; ++ changed = 1; ++ } ++ ++ if (changed) { ++ ret = pcm512x_update_mute(pcm512x); ++ if (ret != 0) { ++ dev_err(component->dev, ++ "Failed to update digital mute: %d\n", ret); ++ mutex_unlock(&pcm512x->mutex); ++ return ret; ++ } ++ } ++ ++ mutex_unlock(&pcm512x->mutex); ++ ++ return changed; ++} ++ + static const struct snd_kcontrol_new pcm512x_controls[] = { + SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, + PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), +@@ -392,8 +449,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume + PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), + SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, + PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), +-SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, +- PCM512x_RQMR_SHIFT, 1, 1), ++{ ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Digital Playback Switch", ++ .index = 0, ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, ++ .info = snd_ctl_boolean_stereo_info, ++ .get = pcm512x_digital_playback_switch_get, ++ .put = pcm512x_digital_playback_switch_put ++}, + + SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), + SOC_ENUM("DSP Program", pcm512x_dsp_program), +@@ -1323,6 +1387,56 @@ static int pcm512x_set_fmt(struct snd_so + return 0; + } + ++static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); ++ int ret; ++ unsigned int mute_det; ++ ++ mutex_lock(&pcm512x->mutex); ++ ++ if (mute) { ++ pcm512x->mute |= 0x1; ++ ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE, ++ PCM512x_RQML | PCM512x_RQMR, ++ PCM512x_RQML | PCM512x_RQMR); ++ if (ret != 0) { ++ dev_err(component->dev, ++ "Failed to set digital mute: %d\n", ret); ++ mutex_unlock(&pcm512x->mutex); ++ return ret; ++ } ++ ++ regmap_read_poll_timeout(pcm512x->regmap, ++ PCM512x_ANALOG_MUTE_DET, ++ mute_det, (mute_det & 0x3) == 0, ++ 200, 10000); ++ ++ mutex_unlock(&pcm512x->mutex); ++ } else { ++ pcm512x->mute &= ~0x1; ++ ret = pcm512x_update_mute(pcm512x); ++ if (ret != 0) { ++ dev_err(component->dev, ++ "Failed to update digital mute: %d\n", ret); ++ mutex_unlock(&pcm512x->mutex); ++ return ret; ++ } ++ ++ regmap_read_poll_timeout(pcm512x->regmap, ++ PCM512x_ANALOG_MUTE_DET, ++ mute_det, ++ (mute_det & 0x3) ++ == ((~pcm512x->mute >> 1) & 0x3), ++ 200, 10000); ++ } ++ ++ mutex_unlock(&pcm512x->mutex); ++ ++ return 0; ++} ++ + static int pcm512x_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int width) +@@ -1348,6 +1462,7 @@ static const struct snd_soc_dai_ops pcm5 + .startup = pcm512x_dai_startup, + .hw_params = pcm512x_hw_params, + .set_fmt = pcm512x_set_fmt, ++ .digital_mute = pcm512x_digital_mute, + .set_tdm_slot = pcm512x_set_tdm_slot, + }; + +@@ -1414,6 +1529,8 @@ int pcm512x_probe(struct device *dev, st + if (!pcm512x) + return -ENOMEM; + ++ mutex_init(&pcm512x->mutex); ++ + dev_set_drvdata(dev, pcm512x); + pcm512x->regmap = regmap; + +--- a/sound/soc/codecs/pcm512x.h ++++ b/sound/soc/codecs/pcm512x.h +@@ -112,7 +112,9 @@ + #define PCM512x_RQST_SHIFT 4 + + /* Page 0, Register 3 - mute */ ++#define PCM512x_RQMR (1 << 0) + #define PCM512x_RQMR_SHIFT 0 ++#define PCM512x_RQML (1 << 4) + #define PCM512x_RQML_SHIFT 4 + + /* Page 0, Register 4 - PLL */ |