mirror of
				https://github.com/Ysurac/openmptcprouter.git
				synced 2025-03-09 15:40:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			203 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			203 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 0919343d76c94ffb6173bf65b4389fb6fd4eb9d4 Mon Sep 17 00:00:00 2001
 | |
| From: Dimitris Papavasiliou <dpapavas@gmail.com>
 | |
| Date: Sat, 24 Nov 2018 22:05:42 +0200
 | |
| Subject: [PATCH 340/432] 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(-)
 | |
| 
 | |
| diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
 | |
| index 9a6a6e3a0eb9..47cf3013ead5 100644
 | |
| --- 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_veds =
 | |
|  	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_ANALOG_GAIN_CTRL,
 | |
|  	       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_soc_dai *dai, unsigned int fmt)
 | |
|  	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 pcm512x_dai_ops = {
 | |
|  	.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, struct regmap *regmap)
 | |
|  	if (!pcm512x)
 | |
|  		return -ENOMEM;
 | |
|  
 | |
| +	mutex_init(&pcm512x->mutex);
 | |
| +
 | |
|  	dev_set_drvdata(dev, pcm512x);
 | |
|  	pcm512x->regmap = regmap;
 | |
|  
 | |
| diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h
 | |
| index d70d9c0c2088..9dda8693498e 100644
 | |
| --- 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 */
 | |
| -- 
 | |
| 2.19.1
 | |
| 
 |