aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2014-11-03 13:33:03 -0500
committerMark Brown <broonie@kernel.org>2014-11-08 04:44:36 -0500
commitcf1f2ebe8d6176de80ef9d9c979f998ec38fb265 (patch)
tree83c19ea088ca0eca54b20dfb4fef3e42f445a6e6
parent65ba65f200b6f24b9a0638e3636ad6647259a26d (diff)
ASoC: wm9712/wm9713: Replace virtual registers with custom put/get callbacks
The wm9712/wm9713 has separate mixers for the left and the right channel, but the inputs to the mixers are enabled/disabled by the same control. Currently this is implemented by the driver by registering two virtual controls for each physical control, one for the left mixer and one for the right mixer. Using virtual registers will no longer work when the driver has been converted to regmap. This patch converts the driver to use controls with custom put/get callbacks instead which implement the logic making sure that the physical control is unmuted when either the left or the right control is unmuted. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/wm9712.c163
-rw-r--r--sound/soc/codecs/wm9713.c153
2 files changed, 194 insertions, 122 deletions
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index f3aab6e1d92a..3fad37e0d33d 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -23,6 +23,11 @@
23#include <sound/tlv.h> 23#include <sound/tlv.h>
24#include "wm9712.h" 24#include "wm9712.h"
25 25
26struct wm9712_priv {
27 unsigned int hp_mixer[2];
28 struct mutex lock;
29};
30
26static unsigned int ac97_read(struct snd_soc_codec *codec, 31static unsigned int ac97_read(struct snd_soc_codec *codec,
27 unsigned int reg); 32 unsigned int reg);
28static int ac97_write(struct snd_soc_codec *codec, 33static int ac97_write(struct snd_soc_codec *codec,
@@ -48,12 +53,10 @@ static const u16 wm9712_reg[] = {
48 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ 53 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */
49 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ 54 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */
50 0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */ 55 0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */
51 0x0000, 0x0000 /* virtual hp mixers */
52}; 56};
53 57
54/* virtual HP mixers regs */ 58#define HPL_MIXER 0x0
55#define HPL_MIXER 0x80 59#define HPR_MIXER 0x1
56#define HPR_MIXER 0x82
57 60
58static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"}; 61static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"};
59static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"}; 62static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"};
@@ -157,75 +160,108 @@ SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv),
157SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv), 160SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv),
158}; 161};
159 162
163static const unsigned int wm9712_mixer_mute_regs[] = {
164 AC97_VIDEO,
165 AC97_PCM,
166 AC97_LINE,
167 AC97_PHONE,
168 AC97_CD,
169 AC97_PC_BEEP,
170};
171
160/* We have to create a fake left and right HP mixers because 172/* We have to create a fake left and right HP mixers because
161 * the codec only has a single control that is shared by both channels. 173 * the codec only has a single control that is shared by both channels.
162 * This makes it impossible to determine the audio path. 174 * This makes it impossible to determine the audio path.
163 */ 175 */
164static int mixer_event(struct snd_soc_dapm_widget *w, 176static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
165 struct snd_kcontrol *k, int event) 177 struct snd_ctl_elem_value *ucontrol)
166{ 178{
167 u16 l, r, beep, line, phone, mic, pcm, aux; 179 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
168 180 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
169 l = ac97_read(w->codec, HPL_MIXER); 181 struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
170 r = ac97_read(w->codec, HPR_MIXER); 182 unsigned int val = ucontrol->value.enumerated.item[0];
171 beep = ac97_read(w->codec, AC97_PC_BEEP); 183 struct soc_mixer_control *mc =
172 mic = ac97_read(w->codec, AC97_VIDEO); 184 (struct soc_mixer_control *)kcontrol->private_value;
173 phone = ac97_read(w->codec, AC97_PHONE); 185 unsigned int mixer, mask, shift, old;
174 line = ac97_read(w->codec, AC97_LINE); 186 struct snd_soc_dapm_update update;
175 pcm = ac97_read(w->codec, AC97_PCM); 187 bool change;
176 aux = ac97_read(w->codec, AC97_CD); 188
177 189 mixer = mc->shift >> 8;
178 if (l & 0x1 || r & 0x1) 190 shift = mc->shift & 0xff;
179 ac97_write(w->codec, AC97_VIDEO, mic & 0x7fff); 191 mask = 1 << shift;
192
193 mutex_lock(&wm9712->lock);
194 old = wm9712->hp_mixer[mixer];
195 if (ucontrol->value.enumerated.item[0])
196 wm9712->hp_mixer[mixer] |= mask;
180 else 197 else
181 ac97_write(w->codec, AC97_VIDEO, mic | 0x8000); 198 wm9712->hp_mixer[mixer] &= ~mask;
199
200 change = old != wm9712->hp_mixer[mixer];
201 if (change) {
202 update.kcontrol = kcontrol;
203 update.reg = wm9712_mixer_mute_regs[shift];
204 update.mask = 0x8000;
205 if ((wm9712->hp_mixer[0] & mask) ||
206 (wm9712->hp_mixer[1] & mask))
207 update.val = 0x0;
208 else
209 update.val = 0x8000;
210
211 snd_soc_dapm_mixer_update_power(dapm, kcontrol, val,
212 &update);
213 }
182 214
183 if (l & 0x2 || r & 0x2) 215 mutex_unlock(&wm9712->lock);
184 ac97_write(w->codec, AC97_PCM, pcm & 0x7fff);
185 else
186 ac97_write(w->codec, AC97_PCM, pcm | 0x8000);
187 216
188 if (l & 0x4 || r & 0x4) 217 return change;
189 ac97_write(w->codec, AC97_LINE, line & 0x7fff); 218}
190 else
191 ac97_write(w->codec, AC97_LINE, line | 0x8000);
192 219
193 if (l & 0x8 || r & 0x8) 220static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
194 ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); 221 struct snd_ctl_elem_value *ucontrol)
195 else 222{
196 ac97_write(w->codec, AC97_PHONE, phone | 0x8000); 223 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
224 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
225 struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
226 struct soc_mixer_control *mc =
227 (struct soc_mixer_control *)kcontrol->private_value;
228 unsigned int shift, mixer;
197 229
198 if (l & 0x10 || r & 0x10) 230 mixer = mc->shift >> 8;
199 ac97_write(w->codec, AC97_CD, aux & 0x7fff); 231 shift = mc->shift & 0xff;
200 else
201 ac97_write(w->codec, AC97_CD, aux | 0x8000);
202 232
203 if (l & 0x20 || r & 0x20) 233 ucontrol->value.enumerated.item[0] =
204 ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); 234 (wm9712->hp_mixer[mixer] >> shift) & 1;
205 else
206 ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000);
207 235
208 return 0; 236 return 0;
209} 237}
210 238
239#define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) { \
240 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
241 .info = snd_soc_info_volsw, \
242 .get = wm9712_hp_mixer_get, .put = wm9712_hp_mixer_put, \
243 .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, \
244 (xmixer << 8) | xshift, 1, 0, 0) \
245}
246
211/* Left Headphone Mixers */ 247/* Left Headphone Mixers */
212static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = { 248static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = {
213 SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPL_MIXER, 5, 1, 0), 249 WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPL_MIXER, 5),
214 SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 4, 1, 0), 250 WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 4),
215 SOC_DAPM_SINGLE("Phone Bypass Switch", HPL_MIXER, 3, 1, 0), 251 WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPL_MIXER, 3),
216 SOC_DAPM_SINGLE("Line Bypass Switch", HPL_MIXER, 2, 1, 0), 252 WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPL_MIXER, 2),
217 SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0), 253 WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 1),
218 SOC_DAPM_SINGLE("Mic Sidetone Switch", HPL_MIXER, 0, 1, 0), 254 WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPL_MIXER, 0),
219}; 255};
220 256
221/* Right Headphone Mixers */ 257/* Right Headphone Mixers */
222static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = { 258static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = {
223 SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPR_MIXER, 5, 1, 0), 259 WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPR_MIXER, 5),
224 SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 4, 1, 0), 260 WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 4),
225 SOC_DAPM_SINGLE("Phone Bypass Switch", HPR_MIXER, 3, 1, 0), 261 WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPR_MIXER, 3),
226 SOC_DAPM_SINGLE("Line Bypass Switch", HPR_MIXER, 2, 1, 0), 262 WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPR_MIXER, 2),
227 SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0), 263 WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 1),
228 SOC_DAPM_SINGLE("Mic Sidetone Switch", HPR_MIXER, 0, 1, 0), 264 WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPR_MIXER, 0),
229}; 265};
230 266
231/* Speaker Mixer */ 267/* Speaker Mixer */
@@ -299,12 +335,10 @@ SND_SOC_DAPM_MUX("Right Mic Select Source", SND_SOC_NOPM, 0, 0,
299SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0, 335SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0,
300 &wm9712_diff_sel_controls), 336 &wm9712_diff_sel_controls),
301SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), 337SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
302SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_INT_PAGING, 9, 1, 338SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_INT_PAGING, 9, 1,
303 &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls), 339 &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls)),
304 mixer_event, SND_SOC_DAPM_POST_REG), 340SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_INT_PAGING, 8, 1,
305SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_INT_PAGING, 8, 1, 341 &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls)),
306 &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls),
307 mixer_event, SND_SOC_DAPM_POST_REG),
308SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1, 342SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1,
309 &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)), 343 &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)),
310SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1, 344SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1,
@@ -471,8 +505,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
471{ 505{
472 u16 *cache = codec->reg_cache; 506 u16 *cache = codec->reg_cache;
473 507
474 if (reg < 0x7c) 508 soc_ac97_ops->write(codec->ac97, reg, val);
475 soc_ac97_ops->write(codec->ac97, reg, val);
476 reg = reg >> 1; 509 reg = reg >> 1;
477 if (reg < (ARRAY_SIZE(wm9712_reg))) 510 if (reg < (ARRAY_SIZE(wm9712_reg)))
478 cache[reg] = val; 511 cache[reg] = val;
@@ -684,6 +717,16 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
684 717
685static int wm9712_probe(struct platform_device *pdev) 718static int wm9712_probe(struct platform_device *pdev)
686{ 719{
720 struct wm9712_priv *wm9712;
721
722 wm9712 = devm_kzalloc(&pdev->dev, sizeof(*wm9712), GFP_KERNEL);
723 if (wm9712 == NULL)
724 return -ENOMEM;
725
726 mutex_init(&wm9712->lock);
727
728 platform_set_drvdata(pdev, wm9712);
729
687 return snd_soc_register_codec(&pdev->dev, 730 return snd_soc_register_codec(&pdev->dev,
688 &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai)); 731 &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai));
689} 732}
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index ac13fc8f5c70..998e4c7b6b12 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -31,6 +31,8 @@
31 31
32struct wm9713_priv { 32struct wm9713_priv {
33 u32 pll_in; /* PLL input frequency */ 33 u32 pll_in; /* PLL input frequency */
34 unsigned int hp_mixer[2];
35 struct mutex lock;
34}; 36};
35 37
36static unsigned int ac97_read(struct snd_soc_codec *codec, 38static unsigned int ac97_read(struct snd_soc_codec *codec,
@@ -59,12 +61,10 @@ static const u16 wm9713_reg[] = {
59 0x0000, 0x0000, 0x0000, 0x0000, 61 0x0000, 0x0000, 0x0000, 0x0000,
60 0x0000, 0x0000, 0x0000, 0x0006, 62 0x0000, 0x0000, 0x0000, 0x0006,
61 0x0001, 0x0000, 0x574d, 0x4c13, 63 0x0001, 0x0000, 0x574d, 0x4c13,
62 0x0000, 0x0000
63}; 64};
64 65
65/* virtual HP mixers regs */ 66#define HPL_MIXER 0
66#define HPL_MIXER 0x80 67#define HPR_MIXER 1
67#define HPR_MIXER 0x82
68 68
69static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"}; 69static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"};
70static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"}; 70static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"};
@@ -233,6 +233,14 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
233 return 0; 233 return 0;
234} 234}
235 235
236static const unsigned int wm9713_mixer_mute_regs[] = {
237 AC97_PC_BEEP,
238 AC97_MASTER_TONE,
239 AC97_PHONE,
240 AC97_REC_SEL,
241 AC97_PCM,
242 AC97_AUX,
243};
236 244
237/* We have to create a fake left and right HP mixers because 245/* We have to create a fake left and right HP mixers because
238 * the codec only has a single control that is shared by both channels. 246 * the codec only has a single control that is shared by both channels.
@@ -240,73 +248,95 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
240 * register map, thus we add a new (virtual) register to help determine the 248 * register map, thus we add a new (virtual) register to help determine the
241 * audio route within the device. 249 * audio route within the device.
242 */ 250 */
243static int mixer_event(struct snd_soc_dapm_widget *w, 251static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
244 struct snd_kcontrol *kcontrol, int event) 252 struct snd_ctl_elem_value *ucontrol)
245{ 253{
246 u16 l, r, beep, tone, phone, rec, pcm, aux; 254 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
247 255 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
248 l = ac97_read(w->codec, HPL_MIXER); 256 struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
249 r = ac97_read(w->codec, HPR_MIXER); 257 unsigned int val = ucontrol->value.enumerated.item[0];
250 beep = ac97_read(w->codec, AC97_PC_BEEP); 258 struct soc_mixer_control *mc =
251 tone = ac97_read(w->codec, AC97_MASTER_TONE); 259 (struct soc_mixer_control *)kcontrol->private_value;
252 phone = ac97_read(w->codec, AC97_PHONE); 260 unsigned int mixer, mask, shift, old;
253 rec = ac97_read(w->codec, AC97_REC_SEL); 261 struct snd_soc_dapm_update update;
254 pcm = ac97_read(w->codec, AC97_PCM); 262 bool change;
255 aux = ac97_read(w->codec, AC97_AUX); 263
256 264 mixer = mc->shift >> 8;
257 if (event & SND_SOC_DAPM_PRE_REG) 265 shift = mc->shift & 0xff;
258 return 0; 266 mask = (1 << shift);
259 if ((l & 0x1) || (r & 0x1)) 267
260 ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); 268 mutex_lock(&wm9713->lock);
269 old = wm9713->hp_mixer[mixer];
270 if (ucontrol->value.enumerated.item[0])
271 wm9713->hp_mixer[mixer] |= mask;
261 else 272 else
262 ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000); 273 wm9713->hp_mixer[mixer] &= ~mask;
274
275 change = old != wm9713->hp_mixer[mixer];
276 if (change) {
277 update.kcontrol = kcontrol;
278 update.reg = wm9713_mixer_mute_regs[shift];
279 update.mask = 0x8000;
280 if ((wm9713->hp_mixer[0] & mask) ||
281 (wm9713->hp_mixer[1] & mask))
282 update.val = 0x0;
283 else
284 update.val = 0x8000;
285
286 snd_soc_dapm_mixer_update_power(dapm, kcontrol, val,
287 &update);
288 }
263 289
264 if ((l & 0x2) || (r & 0x2)) 290 mutex_unlock(&wm9713->lock);
265 ac97_write(w->codec, AC97_MASTER_TONE, tone & 0x7fff);
266 else
267 ac97_write(w->codec, AC97_MASTER_TONE, tone | 0x8000);
268 291
269 if ((l & 0x4) || (r & 0x4)) 292 return change;
270 ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); 293}
271 else
272 ac97_write(w->codec, AC97_PHONE, phone | 0x8000);
273 294
274 if ((l & 0x8) || (r & 0x8)) 295static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol,
275 ac97_write(w->codec, AC97_REC_SEL, rec & 0x7fff); 296 struct snd_ctl_elem_value *ucontrol)
276 else 297{
277 ac97_write(w->codec, AC97_REC_SEL, rec | 0x8000); 298 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
299 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
300 struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
301 struct soc_mixer_control *mc =
302 (struct soc_mixer_control *)kcontrol->private_value;
303 unsigned int mixer, shift;
278 304
279 if ((l & 0x10) || (r & 0x10)) 305 mixer = mc->shift >> 8;
280 ac97_write(w->codec, AC97_PCM, pcm & 0x7fff); 306 shift = mc->shift & 0xff;
281 else
282 ac97_write(w->codec, AC97_PCM, pcm | 0x8000);
283 307
284 if ((l & 0x20) || (r & 0x20)) 308 ucontrol->value.enumerated.item[0] =
285 ac97_write(w->codec, AC97_AUX, aux & 0x7fff); 309 (wm9713->hp_mixer[mixer] >> shift) & 1;
286 else
287 ac97_write(w->codec, AC97_AUX, aux | 0x8000);
288 310
289 return 0; 311 return 0;
290} 312}
291 313
314#define WM9713_HP_MIXER_CTRL(xname, xmixer, xshift) { \
315 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
316 .info = snd_soc_info_volsw, \
317 .get = wm9713_hp_mixer_get, .put = wm9713_hp_mixer_put, \
318 .private_value = SOC_DOUBLE_VALUE(SND_SOC_NOPM, \
319 xshift, xmixer, 1, 0, 0) \
320}
321
292/* Left Headphone Mixers */ 322/* Left Headphone Mixers */
293static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = { 323static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = {
294SOC_DAPM_SINGLE("Beep Playback Switch", HPL_MIXER, 5, 1, 0), 324WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPL_MIXER, 5),
295SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 4, 1, 0), 325WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPL_MIXER, 4),
296SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 3, 1, 0), 326WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 3),
297SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 2, 1, 0), 327WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 2),
298SOC_DAPM_SINGLE("MonoIn Playback Switch", HPL_MIXER, 1, 1, 0), 328WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPL_MIXER, 1),
299SOC_DAPM_SINGLE("Bypass Playback Switch", HPL_MIXER, 0, 1, 0), 329WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPL_MIXER, 0),
300}; 330};
301 331
302/* Right Headphone Mixers */ 332/* Right Headphone Mixers */
303static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = { 333static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = {
304SOC_DAPM_SINGLE("Beep Playback Switch", HPR_MIXER, 5, 1, 0), 334WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPR_MIXER, 5),
305SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 4, 1, 0), 335WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPR_MIXER, 4),
306SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 3, 1, 0), 336WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 3),
307SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 2, 1, 0), 337WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 2),
308SOC_DAPM_SINGLE("MonoIn Playback Switch", HPR_MIXER, 1, 1, 0), 338WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPR_MIXER, 1),
309SOC_DAPM_SINGLE("Bypass Playback Switch", HPR_MIXER, 0, 1, 0), 339WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPR_MIXER, 0),
310}; 340};
311 341
312/* headphone capture mux */ 342/* headphone capture mux */
@@ -428,12 +458,10 @@ SND_SOC_DAPM_MUX("Mic A Source", SND_SOC_NOPM, 0, 0,
428 &wm9713_mic_sel_mux_controls), 458 &wm9713_mic_sel_mux_controls),
429SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0, 459SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0,
430 &wm9713_micb_sel_mux_controls), 460 &wm9713_micb_sel_mux_controls),
431SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_EXTENDED_MID, 3, 1, 461SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_EXTENDED_MID, 3, 1,
432 &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls), 462 &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls)),
433 mixer_event, SND_SOC_DAPM_POST_REG), 463SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_EXTENDED_MID, 2, 1,
434SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_EXTENDED_MID, 2, 1, 464 &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls)),
435 &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls),
436 mixer_event, SND_SOC_DAPM_POST_REG),
437SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1, 465SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1,
438 &wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)), 466 &wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)),
439SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1, 467SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1,
@@ -666,8 +694,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
666 unsigned int val) 694 unsigned int val)
667{ 695{
668 u16 *cache = codec->reg_cache; 696 u16 *cache = codec->reg_cache;
669 if (reg < 0x7c) 697 soc_ac97_ops->write(codec->ac97, reg, val);
670 soc_ac97_ops->write(codec->ac97, reg, val);
671 reg = reg >> 1; 698 reg = reg >> 1;
672 if (reg < (ARRAY_SIZE(wm9713_reg))) 699 if (reg < (ARRAY_SIZE(wm9713_reg)))
673 cache[reg] = val; 700 cache[reg] = val;
@@ -1251,6 +1278,8 @@ static int wm9713_probe(struct platform_device *pdev)
1251 if (wm9713 == NULL) 1278 if (wm9713 == NULL)
1252 return -ENOMEM; 1279 return -ENOMEM;
1253 1280
1281 mutex_init(&wm9713->lock);
1282
1254 platform_set_drvdata(pdev, wm9713); 1283 platform_set_drvdata(pdev, wm9713);
1255 1284
1256 return snd_soc_register_codec(&pdev->dev, 1285 return snd_soc_register_codec(&pdev->dev,