]> git.ipfire.org Git - thirdparty/linux.git/blame - sound/pci/hda/patch_analog.c
ALSA: hda - proc - add support for dynamic controls to mixer<->NID mapping
[thirdparty/linux.git] / sound / pci / hda / patch_analog.c
CommitLineData
1da177e4 1/*
0ac8551e
TI
2 * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
3 * AD1986A, AD1988
1da177e4 4 *
2bac647c 5 * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
1da177e4
LT
6 *
7 * This driver is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This driver is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
1da177e4
LT
22#include <linux/init.h>
23#include <linux/delay.h>
24#include <linux/slab.h>
25#include <linux/pci.h>
62932df8 26
1da177e4
LT
27#include <sound/core.h>
28#include "hda_codec.h"
29#include "hda_local.h"
c5a4bcd0 30#include "hda_beep.h"
1da177e4 31
4a3fdf3d 32struct ad198x_spec {
c8b6bf9b 33 struct snd_kcontrol_new *mixers[5];
985be54b 34 int num_mixers;
c5a4bcd0 35 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
d32410b1 36 const struct hda_verb *init_verbs[5]; /* initialization verbs
985be54b
TI
37 * don't forget NULL termination!
38 */
39 unsigned int num_init_verbs;
40
41 /* playback */
42 struct hda_multi_out multiout; /* playback set-up
43 * max_channels, dacs must be set
44 * dig_out_nid and hp_nid are optional
45 */
fd66e0d0 46 unsigned int cur_eapd;
2125cad2 47 unsigned int need_dac_fix;
985be54b
TI
48
49 /* capture */
50 unsigned int num_adc_nids;
51 hda_nid_t *adc_nids;
52 hda_nid_t dig_in_nid; /* digital-in NID; optional */
53
54 /* capture source */
4a3fdf3d 55 const struct hda_input_mux *input_mux;
2e5b9567 56 hda_nid_t *capsrc_nids;
985be54b
TI
57 unsigned int cur_mux[3];
58
59 /* channel model */
d2a6d7dc 60 const struct hda_channel_mode *channel_mode;
985be54b
TI
61 int num_channel_mode;
62
63 /* PCM information */
2bac647c 64 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
985be54b 65
4a3fdf3d 66 unsigned int spdif_route;
d32410b1
TI
67
68 /* dynamic controls, init_verbs and input_mux */
69 struct auto_pin_cfg autocfg;
603c4019 70 struct snd_array kctls;
d32410b1 71 struct hda_input_mux private_imux;
41923e44 72 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
cb53c626 73
8ab78c74 74 unsigned int jack_present :1;
03c405ad 75 unsigned int inv_jack_detect:1;
8ab78c74 76
cb53c626
TI
77#ifdef CONFIG_SND_HDA_POWER_SAVE
78 struct hda_loopback_check loopback;
79#endif
2134ea4f
TI
80 /* for virtual master */
81 hda_nid_t vmaster_nid;
2134ea4f
TI
82 const char **slave_vols;
83 const char **slave_sws;
1da177e4
LT
84};
85
4a3fdf3d
TI
86/*
87 * input MUX handling (common part)
88 */
c8b6bf9b 89static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
4a3fdf3d
TI
90{
91 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
92 struct ad198x_spec *spec = codec->spec;
93
94 return snd_hda_input_mux_info(spec->input_mux, uinfo);
95}
96
c8b6bf9b 97static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4a3fdf3d
TI
98{
99 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
100 struct ad198x_spec *spec = codec->spec;
985be54b 101 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
4a3fdf3d 102
985be54b 103 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
4a3fdf3d
TI
104 return 0;
105}
106
c8b6bf9b 107static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4a3fdf3d
TI
108{
109 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
110 struct ad198x_spec *spec = codec->spec;
985be54b 111 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
4a3fdf3d
TI
112
113 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
2e5b9567
TI
114 spec->capsrc_nids[adc_idx],
115 &spec->cur_mux[adc_idx]);
4a3fdf3d
TI
116}
117
118/*
119 * initialization (common callbacks)
120 */
121static int ad198x_init(struct hda_codec *codec)
122{
123 struct ad198x_spec *spec = codec->spec;
985be54b
TI
124 int i;
125
126 for (i = 0; i < spec->num_init_verbs; i++)
127 snd_hda_sequence_write(codec, spec->init_verbs[i]);
4a3fdf3d
TI
128 return 0;
129}
130
2134ea4f
TI
131static const char *ad_slave_vols[] = {
132 "Front Playback Volume",
133 "Surround Playback Volume",
134 "Center Playback Volume",
135 "LFE Playback Volume",
136 "Side Playback Volume",
137 "Headphone Playback Volume",
138 "Mono Playback Volume",
628ed133 139 "Speaker Playback Volume",
4806ef0c 140 "IEC958 Playback Volume",
2134ea4f
TI
141 NULL
142};
143
144static const char *ad_slave_sws[] = {
145 "Front Playback Switch",
146 "Surround Playback Switch",
147 "Center Playback Switch",
148 "LFE Playback Switch",
149 "Side Playback Switch",
150 "Headphone Playback Switch",
151 "Mono Playback Switch",
628ed133 152 "Speaker Playback Switch",
4806ef0c 153 "IEC958 Playback Switch",
2134ea4f
TI
154 NULL
155};
156
603c4019
TI
157static void ad198x_free_kctls(struct hda_codec *codec);
158
c5a4bcd0
TI
159/* additional beep mixers; the actual parameters are overwritten at build */
160static struct snd_kcontrol_new ad_beep_mixer[] = {
161 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
123c07ae 162 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
c5a4bcd0
TI
163 { } /* end */
164};
165
166#define set_beep_amp(spec, nid, idx, dir) \
167 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
168
4a3fdf3d
TI
169static int ad198x_build_controls(struct hda_codec *codec)
170{
171 struct ad198x_spec *spec = codec->spec;
985be54b 172 unsigned int i;
4a3fdf3d
TI
173 int err;
174
985be54b
TI
175 for (i = 0; i < spec->num_mixers; i++) {
176 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
177 if (err < 0)
178 return err;
179 }
180 if (spec->multiout.dig_out_nid) {
4a3fdf3d 181 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
985be54b
TI
182 if (err < 0)
183 return err;
9a08160b
TI
184 err = snd_hda_create_spdif_share_sw(codec,
185 &spec->multiout);
186 if (err < 0)
187 return err;
188 spec->multiout.share_spdif = 1;
985be54b
TI
189 }
190 if (spec->dig_in_nid) {
191 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
192 if (err < 0)
193 return err;
194 }
2134ea4f 195
c5a4bcd0
TI
196 /* create beep controls if needed */
197 if (spec->beep_amp) {
198 struct snd_kcontrol_new *knew;
199 for (knew = ad_beep_mixer; knew->name; knew++) {
200 struct snd_kcontrol *kctl;
201 kctl = snd_ctl_new1(knew, codec);
202 if (!kctl)
203 return -ENOMEM;
204 kctl->private_value = spec->beep_amp;
3911a4c1
JK
205 err = snd_hda_ctl_add(codec,
206 get_amp_nid_(spec->beep_amp),
207 kctl);
c5a4bcd0
TI
208 if (err < 0)
209 return err;
210 }
211 }
212
2134ea4f
TI
213 /* if we have no master control, let's create it */
214 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
1c82ed1b 215 unsigned int vmaster_tlv[4];
2134ea4f 216 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
1c82ed1b 217 HDA_OUTPUT, vmaster_tlv);
2134ea4f 218 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
1c82ed1b 219 vmaster_tlv,
2134ea4f
TI
220 (spec->slave_vols ?
221 spec->slave_vols : ad_slave_vols));
222 if (err < 0)
223 return err;
224 }
225 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
226 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
227 NULL,
228 (spec->slave_sws ?
229 spec->slave_sws : ad_slave_sws));
230 if (err < 0)
231 return err;
232 }
233
603c4019 234 ad198x_free_kctls(codec); /* no longer needed */
4a3fdf3d
TI
235 return 0;
236}
237
cb53c626
TI
238#ifdef CONFIG_SND_HDA_POWER_SAVE
239static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
240{
241 struct ad198x_spec *spec = codec->spec;
242 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
243}
244#endif
245
4a3fdf3d
TI
246/*
247 * Analog playback callbacks
248 */
249static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
250 struct hda_codec *codec,
c8b6bf9b 251 struct snd_pcm_substream *substream)
4a3fdf3d
TI
252{
253 struct ad198x_spec *spec = codec->spec;
9a08160b
TI
254 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
255 hinfo);
4a3fdf3d
TI
256}
257
258static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
259 struct hda_codec *codec,
260 unsigned int stream_tag,
261 unsigned int format,
c8b6bf9b 262 struct snd_pcm_substream *substream)
4a3fdf3d
TI
263{
264 struct ad198x_spec *spec = codec->spec;
265 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
266 format, substream);
267}
268
269static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
270 struct hda_codec *codec,
c8b6bf9b 271 struct snd_pcm_substream *substream)
4a3fdf3d
TI
272{
273 struct ad198x_spec *spec = codec->spec;
274 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
275}
276
277/*
278 * Digital out
279 */
280static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
281 struct hda_codec *codec,
c8b6bf9b 282 struct snd_pcm_substream *substream)
4a3fdf3d
TI
283{
284 struct ad198x_spec *spec = codec->spec;
285 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
286}
287
288static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
289 struct hda_codec *codec,
c8b6bf9b 290 struct snd_pcm_substream *substream)
4a3fdf3d
TI
291{
292 struct ad198x_spec *spec = codec->spec;
293 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
294}
295
6b97eb45
TI
296static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
297 struct hda_codec *codec,
298 unsigned int stream_tag,
299 unsigned int format,
300 struct snd_pcm_substream *substream)
301{
302 struct ad198x_spec *spec = codec->spec;
303 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
304 format, substream);
305}
306
9411e21c
TI
307static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
308 struct hda_codec *codec,
309 struct snd_pcm_substream *substream)
310{
311 struct ad198x_spec *spec = codec->spec;
312 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
313}
314
4a3fdf3d
TI
315/*
316 * Analog capture
317 */
318static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
319 struct hda_codec *codec,
320 unsigned int stream_tag,
321 unsigned int format,
c8b6bf9b 322 struct snd_pcm_substream *substream)
4a3fdf3d
TI
323{
324 struct ad198x_spec *spec = codec->spec;
985be54b
TI
325 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
326 stream_tag, 0, format);
4a3fdf3d
TI
327 return 0;
328}
329
330static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
331 struct hda_codec *codec,
c8b6bf9b 332 struct snd_pcm_substream *substream)
4a3fdf3d
TI
333{
334 struct ad198x_spec *spec = codec->spec;
888afa15 335 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
4a3fdf3d
TI
336 return 0;
337}
338
339
340/*
341 */
342static struct hda_pcm_stream ad198x_pcm_analog_playback = {
343 .substreams = 1,
344 .channels_min = 2,
985be54b 345 .channels_max = 6, /* changed later */
4a3fdf3d
TI
346 .nid = 0, /* fill later */
347 .ops = {
348 .open = ad198x_playback_pcm_open,
349 .prepare = ad198x_playback_pcm_prepare,
350 .cleanup = ad198x_playback_pcm_cleanup
351 },
352};
353
354static struct hda_pcm_stream ad198x_pcm_analog_capture = {
985be54b 355 .substreams = 1,
4a3fdf3d
TI
356 .channels_min = 2,
357 .channels_max = 2,
358 .nid = 0, /* fill later */
359 .ops = {
360 .prepare = ad198x_capture_pcm_prepare,
361 .cleanup = ad198x_capture_pcm_cleanup
362 },
363};
364
365static struct hda_pcm_stream ad198x_pcm_digital_playback = {
366 .substreams = 1,
367 .channels_min = 2,
368 .channels_max = 2,
369 .nid = 0, /* fill later */
370 .ops = {
371 .open = ad198x_dig_playback_pcm_open,
6b97eb45 372 .close = ad198x_dig_playback_pcm_close,
9411e21c
TI
373 .prepare = ad198x_dig_playback_pcm_prepare,
374 .cleanup = ad198x_dig_playback_pcm_cleanup
4a3fdf3d
TI
375 },
376};
377
985be54b
TI
378static struct hda_pcm_stream ad198x_pcm_digital_capture = {
379 .substreams = 1,
380 .channels_min = 2,
381 .channels_max = 2,
382 /* NID is set in alc_build_pcms */
383};
384
4a3fdf3d
TI
385static int ad198x_build_pcms(struct hda_codec *codec)
386{
387 struct ad198x_spec *spec = codec->spec;
388 struct hda_pcm *info = spec->pcm_rec;
389
390 codec->num_pcms = 1;
391 codec->pcm_info = info;
392
393 info->name = "AD198x Analog";
394 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
395 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
396 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
397 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
985be54b
TI
398 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
399 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
4a3fdf3d
TI
400
401 if (spec->multiout.dig_out_nid) {
402 info++;
403 codec->num_pcms++;
404 info->name = "AD198x Digital";
7ba72ba1 405 info->pcm_type = HDA_PCM_TYPE_SPDIF;
4a3fdf3d
TI
406 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
407 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
985be54b
TI
408 if (spec->dig_in_nid) {
409 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
410 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
411 }
4a3fdf3d
TI
412 }
413
414 return 0;
415}
416
603c4019 417static void ad198x_free_kctls(struct hda_codec *codec)
4a3fdf3d 418{
d32410b1 419 struct ad198x_spec *spec = codec->spec;
d32410b1 420
603c4019
TI
421 if (spec->kctls.list) {
422 struct snd_kcontrol_new *kctl = spec->kctls.list;
423 int i;
424 for (i = 0; i < spec->kctls.used; i++)
425 kfree(kctl[i].name);
d32410b1 426 }
603c4019
TI
427 snd_array_free(&spec->kctls);
428}
429
430static void ad198x_free(struct hda_codec *codec)
431{
432 struct ad198x_spec *spec = codec->spec;
433
434 if (!spec)
435 return;
436
437 ad198x_free_kctls(codec);
c5a4bcd0
TI
438 kfree(spec);
439 snd_hda_detach_beep_device(codec);
4a3fdf3d
TI
440}
441
4a3fdf3d
TI
442static struct hda_codec_ops ad198x_patch_ops = {
443 .build_controls = ad198x_build_controls,
444 .build_pcms = ad198x_build_pcms,
445 .init = ad198x_init,
446 .free = ad198x_free,
cb53c626
TI
447#ifdef CONFIG_SND_HDA_POWER_SAVE
448 .check_power_status = ad198x_check_power_status,
449#endif
4a3fdf3d
TI
450};
451
452
18a815d7
TI
453/*
454 * EAPD control
455 * the private value = nid | (invert << 8)
456 */
a5ce8890 457#define ad198x_eapd_info snd_ctl_boolean_mono_info
18a815d7
TI
458
459static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
460 struct snd_ctl_elem_value *ucontrol)
461{
462 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
463 struct ad198x_spec *spec = codec->spec;
464 int invert = (kcontrol->private_value >> 8) & 1;
465 if (invert)
466 ucontrol->value.integer.value[0] = ! spec->cur_eapd;
467 else
468 ucontrol->value.integer.value[0] = spec->cur_eapd;
469 return 0;
470}
471
472static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
473 struct snd_ctl_elem_value *ucontrol)
474{
475 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
476 struct ad198x_spec *spec = codec->spec;
477 int invert = (kcontrol->private_value >> 8) & 1;
478 hda_nid_t nid = kcontrol->private_value & 0xff;
479 unsigned int eapd;
68ea7b2f 480 eapd = !!ucontrol->value.integer.value[0];
18a815d7
TI
481 if (invert)
482 eapd = !eapd;
82beb8fd 483 if (eapd == spec->cur_eapd)
18a815d7
TI
484 return 0;
485 spec->cur_eapd = eapd;
82beb8fd
TI
486 snd_hda_codec_write_cache(codec, nid,
487 0, AC_VERB_SET_EAPD_BTLENABLE,
488 eapd ? 0x02 : 0x00);
18a815d7
TI
489 return 1;
490}
491
9230d214
TI
492static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
493 struct snd_ctl_elem_info *uinfo);
494static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
495 struct snd_ctl_elem_value *ucontrol);
496static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
497 struct snd_ctl_elem_value *ucontrol);
498
499
4a3fdf3d
TI
500/*
501 * AD1986A specific
502 */
503
1da177e4
LT
504#define AD1986A_SPDIF_OUT 0x02
505#define AD1986A_FRONT_DAC 0x03
506#define AD1986A_SURR_DAC 0x04
507#define AD1986A_CLFE_DAC 0x05
508#define AD1986A_ADC 0x06
509
510static hda_nid_t ad1986a_dac_nids[3] = {
511 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
512};
985be54b 513static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
18a815d7 514static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
1da177e4
LT
515
516static struct hda_input_mux ad1986a_capture_source = {
517 .num_items = 7,
518 .items = {
519 { "Mic", 0x0 },
520 { "CD", 0x1 },
521 { "Aux", 0x3 },
522 { "Line", 0x4 },
523 { "Mix", 0x5 },
524 { "Mono", 0x6 },
525 { "Phone", 0x7 },
526 },
527};
528
1da177e4 529
532d5381
TI
530static struct hda_bind_ctls ad1986a_bind_pcm_vol = {
531 .ops = &snd_hda_bind_vol,
532 .values = {
533 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
534 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
535 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
536 0
537 },
538};
1da177e4 539
532d5381
TI
540static struct hda_bind_ctls ad1986a_bind_pcm_sw = {
541 .ops = &snd_hda_bind_sw,
542 .values = {
543 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
544 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
545 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
546 0
547 },
548};
1da177e4 549
1da177e4
LT
550/*
551 * mixers
552 */
c8b6bf9b 553static struct snd_kcontrol_new ad1986a_mixers[] = {
532d5381
TI
554 /*
555 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
556 */
557 HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
558 HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
1da177e4
LT
559 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
560 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
561 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
562 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
563 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
564 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
565 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
566 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
567 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
568 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
569 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
570 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
571 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
572 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
573 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
574 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
575 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
576 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
fe8970b4 577 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
1da177e4
LT
578 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
579 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
580 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
581 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
582 {
583 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
584 .name = "Capture Source",
4a3fdf3d
TI
585 .info = ad198x_mux_enum_info,
586 .get = ad198x_mux_enum_get,
587 .put = ad198x_mux_enum_put,
1da177e4
LT
588 },
589 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
590 { } /* end */
591};
592
9230d214
TI
593/* additional mixers for 3stack mode */
594static struct snd_kcontrol_new ad1986a_3st_mixers[] = {
595 {
596 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
597 .name = "Channel Mode",
598 .info = ad198x_ch_mode_info,
599 .get = ad198x_ch_mode_get,
600 .put = ad198x_ch_mode_put,
601 },
602 { } /* end */
603};
604
605/* laptop model - 2ch only */
606static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
607
20a45e86
TI
608/* master controls both pins 0x1a and 0x1b */
609static struct hda_bind_ctls ad1986a_laptop_master_vol = {
610 .ops = &snd_hda_bind_vol,
611 .values = {
612 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
613 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
614 0,
615 },
616};
617
618static struct hda_bind_ctls ad1986a_laptop_master_sw = {
619 .ops = &snd_hda_bind_sw,
620 .values = {
621 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
622 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
623 0,
624 },
625};
626
9230d214
TI
627static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
628 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
629 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
20a45e86
TI
630 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
631 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
9230d214
TI
632 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
633 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
634 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
635 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
636 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
637 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
638 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
639 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
fe8970b4 640 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
c5a4bcd0 641 /*
9230d214
TI
642 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
643 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
644 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
645 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
646 {
647 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
648 .name = "Capture Source",
649 .info = ad198x_mux_enum_info,
650 .get = ad198x_mux_enum_get,
651 .put = ad198x_mux_enum_put,
652 },
653 { } /* end */
654};
655
825aa972
TI
656/* laptop-eapd model - 2ch only */
657
825aa972
TI
658static struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
659 .num_items = 3,
660 .items = {
661 { "Mic", 0x0 },
662 { "Internal Mic", 0x4 },
663 { "Mix", 0x5 },
664 },
665};
666
5d5d5f43
TI
667static struct hda_input_mux ad1986a_automic_capture_source = {
668 .num_items = 2,
669 .items = {
670 { "Mic", 0x0 },
671 { "Mix", 0x5 },
672 },
673};
674
16d11a82 675static struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
1725b82a
TI
676 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
677 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
1725b82a
TI
678 { } /* end */
679};
680
16d11a82 681static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
825aa972
TI
682 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
683 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
825aa972
TI
684 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
685 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
fe8970b4 686 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
825aa972
TI
687 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
688 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
689 {
690 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
691 .name = "Capture Source",
692 .info = ad198x_mux_enum_info,
693 .get = ad198x_mux_enum_get,
694 .put = ad198x_mux_enum_put,
695 },
696 {
697 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
698 .name = "External Amplifier",
699 .info = ad198x_eapd_info,
700 .get = ad198x_eapd_get,
701 .put = ad198x_eapd_put,
702 .private_value = 0x1b | (1 << 8), /* port-D, inversed */
703 },
704 { } /* end */
705};
706
16d11a82
TI
707static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
708 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
709 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
710 { } /* end */
711};
712
5d5d5f43
TI
713/* re-connect the mic boost input according to the jack sensing */
714static void ad1986a_automic(struct hda_codec *codec)
715{
716 unsigned int present;
717 present = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_PIN_SENSE, 0);
718 /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
719 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
720 (present & AC_PINSENSE_PRESENCE) ? 0 : 2);
721}
722
723#define AD1986A_MIC_EVENT 0x36
724
725static void ad1986a_automic_unsol_event(struct hda_codec *codec,
726 unsigned int res)
727{
728 if ((res >> 26) != AD1986A_MIC_EVENT)
729 return;
730 ad1986a_automic(codec);
731}
732
733static int ad1986a_automic_init(struct hda_codec *codec)
734{
735 ad198x_init(codec);
736 ad1986a_automic(codec);
737 return 0;
738}
739
8ab78c74
TI
740/* laptop-automute - 2ch only */
741
742static void ad1986a_update_hp(struct hda_codec *codec)
743{
744 struct ad198x_spec *spec = codec->spec;
745 unsigned int mute;
746
747 if (spec->jack_present)
748 mute = HDA_AMP_MUTE; /* mute internal speaker */
749 else
750 /* unmute internal speaker if necessary */
751 mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
752 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
753 HDA_AMP_MUTE, mute);
754}
755
756static void ad1986a_hp_automute(struct hda_codec *codec)
757{
758 struct ad198x_spec *spec = codec->spec;
759 unsigned int present;
760
761 present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0);
03c405ad
TI
762 spec->jack_present = !!(present & 0x80000000);
763 if (spec->inv_jack_detect)
764 spec->jack_present = !spec->jack_present;
8ab78c74
TI
765 ad1986a_update_hp(codec);
766}
767
768#define AD1986A_HP_EVENT 0x37
769
770static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
771{
772 if ((res >> 26) != AD1986A_HP_EVENT)
773 return;
774 ad1986a_hp_automute(codec);
775}
776
777static int ad1986a_hp_init(struct hda_codec *codec)
778{
779 ad198x_init(codec);
780 ad1986a_hp_automute(codec);
781 return 0;
782}
783
784/* bind hp and internal speaker mute (with plug check) */
785static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
786 struct snd_ctl_elem_value *ucontrol)
787{
788 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
789 long *valp = ucontrol->value.integer.value;
790 int change;
791
792 change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
793 HDA_AMP_MUTE,
794 valp[0] ? 0 : HDA_AMP_MUTE);
795 change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
796 HDA_AMP_MUTE,
797 valp[1] ? 0 : HDA_AMP_MUTE);
798 if (change)
799 ad1986a_update_hp(codec);
800 return change;
801}
802
16d11a82 803static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
8ab78c74
TI
804 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
805 {
806 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
807 .name = "Master Playback Switch",
808 .info = snd_hda_mixer_amp_switch_info,
809 .get = snd_hda_mixer_amp_switch_get,
810 .put = ad1986a_hp_master_sw_put,
811 .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
812 },
8ab78c74
TI
813 { } /* end */
814};
815
16d11a82 816
1da177e4
LT
817/*
818 * initialization verbs
819 */
820static struct hda_verb ad1986a_init_verbs[] = {
821 /* Front, Surround, CLFE DAC; mute as default */
822 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
823 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
824 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
825 /* Downmix - off */
826 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
827 /* HP, Line-Out, Surround, CLFE selectors */
828 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
829 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
830 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
831 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
832 /* Mono selector */
833 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
834 /* Mic selector: Mic 1/2 pin */
835 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
836 /* Line-in selector: Line-in */
837 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
838 /* Mic 1/2 swap */
839 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
840 /* Record selector: mic */
841 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
842 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
843 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
844 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
845 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
846 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
847 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
848 /* PC beep */
849 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
850 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
851 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
852 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
853 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
854 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
855 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
4a3fdf3d
TI
856 /* HP Pin */
857 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
858 /* Front, Surround, CLFE Pins */
859 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
860 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
861 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
862 /* Mono Pin */
863 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
864 /* Mic Pin */
865 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
866 /* Line, Aux, CD, Beep-In Pin */
867 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
868 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
869 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
870 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
871 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1da177e4
LT
872 { } /* end */
873};
874
9230d214
TI
875static struct hda_verb ad1986a_ch2_init[] = {
876 /* Surround out -> Line In */
fb956c16
TI
877 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
878 /* Line-in selectors */
879 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
9230d214 880 /* CLFE -> Mic in */
fb956c16
TI
881 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
882 /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
883 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
9230d214
TI
884 { } /* end */
885};
886
887static struct hda_verb ad1986a_ch4_init[] = {
888 /* Surround out -> Surround */
fb956c16
TI
889 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
890 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
9230d214 891 /* CLFE -> Mic in */
fb956c16
TI
892 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
893 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
9230d214
TI
894 { } /* end */
895};
896
897static struct hda_verb ad1986a_ch6_init[] = {
898 /* Surround out -> Surround out */
fb956c16
TI
899 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
900 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
9230d214 901 /* CLFE -> CLFE */
fb956c16
TI
902 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
903 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
9230d214
TI
904 { } /* end */
905};
906
907static struct hda_channel_mode ad1986a_modes[3] = {
908 { 2, ad1986a_ch2_init },
909 { 4, ad1986a_ch4_init },
910 { 6, ad1986a_ch6_init },
911};
912
825aa972
TI
913/* eapd initialization */
914static struct hda_verb ad1986a_eapd_init_verbs[] = {
f36090fe 915 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
825aa972
TI
916 {}
917};
918
5d5d5f43
TI
919static struct hda_verb ad1986a_automic_verbs[] = {
920 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
921 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
922 /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
923 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
924 {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
925 {}
926};
927
f36090fe
TD
928/* Ultra initialization */
929static struct hda_verb ad1986a_ultra_init[] = {
930 /* eapd initialization */
931 { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
932 /* CLFE -> Mic in */
933 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
934 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
935 { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
936 { } /* end */
937};
938
8ab78c74
TI
939/* pin sensing on HP jack */
940static struct hda_verb ad1986a_hp_init_verbs[] = {
941 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
942 {}
943};
944
c912e7a5
TI
945static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
946 unsigned int res)
947{
948 switch (res >> 26) {
949 case AD1986A_HP_EVENT:
950 ad1986a_hp_automute(codec);
951 break;
952 case AD1986A_MIC_EVENT:
953 ad1986a_automic(codec);
954 break;
955 }
956}
957
958static int ad1986a_samsung_p50_init(struct hda_codec *codec)
959{
960 ad198x_init(codec);
961 ad1986a_hp_automute(codec);
962 ad1986a_automic(codec);
963 return 0;
964}
965
8ab78c74 966
9230d214 967/* models */
f5fcc13c
TI
968enum {
969 AD1986A_6STACK,
970 AD1986A_3STACK,
971 AD1986A_LAPTOP,
972 AD1986A_LAPTOP_EAPD,
8ab78c74 973 AD1986A_LAPTOP_AUTOMUTE,
f36090fe 974 AD1986A_ULTRA,
1725b82a 975 AD1986A_SAMSUNG,
c912e7a5 976 AD1986A_SAMSUNG_P50,
f5fcc13c
TI
977 AD1986A_MODELS
978};
979
980static const char *ad1986a_models[AD1986A_MODELS] = {
981 [AD1986A_6STACK] = "6stack",
982 [AD1986A_3STACK] = "3stack",
983 [AD1986A_LAPTOP] = "laptop",
984 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
8ab78c74 985 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
f36090fe 986 [AD1986A_ULTRA] = "ultra",
1725b82a 987 [AD1986A_SAMSUNG] = "samsung",
c912e7a5 988 [AD1986A_SAMSUNG_P50] = "samsung-p50",
f5fcc13c
TI
989};
990
991static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
992 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
f5fcc13c 993 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
f5fcc13c 994 SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
ac3e3741 995 SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
f5fcc13c
TI
996 SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
997 SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
998 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
999 SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
d9f9b8ba 1000 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
658fba0e 1001 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
f5fcc13c
TI
1002 SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
1003 SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
1004 SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
1005 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
1006 SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
ac3e3741 1007 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
7db756f2 1008 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
18768991 1009 SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
f5fcc13c 1010 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
c912e7a5 1011 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
f36090fe 1012 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
dea0a509 1013 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
ac3e3741 1014 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
18768991 1015 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
f5fcc13c 1016 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
8ab78c74 1017 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
f5fcc13c 1018 SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
9230d214
TI
1019 {}
1020};
1da177e4 1021
cb53c626
TI
1022#ifdef CONFIG_SND_HDA_POWER_SAVE
1023static struct hda_amp_list ad1986a_loopbacks[] = {
1024 { 0x13, HDA_OUTPUT, 0 }, /* Mic */
1025 { 0x14, HDA_OUTPUT, 0 }, /* Phone */
1026 { 0x15, HDA_OUTPUT, 0 }, /* CD */
1027 { 0x16, HDA_OUTPUT, 0 }, /* Aux */
1028 { 0x17, HDA_OUTPUT, 0 }, /* Line */
1029 { } /* end */
1030};
1031#endif
1032
8c0d9649
TI
1033static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
1034{
2f334f92 1035 unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
8c0d9649
TI
1036 return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
1037}
1038
4a3fdf3d 1039static int patch_ad1986a(struct hda_codec *codec)
1da177e4 1040{
4a3fdf3d 1041 struct ad198x_spec *spec;
c5a4bcd0 1042 int err, board_config;
1da177e4 1043
e560d8d8 1044 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4a3fdf3d
TI
1045 if (spec == NULL)
1046 return -ENOMEM;
1047
4a3fdf3d
TI
1048 codec->spec = spec;
1049
c5a4bcd0
TI
1050 err = snd_hda_attach_beep_device(codec, 0x19);
1051 if (err < 0) {
1052 ad198x_free(codec);
1053 return err;
1054 }
1055 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1056
4a3fdf3d
TI
1057 spec->multiout.max_channels = 6;
1058 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
1059 spec->multiout.dac_nids = ad1986a_dac_nids;
1060 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
985be54b
TI
1061 spec->num_adc_nids = 1;
1062 spec->adc_nids = ad1986a_adc_nids;
a7ee8201 1063 spec->capsrc_nids = ad1986a_capsrc_nids;
4a3fdf3d 1064 spec->input_mux = &ad1986a_capture_source;
985be54b
TI
1065 spec->num_mixers = 1;
1066 spec->mixers[0] = ad1986a_mixers;
1067 spec->num_init_verbs = 1;
1068 spec->init_verbs[0] = ad1986a_init_verbs;
cb53c626
TI
1069#ifdef CONFIG_SND_HDA_POWER_SAVE
1070 spec->loopback.amplist = ad1986a_loopbacks;
1071#endif
2134ea4f 1072 spec->vmaster_nid = 0x1b;
4a3fdf3d
TI
1073
1074 codec->patch_ops = ad198x_patch_ops;
1da177e4 1075
9230d214 1076 /* override some parameters */
f5fcc13c
TI
1077 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
1078 ad1986a_models,
1079 ad1986a_cfg_tbl);
9230d214
TI
1080 switch (board_config) {
1081 case AD1986A_3STACK:
1082 spec->num_mixers = 2;
1083 spec->mixers[1] = ad1986a_3st_mixers;
fb956c16
TI
1084 spec->num_init_verbs = 2;
1085 spec->init_verbs[1] = ad1986a_ch2_init;
9230d214
TI
1086 spec->channel_mode = ad1986a_modes;
1087 spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
2125cad2
TI
1088 spec->need_dac_fix = 1;
1089 spec->multiout.max_channels = 2;
1090 spec->multiout.num_dacs = 1;
9230d214
TI
1091 break;
1092 case AD1986A_LAPTOP:
1093 spec->mixers[0] = ad1986a_laptop_mixers;
1094 spec->multiout.max_channels = 2;
1095 spec->multiout.num_dacs = 1;
1096 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1097 break;
825aa972 1098 case AD1986A_LAPTOP_EAPD:
16d11a82
TI
1099 spec->num_mixers = 3;
1100 spec->mixers[0] = ad1986a_laptop_master_mixers;
1101 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1102 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1725b82a
TI
1103 spec->num_init_verbs = 2;
1104 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1105 spec->multiout.max_channels = 2;
1106 spec->multiout.num_dacs = 1;
1107 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1108 if (!is_jack_available(codec, 0x25))
1109 spec->multiout.dig_out_nid = 0;
1110 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1111 break;
1112 case AD1986A_SAMSUNG:
16d11a82
TI
1113 spec->num_mixers = 2;
1114 spec->mixers[0] = ad1986a_laptop_master_mixers;
1115 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
5d5d5f43 1116 spec->num_init_verbs = 3;
825aa972 1117 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
5d5d5f43 1118 spec->init_verbs[2] = ad1986a_automic_verbs;
825aa972
TI
1119 spec->multiout.max_channels = 2;
1120 spec->multiout.num_dacs = 1;
1121 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
8c0d9649
TI
1122 if (!is_jack_available(codec, 0x25))
1123 spec->multiout.dig_out_nid = 0;
5d5d5f43
TI
1124 spec->input_mux = &ad1986a_automic_capture_source;
1125 codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
1126 codec->patch_ops.init = ad1986a_automic_init;
825aa972 1127 break;
c912e7a5
TI
1128 case AD1986A_SAMSUNG_P50:
1129 spec->num_mixers = 2;
1130 spec->mixers[0] = ad1986a_automute_master_mixers;
1131 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1132 spec->num_init_verbs = 4;
1133 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1134 spec->init_verbs[2] = ad1986a_automic_verbs;
1135 spec->init_verbs[3] = ad1986a_hp_init_verbs;
1136 spec->multiout.max_channels = 2;
1137 spec->multiout.num_dacs = 1;
1138 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1139 if (!is_jack_available(codec, 0x25))
1140 spec->multiout.dig_out_nid = 0;
1141 spec->input_mux = &ad1986a_automic_capture_source;
1142 codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
1143 codec->patch_ops.init = ad1986a_samsung_p50_init;
1144 break;
8ab78c74 1145 case AD1986A_LAPTOP_AUTOMUTE:
16d11a82
TI
1146 spec->num_mixers = 3;
1147 spec->mixers[0] = ad1986a_automute_master_mixers;
1148 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1149 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
8ab78c74
TI
1150 spec->num_init_verbs = 3;
1151 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1152 spec->init_verbs[2] = ad1986a_hp_init_verbs;
1153 spec->multiout.max_channels = 2;
1154 spec->multiout.num_dacs = 1;
1155 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
8c0d9649
TI
1156 if (!is_jack_available(codec, 0x25))
1157 spec->multiout.dig_out_nid = 0;
8ab78c74
TI
1158 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1159 codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
1160 codec->patch_ops.init = ad1986a_hp_init;
03c405ad
TI
1161 /* Lenovo N100 seems to report the reversed bit
1162 * for HP jack-sensing
1163 */
1164 spec->inv_jack_detect = 1;
8ab78c74 1165 break;
f36090fe
TD
1166 case AD1986A_ULTRA:
1167 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1168 spec->num_init_verbs = 2;
1169 spec->init_verbs[1] = ad1986a_ultra_init;
1170 spec->multiout.max_channels = 2;
1171 spec->multiout.num_dacs = 1;
1172 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1173 spec->multiout.dig_out_nid = 0;
1174 break;
9230d214
TI
1175 }
1176
d29240ce
TI
1177 /* AD1986A has a hardware problem that it can't share a stream
1178 * with multiple output pins. The copy of front to surrounds
1179 * causes noisy or silent outputs at a certain timing, e.g.
1180 * changing the volume.
1181 * So, let's disable the shared stream.
1182 */
1183 spec->multiout.no_share_stream = 1;
1184
1da177e4
LT
1185 return 0;
1186}
1187
1188/*
4a3fdf3d 1189 * AD1983 specific
1da177e4 1190 */
1da177e4 1191
4a3fdf3d
TI
1192#define AD1983_SPDIF_OUT 0x02
1193#define AD1983_DAC 0x03
1194#define AD1983_ADC 0x04
1da177e4 1195
4a3fdf3d 1196static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
985be54b 1197static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
18a815d7 1198static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
4a3fdf3d
TI
1199
1200static struct hda_input_mux ad1983_capture_source = {
1201 .num_items = 4,
1202 .items = {
1203 { "Mic", 0x0 },
1204 { "Line", 0x1 },
1205 { "Mix", 0x2 },
1206 { "Mix Mono", 0x3 },
1207 },
1208};
1da177e4
LT
1209
1210/*
4a3fdf3d 1211 * SPDIF playback route
1da177e4 1212 */
c8b6bf9b 1213static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1da177e4 1214{
4a3fdf3d
TI
1215 static char *texts[] = { "PCM", "ADC" };
1216
1217 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1218 uinfo->count = 1;
1219 uinfo->value.enumerated.items = 2;
1220 if (uinfo->value.enumerated.item > 1)
1221 uinfo->value.enumerated.item = 1;
1222 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1223 return 0;
1da177e4
LT
1224}
1225
c8b6bf9b 1226static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1da177e4 1227{
4a3fdf3d
TI
1228 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1229 struct ad198x_spec *spec = codec->spec;
1da177e4 1230
4a3fdf3d 1231 ucontrol->value.enumerated.item[0] = spec->spdif_route;
1da177e4
LT
1232 return 0;
1233}
1234
c8b6bf9b 1235static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1da177e4 1236{
4a3fdf3d
TI
1237 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1238 struct ad198x_spec *spec = codec->spec;
1239
68ea7b2f
TI
1240 if (ucontrol->value.enumerated.item[0] > 1)
1241 return -EINVAL;
4a3fdf3d
TI
1242 if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
1243 spec->spdif_route = ucontrol->value.enumerated.item[0];
82beb8fd
TI
1244 snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
1245 AC_VERB_SET_CONNECT_SEL,
1246 spec->spdif_route);
4a3fdf3d
TI
1247 return 1;
1248 }
1da177e4
LT
1249 return 0;
1250}
1251
c8b6bf9b 1252static struct snd_kcontrol_new ad1983_mixers[] = {
4a3fdf3d
TI
1253 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1254 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1255 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1256 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1257 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1258 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1259 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1260 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1261 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1262 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1263 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1264 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
4a3fdf3d
TI
1265 HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
1266 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1267 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1268 {
1269 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1270 .name = "Capture Source",
1271 .info = ad198x_mux_enum_info,
1272 .get = ad198x_mux_enum_get,
1273 .put = ad198x_mux_enum_put,
1da177e4 1274 },
4a3fdf3d
TI
1275 {
1276 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6540dffa 1277 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4a3fdf3d
TI
1278 .info = ad1983_spdif_route_info,
1279 .get = ad1983_spdif_route_get,
1280 .put = ad1983_spdif_route_put,
1da177e4 1281 },
4a3fdf3d 1282 { } /* end */
1da177e4
LT
1283};
1284
4a3fdf3d
TI
1285static struct hda_verb ad1983_init_verbs[] = {
1286 /* Front, HP, Mono; mute as default */
1287 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1288 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1289 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1290 /* Beep, PCM, Mic, Line-In: mute */
1291 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1292 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1293 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1294 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1295 /* Front, HP selectors; from Mix */
1296 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1297 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1298 /* Mono selector; from Mix */
1299 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1300 /* Mic selector; Mic */
1301 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
1302 /* Line-in selector: Line-in */
1303 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
1304 /* Mic boost: 0dB */
1305 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1306 /* Record selector: mic */
1307 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1308 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1309 /* SPDIF route: PCM */
1310 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1311 /* Front Pin */
1312 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1313 /* HP Pin */
1314 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1315 /* Mono Pin */
1316 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1317 /* Mic Pin */
1318 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1319 /* Line Pin */
1320 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1321 { } /* end */
1da177e4
LT
1322};
1323
cb53c626
TI
1324#ifdef CONFIG_SND_HDA_POWER_SAVE
1325static struct hda_amp_list ad1983_loopbacks[] = {
1326 { 0x12, HDA_OUTPUT, 0 }, /* Mic */
1327 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1328 { } /* end */
1329};
1330#endif
985be54b 1331
4a3fdf3d 1332static int patch_ad1983(struct hda_codec *codec)
1da177e4 1333{
4a3fdf3d 1334 struct ad198x_spec *spec;
c5a4bcd0 1335 int err;
1da177e4 1336
e560d8d8 1337 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4a3fdf3d
TI
1338 if (spec == NULL)
1339 return -ENOMEM;
1da177e4 1340
4a3fdf3d
TI
1341 codec->spec = spec;
1342
c5a4bcd0
TI
1343 err = snd_hda_attach_beep_device(codec, 0x10);
1344 if (err < 0) {
1345 ad198x_free(codec);
1346 return err;
1347 }
1348 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1349
4a3fdf3d
TI
1350 spec->multiout.max_channels = 2;
1351 spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
1352 spec->multiout.dac_nids = ad1983_dac_nids;
1353 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
985be54b
TI
1354 spec->num_adc_nids = 1;
1355 spec->adc_nids = ad1983_adc_nids;
18a815d7 1356 spec->capsrc_nids = ad1983_capsrc_nids;
4a3fdf3d 1357 spec->input_mux = &ad1983_capture_source;
985be54b
TI
1358 spec->num_mixers = 1;
1359 spec->mixers[0] = ad1983_mixers;
1360 spec->num_init_verbs = 1;
1361 spec->init_verbs[0] = ad1983_init_verbs;
4a3fdf3d 1362 spec->spdif_route = 0;
cb53c626
TI
1363#ifdef CONFIG_SND_HDA_POWER_SAVE
1364 spec->loopback.amplist = ad1983_loopbacks;
1365#endif
2134ea4f 1366 spec->vmaster_nid = 0x05;
1da177e4 1367
4a3fdf3d 1368 codec->patch_ops = ad198x_patch_ops;
1da177e4
LT
1369
1370 return 0;
1371}
1372
1da177e4 1373
4a3fdf3d
TI
1374/*
1375 * AD1981 HD specific
1376 */
1da177e4 1377
4a3fdf3d
TI
1378#define AD1981_SPDIF_OUT 0x02
1379#define AD1981_DAC 0x03
1380#define AD1981_ADC 0x04
1381
1382static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
985be54b 1383static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
18a815d7 1384static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
4a3fdf3d
TI
1385
1386/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
1387static struct hda_input_mux ad1981_capture_source = {
1388 .num_items = 7,
1389 .items = {
1390 { "Front Mic", 0x0 },
1391 { "Line", 0x1 },
1392 { "Mix", 0x2 },
1393 { "Mix Mono", 0x3 },
1394 { "CD", 0x4 },
1395 { "Mic", 0x6 },
1396 { "Aux", 0x7 },
1397 },
1da177e4
LT
1398};
1399
c8b6bf9b 1400static struct snd_kcontrol_new ad1981_mixers[] = {
4a3fdf3d
TI
1401 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1402 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1403 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1404 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1405 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1406 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1407 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1408 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1409 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1410 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1411 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1412 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1413 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1414 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1415 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1416 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1417 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1418 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
4a3fdf3d
TI
1419 HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
1420 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
1421 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1422 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1423 {
1424 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1425 .name = "Capture Source",
1426 .info = ad198x_mux_enum_info,
1427 .get = ad198x_mux_enum_get,
1428 .put = ad198x_mux_enum_put,
1429 },
1430 /* identical with AD1983 */
1431 {
1432 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6540dffa 1433 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4a3fdf3d
TI
1434 .info = ad1983_spdif_route_info,
1435 .get = ad1983_spdif_route_get,
1436 .put = ad1983_spdif_route_put,
1437 },
1438 { } /* end */
1439};
1440
1441static struct hda_verb ad1981_init_verbs[] = {
1442 /* Front, HP, Mono; mute as default */
1443 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1444 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1445 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1446 /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
1447 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1448 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1449 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1450 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1451 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1452 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1453 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1454 /* Front, HP selectors; from Mix */
1455 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1456 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1457 /* Mono selector; from Mix */
1458 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1459 /* Mic Mixer; select Front Mic */
1460 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1461 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1462 /* Mic boost: 0dB */
6d6e17de
TI
1463 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1464 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4a3fdf3d
TI
1465 /* Record selector: Front mic */
1466 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1467 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1468 /* SPDIF route: PCM */
1469 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1470 /* Front Pin */
1471 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1472 /* HP Pin */
1473 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1474 /* Mono Pin */
1475 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1476 /* Front & Rear Mic Pins */
1477 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1478 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1479 /* Line Pin */
1480 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1481 /* Digital Beep */
1482 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
1483 /* Line-Out as Input: disabled */
1484 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1485 { } /* end */
1486};
1487
cb53c626
TI
1488#ifdef CONFIG_SND_HDA_POWER_SAVE
1489static struct hda_amp_list ad1981_loopbacks[] = {
1490 { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
1491 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1492 { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
1493 { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
1494 { 0x1d, HDA_OUTPUT, 0 }, /* CD */
1495 { } /* end */
1496};
1497#endif
1498
18a815d7
TI
1499/*
1500 * Patch for HP nx6320
1501 *
18768991 1502 * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
18a815d7
TI
1503 * speaker output enabled _and_ mute-LED off.
1504 */
1505
1506#define AD1981_HP_EVENT 0x37
1507#define AD1981_MIC_EVENT 0x38
1508
1509static struct hda_verb ad1981_hp_init_verbs[] = {
1510 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
1511 /* pin sensing on HP and Mic jacks */
1512 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1513 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1514 {}
1515};
1516
1517/* turn on/off EAPD (+ mute HP) as a master switch */
1518static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1519 struct snd_ctl_elem_value *ucontrol)
1520{
1521 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1522 struct ad198x_spec *spec = codec->spec;
1523
1524 if (! ad198x_eapd_put(kcontrol, ucontrol))
1525 return 0;
f0824812
TI
1526 /* change speaker pin appropriately */
1527 snd_hda_codec_write(codec, 0x05, 0,
1528 AC_VERB_SET_PIN_WIDGET_CONTROL,
1529 spec->cur_eapd ? PIN_OUT : 0);
18a815d7 1530 /* toggle HP mute appropriately */
47fd830a
TI
1531 snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
1532 HDA_AMP_MUTE,
1533 spec->cur_eapd ? 0 : HDA_AMP_MUTE);
18a815d7
TI
1534 return 1;
1535}
1536
1537/* bind volumes of both NID 0x05 and 0x06 */
cca3b371
TI
1538static struct hda_bind_ctls ad1981_hp_bind_master_vol = {
1539 .ops = &snd_hda_bind_vol,
1540 .values = {
1541 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
1542 HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
1543 0
1544 },
1545};
18a815d7
TI
1546
1547/* mute internal speaker if HP is plugged */
1548static void ad1981_hp_automute(struct hda_codec *codec)
1549{
1550 unsigned int present;
1551
1552 present = snd_hda_codec_read(codec, 0x06, 0,
1553 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
47fd830a
TI
1554 snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
1555 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
18a815d7
TI
1556}
1557
1558/* toggle input of built-in and mic jack appropriately */
1559static void ad1981_hp_automic(struct hda_codec *codec)
1560{
1561 static struct hda_verb mic_jack_on[] = {
1562 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1563 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1564 {}
1565 };
1566 static struct hda_verb mic_jack_off[] = {
1567 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1568 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1569 {}
1570 };
1571 unsigned int present;
1572
1573 present = snd_hda_codec_read(codec, 0x08, 0,
1574 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1575 if (present)
1576 snd_hda_sequence_write(codec, mic_jack_on);
1577 else
1578 snd_hda_sequence_write(codec, mic_jack_off);
1579}
1580
1581/* unsolicited event for HP jack sensing */
1582static void ad1981_hp_unsol_event(struct hda_codec *codec,
1583 unsigned int res)
1584{
1585 res >>= 26;
1586 switch (res) {
1587 case AD1981_HP_EVENT:
1588 ad1981_hp_automute(codec);
1589 break;
1590 case AD1981_MIC_EVENT:
1591 ad1981_hp_automic(codec);
1592 break;
1593 }
1594}
1595
1596static struct hda_input_mux ad1981_hp_capture_source = {
1597 .num_items = 3,
1598 .items = {
1599 { "Mic", 0x0 },
1600 { "Docking-Station", 0x1 },
1601 { "Mix", 0x2 },
1602 },
1603};
1604
1605static struct snd_kcontrol_new ad1981_hp_mixers[] = {
cca3b371 1606 HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
18a815d7
TI
1607 {
1608 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1609 .name = "Master Playback Switch",
1610 .info = ad198x_eapd_info,
1611 .get = ad198x_eapd_get,
1612 .put = ad1981_hp_master_sw_put,
1613 .private_value = 0x05,
1614 },
1615 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1616 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1617#if 0
1618 /* FIXME: analog mic/line loopback doesn't work with my tests...
1619 * (although recording is OK)
1620 */
1621 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1622 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1623 HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1624 HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1625 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1626 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1627 /* FIXME: does this laptop have analog CD connection? */
1628 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1629 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1630#endif
1631 HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
1632 HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT),
1633 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1634 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1635 {
1636 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1637 .name = "Capture Source",
1638 .info = ad198x_mux_enum_info,
1639 .get = ad198x_mux_enum_get,
1640 .put = ad198x_mux_enum_put,
1641 },
1642 { } /* end */
1643};
1644
1645/* initialize jack-sensing, too */
1646static int ad1981_hp_init(struct hda_codec *codec)
1647{
1648 ad198x_init(codec);
1649 ad1981_hp_automute(codec);
1650 ad1981_hp_automic(codec);
1651 return 0;
1652}
1653
18768991
TD
1654/* configuration for Toshiba Laptops */
1655static struct hda_verb ad1981_toshiba_init_verbs[] = {
1656 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
1657 /* pin sensing on HP and Mic jacks */
1658 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1659 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1660 {}
1661};
1662
1663static struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
1664 HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
1665 HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
1666 { }
1667};
1668
01686c5f
TI
1669/* configuration for Lenovo Thinkpad T60 */
1670static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
1671 HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1672 HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1673 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1674 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1675 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1676 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1677 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1678 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1679 HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
1680 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1681 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1682 {
1683 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1684 .name = "Capture Source",
1685 .info = ad198x_mux_enum_info,
1686 .get = ad198x_mux_enum_get,
1687 .put = ad198x_mux_enum_put,
1688 },
6540dffa
TI
1689 /* identical with AD1983 */
1690 {
1691 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1692 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1693 .info = ad1983_spdif_route_info,
1694 .get = ad1983_spdif_route_get,
1695 .put = ad1983_spdif_route_put,
1696 },
01686c5f
TI
1697 { } /* end */
1698};
1699
1700static struct hda_input_mux ad1981_thinkpad_capture_source = {
1701 .num_items = 3,
1702 .items = {
1703 { "Mic", 0x0 },
1704 { "Mix", 0x2 },
1705 { "CD", 0x4 },
1706 },
1707};
1708
18a815d7 1709/* models */
f5fcc13c
TI
1710enum {
1711 AD1981_BASIC,
1712 AD1981_HP,
1713 AD1981_THINKPAD,
18768991 1714 AD1981_TOSHIBA,
f5fcc13c
TI
1715 AD1981_MODELS
1716};
18a815d7 1717
f5fcc13c
TI
1718static const char *ad1981_models[AD1981_MODELS] = {
1719 [AD1981_HP] = "hp",
1720 [AD1981_THINKPAD] = "thinkpad",
1721 [AD1981_BASIC] = "basic",
18768991 1722 [AD1981_TOSHIBA] = "toshiba"
f5fcc13c
TI
1723};
1724
1725static struct snd_pci_quirk ad1981_cfg_tbl[] = {
ac3e3741 1726 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
470eaf6b 1727 SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
8970ccda 1728 /* All HP models */
dea0a509 1729 SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
ac3e3741 1730 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
01686c5f 1731 /* Lenovo Thinkpad T60/X60/Z6xx */
dea0a509 1732 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
ac3e3741
TI
1733 /* HP nx6320 (reversed SSID, H/W bug) */
1734 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
18a815d7
TI
1735 {}
1736};
1737
4a3fdf3d 1738static int patch_ad1981(struct hda_codec *codec)
1da177e4 1739{
4a3fdf3d 1740 struct ad198x_spec *spec;
c5a4bcd0 1741 int err, board_config;
1da177e4 1742
e560d8d8 1743 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1da177e4
LT
1744 if (spec == NULL)
1745 return -ENOMEM;
1746
1da177e4
LT
1747 codec->spec = spec;
1748
c5a4bcd0
TI
1749 err = snd_hda_attach_beep_device(codec, 0x10);
1750 if (err < 0) {
1751 ad198x_free(codec);
1752 return err;
1753 }
1754 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
1755
4a3fdf3d
TI
1756 spec->multiout.max_channels = 2;
1757 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
1758 spec->multiout.dac_nids = ad1981_dac_nids;
1759 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
985be54b
TI
1760 spec->num_adc_nids = 1;
1761 spec->adc_nids = ad1981_adc_nids;
18a815d7 1762 spec->capsrc_nids = ad1981_capsrc_nids;
4a3fdf3d 1763 spec->input_mux = &ad1981_capture_source;
985be54b
TI
1764 spec->num_mixers = 1;
1765 spec->mixers[0] = ad1981_mixers;
1766 spec->num_init_verbs = 1;
1767 spec->init_verbs[0] = ad1981_init_verbs;
4a3fdf3d 1768 spec->spdif_route = 0;
cb53c626
TI
1769#ifdef CONFIG_SND_HDA_POWER_SAVE
1770 spec->loopback.amplist = ad1981_loopbacks;
1771#endif
2134ea4f 1772 spec->vmaster_nid = 0x05;
1da177e4 1773
4a3fdf3d 1774 codec->patch_ops = ad198x_patch_ops;
1da177e4 1775
18a815d7 1776 /* override some parameters */
f5fcc13c
TI
1777 board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
1778 ad1981_models,
1779 ad1981_cfg_tbl);
18a815d7
TI
1780 switch (board_config) {
1781 case AD1981_HP:
1782 spec->mixers[0] = ad1981_hp_mixers;
1783 spec->num_init_verbs = 2;
1784 spec->init_verbs[1] = ad1981_hp_init_verbs;
1785 spec->multiout.dig_out_nid = 0;
1786 spec->input_mux = &ad1981_hp_capture_source;
1787
1788 codec->patch_ops.init = ad1981_hp_init;
1789 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1790 break;
01686c5f
TI
1791 case AD1981_THINKPAD:
1792 spec->mixers[0] = ad1981_thinkpad_mixers;
01686c5f
TI
1793 spec->input_mux = &ad1981_thinkpad_capture_source;
1794 break;
18768991
TD
1795 case AD1981_TOSHIBA:
1796 spec->mixers[0] = ad1981_hp_mixers;
1797 spec->mixers[1] = ad1981_toshiba_mixers;
1798 spec->num_init_verbs = 2;
1799 spec->init_verbs[1] = ad1981_toshiba_init_verbs;
1800 spec->multiout.dig_out_nid = 0;
1801 spec->input_mux = &ad1981_hp_capture_source;
1802 codec->patch_ops.init = ad1981_hp_init;
1803 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1804 break;
18a815d7 1805 }
1da177e4
LT
1806 return 0;
1807}
1808
4a3fdf3d 1809
fd66e0d0
TI
1810/*
1811 * AD1988
1812 *
1813 * Output pins and routes
1814 *
d32410b1 1815 * Pin Mix Sel DAC (*)
fd66e0d0
TI
1816 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
1817 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
1818 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
1819 * port-D 0x12 (mute/hp) <- 0x29 <- 04
1820 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
1821 * port-F 0x16 (mute) <- 0x2a <- 06
1822 * port-G 0x24 (mute) <- 0x27 <- 05
1823 * port-H 0x25 (mute) <- 0x28 <- 0a
1824 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
1825 *
d32410b1
TI
1826 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
1827 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
fd66e0d0
TI
1828 *
1829 * Input pins and routes
1830 *
1831 * pin boost mix input # / adc input #
1832 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
1833 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
1834 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
1835 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
1836 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
1837 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
1838 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
1839 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
1840 *
1841 *
1842 * DAC assignment
d32410b1 1843 * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
f8c7c7b8 1844 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
fd66e0d0
TI
1845 *
1846 * Inputs of Analog Mix (0x20)
1847 * 0:Port-B (front mic)
1848 * 1:Port-C/G/H (line-in)
1849 * 2:Port-A
1850 * 3:Port-D (line-in/2)
1851 * 4:Port-E/G/H (mic-in)
1852 * 5:Port-F (mic2-in)
1853 * 6:CD
1854 * 7:Beep
1855 *
1856 * ADC selection
1857 * 0:Port-A
1858 * 1:Port-B (front mic-in)
1859 * 2:Port-C (line-in)
1860 * 3:Port-F (mic2-in)
1861 * 4:Port-E (mic-in)
1862 * 5:CD
1863 * 6:Port-G
1864 * 7:Port-H
1865 * 8:Port-D (line-in/2)
1866 * 9:Mix
1867 *
1868 * Proposed pin assignments by the datasheet
1869 *
1870 * 6-stack
1871 * Port-A front headphone
1872 * B front mic-in
1873 * C rear line-in
1874 * D rear front-out
1875 * E rear mic-in
1876 * F rear surround
1877 * G rear CLFE
1878 * H rear side
1879 *
1880 * 3-stack
1881 * Port-A front headphone
1882 * B front mic
1883 * C rear line-in/surround
1884 * D rear front-out
1885 * E rear mic-in/CLFE
1886 *
1887 * laptop
1888 * Port-A headphone
1889 * B mic-in
1890 * C docking station
1891 * D internal speaker (with EAPD)
1892 * E/F quad mic array
1893 */
1894
1895
1896/* models */
1897enum {
1898 AD1988_6STACK,
1899 AD1988_6STACK_DIG,
1900 AD1988_3STACK,
1901 AD1988_3STACK_DIG,
1902 AD1988_LAPTOP,
1903 AD1988_LAPTOP_DIG,
d32410b1 1904 AD1988_AUTO,
fd66e0d0
TI
1905 AD1988_MODEL_LAST,
1906};
1907
d32410b1
TI
1908/* reivision id to check workarounds */
1909#define AD1988A_REV2 0x100200
1910
1a806f48
TI
1911#define is_rev2(codec) \
1912 ((codec)->vendor_id == 0x11d41988 && \
1913 (codec)->revision_id == AD1988A_REV2)
fd66e0d0
TI
1914
1915/*
1916 * mixers
1917 */
1918
d32410b1 1919static hda_nid_t ad1988_6stack_dac_nids[4] = {
fd66e0d0
TI
1920 0x04, 0x06, 0x05, 0x0a
1921};
1922
d32410b1 1923static hda_nid_t ad1988_3stack_dac_nids[3] = {
f8c7c7b8 1924 0x04, 0x05, 0x0a
d32410b1
TI
1925};
1926
1927/* for AD1988A revision-2, DAC2-4 are swapped */
1928static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
1929 0x04, 0x05, 0x0a, 0x06
1930};
1931
1932static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
f8c7c7b8 1933 0x04, 0x0a, 0x06
d32410b1
TI
1934};
1935
fd66e0d0
TI
1936static hda_nid_t ad1988_adc_nids[3] = {
1937 0x08, 0x09, 0x0f
1938};
1939
2e5b9567
TI
1940static hda_nid_t ad1988_capsrc_nids[3] = {
1941 0x0c, 0x0d, 0x0e
1942};
1943
9cae0c63
RJ
1944#define AD1988_SPDIF_OUT 0x02
1945#define AD1988_SPDIF_OUT_HDMI 0x0b
fd66e0d0
TI
1946#define AD1988_SPDIF_IN 0x07
1947
3a08e30d
TI
1948static hda_nid_t ad1989b_slave_dig_outs[] = {
1949 AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
9cae0c63
RJ
1950};
1951
fd66e0d0
TI
1952static struct hda_input_mux ad1988_6stack_capture_source = {
1953 .num_items = 5,
1954 .items = {
fb304ce5
TI
1955 { "Front Mic", 0x1 }, /* port-B */
1956 { "Line", 0x2 }, /* port-C */
1957 { "Mic", 0x4 }, /* port-E */
fd66e0d0
TI
1958 { "CD", 0x5 },
1959 { "Mix", 0x9 },
1960 },
1961};
1962
1963static struct hda_input_mux ad1988_laptop_capture_source = {
1964 .num_items = 3,
1965 .items = {
fb304ce5 1966 { "Mic/Line", 0x1 }, /* port-B */
fd66e0d0
TI
1967 { "CD", 0x5 },
1968 { "Mix", 0x9 },
1969 },
1970};
1971
1972/*
1973 */
1974static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
1975 struct snd_ctl_elem_info *uinfo)
1976{
1977 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1978 struct ad198x_spec *spec = codec->spec;
1979 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
1980 spec->num_channel_mode);
1981}
1982
1983static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
1984 struct snd_ctl_elem_value *ucontrol)
1985{
1986 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1987 struct ad198x_spec *spec = codec->spec;
1988 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
1989 spec->num_channel_mode, spec->multiout.max_channels);
1990}
1991
1992static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
1993 struct snd_ctl_elem_value *ucontrol)
1994{
1995 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1996 struct ad198x_spec *spec = codec->spec;
4e195a7b
TI
1997 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
1998 spec->num_channel_mode,
1999 &spec->multiout.max_channels);
bd2033f2 2000 if (err >= 0 && spec->need_dac_fix)
2125cad2 2001 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
4e195a7b 2002 return err;
fd66e0d0
TI
2003}
2004
fd66e0d0 2005/* 6-stack mode */
d32410b1 2006static struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
fd66e0d0
TI
2007 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2008 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2009 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2010 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2011 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2ece5f42 2012 { } /* end */
d32410b1
TI
2013};
2014
2015static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
2016 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2017 HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
2018 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2019 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
2020 HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2ece5f42 2021 { } /* end */
d32410b1 2022};
fd66e0d0 2023
d32410b1 2024static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
fd66e0d0
TI
2025 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2026 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
2027 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
2028 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
2029 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
2030 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2031 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2032
2033 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2034 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2035 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2036 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2037 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2038 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2039 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2040 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2041
2e5b9567 2042 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
fd66e0d0
TI
2043 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2044
2045 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2046 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
2047
2048 { } /* end */
2049};
2050
2051/* 3-stack mode */
d32410b1 2052static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
fd66e0d0 2053 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
d32410b1 2054 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
fd66e0d0
TI
2055 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2056 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2ece5f42 2057 { } /* end */
d32410b1
TI
2058};
2059
2060static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
2061 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
f8c7c7b8
TI
2062 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2063 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
2064 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
2ece5f42 2065 { } /* end */
d32410b1 2066};
fd66e0d0 2067
d32410b1 2068static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
fd66e0d0 2069 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
d32410b1
TI
2070 HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
2071 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
2072 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
fd66e0d0
TI
2073 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2074 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2075
2076 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2077 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2078 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2079 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2080 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2081 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2082 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2083 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2084
2e5b9567 2085 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
fd66e0d0
TI
2086 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2087
2088 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2089 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
2090 {
2091 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2092 .name = "Channel Mode",
2093 .info = ad198x_ch_mode_info,
2094 .get = ad198x_ch_mode_get,
2095 .put = ad198x_ch_mode_put,
2096 },
2097
2098 { } /* end */
2099};
2100
2101/* laptop mode */
2102static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
2103 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2104 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
2105 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2106
2107 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2108 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2109 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2110 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2111 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2112 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2113
2e5b9567 2114 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
fd66e0d0
TI
2115 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2116
2117 HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2118
2119 {
2120 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2121 .name = "External Amplifier",
18a815d7
TI
2122 .info = ad198x_eapd_info,
2123 .get = ad198x_eapd_get,
2124 .put = ad198x_eapd_put,
2125 .private_value = 0x12 | (1 << 8), /* port-D, inversed */
fd66e0d0
TI
2126 },
2127
2128 { } /* end */
2129};
2130
2131/* capture */
2132static struct snd_kcontrol_new ad1988_capture_mixers[] = {
2133 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
2134 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
2135 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
2136 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
2137 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
2138 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
2139 {
2140 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2141 /* The multiple "Capture Source" controls confuse alsamixer
2142 * So call somewhat different..
fd66e0d0
TI
2143 */
2144 /* .name = "Capture Source", */
2145 .name = "Input Source",
2146 .count = 3,
2147 .info = ad198x_mux_enum_info,
2148 .get = ad198x_mux_enum_get,
2149 .put = ad198x_mux_enum_put,
2150 },
2151 { } /* end */
2152};
2153
2154static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
2155 struct snd_ctl_elem_info *uinfo)
2156{
2157 static char *texts[] = {
2158 "PCM", "ADC1", "ADC2", "ADC3"
2159 };
2160 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2161 uinfo->count = 1;
2162 uinfo->value.enumerated.items = 4;
2163 if (uinfo->value.enumerated.item >= 4)
2164 uinfo->value.enumerated.item = 3;
2165 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2166 return 0;
2167}
2168
2169static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
2170 struct snd_ctl_elem_value *ucontrol)
2171{
2172 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2173 unsigned int sel;
2174
bddcf541
TI
2175 sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
2176 AC_AMP_GET_INPUT);
2177 if (!(sel & 0x80))
2178 ucontrol->value.enumerated.item[0] = 0;
2179 else {
35b26722
TI
2180 sel = snd_hda_codec_read(codec, 0x0b, 0,
2181 AC_VERB_GET_CONNECT_SEL, 0);
2182 if (sel < 3)
fd66e0d0
TI
2183 sel++;
2184 else
2185 sel = 0;
bddcf541 2186 ucontrol->value.enumerated.item[0] = sel;
fd66e0d0 2187 }
fd66e0d0
TI
2188 return 0;
2189}
2190
2191static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
2192 struct snd_ctl_elem_value *ucontrol)
2193{
2194 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
35b26722 2195 unsigned int val, sel;
fd66e0d0
TI
2196 int change;
2197
35b26722 2198 val = ucontrol->value.enumerated.item[0];
68ea7b2f
TI
2199 if (val > 3)
2200 return -EINVAL;
35b26722 2201 if (!val) {
bddcf541
TI
2202 sel = snd_hda_codec_read(codec, 0x1d, 0,
2203 AC_VERB_GET_AMP_GAIN_MUTE,
2204 AC_AMP_GET_INPUT);
2205 change = sel & 0x80;
82beb8fd
TI
2206 if (change) {
2207 snd_hda_codec_write_cache(codec, 0x1d, 0,
2208 AC_VERB_SET_AMP_GAIN_MUTE,
2209 AMP_IN_UNMUTE(0));
2210 snd_hda_codec_write_cache(codec, 0x1d, 0,
2211 AC_VERB_SET_AMP_GAIN_MUTE,
2212 AMP_IN_MUTE(1));
bddcf541 2213 }
fd66e0d0 2214 } else {
bddcf541
TI
2215 sel = snd_hda_codec_read(codec, 0x1d, 0,
2216 AC_VERB_GET_AMP_GAIN_MUTE,
2217 AC_AMP_GET_INPUT | 0x01);
2218 change = sel & 0x80;
82beb8fd
TI
2219 if (change) {
2220 snd_hda_codec_write_cache(codec, 0x1d, 0,
2221 AC_VERB_SET_AMP_GAIN_MUTE,
2222 AMP_IN_MUTE(0));
2223 snd_hda_codec_write_cache(codec, 0x1d, 0,
2224 AC_VERB_SET_AMP_GAIN_MUTE,
2225 AMP_IN_UNMUTE(1));
bddcf541 2226 }
35b26722
TI
2227 sel = snd_hda_codec_read(codec, 0x0b, 0,
2228 AC_VERB_GET_CONNECT_SEL, 0) + 1;
2229 change |= sel != val;
82beb8fd
TI
2230 if (change)
2231 snd_hda_codec_write_cache(codec, 0x0b, 0,
2232 AC_VERB_SET_CONNECT_SEL,
2233 val - 1);
fd66e0d0
TI
2234 }
2235 return change;
2236}
2237
2238static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
2239 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2240 {
2241 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2242 .name = "IEC958 Playback Source",
2243 .info = ad1988_spdif_playback_source_info,
2244 .get = ad1988_spdif_playback_source_get,
2245 .put = ad1988_spdif_playback_source_put,
2246 },
2247 { } /* end */
2248};
2249
2250static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
2251 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
2252 { } /* end */
2253};
2254
3adb8abc
TI
2255static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
2256 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
9cae0c63 2257 HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
3adb8abc
TI
2258 { } /* end */
2259};
fd66e0d0
TI
2260
2261/*
2262 * initialization verbs
2263 */
2264
2265/*
2266 * for 6-stack (+dig)
2267 */
2268static struct hda_verb ad1988_6stack_init_verbs[] = {
2e5b9567
TI
2269 /* Front, Surround, CLFE, side DAC; unmute as default */
2270 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2271 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2272 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2273 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
fd66e0d0
TI
2274 /* Port-A front headphon path */
2275 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2276 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2277 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2278 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2279 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2280 /* Port-D line-out path */
2281 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2282 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2283 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2284 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2285 /* Port-F surround path */
2286 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2287 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2288 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2289 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2290 /* Port-G CLFE path */
2291 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2292 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2293 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2294 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2295 /* Port-H side path */
2296 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2297 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2298 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2299 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2300 /* Mono out path */
2301 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2302 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2303 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2304 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2305 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2306 /* Port-B front mic-in path */
2307 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2308 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2309 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2310 /* Port-C line-in path */
2311 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2312 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2313 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2314 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2315 /* Port-E mic-in path */
2316 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2317 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2318 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2319 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
695005cf
JS
2320 /* Analog CD Input */
2321 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
db3da6c1
TI
2322 /* Analog Mix output amp */
2323 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
fd66e0d0
TI
2324
2325 { }
2326};
2327
2328static struct hda_verb ad1988_capture_init_verbs[] = {
2329 /* mute analog mix */
2330 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2331 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2332 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2333 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2334 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2335 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2336 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2337 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2338 /* select ADCs - front-mic */
2339 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2340 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2341 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
fd66e0d0
TI
2342
2343 { }
2344};
2345
2346static struct hda_verb ad1988_spdif_init_verbs[] = {
2347 /* SPDIF out sel */
2348 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
2349 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
2350 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
bddcf541 2351 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
fd66e0d0
TI
2352 /* SPDIF out pin */
2353 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
fd66e0d0
TI
2354
2355 { }
2356};
2357
3adb8abc
TI
2358/* AD1989 has no ADC -> SPDIF route */
2359static struct hda_verb ad1989_spdif_init_verbs[] = {
e8bfc6c1
RJ
2360 /* SPDIF-1 out pin */
2361 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3adb8abc 2362 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
e8bfc6c1
RJ
2363 /* SPDIF-2/HDMI out pin */
2364 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2365 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3adb8abc
TI
2366 { }
2367};
2368
fd66e0d0
TI
2369/*
2370 * verbs for 3stack (+dig)
2371 */
2372static struct hda_verb ad1988_3stack_ch2_init[] = {
2373 /* set port-C to line-in */
2374 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2375 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2376 /* set port-E to mic-in */
2377 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2378 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2379 { } /* end */
2380};
2381
2382static struct hda_verb ad1988_3stack_ch6_init[] = {
2383 /* set port-C to surround out */
fd66e0d0 2384 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
d32410b1 2385 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
fd66e0d0 2386 /* set port-E to CLFE out */
fd66e0d0 2387 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
d32410b1 2388 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
fd66e0d0
TI
2389 { } /* end */
2390};
2391
2392static struct hda_channel_mode ad1988_3stack_modes[2] = {
2393 { 2, ad1988_3stack_ch2_init },
2394 { 6, ad1988_3stack_ch6_init },
2395};
2396
2397static struct hda_verb ad1988_3stack_init_verbs[] = {
2e5b9567
TI
2398 /* Front, Surround, CLFE, side DAC; unmute as default */
2399 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2400 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2401 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2402 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
fd66e0d0
TI
2403 /* Port-A front headphon path */
2404 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2405 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2406 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2407 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2408 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2409 /* Port-D line-out path */
2410 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2411 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2412 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2413 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2414 /* Mono out path */
2415 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2416 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2417 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2418 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2419 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2420 /* Port-B front mic-in path */
2421 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2422 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2423 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
d32410b1
TI
2424 /* Port-C line-in/surround path - 6ch mode as default */
2425 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2426 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
fd66e0d0 2427 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
d32410b1 2428 {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
fd66e0d0 2429 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
d32410b1
TI
2430 /* Port-E mic-in/CLFE path - 6ch mode as default */
2431 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2432 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
fd66e0d0 2433 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
f8c7c7b8 2434 {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
fd66e0d0
TI
2435 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2436 /* mute analog mix */
2437 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2438 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2439 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2440 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2441 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2442 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2443 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2444 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2445 /* select ADCs - front-mic */
2446 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2447 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2448 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
db3da6c1
TI
2449 /* Analog Mix output amp */
2450 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
fd66e0d0
TI
2451 { }
2452};
2453
2454/*
2455 * verbs for laptop mode (+dig)
2456 */
2457static struct hda_verb ad1988_laptop_hp_on[] = {
2458 /* unmute port-A and mute port-D */
2459 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2460 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2461 { } /* end */
2462};
2463static struct hda_verb ad1988_laptop_hp_off[] = {
2464 /* mute port-A and unmute port-D */
2465 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2466 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2467 { } /* end */
2468};
2469
2470#define AD1988_HP_EVENT 0x01
2471
2472static struct hda_verb ad1988_laptop_init_verbs[] = {
2e5b9567
TI
2473 /* Front, Surround, CLFE, side DAC; unmute as default */
2474 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2475 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2476 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2477 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
fd66e0d0
TI
2478 /* Port-A front headphon path */
2479 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2480 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2481 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2482 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2483 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2484 /* unsolicited event for pin-sense */
2485 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
2486 /* Port-D line-out path + EAPD */
2487 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2488 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2489 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2490 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2491 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
2492 /* Mono out path */
2493 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2494 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2495 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2496 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2497 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2498 /* Port-B mic-in path */
2499 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2500 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2501 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2502 /* Port-C docking station - try to output */
2503 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2504 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2505 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2506 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2507 /* mute analog mix */
2508 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2509 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2510 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2511 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2512 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2513 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2514 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2515 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2516 /* select ADCs - mic */
2517 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2518 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2519 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
db3da6c1
TI
2520 /* Analog Mix output amp */
2521 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
fd66e0d0
TI
2522 { }
2523};
2524
2525static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
2526{
2527 if ((res >> 26) != AD1988_HP_EVENT)
2528 return;
2529 if (snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & (1 << 31))
2530 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
2531 else
2532 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
2533}
2534
cb53c626
TI
2535#ifdef CONFIG_SND_HDA_POWER_SAVE
2536static struct hda_amp_list ad1988_loopbacks[] = {
2537 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
2538 { 0x20, HDA_INPUT, 1 }, /* Line */
2539 { 0x20, HDA_INPUT, 4 }, /* Mic */
2540 { 0x20, HDA_INPUT, 6 }, /* CD */
2541 { } /* end */
2542};
2543#endif
fd66e0d0 2544
d32410b1
TI
2545/*
2546 * Automatic parse of I/O pins from the BIOS configuration
2547 */
2548
d32410b1
TI
2549enum {
2550 AD_CTL_WIDGET_VOL,
2551 AD_CTL_WIDGET_MUTE,
2552 AD_CTL_BIND_MUTE,
2553};
2554static struct snd_kcontrol_new ad1988_control_templates[] = {
2555 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2556 HDA_CODEC_MUTE(NULL, 0, 0, 0),
2557 HDA_BIND_MUTE(NULL, 0, 0, 0),
2558};
2559
2560/* add dynamic controls */
2561static int add_control(struct ad198x_spec *spec, int type, const char *name,
2562 unsigned long val)
2563{
2564 struct snd_kcontrol_new *knew;
2565
603c4019
TI
2566 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2567 knew = snd_array_new(&spec->kctls);
2568 if (!knew)
2569 return -ENOMEM;
d32410b1
TI
2570 *knew = ad1988_control_templates[type];
2571 knew->name = kstrdup(name, GFP_KERNEL);
2572 if (! knew->name)
2573 return -ENOMEM;
4d02d1b6
JK
2574 if (get_amp_nid_(val))
2575 knew->subdevice = (1<<31)|get_amp_nid_(val);
d32410b1 2576 knew->private_value = val;
d32410b1
TI
2577 return 0;
2578}
2579
2580#define AD1988_PIN_CD_NID 0x18
2581#define AD1988_PIN_BEEP_NID 0x10
2582
2583static hda_nid_t ad1988_mixer_nids[8] = {
2584 /* A B C D E F G H */
2585 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28
2586};
2587
2588static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
2589{
2590 static hda_nid_t idx_to_dac[8] = {
2591 /* A B C D E F G H */
f8c7c7b8 2592 0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
d32410b1
TI
2593 };
2594 static hda_nid_t idx_to_dac_rev2[8] = {
2595 /* A B C D E F G H */
f8c7c7b8 2596 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
d32410b1 2597 };
1a806f48 2598 if (is_rev2(codec))
d32410b1
TI
2599 return idx_to_dac_rev2[idx];
2600 else
2601 return idx_to_dac[idx];
2602}
2603
2604static hda_nid_t ad1988_boost_nids[8] = {
2605 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0
2606};
2607
2608static int ad1988_pin_idx(hda_nid_t nid)
2609{
2610 static hda_nid_t ad1988_io_pins[8] = {
2611 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25
2612 };
2613 int i;
2614 for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++)
2615 if (ad1988_io_pins[i] == nid)
2616 return i;
2617 return 0; /* should be -1 */
2618}
2619
2620static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
2621{
2622 static int loopback_idx[8] = {
2623 2, 0, 1, 3, 4, 5, 1, 4
2624 };
2625 switch (nid) {
2626 case AD1988_PIN_CD_NID:
2627 return 6;
2628 default:
2629 return loopback_idx[ad1988_pin_idx(nid)];
2630 }
2631}
2632
2633static int ad1988_pin_to_adc_idx(hda_nid_t nid)
2634{
2635 static int adc_idx[8] = {
2636 0, 1, 2, 8, 4, 3, 6, 7
2637 };
2638 switch (nid) {
2639 case AD1988_PIN_CD_NID:
2640 return 5;
2641 default:
2642 return adc_idx[ad1988_pin_idx(nid)];
2643 }
2644}
2645
2646/* fill in the dac_nids table from the parsed pin configuration */
2647static int ad1988_auto_fill_dac_nids(struct hda_codec *codec,
2648 const struct auto_pin_cfg *cfg)
2649{
2650 struct ad198x_spec *spec = codec->spec;
2651 int i, idx;
2652
2653 spec->multiout.dac_nids = spec->private_dac_nids;
2654
2655 /* check the pins hardwired to audio widget */
2656 for (i = 0; i < cfg->line_outs; i++) {
2657 idx = ad1988_pin_idx(cfg->line_out_pins[i]);
2658 spec->multiout.dac_nids[i] = ad1988_idx_to_dac(codec, idx);
2659 }
2660 spec->multiout.num_dacs = cfg->line_outs;
2661 return 0;
2662}
2663
2664/* add playback controls from the parsed DAC table */
2665static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec,
2666 const struct auto_pin_cfg *cfg)
2667{
2668 char name[32];
2669 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
2670 hda_nid_t nid;
2671 int i, err;
2672
2673 for (i = 0; i < cfg->line_outs; i++) {
2674 hda_nid_t dac = spec->multiout.dac_nids[i];
2675 if (! dac)
2676 continue;
2677 nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])];
2678 if (i == 2) {
2679 /* Center/LFE */
2680 err = add_control(spec, AD_CTL_WIDGET_VOL,
2681 "Center Playback Volume",
2682 HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT));
2683 if (err < 0)
2684 return err;
2685 err = add_control(spec, AD_CTL_WIDGET_VOL,
2686 "LFE Playback Volume",
2687 HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT));
2688 if (err < 0)
2689 return err;
2690 err = add_control(spec, AD_CTL_BIND_MUTE,
2691 "Center Playback Switch",
2692 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT));
2693 if (err < 0)
2694 return err;
2695 err = add_control(spec, AD_CTL_BIND_MUTE,
2696 "LFE Playback Switch",
2697 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT));
2698 if (err < 0)
2699 return err;
2700 } else {
2701 sprintf(name, "%s Playback Volume", chname[i]);
2702 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2703 HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT));
2704 if (err < 0)
2705 return err;
2706 sprintf(name, "%s Playback Switch", chname[i]);
2707 err = add_control(spec, AD_CTL_BIND_MUTE, name,
2708 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
2709 if (err < 0)
2710 return err;
2711 }
2712 }
2713 return 0;
2714}
2715
2716/* add playback controls for speaker and HP outputs */
2717static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
2718 const char *pfx)
2719{
2720 struct ad198x_spec *spec = codec->spec;
2721 hda_nid_t nid;
43785eae 2722 int i, idx, err;
d32410b1
TI
2723 char name[32];
2724
2725 if (! pin)
2726 return 0;
2727
2728 idx = ad1988_pin_idx(pin);
2729 nid = ad1988_idx_to_dac(codec, idx);
43785eae
TI
2730 /* check whether the corresponding DAC was already taken */
2731 for (i = 0; i < spec->autocfg.line_outs; i++) {
2732 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2733 hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin));
2734 if (dac == nid)
2735 break;
2736 }
2737 if (i >= spec->autocfg.line_outs) {
2738 /* specify the DAC as the extra output */
2739 if (!spec->multiout.hp_nid)
2740 spec->multiout.hp_nid = nid;
2741 else
2742 spec->multiout.extra_out_nid[0] = nid;
2743 /* control HP volume/switch on the output mixer amp */
2744 sprintf(name, "%s Playback Volume", pfx);
2745 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2746 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2747 if (err < 0)
2748 return err;
2749 }
d32410b1
TI
2750 nid = ad1988_mixer_nids[idx];
2751 sprintf(name, "%s Playback Switch", pfx);
2752 if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,
2753 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
2754 return err;
2755 return 0;
2756}
2757
2758/* create input playback/capture controls for the given pin */
2759static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
2760 const char *ctlname, int boost)
2761{
2762 char name[32];
2763 int err, idx;
2764
2765 sprintf(name, "%s Playback Volume", ctlname);
2766 idx = ad1988_pin_to_loopback_idx(pin);
2767 if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2768 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2769 return err;
2770 sprintf(name, "%s Playback Switch", ctlname);
2771 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name,
2772 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2773 return err;
2774 if (boost) {
2775 hda_nid_t bnid;
2776 idx = ad1988_pin_idx(pin);
2777 bnid = ad1988_boost_nids[idx];
2778 if (bnid) {
2779 sprintf(name, "%s Boost", ctlname);
2780 return add_control(spec, AD_CTL_WIDGET_VOL, name,
2781 HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));
2782
2783 }
2784 }
2785 return 0;
2786}
2787
2788/* create playback/capture controls for input pins */
2789static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec,
2790 const struct auto_pin_cfg *cfg)
2791{
d32410b1
TI
2792 struct hda_input_mux *imux = &spec->private_imux;
2793 int i, err;
2794
2795 for (i = 0; i < AUTO_PIN_LAST; i++) {
4a471b7d
TI
2796 err = new_analog_input(spec, cfg->input_pins[i],
2797 auto_pin_cfg_labels[i],
d32410b1
TI
2798 i <= AUTO_PIN_FRONT_MIC);
2799 if (err < 0)
2800 return err;
4a471b7d 2801 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
d32410b1
TI
2802 imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);
2803 imux->num_items++;
2804 }
2805 imux->items[imux->num_items].label = "Mix";
2806 imux->items[imux->num_items].index = 9;
2807 imux->num_items++;
2808
2809 if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
2810 "Analog Mix Playback Volume",
2811 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
2812 return err;
2813 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE,
2814 "Analog Mix Playback Switch",
2815 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
2816 return err;
2817
2818 return 0;
2819}
2820
2821static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
2822 hda_nid_t nid, int pin_type,
2823 int dac_idx)
2824{
2825 /* set as output */
2826 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
2827 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
2828 switch (nid) {
2829 case 0x11: /* port-A - DAC 04 */
2830 snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2831 break;
2832 case 0x14: /* port-B - DAC 06 */
2833 snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02);
2834 break;
2835 case 0x15: /* port-C - DAC 05 */
2836 snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00);
2837 break;
f8c7c7b8 2838 case 0x17: /* port-E - DAC 0a */
d32410b1
TI
2839 snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2840 break;
2841 case 0x13: /* mono - DAC 04 */
2842 snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2843 break;
2844 }
2845}
2846
2847static void ad1988_auto_init_multi_out(struct hda_codec *codec)
2848{
2849 struct ad198x_spec *spec = codec->spec;
2850 int i;
2851
2852 for (i = 0; i < spec->autocfg.line_outs; i++) {
2853 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2854 ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
2855 }
2856}
2857
2858static void ad1988_auto_init_extra_out(struct hda_codec *codec)
2859{
2860 struct ad198x_spec *spec = codec->spec;
2861 hda_nid_t pin;
2862
82bc955f 2863 pin = spec->autocfg.speaker_pins[0];
d32410b1
TI
2864 if (pin) /* connect to front */
2865 ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
eb06ed8f 2866 pin = spec->autocfg.hp_pins[0];
d32410b1
TI
2867 if (pin) /* connect to front */
2868 ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
2869}
2870
2871static void ad1988_auto_init_analog_input(struct hda_codec *codec)
2872{
2873 struct ad198x_spec *spec = codec->spec;
2874 int i, idx;
2875
2876 for (i = 0; i < AUTO_PIN_LAST; i++) {
2877 hda_nid_t nid = spec->autocfg.input_pins[i];
2878 if (! nid)
2879 continue;
2880 switch (nid) {
2881 case 0x15: /* port-C */
2882 snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
2883 break;
2884 case 0x17: /* port-E */
2885 snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
2886 break;
2887 }
2888 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2889 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
2890 if (nid != AD1988_PIN_CD_NID)
2891 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
2892 AMP_OUT_MUTE);
2893 idx = ad1988_pin_idx(nid);
2894 if (ad1988_boost_nids[idx])
2895 snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0,
2896 AC_VERB_SET_AMP_GAIN_MUTE,
2897 AMP_OUT_ZERO);
2898 }
2899}
2900
2901/* parse the BIOS configuration and set up the alc_spec */
2902/* return 1 if successful, 0 if the proper config is not found, or a negative error code */
2903static int ad1988_parse_auto_config(struct hda_codec *codec)
2904{
2905 struct ad198x_spec *spec = codec->spec;
2906 int err;
2907
df694daa 2908 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
d32410b1
TI
2909 return err;
2910 if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2911 return err;
82bc955f 2912 if (! spec->autocfg.line_outs)
d32410b1
TI
2913 return 0; /* can't find valid BIOS pin config */
2914 if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
82bc955f
TI
2915 (err = ad1988_auto_create_extra_out(codec,
2916 spec->autocfg.speaker_pins[0],
d32410b1 2917 "Speaker")) < 0 ||
eb06ed8f 2918 (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
d32410b1
TI
2919 "Headphone")) < 0 ||
2920 (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
2921 return err;
2922
2923 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2924
0852d7a6 2925 if (spec->autocfg.dig_outs)
d32410b1
TI
2926 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
2927 if (spec->autocfg.dig_in_pin)
2928 spec->dig_in_nid = AD1988_SPDIF_IN;
2929
603c4019
TI
2930 if (spec->kctls.list)
2931 spec->mixers[spec->num_mixers++] = spec->kctls.list;
d32410b1
TI
2932
2933 spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
2934
2935 spec->input_mux = &spec->private_imux;
2936
2937 return 1;
2938}
2939
2940/* init callback for auto-configuration model -- overriding the default init */
2941static int ad1988_auto_init(struct hda_codec *codec)
2942{
2943 ad198x_init(codec);
2944 ad1988_auto_init_multi_out(codec);
2945 ad1988_auto_init_extra_out(codec);
2946 ad1988_auto_init_analog_input(codec);
2947 return 0;
2948}
2949
2950
fd66e0d0
TI
2951/*
2952 */
2953
f5fcc13c
TI
2954static const char *ad1988_models[AD1988_MODEL_LAST] = {
2955 [AD1988_6STACK] = "6stack",
2956 [AD1988_6STACK_DIG] = "6stack-dig",
2957 [AD1988_3STACK] = "3stack",
2958 [AD1988_3STACK_DIG] = "3stack-dig",
2959 [AD1988_LAPTOP] = "laptop",
2960 [AD1988_LAPTOP_DIG] = "laptop-dig",
2961 [AD1988_AUTO] = "auto",
fd66e0d0
TI
2962};
2963
a64c8cd6 2964static struct snd_pci_quirk ad1988_cfg_tbl[] = {
18768991 2965 SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
ac3e3741 2966 SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
b9e16bc5 2967 SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
f51ff993 2968 SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
a64c8cd6
TD
2969 {}
2970};
2971
fd66e0d0
TI
2972static int patch_ad1988(struct hda_codec *codec)
2973{
2974 struct ad198x_spec *spec;
c5a4bcd0 2975 int err, board_config;
fd66e0d0
TI
2976
2977 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2978 if (spec == NULL)
2979 return -ENOMEM;
2980
fd66e0d0
TI
2981 codec->spec = spec;
2982
1a806f48 2983 if (is_rev2(codec))
f8c7c7b8
TI
2984 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
2985
f5fcc13c 2986 board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
a64c8cd6 2987 ad1988_models, ad1988_cfg_tbl);
f5fcc13c 2988 if (board_config < 0) {
9a11f1aa
TI
2989 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
2990 codec->chip_name);
d32410b1
TI
2991 board_config = AD1988_AUTO;
2992 }
2993
2994 if (board_config == AD1988_AUTO) {
2995 /* automatic parse from the BIOS config */
c5a4bcd0 2996 err = ad1988_parse_auto_config(codec);
d32410b1
TI
2997 if (err < 0) {
2998 ad198x_free(codec);
2999 return err;
3000 } else if (! err) {
3001 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n");
3002 board_config = AD1988_6STACK;
3003 }
fd66e0d0
TI
3004 }
3005
c5a4bcd0
TI
3006 err = snd_hda_attach_beep_device(codec, 0x10);
3007 if (err < 0) {
3008 ad198x_free(codec);
3009 return err;
3010 }
3011 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3012
fd66e0d0
TI
3013 switch (board_config) {
3014 case AD1988_6STACK:
3015 case AD1988_6STACK_DIG:
3016 spec->multiout.max_channels = 8;
3017 spec->multiout.num_dacs = 4;
1a806f48 3018 if (is_rev2(codec))
d32410b1
TI
3019 spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
3020 else
3021 spec->multiout.dac_nids = ad1988_6stack_dac_nids;
fd66e0d0 3022 spec->input_mux = &ad1988_6stack_capture_source;
d32410b1 3023 spec->num_mixers = 2;
1a806f48 3024 if (is_rev2(codec))
d32410b1
TI
3025 spec->mixers[0] = ad1988_6stack_mixers1_rev2;
3026 else
3027 spec->mixers[0] = ad1988_6stack_mixers1;
3028 spec->mixers[1] = ad1988_6stack_mixers2;
fd66e0d0
TI
3029 spec->num_init_verbs = 1;
3030 spec->init_verbs[0] = ad1988_6stack_init_verbs;
3031 if (board_config == AD1988_6STACK_DIG) {
3032 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3033 spec->dig_in_nid = AD1988_SPDIF_IN;
3034 }
3035 break;
3036 case AD1988_3STACK:
3037 case AD1988_3STACK_DIG:
3038 spec->multiout.max_channels = 6;
3039 spec->multiout.num_dacs = 3;
1a806f48 3040 if (is_rev2(codec))
d32410b1
TI
3041 spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
3042 else
3043 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
fd66e0d0
TI
3044 spec->input_mux = &ad1988_6stack_capture_source;
3045 spec->channel_mode = ad1988_3stack_modes;
3046 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
d32410b1 3047 spec->num_mixers = 2;
1a806f48 3048 if (is_rev2(codec))
d32410b1
TI
3049 spec->mixers[0] = ad1988_3stack_mixers1_rev2;
3050 else
3051 spec->mixers[0] = ad1988_3stack_mixers1;
3052 spec->mixers[1] = ad1988_3stack_mixers2;
fd66e0d0
TI
3053 spec->num_init_verbs = 1;
3054 spec->init_verbs[0] = ad1988_3stack_init_verbs;
3055 if (board_config == AD1988_3STACK_DIG)
3056 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3057 break;
3058 case AD1988_LAPTOP:
3059 case AD1988_LAPTOP_DIG:
3060 spec->multiout.max_channels = 2;
3061 spec->multiout.num_dacs = 1;
d32410b1 3062 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
fd66e0d0
TI
3063 spec->input_mux = &ad1988_laptop_capture_source;
3064 spec->num_mixers = 1;
3065 spec->mixers[0] = ad1988_laptop_mixers;
3066 spec->num_init_verbs = 1;
3067 spec->init_verbs[0] = ad1988_laptop_init_verbs;
3068 if (board_config == AD1988_LAPTOP_DIG)
3069 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3070 break;
3071 }
3072
d32410b1
TI
3073 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
3074 spec->adc_nids = ad1988_adc_nids;
3075 spec->capsrc_nids = ad1988_capsrc_nids;
fd66e0d0
TI
3076 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
3077 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
3078 if (spec->multiout.dig_out_nid) {
3adb8abc
TI
3079 if (codec->vendor_id >= 0x11d4989a) {
3080 spec->mixers[spec->num_mixers++] =
3081 ad1989_spdif_out_mixers;
3082 spec->init_verbs[spec->num_init_verbs++] =
3083 ad1989_spdif_init_verbs;
9cae0c63 3084 codec->slave_dig_outs = ad1989b_slave_dig_outs;
3adb8abc
TI
3085 } else {
3086 spec->mixers[spec->num_mixers++] =
3087 ad1988_spdif_out_mixers;
3088 spec->init_verbs[spec->num_init_verbs++] =
3089 ad1988_spdif_init_verbs;
3090 }
fd66e0d0 3091 }
3adb8abc 3092 if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a)
fd66e0d0
TI
3093 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
3094
3095 codec->patch_ops = ad198x_patch_ops;
3096 switch (board_config) {
d32410b1
TI
3097 case AD1988_AUTO:
3098 codec->patch_ops.init = ad1988_auto_init;
3099 break;
fd66e0d0
TI
3100 case AD1988_LAPTOP:
3101 case AD1988_LAPTOP_DIG:
3102 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
3103 break;
3104 }
cb53c626
TI
3105#ifdef CONFIG_SND_HDA_POWER_SAVE
3106 spec->loopback.amplist = ad1988_loopbacks;
3107#endif
2134ea4f 3108 spec->vmaster_nid = 0x04;
fd66e0d0
TI
3109
3110 return 0;
3111}
3112
3113
2bac647c
TI
3114/*
3115 * AD1884 / AD1984
3116 *
3117 * port-B - front line/mic-in
3118 * port-E - aux in/out
3119 * port-F - aux in/out
3120 * port-C - rear line/mic-in
3121 * port-D - rear line/hp-out
3122 * port-A - front line/hp-out
3123 *
3124 * AD1984 = AD1884 + two digital mic-ins
3125 *
3126 * FIXME:
3127 * For simplicity, we share the single DAC for both HP and line-outs
3128 * right now. The inidividual playbacks could be easily implemented,
3129 * but no build-up framework is given, so far.
3130 */
3131
3132static hda_nid_t ad1884_dac_nids[1] = {
3133 0x04,
3134};
3135
3136static hda_nid_t ad1884_adc_nids[2] = {
3137 0x08, 0x09,
3138};
3139
3140static hda_nid_t ad1884_capsrc_nids[2] = {
3141 0x0c, 0x0d,
3142};
3143
3144#define AD1884_SPDIF_OUT 0x02
3145
3146static struct hda_input_mux ad1884_capture_source = {
3147 .num_items = 4,
3148 .items = {
3149 { "Front Mic", 0x0 },
3150 { "Mic", 0x1 },
3151 { "CD", 0x2 },
3152 { "Mix", 0x3 },
3153 },
3154};
3155
3156static struct snd_kcontrol_new ad1884_base_mixers[] = {
3157 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3158 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3159 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3160 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3161 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3162 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3163 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3164 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3165 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3166 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3167 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3168 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
2bac647c
TI
3169 HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
3170 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3171 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3172 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3173 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3174 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3175 {
3176 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3177 /* The multiple "Capture Source" controls confuse alsamixer
3178 * So call somewhat different..
2bac647c
TI
3179 */
3180 /* .name = "Capture Source", */
3181 .name = "Input Source",
3182 .count = 2,
3183 .info = ad198x_mux_enum_info,
3184 .get = ad198x_mux_enum_get,
3185 .put = ad198x_mux_enum_put,
3186 },
3187 /* SPDIF controls */
3188 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3189 {
3190 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3191 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3192 /* identical with ad1983 */
3193 .info = ad1983_spdif_route_info,
3194 .get = ad1983_spdif_route_get,
3195 .put = ad1983_spdif_route_put,
3196 },
3197 { } /* end */
3198};
3199
3200static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
3201 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
3202 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
3203 HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
538c49c4 3204 HDA_INPUT),
2bac647c 3205 HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
538c49c4 3206 HDA_INPUT),
2bac647c
TI
3207 { } /* end */
3208};
3209
3210/*
3211 * initialization verbs
3212 */
3213static struct hda_verb ad1884_init_verbs[] = {
3214 /* DACs; mute as default */
3b194401
TI
3215 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3216 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2bac647c
TI
3217 /* Port-A (HP) mixer */
3218 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3219 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3220 /* Port-A pin */
3221 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3222 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3223 /* HP selector - select DAC2 */
3224 {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
3225 /* Port-D (Line-out) mixer */
3226 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3227 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3228 /* Port-D pin */
3229 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3230 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3231 /* Mono-out mixer */
3232 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3233 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3234 /* Mono-out pin */
3235 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3236 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3237 /* Mono selector */
3238 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
3239 /* Port-B (front mic) pin */
3240 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
60e388e8 3241 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2bac647c
TI
3242 /* Port-C (rear mic) pin */
3243 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
60e388e8 3244 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2bac647c
TI
3245 /* Analog mixer; mute as default */
3246 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3247 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3248 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3249 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3250 /* Analog Mix output amp */
3251 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
3252 /* SPDIF output selector */
3253 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
3254 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3255 { } /* end */
3256};
3257
cb53c626
TI
3258#ifdef CONFIG_SND_HDA_POWER_SAVE
3259static struct hda_amp_list ad1884_loopbacks[] = {
3260 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3261 { 0x20, HDA_INPUT, 1 }, /* Mic */
3262 { 0x20, HDA_INPUT, 2 }, /* CD */
3263 { 0x20, HDA_INPUT, 4 }, /* Docking */
3264 { } /* end */
3265};
3266#endif
3267
2134ea4f
TI
3268static const char *ad1884_slave_vols[] = {
3269 "PCM Playback Volume",
3270 "Mic Playback Volume",
3271 "Mono Playback Volume",
3272 "Front Mic Playback Volume",
3273 "Mic Playback Volume",
3274 "CD Playback Volume",
3275 "Internal Mic Playback Volume",
bca68467 3276 "Docking Mic Playback Volume",
c5a4bcd0 3277 /* "Beep Playback Volume", */
4806ef0c 3278 "IEC958 Playback Volume",
2134ea4f
TI
3279 NULL
3280};
3281
2bac647c
TI
3282static int patch_ad1884(struct hda_codec *codec)
3283{
3284 struct ad198x_spec *spec;
c5a4bcd0 3285 int err;
2bac647c
TI
3286
3287 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3288 if (spec == NULL)
3289 return -ENOMEM;
3290
2bac647c
TI
3291 codec->spec = spec;
3292
c5a4bcd0
TI
3293 err = snd_hda_attach_beep_device(codec, 0x10);
3294 if (err < 0) {
3295 ad198x_free(codec);
3296 return err;
3297 }
3298 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3299
2bac647c
TI
3300 spec->multiout.max_channels = 2;
3301 spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
3302 spec->multiout.dac_nids = ad1884_dac_nids;
3303 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3304 spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
3305 spec->adc_nids = ad1884_adc_nids;
3306 spec->capsrc_nids = ad1884_capsrc_nids;
3307 spec->input_mux = &ad1884_capture_source;
3308 spec->num_mixers = 1;
3309 spec->mixers[0] = ad1884_base_mixers;
3310 spec->num_init_verbs = 1;
3311 spec->init_verbs[0] = ad1884_init_verbs;
3312 spec->spdif_route = 0;
cb53c626
TI
3313#ifdef CONFIG_SND_HDA_POWER_SAVE
3314 spec->loopback.amplist = ad1884_loopbacks;
3315#endif
2134ea4f
TI
3316 spec->vmaster_nid = 0x04;
3317 /* we need to cover all playback volumes */
3318 spec->slave_vols = ad1884_slave_vols;
2bac647c
TI
3319
3320 codec->patch_ops = ad198x_patch_ops;
3321
3322 return 0;
3323}
3324
3325/*
3326 * Lenovo Thinkpad T61/X61
3327 */
3328static struct hda_input_mux ad1984_thinkpad_capture_source = {
b26451c0 3329 .num_items = 4,
2bac647c
TI
3330 .items = {
3331 { "Mic", 0x0 },
3332 { "Internal Mic", 0x1 },
3333 { "Mix", 0x3 },
b26451c0 3334 { "Docking-Station", 0x4 },
2bac647c
TI
3335 },
3336};
3337
0aaa22e5
DK
3338
3339/*
3340 * Dell Precision T3400
3341 */
3342static struct hda_input_mux ad1984_dell_desktop_capture_source = {
3343 .num_items = 3,
3344 .items = {
3345 { "Front Mic", 0x0 },
3346 { "Line-In", 0x1 },
3347 { "Mix", 0x3 },
3348 },
3349};
3350
3351
2bac647c
TI
3352static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
3353 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3354 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3355 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3356 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3357 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3358 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3359 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3360 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3361 HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3362 HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
2bac647c
TI
3363 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3364 HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
0ba7962b 3365 HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
2bac647c
TI
3366 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3367 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3368 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3369 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3370 {
3371 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3372 /* The multiple "Capture Source" controls confuse alsamixer
3373 * So call somewhat different..
2bac647c
TI
3374 */
3375 /* .name = "Capture Source", */
3376 .name = "Input Source",
3377 .count = 2,
3378 .info = ad198x_mux_enum_info,
3379 .get = ad198x_mux_enum_get,
3380 .put = ad198x_mux_enum_put,
3381 },
ebf00c54
JY
3382 /* SPDIF controls */
3383 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3384 {
3385 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3386 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3387 /* identical with ad1983 */
3388 .info = ad1983_spdif_route_info,
3389 .get = ad1983_spdif_route_get,
3390 .put = ad1983_spdif_route_put,
3391 },
2bac647c
TI
3392 { } /* end */
3393};
3394
3395/* additional verbs */
3396static struct hda_verb ad1984_thinkpad_init_verbs[] = {
3397 /* Port-E (docking station mic) pin */
3398 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3399 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3400 /* docking mic boost */
70040c07 3401 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2bac647c
TI
3402 /* Analog mixer - docking mic; mute as default */
3403 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
b959d1f8
TI
3404 /* enable EAPD bit */
3405 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
2bac647c
TI
3406 { } /* end */
3407};
3408
0aaa22e5
DK
3409/*
3410 * Dell Precision T3400
3411 */
3412static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
3413 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3414 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3415 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3416 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3417 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3418 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3419 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3420 HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
3421 HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
0aaa22e5
DK
3422 HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
3423 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3424 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3425 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3426 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3427 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3428 {
3429 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3430 /* The multiple "Capture Source" controls confuse alsamixer
3431 * So call somewhat different..
3432 */
3433 /* .name = "Capture Source", */
3434 .name = "Input Source",
3435 .count = 2,
3436 .info = ad198x_mux_enum_info,
3437 .get = ad198x_mux_enum_get,
3438 .put = ad198x_mux_enum_put,
3439 },
3440 { } /* end */
3441};
3442
2bac647c
TI
3443/* Digial MIC ADC NID 0x05 + 0x06 */
3444static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
3445 struct hda_codec *codec,
3446 unsigned int stream_tag,
3447 unsigned int format,
3448 struct snd_pcm_substream *substream)
3449{
3450 snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
3451 stream_tag, 0, format);
3452 return 0;
3453}
3454
3455static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
3456 struct hda_codec *codec,
3457 struct snd_pcm_substream *substream)
3458{
888afa15 3459 snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
2bac647c
TI
3460 return 0;
3461}
3462
3463static struct hda_pcm_stream ad1984_pcm_dmic_capture = {
3464 .substreams = 2,
3465 .channels_min = 2,
3466 .channels_max = 2,
3467 .nid = 0x05,
3468 .ops = {
3469 .prepare = ad1984_pcm_dmic_prepare,
3470 .cleanup = ad1984_pcm_dmic_cleanup
3471 },
3472};
3473
3474static int ad1984_build_pcms(struct hda_codec *codec)
3475{
3476 struct ad198x_spec *spec = codec->spec;
3477 struct hda_pcm *info;
3478 int err;
3479
3480 err = ad198x_build_pcms(codec);
3481 if (err < 0)
3482 return err;
3483
3484 info = spec->pcm_rec + codec->num_pcms;
3485 codec->num_pcms++;
3486 info->name = "AD1984 Digital Mic";
3487 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
3488 return 0;
3489}
3490
3491/* models */
3492enum {
3493 AD1984_BASIC,
3494 AD1984_THINKPAD,
0aaa22e5 3495 AD1984_DELL_DESKTOP,
2bac647c
TI
3496 AD1984_MODELS
3497};
3498
3499static const char *ad1984_models[AD1984_MODELS] = {
3500 [AD1984_BASIC] = "basic",
3501 [AD1984_THINKPAD] = "thinkpad",
0aaa22e5 3502 [AD1984_DELL_DESKTOP] = "dell_desktop",
2bac647c
TI
3503};
3504
3505static struct snd_pci_quirk ad1984_cfg_tbl[] = {
3506 /* Lenovo Thinkpad T61/X61 */
dea0a509 3507 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
0aaa22e5 3508 SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
2bac647c
TI
3509 {}
3510};
3511
3512static int patch_ad1984(struct hda_codec *codec)
3513{
3514 struct ad198x_spec *spec;
3515 int board_config, err;
3516
3517 err = patch_ad1884(codec);
3518 if (err < 0)
3519 return err;
3520 spec = codec->spec;
3521 board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
3522 ad1984_models, ad1984_cfg_tbl);
3523 switch (board_config) {
3524 case AD1984_BASIC:
3525 /* additional digital mics */
3526 spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
3527 codec->patch_ops.build_pcms = ad1984_build_pcms;
3528 break;
3529 case AD1984_THINKPAD:
ebf00c54 3530 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
2bac647c
TI
3531 spec->input_mux = &ad1984_thinkpad_capture_source;
3532 spec->mixers[0] = ad1984_thinkpad_mixers;
3533 spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
3534 break;
0aaa22e5
DK
3535 case AD1984_DELL_DESKTOP:
3536 spec->multiout.dig_out_nid = 0;
3537 spec->input_mux = &ad1984_dell_desktop_capture_source;
3538 spec->mixers[0] = ad1984_dell_desktop_mixers;
3539 break;
2bac647c
TI
3540 }
3541 return 0;
3542}
3543
3544
c5059259
TI
3545/*
3546 * AD1883 / AD1884A / AD1984A / AD1984B
3547 *
3548 * port-B (0x14) - front mic-in
3549 * port-E (0x1c) - rear mic-in
3550 * port-F (0x16) - CD / ext out
3551 * port-C (0x15) - rear line-in
3552 * port-D (0x12) - rear line-out
3553 * port-A (0x11) - front hp-out
3554 *
3555 * AD1984A = AD1884A + digital-mic
3556 * AD1883 = equivalent with AD1984A
3557 * AD1984B = AD1984A + extra SPDIF-out
3558 *
3559 * FIXME:
3560 * We share the single DAC for both HP and line-outs (see AD1884/1984).
3561 */
3562
3563static hda_nid_t ad1884a_dac_nids[1] = {
3564 0x03,
3565};
3566
3567#define ad1884a_adc_nids ad1884_adc_nids
3568#define ad1884a_capsrc_nids ad1884_capsrc_nids
3569
3570#define AD1884A_SPDIF_OUT 0x02
3571
3572static struct hda_input_mux ad1884a_capture_source = {
3573 .num_items = 5,
3574 .items = {
3575 { "Front Mic", 0x0 },
3576 { "Mic", 0x4 },
3577 { "Line", 0x1 },
3578 { "CD", 0x2 },
3579 { "Mix", 0x3 },
3580 },
3581};
3582
3583static struct snd_kcontrol_new ad1884a_base_mixers[] = {
3584 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3585 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3586 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3587 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3588 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3589 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3590 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3591 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3592 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3593 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3594 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
3595 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
3596 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3597 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3598 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3599 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
c5059259
TI
3600 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3601 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
3602 HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3603 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3604 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3605 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3606 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3607 {
3608 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3609 /* The multiple "Capture Source" controls confuse alsamixer
3610 * So call somewhat different..
3611 */
3612 /* .name = "Capture Source", */
3613 .name = "Input Source",
3614 .count = 2,
3615 .info = ad198x_mux_enum_info,
3616 .get = ad198x_mux_enum_get,
3617 .put = ad198x_mux_enum_put,
3618 },
3619 /* SPDIF controls */
3620 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3621 {
3622 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3623 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3624 /* identical with ad1983 */
3625 .info = ad1983_spdif_route_info,
3626 .get = ad1983_spdif_route_get,
3627 .put = ad1983_spdif_route_put,
3628 },
3629 { } /* end */
3630};
3631
3632/*
3633 * initialization verbs
3634 */
3635static struct hda_verb ad1884a_init_verbs[] = {
3636 /* DACs; unmute as default */
3637 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3638 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3639 /* Port-A (HP) mixer - route only from analog mixer */
3640 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3641 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3642 /* Port-A pin */
3643 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3644 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3645 /* Port-D (Line-out) mixer - route only from analog mixer */
3646 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3647 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3648 /* Port-D pin */
3649 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3650 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3651 /* Mono-out mixer - route only from analog mixer */
3652 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3653 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3654 /* Mono-out pin */
3655 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3656 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3657 /* Port-B (front mic) pin */
3658 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
60e388e8 3659 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
c5059259
TI
3660 /* Port-C (rear line-in) pin */
3661 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
60e388e8 3662 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
c5059259
TI
3663 /* Port-E (rear mic) pin */
3664 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3665 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3666 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
3667 /* Port-F (CD) pin */
3668 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3669 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3670 /* Analog mixer; mute as default */
3671 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3672 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3673 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3674 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3675 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
3676 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
3677 /* Analog Mix output amp */
3678 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3679 /* capture sources */
3680 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
3681 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3682 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
3683 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3684 /* SPDIF output amp */
3685 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3686 { } /* end */
3687};
3688
3689#ifdef CONFIG_SND_HDA_POWER_SAVE
3690static struct hda_amp_list ad1884a_loopbacks[] = {
3691 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3692 { 0x20, HDA_INPUT, 1 }, /* Mic */
3693 { 0x20, HDA_INPUT, 2 }, /* CD */
3694 { 0x20, HDA_INPUT, 4 }, /* Docking */
3695 { } /* end */
3696};
3697#endif
3698
3699/*
3700 * Laptop model
3701 *
3702 * Port A: Headphone jack
3703 * Port B: MIC jack
3704 * Port C: Internal MIC
3705 * Port D: Dock Line Out (if enabled)
3706 * Port E: Dock Line In (if enabled)
3707 * Port F: Internal speakers
3708 */
3709
17bbaa6f
TI
3710static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
3711 struct snd_ctl_elem_value *ucontrol)
3712{
3713 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3714 int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
3715 int mute = (!ucontrol->value.integer.value[0] &&
3716 !ucontrol->value.integer.value[1]);
3717 /* toggle GPIO1 according to the mute state */
3718 snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
3719 mute ? 0x02 : 0x0);
3720 return ret;
3721}
c5059259
TI
3722
3723static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
3724 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
17bbaa6f
TI
3725 {
3726 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3727 .name = "Master Playback Switch",
3728 .info = snd_hda_mixer_amp_switch_info,
3729 .get = snd_hda_mixer_amp_switch_get,
3730 .put = ad1884a_mobile_master_sw_put,
3731 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3732 },
c5059259
TI
3733 HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3734 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3735 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3736 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3737 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3738 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3739 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3740 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3741 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
c5059259
TI
3742 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3743 HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
3744 HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3745 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3746 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
c5059259
TI
3747 { } /* end */
3748};
3749
b40b04ad
TI
3750static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
3751 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
099db17e
TI
3752 /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
3753 {
3754 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3755 .name = "Master Playback Switch",
3756 .info = snd_hda_mixer_amp_switch_info,
3757 .get = snd_hda_mixer_amp_switch_get,
3758 .put = ad1884a_mobile_master_sw_put,
3759 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3760 },
b40b04ad
TI
3761 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3762 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
269ef19c
TI
3763 HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
3764 HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
b40b04ad
TI
3765 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3766 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
b40b04ad
TI
3767 { } /* end */
3768};
3769
c5059259
TI
3770/* mute internal speaker if HP is plugged */
3771static void ad1884a_hp_automute(struct hda_codec *codec)
3772{
3773 unsigned int present;
3774
3775 present = snd_hda_codec_read(codec, 0x11, 0,
3776 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
3777 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
3778 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
3779 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
3780 present ? 0x00 : 0x02);
3781}
3782
269ef19c
TI
3783/* switch to external mic if plugged */
3784static void ad1884a_hp_automic(struct hda_codec *codec)
3785{
3786 unsigned int present;
3787
3788 present = snd_hda_codec_read(codec, 0x14, 0,
3789 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
3790 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
3791 present ? 0 : 1);
3792}
3793
c5059259 3794#define AD1884A_HP_EVENT 0x37
269ef19c 3795#define AD1884A_MIC_EVENT 0x36
c5059259
TI
3796
3797/* unsolicited event for HP jack sensing */
3798static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
3799{
269ef19c
TI
3800 switch (res >> 26) {
3801 case AD1884A_HP_EVENT:
3802 ad1884a_hp_automute(codec);
3803 break;
3804 case AD1884A_MIC_EVENT:
3805 ad1884a_hp_automic(codec);
3806 break;
3807 }
c5059259
TI
3808}
3809
3810/* initialize jack-sensing, too */
3811static int ad1884a_hp_init(struct hda_codec *codec)
3812{
3813 ad198x_init(codec);
3814 ad1884a_hp_automute(codec);
269ef19c 3815 ad1884a_hp_automic(codec);
c5059259
TI
3816 return 0;
3817}
3818
17bbaa6f
TI
3819/* mute internal speaker if HP or docking HP is plugged */
3820static void ad1884a_laptop_automute(struct hda_codec *codec)
3821{
3822 unsigned int present;
3823
3824 present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0);
3825 present &= AC_PINSENSE_PRESENCE;
3826 if (!present) {
3827 present = snd_hda_codec_read(codec, 0x12, 0,
3828 AC_VERB_GET_PIN_SENSE, 0);
3829 present &= AC_PINSENSE_PRESENCE;
3830 }
3831 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
3832 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
3833 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
3834 present ? 0x00 : 0x02);
3835}
3836
3837/* switch to external mic if plugged */
3838static void ad1884a_laptop_automic(struct hda_codec *codec)
3839{
3840 unsigned int idx;
3841
3842 if (snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) &
3843 AC_PINSENSE_PRESENCE)
3844 idx = 0;
3845 else if (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) &
3846 AC_PINSENSE_PRESENCE)
3847 idx = 4;
3848 else
3849 idx = 1;
3850 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
3851}
3852
3853/* unsolicited event for HP jack sensing */
3854static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
3855 unsigned int res)
3856{
3857 switch (res >> 26) {
3858 case AD1884A_HP_EVENT:
3859 ad1884a_laptop_automute(codec);
3860 break;
3861 case AD1884A_MIC_EVENT:
3862 ad1884a_laptop_automic(codec);
3863 break;
3864 }
3865}
3866
3867/* initialize jack-sensing, too */
3868static int ad1884a_laptop_init(struct hda_codec *codec)
3869{
3870 ad198x_init(codec);
3871 ad1884a_laptop_automute(codec);
3872 ad1884a_laptop_automic(codec);
3873 return 0;
3874}
3875
c5059259
TI
3876/* additional verbs for laptop model */
3877static struct hda_verb ad1884a_laptop_verbs[] = {
3878 /* Port-A (HP) pin - always unmuted */
3879 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3880 /* Port-F (int speaker) mixer - route only from analog mixer */
3881 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3882 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
150fe14c
WF
3883 /* Port-F (int speaker) pin */
3884 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
c5059259 3885 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
150fe14c
WF
3886 /* required for compaq 6530s/6531s speaker output */
3887 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
269ef19c
TI
3888 /* Port-C pin - internal mic-in */
3889 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3890 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
3891 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
2ad81ba0
TI
3892 /* Port-D (docking line-out) pin - default unmuted */
3893 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
c5059259
TI
3894 /* analog mix */
3895 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3896 /* unsolicited event for pin-sense */
3897 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
17bbaa6f 3898 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
269ef19c 3899 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
17bbaa6f 3900 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
fe7e5681
TI
3901 /* allow to touch GPIO1 (for mute control) */
3902 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
3903 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
3904 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
c5059259
TI
3905 { } /* end */
3906};
3907
7315613f
TI
3908static struct hda_verb ad1884a_mobile_verbs[] = {
3909 /* DACs; unmute as default */
3910 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3911 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3912 /* Port-A (HP) mixer - route only from analog mixer */
3913 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3914 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3915 /* Port-A pin */
3916 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3917 /* Port-A (HP) pin - always unmuted */
3918 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3919 /* Port-B (mic jack) pin */
3920 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3921 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
3922 /* Port-C (int mic) pin */
3923 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3924 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
3925 /* Port-F (int speaker) mixer - route only from analog mixer */
3926 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3927 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3928 /* Port-F pin */
3929 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3930 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3931 /* Analog mixer; mute as default */
3932 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3933 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3934 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3935 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3936 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3937 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
3938 /* Analog Mix output amp */
3939 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3940 /* capture sources */
3941 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
3942 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3943 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
3944 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3945 /* unsolicited event for pin-sense */
3946 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
3947 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
099db17e
TI
3948 /* allow to touch GPIO1 (for mute control) */
3949 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
3950 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
3951 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
7315613f
TI
3952 { } /* end */
3953};
3954
f081374b
TI
3955/*
3956 * Thinkpad X300
3957 * 0x11 - HP
3958 * 0x12 - speaker
3959 * 0x14 - mic-in
3960 * 0x17 - built-in mic
3961 */
3962
3963static struct hda_verb ad1984a_thinkpad_verbs[] = {
3964 /* HP unmute */
3965 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3966 /* analog mix */
3967 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3968 /* turn on EAPD */
3969 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
3970 /* unsolicited event for pin-sense */
3971 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
3972 /* internal mic - dmic */
3973 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
05808ecc
TI
3974 /* set magic COEFs for dmic */
3975 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
3976 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
f081374b
TI
3977 { } /* end */
3978};
3979
3980static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
3981 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3982 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3983 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3984 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3985 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3986 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
f081374b
TI
3987 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3988 HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
3989 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3990 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3991 {
3992 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3993 .name = "Capture Source",
3994 .info = ad198x_mux_enum_info,
3995 .get = ad198x_mux_enum_get,
3996 .put = ad198x_mux_enum_put,
3997 },
3998 { } /* end */
3999};
4000
4001static struct hda_input_mux ad1984a_thinkpad_capture_source = {
4002 .num_items = 3,
4003 .items = {
4004 { "Mic", 0x0 },
4005 { "Internal Mic", 0x5 },
4006 { "Mix", 0x3 },
4007 },
4008};
4009
4010/* mute internal speaker if HP is plugged */
4011static void ad1984a_thinkpad_automute(struct hda_codec *codec)
4012{
4013 unsigned int present;
4014
4015 present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0)
4016 & AC_PINSENSE_PRESENCE;
4017 snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
4018 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4019}
4020
4021/* unsolicited event for HP jack sensing */
4022static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
4023 unsigned int res)
4024{
4025 if ((res >> 26) != AD1884A_HP_EVENT)
4026 return;
4027 ad1984a_thinkpad_automute(codec);
4028}
4029
4030/* initialize jack-sensing, too */
4031static int ad1984a_thinkpad_init(struct hda_codec *codec)
4032{
4033 ad198x_init(codec);
4034 ad1984a_thinkpad_automute(codec);
4035 return 0;
4036}
4037
a72cb4bc
MB
4038/*
4039 * HP Touchsmart
4040 * port-A (0x11) - front hp-out
4041 * port-B (0x14) - unused
4042 * port-C (0x15) - unused
4043 * port-D (0x12) - rear line out
4044 * port-E (0x1c) - front mic-in
4045 * port-F (0x16) - Internal speakers
4046 * digital-mic (0x17) - Internal mic
4047 */
4048
4049static struct hda_verb ad1984a_touchsmart_verbs[] = {
4050 /* DACs; unmute as default */
4051 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4052 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4053 /* Port-A (HP) mixer - route only from analog mixer */
4054 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4055 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4056 /* Port-A pin */
4057 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4058 /* Port-A (HP) pin - always unmuted */
4059 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4060 /* Port-E (int speaker) mixer - route only from analog mixer */
4061 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
4062 /* Port-E pin */
4063 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4064 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4065 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4066 /* Port-F (int speaker) mixer - route only from analog mixer */
4067 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4068 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4069 /* Port-F pin */
4070 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4071 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4072 /* Analog mixer; mute as default */
4073 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4074 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4075 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4076 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4077 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4078 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4079 /* Analog Mix output amp */
4080 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4081 /* capture sources */
4082 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4083 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4084 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4085 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4086 /* unsolicited event for pin-sense */
4087 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4088 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4089 /* allow to touch GPIO1 (for mute control) */
4090 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4091 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4092 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4093 /* internal mic - dmic */
4094 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4095 /* set magic COEFs for dmic */
4096 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4097 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4098 { } /* end */
4099};
4100
4101static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
4102 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4103/* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
4104 {
4105 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4106 .name = "Master Playback Switch",
4107 .info = snd_hda_mixer_amp_switch_info,
4108 .get = snd_hda_mixer_amp_switch_get,
4109 .put = ad1884a_mobile_master_sw_put,
4110 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4111 },
4112 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4113 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4114 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4115 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4116 HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
4117 HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
4118 { } /* end */
4119};
4120
4121/* switch to external mic if plugged */
4122static void ad1984a_touchsmart_automic(struct hda_codec *codec)
4123{
4124 if (snd_hda_codec_read(codec, 0x1c, 0,
4125 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000) {
4126 snd_hda_codec_write(codec, 0x0c, 0,
4127 AC_VERB_SET_CONNECT_SEL, 0x4);
4128 } else {
4129 snd_hda_codec_write(codec, 0x0c, 0,
4130 AC_VERB_SET_CONNECT_SEL, 0x5);
4131 }
4132}
4133
4134
4135/* unsolicited event for HP jack sensing */
4136static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
4137 unsigned int res)
4138{
4139 switch (res >> 26) {
4140 case AD1884A_HP_EVENT:
4141 ad1884a_hp_automute(codec);
4142 break;
4143 case AD1884A_MIC_EVENT:
4144 ad1984a_touchsmart_automic(codec);
4145 break;
4146 }
4147}
4148
4149/* initialize jack-sensing, too */
4150static int ad1984a_touchsmart_init(struct hda_codec *codec)
4151{
4152 ad198x_init(codec);
4153 ad1884a_hp_automute(codec);
4154 ad1984a_touchsmart_automic(codec);
4155 return 0;
4156}
4157
4158
c5059259
TI
4159/*
4160 */
4161
4162enum {
4163 AD1884A_DESKTOP,
4164 AD1884A_LAPTOP,
b40b04ad 4165 AD1884A_MOBILE,
f081374b 4166 AD1884A_THINKPAD,
a72cb4bc 4167 AD1984A_TOUCHSMART,
c5059259
TI
4168 AD1884A_MODELS
4169};
4170
4171static const char *ad1884a_models[AD1884A_MODELS] = {
4172 [AD1884A_DESKTOP] = "desktop",
4173 [AD1884A_LAPTOP] = "laptop",
b40b04ad 4174 [AD1884A_MOBILE] = "mobile",
f081374b 4175 [AD1884A_THINKPAD] = "thinkpad",
a72cb4bc 4176 [AD1984A_TOUCHSMART] = "touchsmart",
b40b04ad
TI
4177};
4178
4179static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
4180 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
d5337deb 4181 SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
5695ff44 4182 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
c2312756 4183 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
ff848471 4184 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
873dc78a
TI
4185 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
4186 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
286f5875 4187 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
f081374b 4188 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
a72cb4bc 4189 SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
b40b04ad 4190 {}
c5059259
TI
4191};
4192
4193static int patch_ad1884a(struct hda_codec *codec)
4194{
4195 struct ad198x_spec *spec;
c5a4bcd0 4196 int err, board_config;
c5059259
TI
4197
4198 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4199 if (spec == NULL)
4200 return -ENOMEM;
4201
c5059259
TI
4202 codec->spec = spec;
4203
c5a4bcd0
TI
4204 err = snd_hda_attach_beep_device(codec, 0x10);
4205 if (err < 0) {
4206 ad198x_free(codec);
4207 return err;
4208 }
4209 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4210
c5059259
TI
4211 spec->multiout.max_channels = 2;
4212 spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
4213 spec->multiout.dac_nids = ad1884a_dac_nids;
4214 spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
4215 spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
4216 spec->adc_nids = ad1884a_adc_nids;
4217 spec->capsrc_nids = ad1884a_capsrc_nids;
4218 spec->input_mux = &ad1884a_capture_source;
4219 spec->num_mixers = 1;
4220 spec->mixers[0] = ad1884a_base_mixers;
4221 spec->num_init_verbs = 1;
4222 spec->init_verbs[0] = ad1884a_init_verbs;
4223 spec->spdif_route = 0;
4224#ifdef CONFIG_SND_HDA_POWER_SAVE
4225 spec->loopback.amplist = ad1884a_loopbacks;
4226#endif
4227 codec->patch_ops = ad198x_patch_ops;
4228
4229 /* override some parameters */
4230 board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
b40b04ad
TI
4231 ad1884a_models,
4232 ad1884a_cfg_tbl);
c5059259
TI
4233 switch (board_config) {
4234 case AD1884A_LAPTOP:
4235 spec->mixers[0] = ad1884a_laptop_mixers;
4236 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
4237 spec->multiout.dig_out_nid = 0;
17bbaa6f
TI
4238 codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
4239 codec->patch_ops.init = ad1884a_laptop_init;
4dc1f87f
TI
4240 /* set the upper-limit for mixer amp to 0dB for avoiding the
4241 * possible damage by overloading
4242 */
4243 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4244 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4245 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4246 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4247 (1 << AC_AMPCAP_MUTE_SHIFT));
c5059259 4248 break;
b40b04ad
TI
4249 case AD1884A_MOBILE:
4250 spec->mixers[0] = ad1884a_mobile_mixers;
7315613f 4251 spec->init_verbs[0] = ad1884a_mobile_verbs;
b40b04ad 4252 spec->multiout.dig_out_nid = 0;
b40b04ad
TI
4253 codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
4254 codec->patch_ops.init = ad1884a_hp_init;
13c989be
TI
4255 /* set the upper-limit for mixer amp to 0dB for avoiding the
4256 * possible damage by overloading
4257 */
4258 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4259 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4260 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4261 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4262 (1 << AC_AMPCAP_MUTE_SHIFT));
b40b04ad 4263 break;
f081374b
TI
4264 case AD1884A_THINKPAD:
4265 spec->mixers[0] = ad1984a_thinkpad_mixers;
4266 spec->init_verbs[spec->num_init_verbs++] =
4267 ad1984a_thinkpad_verbs;
4268 spec->multiout.dig_out_nid = 0;
4269 spec->input_mux = &ad1984a_thinkpad_capture_source;
4270 codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
4271 codec->patch_ops.init = ad1984a_thinkpad_init;
4272 break;
a72cb4bc
MB
4273 case AD1984A_TOUCHSMART:
4274 spec->mixers[0] = ad1984a_touchsmart_mixers;
4275 spec->init_verbs[0] = ad1984a_touchsmart_verbs;
4276 spec->multiout.dig_out_nid = 0;
4277 codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
4278 codec->patch_ops.init = ad1984a_touchsmart_init;
4279 /* set the upper-limit for mixer amp to 0dB for avoiding the
4280 * possible damage by overloading
4281 */
4282 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4283 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4284 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4285 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4286 (1 << AC_AMPCAP_MUTE_SHIFT));
4287 break;
c5059259
TI
4288 }
4289
4290 return 0;
4291}
4292
4293
0ac8551e 4294/*
9e44c6e4 4295 * AD1882 / AD1882A
0ac8551e
TI
4296 *
4297 * port-A - front hp-out
4298 * port-B - front mic-in
4299 * port-C - rear line-in, shared surr-out (3stack)
4300 * port-D - rear line-out
4301 * port-E - rear mic-in, shared clfe-out (3stack)
4302 * port-F - rear surr-out (6stack)
4303 * port-G - rear clfe-out (6stack)
4304 */
4305
4306static hda_nid_t ad1882_dac_nids[3] = {
4307 0x04, 0x03, 0x05
4308};
4309
4310static hda_nid_t ad1882_adc_nids[2] = {
4311 0x08, 0x09,
4312};
4313
4314static hda_nid_t ad1882_capsrc_nids[2] = {
4315 0x0c, 0x0d,
4316};
4317
4318#define AD1882_SPDIF_OUT 0x02
4319
4320/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
4321static struct hda_input_mux ad1882_capture_source = {
4322 .num_items = 5,
4323 .items = {
4324 { "Front Mic", 0x1 },
4325 { "Mic", 0x4 },
4326 { "Line", 0x2 },
4327 { "CD", 0x3 },
4328 { "Mix", 0x7 },
4329 },
4330};
4331
9e44c6e4
TI
4332/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
4333static struct hda_input_mux ad1882a_capture_source = {
4334 .num_items = 5,
4335 .items = {
4336 { "Front Mic", 0x1 },
4337 { "Mic", 0x4},
4338 { "Line", 0x2 },
4339 { "Digital Mic", 0x06 },
4340 { "Mix", 0x7 },
4341 },
4342};
4343
0ac8551e
TI
4344static struct snd_kcontrol_new ad1882_base_mixers[] = {
4345 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
4346 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
4347 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
4348 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
4349 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
4350 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4351 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
4352 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
9e44c6e4 4353
0ac8551e
TI
4354 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
4355 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
4356 HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
4357 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4358 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4359 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
4360 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
4361 {
4362 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4363 /* The multiple "Capture Source" controls confuse alsamixer
4364 * So call somewhat different..
0ac8551e
TI
4365 */
4366 /* .name = "Capture Source", */
4367 .name = "Input Source",
4368 .count = 2,
4369 .info = ad198x_mux_enum_info,
4370 .get = ad198x_mux_enum_get,
4371 .put = ad198x_mux_enum_put,
4372 },
4373 /* SPDIF controls */
4374 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
4375 {
4376 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4377 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4378 /* identical with ad1983 */
4379 .info = ad1983_spdif_route_info,
4380 .get = ad1983_spdif_route_get,
4381 .put = ad1983_spdif_route_put,
4382 },
4383 { } /* end */
4384};
4385
9e44c6e4
TI
4386static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
4387 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4388 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4389 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4390 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4391 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
4392 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
4393 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4394 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
9e44c6e4
TI
4395 { } /* end */
4396};
4397
4398static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
4399 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4400 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4401 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4402 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4403 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
4404 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
4405 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4406 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
9e44c6e4
TI
4407 HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
4408 { } /* end */
4409};
4410
0ac8551e
TI
4411static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
4412 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
4413 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
4414 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
4415 {
4416 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4417 .name = "Channel Mode",
4418 .info = ad198x_ch_mode_info,
4419 .get = ad198x_ch_mode_get,
4420 .put = ad198x_ch_mode_put,
4421 },
4422 { } /* end */
4423};
4424
4425static struct snd_kcontrol_new ad1882_6stack_mixers[] = {
4426 HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
4427 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
4428 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
4429 { } /* end */
4430};
4431
4432static struct hda_verb ad1882_ch2_init[] = {
4433 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4434 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4435 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4436 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4437 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4438 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4439 { } /* end */
4440};
4441
4442static struct hda_verb ad1882_ch4_init[] = {
4443 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4444 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4445 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4446 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4447 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4448 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4449 { } /* end */
4450};
4451
4452static struct hda_verb ad1882_ch6_init[] = {
4453 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4454 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4455 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4456 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4457 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4458 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4459 { } /* end */
4460};
4461
4462static struct hda_channel_mode ad1882_modes[3] = {
4463 { 2, ad1882_ch2_init },
4464 { 4, ad1882_ch4_init },
4465 { 6, ad1882_ch6_init },
4466};
4467
4468/*
4469 * initialization verbs
4470 */
4471static struct hda_verb ad1882_init_verbs[] = {
4472 /* DACs; mute as default */
4473 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4474 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4475 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4476 /* Port-A (HP) mixer */
4477 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4478 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4479 /* Port-A pin */
4480 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4481 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4482 /* HP selector - select DAC2 */
4483 {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
4484 /* Port-D (Line-out) mixer */
4485 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4486 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4487 /* Port-D pin */
4488 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4489 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4490 /* Mono-out mixer */
4491 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4492 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4493 /* Mono-out pin */
4494 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4495 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4496 /* Port-B (front mic) pin */
4497 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4498 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4499 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4500 /* Port-C (line-in) pin */
4501 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4502 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4503 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4504 /* Port-C mixer - mute as input */
4505 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4506 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4507 /* Port-E (mic-in) pin */
4508 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4509 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4510 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4511 /* Port-E mixer - mute as input */
4512 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4513 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4514 /* Port-F (surround) */
4515 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4516 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4517 /* Port-G (CLFE) */
4518 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4519 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4520 /* Analog mixer; mute as default */
4521 /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
4522 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4523 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4524 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4525 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4526 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4527 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4528 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
4529 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
4530 /* Analog Mix output amp */
4531 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
4532 /* SPDIF output selector */
4533 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4534 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
4535 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4536 { } /* end */
4537};
4538
cb53c626
TI
4539#ifdef CONFIG_SND_HDA_POWER_SAVE
4540static struct hda_amp_list ad1882_loopbacks[] = {
4541 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
4542 { 0x20, HDA_INPUT, 1 }, /* Mic */
4543 { 0x20, HDA_INPUT, 4 }, /* Line */
4544 { 0x20, HDA_INPUT, 6 }, /* CD */
4545 { } /* end */
4546};
4547#endif
4548
0ac8551e
TI
4549/* models */
4550enum {
4551 AD1882_3STACK,
4552 AD1882_6STACK,
4553 AD1882_MODELS
4554};
4555
4556static const char *ad1882_models[AD1986A_MODELS] = {
4557 [AD1882_3STACK] = "3stack",
4558 [AD1882_6STACK] = "6stack",
4559};
4560
4561
4562static int patch_ad1882(struct hda_codec *codec)
4563{
4564 struct ad198x_spec *spec;
c5a4bcd0 4565 int err, board_config;
0ac8551e
TI
4566
4567 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4568 if (spec == NULL)
4569 return -ENOMEM;
4570
0ac8551e
TI
4571 codec->spec = spec;
4572
c5a4bcd0
TI
4573 err = snd_hda_attach_beep_device(codec, 0x10);
4574 if (err < 0) {
4575 ad198x_free(codec);
4576 return err;
4577 }
4578 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4579
0ac8551e
TI
4580 spec->multiout.max_channels = 6;
4581 spec->multiout.num_dacs = 3;
4582 spec->multiout.dac_nids = ad1882_dac_nids;
4583 spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
4584 spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
4585 spec->adc_nids = ad1882_adc_nids;
4586 spec->capsrc_nids = ad1882_capsrc_nids;
c247ed6f 4587 if (codec->vendor_id == 0x11d41882)
9e44c6e4
TI
4588 spec->input_mux = &ad1882_capture_source;
4589 else
4590 spec->input_mux = &ad1882a_capture_source;
4591 spec->num_mixers = 2;
0ac8551e 4592 spec->mixers[0] = ad1882_base_mixers;
c247ed6f 4593 if (codec->vendor_id == 0x11d41882)
9e44c6e4
TI
4594 spec->mixers[1] = ad1882_loopback_mixers;
4595 else
4596 spec->mixers[1] = ad1882a_loopback_mixers;
0ac8551e
TI
4597 spec->num_init_verbs = 1;
4598 spec->init_verbs[0] = ad1882_init_verbs;
4599 spec->spdif_route = 0;
cb53c626
TI
4600#ifdef CONFIG_SND_HDA_POWER_SAVE
4601 spec->loopback.amplist = ad1882_loopbacks;
4602#endif
2134ea4f 4603 spec->vmaster_nid = 0x04;
0ac8551e
TI
4604
4605 codec->patch_ops = ad198x_patch_ops;
4606
4607 /* override some parameters */
4608 board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
4609 ad1882_models, NULL);
4610 switch (board_config) {
4611 default:
4612 case AD1882_3STACK:
9e44c6e4
TI
4613 spec->num_mixers = 3;
4614 spec->mixers[2] = ad1882_3stack_mixers;
0ac8551e
TI
4615 spec->channel_mode = ad1882_modes;
4616 spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
4617 spec->need_dac_fix = 1;
4618 spec->multiout.max_channels = 2;
4619 spec->multiout.num_dacs = 1;
4620 break;
4621 case AD1882_6STACK:
9e44c6e4
TI
4622 spec->num_mixers = 3;
4623 spec->mixers[2] = ad1882_6stack_mixers;
0ac8551e
TI
4624 break;
4625 }
4626 return 0;
4627}
4628
4629
1da177e4
LT
4630/*
4631 * patch entries
4632 */
1289e9e8 4633static struct hda_codec_preset snd_hda_preset_analog[] = {
c5059259 4634 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
0ac8551e 4635 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
c5059259 4636 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
2bac647c 4637 { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
c5059259
TI
4638 { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
4639 { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
4a3fdf3d
TI
4640 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
4641 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
2bac647c 4642 { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
1da177e4 4643 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
fd66e0d0 4644 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
71b2ccc3 4645 { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
9e44c6e4 4646 { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
3adb8abc
TI
4647 { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
4648 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
1da177e4
LT
4649 {} /* terminator */
4650};
1289e9e8
TI
4651
4652MODULE_ALIAS("snd-hda-codec-id:11d4*");
4653
4654MODULE_LICENSE("GPL");
4655MODULE_DESCRIPTION("Analog Devices HD-audio codec");
4656
4657static struct hda_codec_preset_list analog_list = {
4658 .preset = snd_hda_preset_analog,
4659 .owner = THIS_MODULE,
4660};
4661
4662static int __init patch_analog_init(void)
4663{
4664 return snd_hda_add_codec_preset(&analog_list);
4665}
4666
4667static void __exit patch_analog_exit(void)
4668{
4669 snd_hda_delete_codec_preset(&analog_list);
4670}
4671
4672module_init(patch_analog_init)
4673module_exit(patch_analog_exit)