brcm63xx: rename target to bcm63xx
[openwrt/staging/wigyori.git] / target / linux / brcm2708 / patches-4.19 / 950-0292-ASoC-pcm512x-Implement-the-digital_mute-interface.patch
1 From 4a15efde52bb79bf44e63b998cd84f896404d728 Mon Sep 17 00:00:00 2001
2 From: Dimitris Papavasiliou <dpapavas@gmail.com>
3 Date: Sat, 24 Nov 2018 22:05:42 +0200
4 Subject: [PATCH] ASoC: pcm512x: Implement the digital_mute interface
5
6 [ Upstream commit 3500f1c589e92e0b6b1f8d31b4084fbde08d49cb ]
7
8 Clicks and pops of various volumes can be produced while the device is
9 opened, closed, put into and taken out of standby, or reconfigured.
10 Fix this, by implementing the digital_mute interface, so that the
11 output is muted during such operations.
12
13 Signed-off-by: Dimitris Papavasiliou <dpapavas@gmail.com>
14 Signed-off-by: Mark Brown <broonie@kernel.org>
15 ---
16 sound/soc/codecs/pcm512x.c | 121 ++++++++++++++++++++++++++++++++++++-
17 sound/soc/codecs/pcm512x.h | 2 +
18 2 files changed, 121 insertions(+), 2 deletions(-)
19
20 --- a/sound/soc/codecs/pcm512x.c
21 +++ b/sound/soc/codecs/pcm512x.c
22 @@ -53,6 +53,8 @@ struct pcm512x_priv {
23 unsigned long overclock_pll;
24 unsigned long overclock_dac;
25 unsigned long overclock_dsp;
26 + int mute;
27 + struct mutex mutex;
28 int lrclk_div;
29 };
30
31 @@ -385,6 +387,61 @@ static const struct soc_enum pcm512x_ved
32 SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
33 pcm512x_ramp_step_text);
34
35 +static int pcm512x_update_mute(struct pcm512x_priv *pcm512x)
36 +{
37 + return regmap_update_bits(
38 + pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR,
39 + (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT)
40 + | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT));
41 +}
42 +
43 +static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
44 + struct snd_ctl_elem_value *ucontrol)
45 +{
46 + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
47 + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
48 +
49 + mutex_lock(&pcm512x->mutex);
50 + ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4);
51 + ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2);
52 + mutex_unlock(&pcm512x->mutex);
53 +
54 + return 0;
55 +}
56 +
57 +static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
58 + struct snd_ctl_elem_value *ucontrol)
59 +{
60 + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
61 + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
62 + int ret, changed = 0;
63 +
64 + mutex_lock(&pcm512x->mutex);
65 +
66 + if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) {
67 + pcm512x->mute ^= 0x4;
68 + changed = 1;
69 + }
70 + if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) {
71 + pcm512x->mute ^= 0x2;
72 + changed = 1;
73 + }
74 +
75 + if (changed) {
76 + ret = pcm512x_update_mute(pcm512x);
77 + if (ret != 0) {
78 + dev_err(component->dev,
79 + "Failed to update digital mute: %d\n", ret);
80 + mutex_unlock(&pcm512x->mutex);
81 + return ret;
82 + }
83 + }
84 +
85 + mutex_unlock(&pcm512x->mutex);
86 +
87 + return changed;
88 +}
89 +
90 static const struct snd_kcontrol_new pcm512x_controls[] = {
91 SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
92 PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
93 @@ -392,8 +449,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume
94 PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
95 SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
96 PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
97 -SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
98 - PCM512x_RQMR_SHIFT, 1, 1),
99 +{
100 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
101 + .name = "Digital Playback Switch",
102 + .index = 0,
103 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
104 + .info = snd_ctl_boolean_stereo_info,
105 + .get = pcm512x_digital_playback_switch_get,
106 + .put = pcm512x_digital_playback_switch_put
107 +},
108
109 SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
110 SOC_ENUM("DSP Program", pcm512x_dsp_program),
111 @@ -1323,6 +1387,56 @@ static int pcm512x_set_fmt(struct snd_so
112 return 0;
113 }
114
115 +static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
116 +{
117 + struct snd_soc_component *component = dai->component;
118 + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
119 + int ret;
120 + unsigned int mute_det;
121 +
122 + mutex_lock(&pcm512x->mutex);
123 +
124 + if (mute) {
125 + pcm512x->mute |= 0x1;
126 + ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE,
127 + PCM512x_RQML | PCM512x_RQMR,
128 + PCM512x_RQML | PCM512x_RQMR);
129 + if (ret != 0) {
130 + dev_err(component->dev,
131 + "Failed to set digital mute: %d\n", ret);
132 + mutex_unlock(&pcm512x->mutex);
133 + return ret;
134 + }
135 +
136 + regmap_read_poll_timeout(pcm512x->regmap,
137 + PCM512x_ANALOG_MUTE_DET,
138 + mute_det, (mute_det & 0x3) == 0,
139 + 200, 10000);
140 +
141 + mutex_unlock(&pcm512x->mutex);
142 + } else {
143 + pcm512x->mute &= ~0x1;
144 + ret = pcm512x_update_mute(pcm512x);
145 + if (ret != 0) {
146 + dev_err(component->dev,
147 + "Failed to update digital mute: %d\n", ret);
148 + mutex_unlock(&pcm512x->mutex);
149 + return ret;
150 + }
151 +
152 + regmap_read_poll_timeout(pcm512x->regmap,
153 + PCM512x_ANALOG_MUTE_DET,
154 + mute_det,
155 + (mute_det & 0x3)
156 + == ((~pcm512x->mute >> 1) & 0x3),
157 + 200, 10000);
158 + }
159 +
160 + mutex_unlock(&pcm512x->mutex);
161 +
162 + return 0;
163 +}
164 +
165 static int pcm512x_set_tdm_slot(struct snd_soc_dai *dai,
166 unsigned int tx_mask, unsigned int rx_mask,
167 int slots, int width)
168 @@ -1348,6 +1462,7 @@ static const struct snd_soc_dai_ops pcm5
169 .startup = pcm512x_dai_startup,
170 .hw_params = pcm512x_hw_params,
171 .set_fmt = pcm512x_set_fmt,
172 + .digital_mute = pcm512x_digital_mute,
173 .set_tdm_slot = pcm512x_set_tdm_slot,
174 };
175
176 @@ -1414,6 +1529,8 @@ int pcm512x_probe(struct device *dev, st
177 if (!pcm512x)
178 return -ENOMEM;
179
180 + mutex_init(&pcm512x->mutex);
181 +
182 dev_set_drvdata(dev, pcm512x);
183 pcm512x->regmap = regmap;
184
185 --- a/sound/soc/codecs/pcm512x.h
186 +++ b/sound/soc/codecs/pcm512x.h
187 @@ -112,7 +112,9 @@
188 #define PCM512x_RQST_SHIFT 4
189
190 /* Page 0, Register 3 - mute */
191 +#define PCM512x_RQMR (1 << 0)
192 #define PCM512x_RQMR_SHIFT 0
193 +#define PCM512x_RQML (1 << 4)
194 #define PCM512x_RQML_SHIFT 4
195
196 /* Page 0, Register 4 - PLL */