14 #include <linux/slab.h>
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/device.h>
29 unsigned int reg,
unsigned int val);
34 static const u16 wm9712_reg[] = {
35 0x6174, 0x8000, 0x8000, 0x8000,
36 0x0f0f, 0xaaa0, 0xc008, 0x6808,
37 0xe808, 0xaaa0, 0xad00, 0x8000,
38 0xe808, 0x3000, 0x8000, 0x0000,
39 0x0000, 0x0000, 0x0000, 0x000f,
40 0x0405, 0x0410, 0xbb80, 0xbb80,
41 0x0000, 0xbb80, 0x0000, 0x0000,
42 0x0000, 0x2000, 0x0000, 0x0000,
43 0x0000, 0x0000, 0x0000, 0x0000,
44 0x0000, 0x0000, 0xf83e, 0xffff,
45 0x0000, 0x0000, 0x0000, 0xf83e,
46 0x0008, 0x0000, 0x0000, 0x0000,
47 0xb032, 0x3e00, 0x0000, 0x0000,
48 0x0000, 0x0000, 0x0000, 0x0000,
49 0x0000, 0x0000, 0x0000, 0x0006,
50 0x0001, 0x0000, 0x574d, 0x4c12,
55 #define HPL_MIXER 0x80
56 #define HPR_MIXER 0x82
58 static const char *wm9712_alc_select[] = {
"None",
"Left",
"Right",
"Stereo"};
59 static const char *wm9712_alc_mux[] = {
"Stereo",
"Left",
"Right",
"None"};
60 static const char *wm9712_out3_src[] = {
"Left",
"VREF",
"Left + Right",
62 static const char *wm9712_spk_src[] = {
"Speaker Mix",
"Headphone Mix"};
63 static const char *wm9712_rec_adc[] = {
"Stereo",
"Left",
"Right",
"Mute"};
64 static const char *wm9712_base[] = {
"Linear Control",
"Adaptive Boost"};
65 static const char *wm9712_rec_gain[] = {
"+1.5dB Steps",
"+0.75dB Steps"};
66 static const char *wm9712_mic[] = {
"Mic 1",
"Differential",
"Mic 2",
68 static const char *wm9712_rec_sel[] = {
"Mic",
"NC",
"NC",
"Speaker Mixer",
69 "Line",
"Headphone Mixer",
"Phone Mixer",
"Phone"};
70 static const char *wm9712_ng_type[] = {
"Constant Gain",
"Mute"};
71 static const char *wm9712_diff_sel[] = {
"Mic",
"Line"};
76 static const struct soc_enum wm9712_enum[] = {
109 SOC_ENUM(
"ALC Function", wm9712_enum[0]),
114 SOC_ENUM(
"ALC NG Type", wm9712_enum[10]),
143 SOC_ENUM(
"Bass Control", wm9712_enum[5]),
151 SOC_ENUM(
"Capture Volume Steps", wm9712_enum[6]),
178 if (l & 0x1 || r & 0x1)
183 if (l & 0x2 || r & 0x2)
188 if (l & 0x4 || r & 0x4)
193 if (l & 0x8 || r & 0x8)
198 if (l & 0x10 || r & 0x10)
203 if (l & 0x20 || r & 0x20)
284 &wm9712_alc_mux_controls),
286 &wm9712_out3_mux_controls),
288 &wm9712_spk_mux_controls),
290 &wm9712_capture_phone_mux_controls),
292 &wm9712_capture_selectl_controls),
294 &wm9712_capture_selectr_controls),
296 &wm9712_mic_src_controls),
298 &wm9712_mic_src_controls),
300 &wm9712_diff_sel_controls),
303 &wm9712_hpl_mixer_controls[0],
ARRAY_SIZE(wm9712_hpl_mixer_controls),
306 &wm9712_hpr_mixer_controls[0],
ARRAY_SIZE(wm9712_hpr_mixer_controls),
309 &wm9712_phone_mixer_controls[0],
ARRAY_SIZE(wm9712_phone_mixer_controls)),
311 &wm9712_speaker_mixer_controls[0],
343 {
"AC97 Mixer",
NULL,
"Left DAC"},
344 {
"AC97 Mixer",
NULL,
"Right DAC"},
347 {
"Left HP Mixer",
"PCBeep Bypass Switch",
"PCBEEP"},
348 {
"Left HP Mixer",
"Aux Playback Switch",
"Aux DAC"},
349 {
"Left HP Mixer",
"Phone Bypass Switch",
"Phone PGA"},
350 {
"Left HP Mixer",
"Line Bypass Switch",
"Line PGA"},
351 {
"Left HP Mixer",
"PCM Playback Switch",
"Left DAC"},
352 {
"Left HP Mixer",
"Mic Sidetone Switch",
"Mic PGA"},
353 {
"Left HP Mixer",
NULL,
"ALC Sidetone Mux"},
356 {
"Right HP Mixer",
"PCBeep Bypass Switch",
"PCBEEP"},
357 {
"Right HP Mixer",
"Aux Playback Switch",
"Aux DAC"},
358 {
"Right HP Mixer",
"Phone Bypass Switch",
"Phone PGA"},
359 {
"Right HP Mixer",
"Line Bypass Switch",
"Line PGA"},
360 {
"Right HP Mixer",
"PCM Playback Switch",
"Right DAC"},
361 {
"Right HP Mixer",
"Mic Sidetone Switch",
"Mic PGA"},
362 {
"Right HP Mixer",
NULL,
"ALC Sidetone Mux"},
365 {
"Speaker Mixer",
"PCBeep Bypass Switch",
"PCBEEP"},
366 {
"Speaker Mixer",
"Line Bypass Switch",
"Line PGA"},
367 {
"Speaker Mixer",
"PCM Playback Switch",
"AC97 Mixer"},
368 {
"Speaker Mixer",
"Phone Bypass Switch",
"Phone PGA"},
369 {
"Speaker Mixer",
"Aux Playback Switch",
"Aux DAC"},
372 {
"Phone Mixer",
"PCBeep Bypass Switch",
"PCBEEP"},
373 {
"Phone Mixer",
"Line Bypass Switch",
"Line PGA"},
374 {
"Phone Mixer",
"Aux Playback Switch",
"Aux DAC"},
375 {
"Phone Mixer",
"PCM Playback Switch",
"AC97 Mixer"},
376 {
"Phone Mixer",
"Mic 1 Sidetone Switch",
"Mic PGA"},
377 {
"Phone Mixer",
"Mic 2 Sidetone Switch",
"Mic PGA"},
380 {
"Line PGA",
NULL,
"LINEINL"},
381 {
"Line PGA",
NULL,
"LINEINR"},
382 {
"Phone PGA",
NULL,
"PHONE"},
383 {
"Mic PGA",
NULL,
"MIC1"},
384 {
"Mic PGA",
NULL,
"MIC2"},
387 {
"Differential Mic",
NULL,
"MIC1"},
388 {
"Differential Mic",
NULL,
"MIC2"},
389 {
"Left Mic Select Source",
"Mic 1",
"MIC1"},
390 {
"Left Mic Select Source",
"Mic 2",
"MIC2"},
391 {
"Left Mic Select Source",
"Stereo",
"MIC1"},
392 {
"Left Mic Select Source",
"Differential",
"Differential Mic"},
393 {
"Right Mic Select Source",
"Mic 1",
"MIC1"},
394 {
"Right Mic Select Source",
"Mic 2",
"MIC2"},
395 {
"Right Mic Select Source",
"Stereo",
"MIC2"},
396 {
"Right Mic Select Source",
"Differential",
"Differential Mic"},
399 {
"Left Capture Select",
"Mic",
"MIC1"},
400 {
"Left Capture Select",
"Speaker Mixer",
"Speaker Mixer"},
401 {
"Left Capture Select",
"Line",
"LINEINL"},
402 {
"Left Capture Select",
"Headphone Mixer",
"Left HP Mixer"},
403 {
"Left Capture Select",
"Phone Mixer",
"Phone Mixer"},
404 {
"Left Capture Select",
"Phone",
"PHONE"},
407 {
"Right Capture Select",
"Mic",
"MIC2"},
408 {
"Right Capture Select",
"Speaker Mixer",
"Speaker Mixer"},
409 {
"Right Capture Select",
"Line",
"LINEINR"},
410 {
"Right Capture Select",
"Headphone Mixer",
"Right HP Mixer"},
411 {
"Right Capture Select",
"Phone Mixer",
"Phone Mixer"},
412 {
"Right Capture Select",
"Phone",
"PHONE"},
415 {
"ALC Sidetone Mux",
"Stereo",
"Left Capture Select"},
416 {
"ALC Sidetone Mux",
"Stereo",
"Right Capture Select"},
417 {
"ALC Sidetone Mux",
"Left",
"Left Capture Select"},
418 {
"ALC Sidetone Mux",
"Right",
"Right Capture Select"},
421 {
"Left ADC",
NULL,
"Left Capture Select"},
422 {
"Right ADC",
NULL,
"Right Capture Select"},
425 {
"MONOOUT",
NULL,
"Phone Mixer"},
426 {
"HPOUTL",
NULL,
"Headphone PGA"},
427 {
"Headphone PGA",
NULL,
"Left HP Mixer"},
428 {
"HPOUTR",
NULL,
"Headphone PGA"},
429 {
"Headphone PGA",
NULL,
"Right HP Mixer"},
432 {
"Mono Mixer",
NULL,
"Left HP Mixer"},
433 {
"Mono Mixer",
NULL,
"Right HP Mixer"},
436 {
"Out3 Mux",
"Left",
"Left HP Mixer"},
437 {
"Out3 Mux",
"Mono",
"Phone Mixer"},
438 {
"Out3 Mux",
"Left + Right",
"Mono Mixer"},
439 {
"Out 3 PGA",
NULL,
"Out3 Mux"},
440 {
"OUT3",
NULL,
"Out 3 PGA"},
443 {
"Speaker Mux",
"Speaker Mix",
"Speaker Mixer"},
444 {
"Speaker Mux",
"Headphone Mix",
"Mono Mixer"},
445 {
"Speaker PGA",
NULL,
"Speaker Mux"},
446 {
"LOUT2",
NULL,
"Speaker PGA"},
447 {
"ROUT2",
NULL,
"Speaker PGA"},
469 static int ac97_write(
struct snd_soc_codec *codec,
unsigned int reg,
499 return ac97_write(codec, reg, runtime->
rate);
520 #define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
521 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
522 SNDRV_PCM_RATE_48000)
525 .prepare = ac97_prepare,
529 .prepare = ac97_aux_prepare,
534 .name =
"wm9712-hifi",
537 .stream_name =
"HiFi Playback",
543 .stream_name =
"HiFi Capture",
548 .ops = &wm9712_dai_ops_hifi,
551 .name =
"wm9712-aux",
553 .stream_name =
"Aux Playback",
558 .ops = &wm9712_dai_ops_aux,
562 static int wm9712_set_bias_level(
struct snd_soc_codec *codec,
582 static int wm9712_reset(
struct snd_soc_codec *codec,
int try_warm)
586 if (ac97_read(codec, 0) == wm9712_reg[0])
593 if (ac97_read(codec, 0) != wm9712_reg[0])
613 ret = wm9712_reset(codec, 1);
623 for (i = 2; i <
ARRAY_SIZE(wm9712_reg) << 1; i += 2) {
625 (i > 0x58 && i != 0x5c))
644 ret = wm9712_reset(codec, 0);
671 .probe = wm9712_soc_probe,
672 .remove = wm9712_soc_remove,
673 .suspend = wm9712_soc_suspend,
674 .resume = wm9712_soc_resume,
677 .set_bias_level = wm9712_set_bias_level,
679 .reg_word_size =
sizeof(
u16),
684 .dapm_routes = wm9712_audio_map,
685 .num_dapm_routes =
ARRAY_SIZE(wm9712_audio_map),
691 &soc_codec_dev_wm9712, wm9712_dai,
ARRAY_SIZE(wm9712_dai));
702 .name =
"wm9712-codec",
706 .probe = wm9712_probe,