blob: f7ff3f7ccb8e938e7f074afea766495907bc7e1e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Takashi Iwai0ac85512007-06-20 15:46:13 +02002 * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
3 * AD1986A, AD1988
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Takashi Iwai2bac6472007-05-18 18:21:41 +02005 * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 *
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/init.h>
23#include <linux/delay.h>
24#include <linux/slab.h>
25#include <linux/pci.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010026
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <sound/core.h>
28#include "hda_codec.h"
29#include "hda_local.h"
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +010030#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020032struct ad198x_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010033 struct snd_kcontrol_new *mixers[5];
Takashi Iwai985be542005-11-02 18:26:49 +010034 int num_mixers;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +010035 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Takashi Iwaid32410b12005-11-24 16:06:23 +010036 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai985be542005-11-02 18:26:49 +010037 * 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 */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +010046 unsigned int cur_eapd;
Takashi Iwai2125cad2006-03-27 12:52:22 +020047 unsigned int need_dac_fix;
Takashi Iwai985be542005-11-02 18:26:49 +010048
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 */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020055 const struct hda_input_mux *input_mux;
Takashi Iwai2e5b9562005-11-21 16:36:15 +010056 hda_nid_t *capsrc_nids;
Takashi Iwai985be542005-11-02 18:26:49 +010057 unsigned int cur_mux[3];
58
59 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +010060 const struct hda_channel_mode *channel_mode;
Takashi Iwai985be542005-11-02 18:26:49 +010061 int num_channel_mode;
62
63 /* PCM information */
Takashi Iwai2bac6472007-05-18 18:21:41 +020064 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai985be542005-11-02 18:26:49 +010065
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020066 unsigned int spdif_route;
Takashi Iwaid32410b12005-11-24 16:06:23 +010067
68 /* dynamic controls, init_verbs and input_mux */
69 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +020070 struct snd_array kctls;
Takashi Iwaid32410b12005-11-24 16:06:23 +010071 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +020072 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwaicb53c622007-08-10 17:21:45 +020073
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +010074 unsigned int jack_present: 1;
75 unsigned int inv_jack_detect: 1;/* inverted jack-detection */
76 unsigned int inv_eapd: 1; /* inverted EAPD implementation */
77 unsigned int analog_beep: 1; /* analog beep input present */
Takashi Iwai8ab78c72007-09-06 14:29:53 +020078
Takashi Iwaicb53c622007-08-10 17:21:45 +020079#ifdef CONFIG_SND_HDA_POWER_SAVE
80 struct hda_loopback_check loopback;
81#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +010082 /* for virtual master */
83 hda_nid_t vmaster_nid;
Takashi Iwai2134ea42008-01-10 16:53:55 +010084 const char **slave_vols;
85 const char **slave_sws;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086};
87
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020088/*
89 * input MUX handling (common part)
90 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010091static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020092{
93 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
94 struct ad198x_spec *spec = codec->spec;
95
96 return snd_hda_input_mux_info(spec->input_mux, uinfo);
97}
98
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010099static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200100{
101 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
102 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100103 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200104
Takashi Iwai985be542005-11-02 18:26:49 +0100105 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200106 return 0;
107}
108
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100109static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200110{
111 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
112 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100113 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200114
115 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Takashi Iwai2e5b9562005-11-21 16:36:15 +0100116 spec->capsrc_nids[adc_idx],
117 &spec->cur_mux[adc_idx]);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200118}
119
120/*
121 * initialization (common callbacks)
122 */
123static int ad198x_init(struct hda_codec *codec)
124{
125 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100126 int i;
127
128 for (i = 0; i < spec->num_init_verbs; i++)
129 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200130 return 0;
131}
132
Takashi Iwai2134ea42008-01-10 16:53:55 +0100133static const char *ad_slave_vols[] = {
134 "Front Playback Volume",
135 "Surround Playback Volume",
136 "Center Playback Volume",
137 "LFE Playback Volume",
138 "Side Playback Volume",
139 "Headphone Playback Volume",
140 "Mono Playback Volume",
Takashi Iwai628ed132008-01-25 11:56:57 +0100141 "Speaker Playback Volume",
Takashi Iwai4806ef02008-01-26 09:58:13 +0100142 "IEC958 Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100143 NULL
144};
145
146static const char *ad_slave_sws[] = {
147 "Front Playback Switch",
148 "Surround Playback Switch",
149 "Center Playback Switch",
150 "LFE Playback Switch",
151 "Side Playback Switch",
152 "Headphone Playback Switch",
153 "Mono Playback Switch",
Takashi Iwai628ed132008-01-25 11:56:57 +0100154 "Speaker Playback Switch",
Takashi Iwai4806ef02008-01-26 09:58:13 +0100155 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100156 NULL
157};
158
Takashi Iwai603c4012008-07-30 15:01:44 +0200159static void ad198x_free_kctls(struct hda_codec *codec);
160
Takashi Iwai67d634c2009-11-16 15:35:59 +0100161#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100162/* additional beep mixers; the actual parameters are overwritten at build */
163static struct snd_kcontrol_new ad_beep_mixer[] = {
164 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +0200165 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100166 { } /* end */
167};
168
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +0100169static struct snd_kcontrol_new ad_beep2_mixer[] = {
170 HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
171 HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
172 { } /* end */
173};
174
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100175#define set_beep_amp(spec, nid, idx, dir) \
176 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
Takashi Iwai67d634c2009-11-16 15:35:59 +0100177#else
178#define set_beep_amp(spec, nid, idx, dir) /* NOP */
179#endif
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100180
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200181static int ad198x_build_controls(struct hda_codec *codec)
182{
183 struct ad198x_spec *spec = codec->spec;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100184 struct snd_kcontrol *kctl;
Takashi Iwai985be542005-11-02 18:26:49 +0100185 unsigned int i;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200186 int err;
187
Takashi Iwai985be542005-11-02 18:26:49 +0100188 for (i = 0; i < spec->num_mixers; i++) {
189 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
190 if (err < 0)
191 return err;
192 }
193 if (spec->multiout.dig_out_nid) {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200194 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
Takashi Iwai985be542005-11-02 18:26:49 +0100195 if (err < 0)
196 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100197 err = snd_hda_create_spdif_share_sw(codec,
198 &spec->multiout);
199 if (err < 0)
200 return err;
201 spec->multiout.share_spdif = 1;
Takashi Iwai985be542005-11-02 18:26:49 +0100202 }
203 if (spec->dig_in_nid) {
204 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
205 if (err < 0)
206 return err;
207 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100208
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100209 /* create beep controls if needed */
Takashi Iwai67d634c2009-11-16 15:35:59 +0100210#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100211 if (spec->beep_amp) {
212 struct snd_kcontrol_new *knew;
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +0100213 knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
214 for ( ; knew->name; knew++) {
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100215 struct snd_kcontrol *kctl;
216 kctl = snd_ctl_new1(knew, codec);
217 if (!kctl)
218 return -ENOMEM;
219 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +0100220 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100221 if (err < 0)
222 return err;
223 }
224 }
Takashi Iwai67d634c2009-11-16 15:35:59 +0100225#endif
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100226
Takashi Iwai2134ea42008-01-10 16:53:55 +0100227 /* if we have no master control, let's create it */
228 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100229 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +0100230 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100231 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100232 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100233 vmaster_tlv,
Takashi Iwai2134ea42008-01-10 16:53:55 +0100234 (spec->slave_vols ?
235 spec->slave_vols : ad_slave_vols));
236 if (err < 0)
237 return err;
238 }
239 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
240 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
241 NULL,
242 (spec->slave_sws ?
243 spec->slave_sws : ad_slave_sws));
244 if (err < 0)
245 return err;
246 }
247
Takashi Iwai603c4012008-07-30 15:01:44 +0200248 ad198x_free_kctls(codec); /* no longer needed */
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100249
250 /* assign Capture Source enums to NID */
251 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
252 if (!kctl)
253 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
254 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwai21949f02009-12-23 08:31:59 +0100255 err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100256 if (err < 0)
257 return err;
258 }
259
260 /* assign IEC958 enums to NID */
261 kctl = snd_hda_find_mixer_ctl(codec,
262 SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
263 if (kctl) {
264 err = snd_hda_add_nid(codec, kctl, 0,
265 spec->multiout.dig_out_nid);
266 if (err < 0)
267 return err;
268 }
269
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200270 return 0;
271}
272
Takashi Iwaicb53c622007-08-10 17:21:45 +0200273#ifdef CONFIG_SND_HDA_POWER_SAVE
274static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
275{
276 struct ad198x_spec *spec = codec->spec;
277 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
278}
279#endif
280
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200281/*
282 * Analog playback callbacks
283 */
284static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
285 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100286 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200287{
288 struct ad198x_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +0100289 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
290 hinfo);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200291}
292
293static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
294 struct hda_codec *codec,
295 unsigned int stream_tag,
296 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100297 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200298{
299 struct ad198x_spec *spec = codec->spec;
300 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
301 format, substream);
302}
303
304static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
305 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100306 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200307{
308 struct ad198x_spec *spec = codec->spec;
309 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
310}
311
312/*
313 * Digital out
314 */
315static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
316 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100317 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200318{
319 struct ad198x_spec *spec = codec->spec;
320 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
321}
322
323static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
324 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100325 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200326{
327 struct ad198x_spec *spec = codec->spec;
328 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
329}
330
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200331static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
332 struct hda_codec *codec,
333 unsigned int stream_tag,
334 unsigned int format,
335 struct snd_pcm_substream *substream)
336{
337 struct ad198x_spec *spec = codec->spec;
338 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
339 format, substream);
340}
341
Takashi Iwai9411e212009-02-13 11:32:28 +0100342static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
343 struct hda_codec *codec,
344 struct snd_pcm_substream *substream)
345{
346 struct ad198x_spec *spec = codec->spec;
347 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
348}
349
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200350/*
351 * Analog capture
352 */
353static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
354 struct hda_codec *codec,
355 unsigned int stream_tag,
356 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100357 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200358{
359 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100360 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
361 stream_tag, 0, format);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200362 return 0;
363}
364
365static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
366 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100367 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200368{
369 struct ad198x_spec *spec = codec->spec;
Takashi Iwai888afa12008-03-18 09:57:50 +0100370 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200371 return 0;
372}
373
374
375/*
376 */
377static struct hda_pcm_stream ad198x_pcm_analog_playback = {
378 .substreams = 1,
379 .channels_min = 2,
Takashi Iwai985be542005-11-02 18:26:49 +0100380 .channels_max = 6, /* changed later */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200381 .nid = 0, /* fill later */
382 .ops = {
383 .open = ad198x_playback_pcm_open,
384 .prepare = ad198x_playback_pcm_prepare,
385 .cleanup = ad198x_playback_pcm_cleanup
386 },
387};
388
389static struct hda_pcm_stream ad198x_pcm_analog_capture = {
Takashi Iwai985be542005-11-02 18:26:49 +0100390 .substreams = 1,
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200391 .channels_min = 2,
392 .channels_max = 2,
393 .nid = 0, /* fill later */
394 .ops = {
395 .prepare = ad198x_capture_pcm_prepare,
396 .cleanup = ad198x_capture_pcm_cleanup
397 },
398};
399
400static struct hda_pcm_stream ad198x_pcm_digital_playback = {
401 .substreams = 1,
402 .channels_min = 2,
403 .channels_max = 2,
404 .nid = 0, /* fill later */
405 .ops = {
406 .open = ad198x_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200407 .close = ad198x_dig_playback_pcm_close,
Takashi Iwai9411e212009-02-13 11:32:28 +0100408 .prepare = ad198x_dig_playback_pcm_prepare,
409 .cleanup = ad198x_dig_playback_pcm_cleanup
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200410 },
411};
412
Takashi Iwai985be542005-11-02 18:26:49 +0100413static struct hda_pcm_stream ad198x_pcm_digital_capture = {
414 .substreams = 1,
415 .channels_min = 2,
416 .channels_max = 2,
417 /* NID is set in alc_build_pcms */
418};
419
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200420static int ad198x_build_pcms(struct hda_codec *codec)
421{
422 struct ad198x_spec *spec = codec->spec;
423 struct hda_pcm *info = spec->pcm_rec;
424
425 codec->num_pcms = 1;
426 codec->pcm_info = info;
427
428 info->name = "AD198x Analog";
429 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
430 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
431 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
432 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
Takashi Iwai985be542005-11-02 18:26:49 +0100433 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
434 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200435
436 if (spec->multiout.dig_out_nid) {
437 info++;
438 codec->num_pcms++;
439 info->name = "AD198x Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +0100440 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200441 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
442 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
Takashi Iwai985be542005-11-02 18:26:49 +0100443 if (spec->dig_in_nid) {
444 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
445 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
446 }
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200447 }
448
449 return 0;
450}
451
Daniel T Chenea52bf22009-12-27 18:48:29 -0500452static inline void ad198x_shutup(struct hda_codec *codec)
453{
454 snd_hda_shutup_pins(codec);
455}
456
Takashi Iwai603c4012008-07-30 15:01:44 +0200457static void ad198x_free_kctls(struct hda_codec *codec)
458{
459 struct ad198x_spec *spec = codec->spec;
460
461 if (spec->kctls.list) {
462 struct snd_kcontrol_new *kctl = spec->kctls.list;
463 int i;
464 for (i = 0; i < spec->kctls.used; i++)
465 kfree(kctl[i].name);
466 }
467 snd_array_free(&spec->kctls);
468}
469
Daniel T Chenea52bf22009-12-27 18:48:29 -0500470static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
471 hda_nid_t hp)
472{
473 struct ad198x_spec *spec = codec->spec;
474 snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
475 !spec->inv_eapd ? 0x00 : 0x02);
476 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
477 !spec->inv_eapd ? 0x00 : 0x02);
478}
479
480static void ad198x_power_eapd(struct hda_codec *codec)
481{
482 /* We currently only handle front, HP */
483 switch (codec->vendor_id) {
484 case 0x11d41882:
485 case 0x11d4882a:
486 case 0x11d41884:
487 case 0x11d41984:
488 case 0x11d41883:
489 case 0x11d4184a:
490 case 0x11d4194a:
491 case 0x11d4194b:
492 ad198x_power_eapd_write(codec, 0x12, 0x11);
493 break;
494 case 0x11d41981:
495 case 0x11d41983:
496 ad198x_power_eapd_write(codec, 0x05, 0x06);
497 break;
498 case 0x11d41986:
499 ad198x_power_eapd_write(codec, 0x1b, 0x1a);
500 break;
501 case 0x11d41988:
502 case 0x11d4198b:
503 case 0x11d4989a:
504 case 0x11d4989b:
505 ad198x_power_eapd_write(codec, 0x29, 0x22);
506 break;
507 }
508}
509
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200510static void ad198x_free(struct hda_codec *codec)
511{
Takashi Iwaid32410b12005-11-24 16:06:23 +0100512 struct ad198x_spec *spec = codec->spec;
Takashi Iwaid32410b12005-11-24 16:06:23 +0100513
Takashi Iwai603c4012008-07-30 15:01:44 +0200514 if (!spec)
515 return;
516
Daniel T Chenea52bf22009-12-27 18:48:29 -0500517 ad198x_shutup(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +0200518 ad198x_free_kctls(codec);
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100519 kfree(spec);
520 snd_hda_detach_beep_device(codec);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200521}
522
Daniel T Chenea52bf22009-12-27 18:48:29 -0500523#ifdef SND_HDA_NEEDS_RESUME
524static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
525{
526 ad198x_shutup(codec);
527 ad198x_power_eapd(codec);
528 return 0;
529}
Daniel T Chenea52bf22009-12-27 18:48:29 -0500530#endif
531
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200532static struct hda_codec_ops ad198x_patch_ops = {
533 .build_controls = ad198x_build_controls,
534 .build_pcms = ad198x_build_pcms,
535 .init = ad198x_init,
536 .free = ad198x_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +0200537#ifdef CONFIG_SND_HDA_POWER_SAVE
538 .check_power_status = ad198x_check_power_status,
539#endif
Daniel T Chenea52bf22009-12-27 18:48:29 -0500540#ifdef SND_HDA_NEEDS_RESUME
541 .suspend = ad198x_suspend,
Daniel T Chenea52bf22009-12-27 18:48:29 -0500542#endif
543 .reboot_notify = ad198x_shutup,
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200544};
545
546
547/*
Takashi Iwai18a815d2006-03-01 19:54:39 +0100548 * EAPD control
Takashi Iwaiee6e3652009-12-08 17:23:33 +0100549 * the private value = nid
Takashi Iwai18a815d2006-03-01 19:54:39 +0100550 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200551#define ad198x_eapd_info snd_ctl_boolean_mono_info
Takashi Iwai18a815d2006-03-01 19:54:39 +0100552
553static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
554 struct snd_ctl_elem_value *ucontrol)
555{
556 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
557 struct ad198x_spec *spec = codec->spec;
Takashi Iwaiee6e3652009-12-08 17:23:33 +0100558 if (spec->inv_eapd)
Takashi Iwai18a815d2006-03-01 19:54:39 +0100559 ucontrol->value.integer.value[0] = ! spec->cur_eapd;
560 else
561 ucontrol->value.integer.value[0] = spec->cur_eapd;
562 return 0;
563}
564
565static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
566 struct snd_ctl_elem_value *ucontrol)
567{
568 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
569 struct ad198x_spec *spec = codec->spec;
Takashi Iwai18a815d2006-03-01 19:54:39 +0100570 hda_nid_t nid = kcontrol->private_value & 0xff;
571 unsigned int eapd;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100572 eapd = !!ucontrol->value.integer.value[0];
Takashi Iwaiee6e3652009-12-08 17:23:33 +0100573 if (spec->inv_eapd)
Takashi Iwai18a815d2006-03-01 19:54:39 +0100574 eapd = !eapd;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200575 if (eapd == spec->cur_eapd)
Takashi Iwai18a815d2006-03-01 19:54:39 +0100576 return 0;
577 spec->cur_eapd = eapd;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200578 snd_hda_codec_write_cache(codec, nid,
579 0, AC_VERB_SET_EAPD_BTLENABLE,
580 eapd ? 0x02 : 0x00);
Takashi Iwai18a815d2006-03-01 19:54:39 +0100581 return 1;
582}
583
Takashi Iwai9230d212006-03-13 13:49:49 +0100584static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
585 struct snd_ctl_elem_info *uinfo);
586static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
587 struct snd_ctl_elem_value *ucontrol);
588static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
589 struct snd_ctl_elem_value *ucontrol);
590
591
Takashi Iwai18a815d2006-03-01 19:54:39 +0100592/*
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200593 * AD1986A specific
594 */
595
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596#define AD1986A_SPDIF_OUT 0x02
597#define AD1986A_FRONT_DAC 0x03
598#define AD1986A_SURR_DAC 0x04
599#define AD1986A_CLFE_DAC 0x05
600#define AD1986A_ADC 0x06
601
602static hda_nid_t ad1986a_dac_nids[3] = {
603 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
604};
Takashi Iwai985be542005-11-02 18:26:49 +0100605static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
Takashi Iwai18a815d2006-03-01 19:54:39 +0100606static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608static struct hda_input_mux ad1986a_capture_source = {
609 .num_items = 7,
610 .items = {
611 { "Mic", 0x0 },
612 { "CD", 0x1 },
613 { "Aux", 0x3 },
614 { "Line", 0x4 },
615 { "Mix", 0x5 },
616 { "Mono", 0x6 },
617 { "Phone", 0x7 },
618 },
619};
620
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
Takashi Iwai532d5382007-07-27 19:02:40 +0200622static struct hda_bind_ctls ad1986a_bind_pcm_vol = {
623 .ops = &snd_hda_bind_vol,
624 .values = {
625 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
626 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
627 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
628 0
629 },
630};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Takashi Iwai532d5382007-07-27 19:02:40 +0200632static struct hda_bind_ctls ad1986a_bind_pcm_sw = {
633 .ops = &snd_hda_bind_sw,
634 .values = {
635 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
636 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
637 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
638 0
639 },
640};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 * mixers
644 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100645static struct snd_kcontrol_new ad1986a_mixers[] = {
Takashi Iwai532d5382007-07-27 19:02:40 +0200646 /*
647 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
648 */
649 HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
650 HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
652 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
653 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
654 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
655 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
656 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
657 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
658 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
659 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
660 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
661 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
662 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
663 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
664 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
665 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
666 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
667 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
668 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
Takashi Iwaife8970b2007-02-26 16:00:34 +0100669 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
671 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
672 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
673 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
674 {
675 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
676 .name = "Capture Source",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200677 .info = ad198x_mux_enum_info,
678 .get = ad198x_mux_enum_get,
679 .put = ad198x_mux_enum_put,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 },
681 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
682 { } /* end */
683};
684
Takashi Iwai9230d212006-03-13 13:49:49 +0100685/* additional mixers for 3stack mode */
686static struct snd_kcontrol_new ad1986a_3st_mixers[] = {
687 {
688 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
689 .name = "Channel Mode",
690 .info = ad198x_ch_mode_info,
691 .get = ad198x_ch_mode_get,
692 .put = ad198x_ch_mode_put,
693 },
694 { } /* end */
695};
696
697/* laptop model - 2ch only */
698static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
699
Takashi Iwai20a45e82007-08-15 22:20:45 +0200700/* master controls both pins 0x1a and 0x1b */
701static struct hda_bind_ctls ad1986a_laptop_master_vol = {
702 .ops = &snd_hda_bind_vol,
703 .values = {
704 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
705 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
706 0,
707 },
708};
709
710static struct hda_bind_ctls ad1986a_laptop_master_sw = {
711 .ops = &snd_hda_bind_sw,
712 .values = {
713 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
714 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
715 0,
716 },
717};
718
Takashi Iwai9230d212006-03-13 13:49:49 +0100719static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
720 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
721 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
Takashi Iwai20a45e82007-08-15 22:20:45 +0200722 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
723 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
Takashi Iwai9230d212006-03-13 13:49:49 +0100724 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
725 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
726 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
727 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
728 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
729 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
730 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
731 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
Takashi Iwaife8970b2007-02-26 16:00:34 +0100732 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100733 /*
Takashi Iwai9230d212006-03-13 13:49:49 +0100734 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
735 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
736 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
737 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
738 {
739 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
740 .name = "Capture Source",
741 .info = ad198x_mux_enum_info,
742 .get = ad198x_mux_enum_get,
743 .put = ad198x_mux_enum_put,
744 },
745 { } /* end */
746};
747
Takashi Iwai825aa9722006-03-17 10:50:49 +0100748/* laptop-eapd model - 2ch only */
749
Takashi Iwai825aa9722006-03-17 10:50:49 +0100750static struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
751 .num_items = 3,
752 .items = {
753 { "Mic", 0x0 },
754 { "Internal Mic", 0x4 },
755 { "Mix", 0x5 },
756 },
757};
758
Takashi Iwai5d5d5f42008-02-12 12:11:36 +0100759static struct hda_input_mux ad1986a_automic_capture_source = {
760 .num_items = 2,
761 .items = {
762 { "Mic", 0x0 },
763 { "Mix", 0x5 },
764 },
765};
766
Takashi Iwai16d11a82009-06-24 14:07:53 +0200767static struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
Takashi Iwai532d5382007-07-27 19:02:40 +0200768 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
769 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
Takashi Iwai16d11a82009-06-24 14:07:53 +0200770 { } /* end */
771};
772
773static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
Takashi Iwai825aa9722006-03-17 10:50:49 +0100774 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
775 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
Takashi Iwai1725b822008-11-21 02:25:48 +0100776 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
777 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
778 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
779 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
780 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
781 {
782 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
783 .name = "Capture Source",
784 .info = ad198x_mux_enum_info,
785 .get = ad198x_mux_enum_get,
786 .put = ad198x_mux_enum_put,
787 },
788 {
789 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
790 .name = "External Amplifier",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100791 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
Takashi Iwai1725b822008-11-21 02:25:48 +0100792 .info = ad198x_eapd_info,
793 .get = ad198x_eapd_get,
794 .put = ad198x_eapd_put,
Takashi Iwaiee6e3652009-12-08 17:23:33 +0100795 .private_value = 0x1b, /* port-D */
Takashi Iwai1725b822008-11-21 02:25:48 +0100796 },
797 { } /* end */
798};
799
Takashi Iwai16d11a82009-06-24 14:07:53 +0200800static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
801 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
802 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
Takashi Iwai825aa9722006-03-17 10:50:49 +0100803 { } /* end */
804};
805
Takashi Iwai5d5d5f42008-02-12 12:11:36 +0100806/* re-connect the mic boost input according to the jack sensing */
807static void ad1986a_automic(struct hda_codec *codec)
808{
809 unsigned int present;
Takashi Iwaid56757a2009-11-18 08:00:14 +0100810 present = snd_hda_jack_detect(codec, 0x1f);
Takashi Iwai5d5d5f42008-02-12 12:11:36 +0100811 /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
812 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
Takashi Iwaid56757a2009-11-18 08:00:14 +0100813 present ? 0 : 2);
Takashi Iwai5d5d5f42008-02-12 12:11:36 +0100814}
815
816#define AD1986A_MIC_EVENT 0x36
817
818static void ad1986a_automic_unsol_event(struct hda_codec *codec,
819 unsigned int res)
820{
821 if ((res >> 26) != AD1986A_MIC_EVENT)
822 return;
823 ad1986a_automic(codec);
824}
825
826static int ad1986a_automic_init(struct hda_codec *codec)
827{
828 ad198x_init(codec);
829 ad1986a_automic(codec);
830 return 0;
831}
832
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200833/* laptop-automute - 2ch only */
834
835static void ad1986a_update_hp(struct hda_codec *codec)
836{
837 struct ad198x_spec *spec = codec->spec;
838 unsigned int mute;
839
840 if (spec->jack_present)
841 mute = HDA_AMP_MUTE; /* mute internal speaker */
842 else
843 /* unmute internal speaker if necessary */
844 mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
845 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
846 HDA_AMP_MUTE, mute);
847}
848
849static void ad1986a_hp_automute(struct hda_codec *codec)
850{
851 struct ad198x_spec *spec = codec->spec;
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200852
Takashi Iwaid56757a2009-11-18 08:00:14 +0100853 spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
Takashi Iwai03c405a2009-06-24 14:10:15 +0200854 if (spec->inv_jack_detect)
855 spec->jack_present = !spec->jack_present;
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200856 ad1986a_update_hp(codec);
857}
858
859#define AD1986A_HP_EVENT 0x37
860
861static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
862{
863 if ((res >> 26) != AD1986A_HP_EVENT)
864 return;
865 ad1986a_hp_automute(codec);
866}
867
868static int ad1986a_hp_init(struct hda_codec *codec)
869{
870 ad198x_init(codec);
871 ad1986a_hp_automute(codec);
872 return 0;
873}
874
875/* bind hp and internal speaker mute (with plug check) */
876static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
877 struct snd_ctl_elem_value *ucontrol)
878{
879 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
880 long *valp = ucontrol->value.integer.value;
881 int change;
882
883 change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
884 HDA_AMP_MUTE,
885 valp[0] ? 0 : HDA_AMP_MUTE);
886 change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
887 HDA_AMP_MUTE,
888 valp[1] ? 0 : HDA_AMP_MUTE);
889 if (change)
890 ad1986a_update_hp(codec);
891 return change;
892}
893
Takashi Iwai16d11a82009-06-24 14:07:53 +0200894static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200895 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
896 {
897 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
898 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +0100899 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200900 .info = snd_hda_mixer_amp_switch_info,
901 .get = snd_hda_mixer_amp_switch_get,
902 .put = ad1986a_hp_master_sw_put,
903 .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
904 },
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200905 { } /* end */
906};
907
Takashi Iwai16d11a82009-06-24 14:07:53 +0200908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909/*
910 * initialization verbs
911 */
912static struct hda_verb ad1986a_init_verbs[] = {
913 /* Front, Surround, CLFE DAC; mute as default */
914 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
915 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
916 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
917 /* Downmix - off */
918 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
919 /* HP, Line-Out, Surround, CLFE selectors */
920 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
921 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
922 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
923 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
924 /* Mono selector */
925 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
926 /* Mic selector: Mic 1/2 pin */
927 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
928 /* Line-in selector: Line-in */
929 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
930 /* Mic 1/2 swap */
931 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
932 /* Record selector: mic */
933 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
934 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
935 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
936 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
937 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
938 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
939 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
940 /* PC beep */
941 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
942 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
943 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
944 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
945 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
946 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
947 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200948 /* HP Pin */
949 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
950 /* Front, Surround, CLFE Pins */
951 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
952 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
953 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
954 /* Mono Pin */
955 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
956 /* Mic Pin */
957 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
958 /* Line, Aux, CD, Beep-In Pin */
959 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
960 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
961 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
962 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
963 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 { } /* end */
965};
966
Takashi Iwai9230d212006-03-13 13:49:49 +0100967static struct hda_verb ad1986a_ch2_init[] = {
968 /* Surround out -> Line In */
Takashi Iwaifb956c12007-04-18 23:03:56 +0200969 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
970 /* Line-in selectors */
971 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
Takashi Iwai9230d212006-03-13 13:49:49 +0100972 /* CLFE -> Mic in */
Takashi Iwaifb956c12007-04-18 23:03:56 +0200973 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
974 /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
975 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
Takashi Iwai9230d212006-03-13 13:49:49 +0100976 { } /* end */
977};
978
979static struct hda_verb ad1986a_ch4_init[] = {
980 /* Surround out -> Surround */
Takashi Iwaifb956c12007-04-18 23:03:56 +0200981 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
982 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
Takashi Iwai9230d212006-03-13 13:49:49 +0100983 /* CLFE -> Mic in */
Takashi Iwaifb956c12007-04-18 23:03:56 +0200984 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
985 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
Takashi Iwai9230d212006-03-13 13:49:49 +0100986 { } /* end */
987};
988
989static struct hda_verb ad1986a_ch6_init[] = {
990 /* Surround out -> Surround out */
Takashi Iwaifb956c12007-04-18 23:03:56 +0200991 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
992 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
Takashi Iwai9230d212006-03-13 13:49:49 +0100993 /* CLFE -> CLFE */
Takashi Iwaifb956c12007-04-18 23:03:56 +0200994 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
995 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
Takashi Iwai9230d212006-03-13 13:49:49 +0100996 { } /* end */
997};
998
999static struct hda_channel_mode ad1986a_modes[3] = {
1000 { 2, ad1986a_ch2_init },
1001 { 4, ad1986a_ch4_init },
1002 { 6, ad1986a_ch6_init },
1003};
1004
Takashi Iwai825aa9722006-03-17 10:50:49 +01001005/* eapd initialization */
1006static struct hda_verb ad1986a_eapd_init_verbs[] = {
Tobin Davisf36090f2007-01-08 11:07:12 +01001007 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
Takashi Iwai825aa9722006-03-17 10:50:49 +01001008 {}
1009};
1010
Takashi Iwai5d5d5f42008-02-12 12:11:36 +01001011static struct hda_verb ad1986a_automic_verbs[] = {
1012 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1013 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1014 /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
1015 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
1016 {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
1017 {}
1018};
1019
Tobin Davisf36090f2007-01-08 11:07:12 +01001020/* Ultra initialization */
1021static struct hda_verb ad1986a_ultra_init[] = {
1022 /* eapd initialization */
1023 { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1024 /* CLFE -> Mic in */
1025 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
1026 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1027 { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
1028 { } /* end */
1029};
1030
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001031/* pin sensing on HP jack */
1032static struct hda_verb ad1986a_hp_init_verbs[] = {
1033 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
1034 {}
1035};
1036
Takashi Iwaic912e7a2009-06-24 14:14:34 +02001037static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
1038 unsigned int res)
1039{
1040 switch (res >> 26) {
1041 case AD1986A_HP_EVENT:
1042 ad1986a_hp_automute(codec);
1043 break;
1044 case AD1986A_MIC_EVENT:
1045 ad1986a_automic(codec);
1046 break;
1047 }
1048}
1049
1050static int ad1986a_samsung_p50_init(struct hda_codec *codec)
1051{
1052 ad198x_init(codec);
1053 ad1986a_hp_automute(codec);
1054 ad1986a_automic(codec);
1055 return 0;
1056}
1057
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001058
Takashi Iwai9230d212006-03-13 13:49:49 +01001059/* models */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001060enum {
1061 AD1986A_6STACK,
1062 AD1986A_3STACK,
1063 AD1986A_LAPTOP,
1064 AD1986A_LAPTOP_EAPD,
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001065 AD1986A_LAPTOP_AUTOMUTE,
Tobin Davisf36090f2007-01-08 11:07:12 +01001066 AD1986A_ULTRA,
Takashi Iwai1725b822008-11-21 02:25:48 +01001067 AD1986A_SAMSUNG,
Takashi Iwaic912e7a2009-06-24 14:14:34 +02001068 AD1986A_SAMSUNG_P50,
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001069 AD1986A_MODELS
1070};
Takashi Iwai9230d212006-03-13 13:49:49 +01001071
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001072static const char *ad1986a_models[AD1986A_MODELS] = {
1073 [AD1986A_6STACK] = "6stack",
1074 [AD1986A_3STACK] = "3stack",
1075 [AD1986A_LAPTOP] = "laptop",
1076 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001077 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
Tobin Davisf36090f2007-01-08 11:07:12 +01001078 [AD1986A_ULTRA] = "ultra",
Takashi Iwai1725b822008-11-21 02:25:48 +01001079 [AD1986A_SAMSUNG] = "samsung",
Takashi Iwaic912e7a2009-06-24 14:14:34 +02001080 [AD1986A_SAMSUNG_P50] = "samsung-p50",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001081};
1082
1083static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
1084 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001085 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001086 SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01001087 SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001088 SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
1089 SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
1090 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
1091 SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
Tobin Davisd9f9b8b2007-11-05 15:13:51 +01001092 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
Tobin Davis658fba02007-04-23 16:41:12 +02001093 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001094 SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
1095 SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
1096 SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
1097 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
1098 SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01001099 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
Daniel T Chenba579eb2010-02-20 11:16:30 -05001100 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
Tobin Davis18768992007-03-12 22:20:51 +01001101 SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001102 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
Takashi Iwaic912e7a2009-06-24 14:14:34 +02001103 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
Tobin Davisf36090f2007-01-08 11:07:12 +01001104 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
Takashi Iwaidea0a502009-02-09 17:14:52 +01001105 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01001106 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
Tobin Davis18768992007-03-12 22:20:51 +01001107 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001108 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001109 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001110 SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
Takashi Iwai9230d212006-03-13 13:49:49 +01001111 {}
1112};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
Takashi Iwaicb53c622007-08-10 17:21:45 +02001114#ifdef CONFIG_SND_HDA_POWER_SAVE
1115static struct hda_amp_list ad1986a_loopbacks[] = {
1116 { 0x13, HDA_OUTPUT, 0 }, /* Mic */
1117 { 0x14, HDA_OUTPUT, 0 }, /* Phone */
1118 { 0x15, HDA_OUTPUT, 0 }, /* CD */
1119 { 0x16, HDA_OUTPUT, 0 }, /* Aux */
1120 { 0x17, HDA_OUTPUT, 0 }, /* Line */
1121 { } /* end */
1122};
1123#endif
1124
Takashi Iwai8c0d9642008-01-28 12:30:17 +01001125static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
1126{
Takashi Iwai2f334f92009-02-20 14:37:42 +01001127 unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai8c0d9642008-01-28 12:30:17 +01001128 return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
1129}
1130
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131static int patch_ad1986a(struct hda_codec *codec)
1132{
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001133 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01001134 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001136 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 if (spec == NULL)
1138 return -ENOMEM;
1139
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 codec->spec = spec;
1141
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01001142 err = snd_hda_attach_beep_device(codec, 0x19);
1143 if (err < 0) {
1144 ad198x_free(codec);
1145 return err;
1146 }
1147 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1148
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 spec->multiout.max_channels = 6;
1150 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
1151 spec->multiout.dac_nids = ad1986a_dac_nids;
1152 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +01001153 spec->num_adc_nids = 1;
1154 spec->adc_nids = ad1986a_adc_nids;
Takashi Iwaia7ee8202006-03-01 20:05:39 +01001155 spec->capsrc_nids = ad1986a_capsrc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001156 spec->input_mux = &ad1986a_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +01001157 spec->num_mixers = 1;
1158 spec->mixers[0] = ad1986a_mixers;
1159 spec->num_init_verbs = 1;
1160 spec->init_verbs[0] = ad1986a_init_verbs;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001161#ifdef CONFIG_SND_HDA_POWER_SAVE
1162 spec->loopback.amplist = ad1986a_loopbacks;
1163#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01001164 spec->vmaster_nid = 0x1b;
Takashi Iwaiee6e3652009-12-08 17:23:33 +01001165 spec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001167 codec->patch_ops = ad198x_patch_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
Takashi Iwai9230d212006-03-13 13:49:49 +01001169 /* override some parameters */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001170 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
1171 ad1986a_models,
1172 ad1986a_cfg_tbl);
Takashi Iwai9230d212006-03-13 13:49:49 +01001173 switch (board_config) {
1174 case AD1986A_3STACK:
1175 spec->num_mixers = 2;
1176 spec->mixers[1] = ad1986a_3st_mixers;
Takashi Iwaifb956c12007-04-18 23:03:56 +02001177 spec->num_init_verbs = 2;
1178 spec->init_verbs[1] = ad1986a_ch2_init;
Takashi Iwai9230d212006-03-13 13:49:49 +01001179 spec->channel_mode = ad1986a_modes;
1180 spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
Takashi Iwai2125cad2006-03-27 12:52:22 +02001181 spec->need_dac_fix = 1;
1182 spec->multiout.max_channels = 2;
1183 spec->multiout.num_dacs = 1;
Takashi Iwai9230d212006-03-13 13:49:49 +01001184 break;
1185 case AD1986A_LAPTOP:
1186 spec->mixers[0] = ad1986a_laptop_mixers;
1187 spec->multiout.max_channels = 2;
1188 spec->multiout.num_dacs = 1;
1189 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1190 break;
Takashi Iwai825aa9722006-03-17 10:50:49 +01001191 case AD1986A_LAPTOP_EAPD:
Takashi Iwai16d11a82009-06-24 14:07:53 +02001192 spec->num_mixers = 3;
1193 spec->mixers[0] = ad1986a_laptop_master_mixers;
1194 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1195 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
Takashi Iwai1725b822008-11-21 02:25:48 +01001196 spec->num_init_verbs = 2;
1197 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1198 spec->multiout.max_channels = 2;
1199 spec->multiout.num_dacs = 1;
1200 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1201 if (!is_jack_available(codec, 0x25))
1202 spec->multiout.dig_out_nid = 0;
1203 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1204 break;
1205 case AD1986A_SAMSUNG:
Takashi Iwai16d11a82009-06-24 14:07:53 +02001206 spec->num_mixers = 2;
1207 spec->mixers[0] = ad1986a_laptop_master_mixers;
1208 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
Takashi Iwai5d5d5f42008-02-12 12:11:36 +01001209 spec->num_init_verbs = 3;
Takashi Iwai825aa9722006-03-17 10:50:49 +01001210 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
Takashi Iwai5d5d5f42008-02-12 12:11:36 +01001211 spec->init_verbs[2] = ad1986a_automic_verbs;
Takashi Iwai825aa9722006-03-17 10:50:49 +01001212 spec->multiout.max_channels = 2;
1213 spec->multiout.num_dacs = 1;
1214 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
Takashi Iwai8c0d9642008-01-28 12:30:17 +01001215 if (!is_jack_available(codec, 0x25))
1216 spec->multiout.dig_out_nid = 0;
Takashi Iwai5d5d5f42008-02-12 12:11:36 +01001217 spec->input_mux = &ad1986a_automic_capture_source;
1218 codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
1219 codec->patch_ops.init = ad1986a_automic_init;
Takashi Iwai825aa9722006-03-17 10:50:49 +01001220 break;
Takashi Iwaic912e7a2009-06-24 14:14:34 +02001221 case AD1986A_SAMSUNG_P50:
1222 spec->num_mixers = 2;
1223 spec->mixers[0] = ad1986a_automute_master_mixers;
1224 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1225 spec->num_init_verbs = 4;
1226 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1227 spec->init_verbs[2] = ad1986a_automic_verbs;
1228 spec->init_verbs[3] = ad1986a_hp_init_verbs;
1229 spec->multiout.max_channels = 2;
1230 spec->multiout.num_dacs = 1;
1231 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1232 if (!is_jack_available(codec, 0x25))
1233 spec->multiout.dig_out_nid = 0;
1234 spec->input_mux = &ad1986a_automic_capture_source;
1235 codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
1236 codec->patch_ops.init = ad1986a_samsung_p50_init;
1237 break;
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001238 case AD1986A_LAPTOP_AUTOMUTE:
Takashi Iwai16d11a82009-06-24 14:07:53 +02001239 spec->num_mixers = 3;
1240 spec->mixers[0] = ad1986a_automute_master_mixers;
1241 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1242 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001243 spec->num_init_verbs = 3;
1244 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1245 spec->init_verbs[2] = ad1986a_hp_init_verbs;
1246 spec->multiout.max_channels = 2;
1247 spec->multiout.num_dacs = 1;
1248 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
Takashi Iwai8c0d9642008-01-28 12:30:17 +01001249 if (!is_jack_available(codec, 0x25))
1250 spec->multiout.dig_out_nid = 0;
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001251 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1252 codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
1253 codec->patch_ops.init = ad1986a_hp_init;
Takashi Iwai03c405a2009-06-24 14:10:15 +02001254 /* Lenovo N100 seems to report the reversed bit
1255 * for HP jack-sensing
1256 */
1257 spec->inv_jack_detect = 1;
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001258 break;
Tobin Davisf36090f2007-01-08 11:07:12 +01001259 case AD1986A_ULTRA:
1260 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1261 spec->num_init_verbs = 2;
1262 spec->init_verbs[1] = ad1986a_ultra_init;
1263 spec->multiout.max_channels = 2;
1264 spec->multiout.num_dacs = 1;
1265 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1266 spec->multiout.dig_out_nid = 0;
1267 break;
Takashi Iwai9230d212006-03-13 13:49:49 +01001268 }
1269
Takashi Iwaid29240c2007-10-26 12:35:56 +02001270 /* AD1986A has a hardware problem that it can't share a stream
1271 * with multiple output pins. The copy of front to surrounds
1272 * causes noisy or silent outputs at a certain timing, e.g.
1273 * changing the volume.
1274 * So, let's disable the shared stream.
1275 */
1276 spec->multiout.no_share_stream = 1;
1277
Takashi Iwai729d55b2009-12-25 22:49:01 +01001278 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02001279 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01001280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 return 0;
1282}
1283
1284/*
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001285 * AD1983 specific
1286 */
1287
1288#define AD1983_SPDIF_OUT 0x02
1289#define AD1983_DAC 0x03
1290#define AD1983_ADC 0x04
1291
1292static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
Takashi Iwai985be542005-11-02 18:26:49 +01001293static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
Takashi Iwai18a815d2006-03-01 19:54:39 +01001294static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001295
1296static struct hda_input_mux ad1983_capture_source = {
1297 .num_items = 4,
1298 .items = {
1299 { "Mic", 0x0 },
1300 { "Line", 0x1 },
1301 { "Mix", 0x2 },
1302 { "Mix Mono", 0x3 },
1303 },
1304};
1305
1306/*
1307 * SPDIF playback route
1308 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001309static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001310{
1311 static char *texts[] = { "PCM", "ADC" };
1312
1313 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1314 uinfo->count = 1;
1315 uinfo->value.enumerated.items = 2;
1316 if (uinfo->value.enumerated.item > 1)
1317 uinfo->value.enumerated.item = 1;
1318 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1319 return 0;
1320}
1321
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001322static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001323{
1324 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1325 struct ad198x_spec *spec = codec->spec;
1326
1327 ucontrol->value.enumerated.item[0] = spec->spdif_route;
1328 return 0;
1329}
1330
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001331static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001332{
1333 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1334 struct ad198x_spec *spec = codec->spec;
1335
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001336 if (ucontrol->value.enumerated.item[0] > 1)
1337 return -EINVAL;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001338 if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
1339 spec->spdif_route = ucontrol->value.enumerated.item[0];
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001340 snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
1341 AC_VERB_SET_CONNECT_SEL,
1342 spec->spdif_route);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001343 return 1;
1344 }
1345 return 0;
1346}
1347
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001348static struct snd_kcontrol_new ad1983_mixers[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001349 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1350 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1351 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1352 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1353 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1354 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1355 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1356 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1357 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1358 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1359 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1360 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001361 HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
1362 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1363 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1364 {
1365 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1366 .name = "Capture Source",
1367 .info = ad198x_mux_enum_info,
1368 .get = ad198x_mux_enum_get,
1369 .put = ad198x_mux_enum_put,
1370 },
1371 {
1372 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwai6540dff2006-06-13 11:57:22 +02001373 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001374 .info = ad1983_spdif_route_info,
1375 .get = ad1983_spdif_route_get,
1376 .put = ad1983_spdif_route_put,
1377 },
1378 { } /* end */
1379};
1380
1381static struct hda_verb ad1983_init_verbs[] = {
1382 /* Front, HP, Mono; mute as default */
1383 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1384 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1385 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1386 /* Beep, PCM, Mic, Line-In: mute */
1387 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1388 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1389 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1390 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1391 /* Front, HP selectors; from Mix */
1392 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1393 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1394 /* Mono selector; from Mix */
1395 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1396 /* Mic selector; Mic */
1397 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
1398 /* Line-in selector: Line-in */
1399 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
1400 /* Mic boost: 0dB */
1401 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1402 /* Record selector: mic */
1403 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1404 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1405 /* SPDIF route: PCM */
1406 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1407 /* Front Pin */
1408 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1409 /* HP Pin */
1410 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1411 /* Mono Pin */
1412 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1413 /* Mic Pin */
1414 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1415 /* Line Pin */
1416 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1417 { } /* end */
1418};
1419
Takashi Iwaicb53c622007-08-10 17:21:45 +02001420#ifdef CONFIG_SND_HDA_POWER_SAVE
1421static struct hda_amp_list ad1983_loopbacks[] = {
1422 { 0x12, HDA_OUTPUT, 0 }, /* Mic */
1423 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1424 { } /* end */
1425};
1426#endif
Takashi Iwai985be542005-11-02 18:26:49 +01001427
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001428static int patch_ad1983(struct hda_codec *codec)
1429{
1430 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01001431 int err;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001432
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001433 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001434 if (spec == NULL)
1435 return -ENOMEM;
1436
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001437 codec->spec = spec;
1438
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01001439 err = snd_hda_attach_beep_device(codec, 0x10);
1440 if (err < 0) {
1441 ad198x_free(codec);
1442 return err;
1443 }
1444 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1445
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001446 spec->multiout.max_channels = 2;
1447 spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
1448 spec->multiout.dac_nids = ad1983_dac_nids;
1449 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +01001450 spec->num_adc_nids = 1;
1451 spec->adc_nids = ad1983_adc_nids;
Takashi Iwai18a815d2006-03-01 19:54:39 +01001452 spec->capsrc_nids = ad1983_capsrc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001453 spec->input_mux = &ad1983_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +01001454 spec->num_mixers = 1;
1455 spec->mixers[0] = ad1983_mixers;
1456 spec->num_init_verbs = 1;
1457 spec->init_verbs[0] = ad1983_init_verbs;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001458 spec->spdif_route = 0;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001459#ifdef CONFIG_SND_HDA_POWER_SAVE
1460 spec->loopback.amplist = ad1983_loopbacks;
1461#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01001462 spec->vmaster_nid = 0x05;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001463
1464 codec->patch_ops = ad198x_patch_ops;
1465
Takashi Iwai729d55b2009-12-25 22:49:01 +01001466 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02001467 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01001468
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001469 return 0;
1470}
1471
1472
1473/*
1474 * AD1981 HD specific
1475 */
1476
1477#define AD1981_SPDIF_OUT 0x02
1478#define AD1981_DAC 0x03
1479#define AD1981_ADC 0x04
1480
1481static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
Takashi Iwai985be542005-11-02 18:26:49 +01001482static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
Takashi Iwai18a815d2006-03-01 19:54:39 +01001483static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001484
1485/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
1486static struct hda_input_mux ad1981_capture_source = {
1487 .num_items = 7,
1488 .items = {
1489 { "Front Mic", 0x0 },
1490 { "Line", 0x1 },
1491 { "Mix", 0x2 },
1492 { "Mix Mono", 0x3 },
1493 { "CD", 0x4 },
1494 { "Mic", 0x6 },
1495 { "Aux", 0x7 },
1496 },
1497};
1498
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001499static struct snd_kcontrol_new ad1981_mixers[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001500 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1501 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1502 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1503 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1504 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1505 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1506 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1507 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1508 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1509 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1510 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1511 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1512 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1513 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1514 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1515 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1516 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1517 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001518 HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
1519 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
1520 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1521 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1522 {
1523 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1524 .name = "Capture Source",
1525 .info = ad198x_mux_enum_info,
1526 .get = ad198x_mux_enum_get,
1527 .put = ad198x_mux_enum_put,
1528 },
1529 /* identical with AD1983 */
1530 {
1531 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwai6540dff2006-06-13 11:57:22 +02001532 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001533 .info = ad1983_spdif_route_info,
1534 .get = ad1983_spdif_route_get,
1535 .put = ad1983_spdif_route_put,
1536 },
1537 { } /* end */
1538};
1539
1540static struct hda_verb ad1981_init_verbs[] = {
1541 /* Front, HP, Mono; mute as default */
1542 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1543 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1544 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1545 /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
1546 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1547 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1548 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1549 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1550 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1551 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1552 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1553 /* Front, HP selectors; from Mix */
1554 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1555 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1556 /* Mono selector; from Mix */
1557 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1558 /* Mic Mixer; select Front Mic */
1559 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1560 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1561 /* Mic boost: 0dB */
Takashi Iwai6d6e17d2009-01-23 12:33:54 +01001562 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1563 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001564 /* Record selector: Front mic */
1565 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1566 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1567 /* SPDIF route: PCM */
1568 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1569 /* Front Pin */
1570 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1571 /* HP Pin */
1572 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1573 /* Mono Pin */
1574 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1575 /* Front & Rear Mic Pins */
1576 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1577 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1578 /* Line Pin */
1579 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1580 /* Digital Beep */
1581 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
1582 /* Line-Out as Input: disabled */
1583 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1584 { } /* end */
1585};
1586
Takashi Iwaicb53c622007-08-10 17:21:45 +02001587#ifdef CONFIG_SND_HDA_POWER_SAVE
1588static struct hda_amp_list ad1981_loopbacks[] = {
1589 { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
1590 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1591 { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
1592 { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
1593 { 0x1d, HDA_OUTPUT, 0 }, /* CD */
1594 { } /* end */
1595};
1596#endif
1597
Takashi Iwai18a815d2006-03-01 19:54:39 +01001598/*
1599 * Patch for HP nx6320
1600 *
Tobin Davis18768992007-03-12 22:20:51 +01001601 * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
Takashi Iwai18a815d2006-03-01 19:54:39 +01001602 * speaker output enabled _and_ mute-LED off.
1603 */
1604
1605#define AD1981_HP_EVENT 0x37
1606#define AD1981_MIC_EVENT 0x38
1607
1608static struct hda_verb ad1981_hp_init_verbs[] = {
1609 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
1610 /* pin sensing on HP and Mic jacks */
1611 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1612 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1613 {}
1614};
1615
1616/* turn on/off EAPD (+ mute HP) as a master switch */
1617static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1618 struct snd_ctl_elem_value *ucontrol)
1619{
1620 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1621 struct ad198x_spec *spec = codec->spec;
1622
1623 if (! ad198x_eapd_put(kcontrol, ucontrol))
1624 return 0;
Takashi Iwaif0824812008-02-11 15:54:34 +01001625 /* change speaker pin appropriately */
1626 snd_hda_codec_write(codec, 0x05, 0,
1627 AC_VERB_SET_PIN_WIDGET_CONTROL,
1628 spec->cur_eapd ? PIN_OUT : 0);
Takashi Iwai18a815d2006-03-01 19:54:39 +01001629 /* toggle HP mute appropriately */
Takashi Iwai47fd8302007-08-10 17:11:07 +02001630 snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
1631 HDA_AMP_MUTE,
1632 spec->cur_eapd ? 0 : HDA_AMP_MUTE);
Takashi Iwai18a815d2006-03-01 19:54:39 +01001633 return 1;
1634}
1635
1636/* bind volumes of both NID 0x05 and 0x06 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02001637static struct hda_bind_ctls ad1981_hp_bind_master_vol = {
1638 .ops = &snd_hda_bind_vol,
1639 .values = {
1640 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
1641 HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
1642 0
1643 },
1644};
Takashi Iwai18a815d2006-03-01 19:54:39 +01001645
1646/* mute internal speaker if HP is plugged */
1647static void ad1981_hp_automute(struct hda_codec *codec)
1648{
1649 unsigned int present;
1650
Takashi Iwaid56757a2009-11-18 08:00:14 +01001651 present = snd_hda_jack_detect(codec, 0x06);
Takashi Iwai47fd8302007-08-10 17:11:07 +02001652 snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
1653 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai18a815d2006-03-01 19:54:39 +01001654}
1655
1656/* toggle input of built-in and mic jack appropriately */
1657static void ad1981_hp_automic(struct hda_codec *codec)
1658{
1659 static struct hda_verb mic_jack_on[] = {
1660 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1661 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1662 {}
1663 };
1664 static struct hda_verb mic_jack_off[] = {
1665 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1666 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1667 {}
1668 };
1669 unsigned int present;
1670
Takashi Iwaid56757a2009-11-18 08:00:14 +01001671 present = snd_hda_jack_detect(codec, 0x08);
Takashi Iwai18a815d2006-03-01 19:54:39 +01001672 if (present)
1673 snd_hda_sequence_write(codec, mic_jack_on);
1674 else
1675 snd_hda_sequence_write(codec, mic_jack_off);
1676}
1677
1678/* unsolicited event for HP jack sensing */
1679static void ad1981_hp_unsol_event(struct hda_codec *codec,
1680 unsigned int res)
1681{
1682 res >>= 26;
1683 switch (res) {
1684 case AD1981_HP_EVENT:
1685 ad1981_hp_automute(codec);
1686 break;
1687 case AD1981_MIC_EVENT:
1688 ad1981_hp_automic(codec);
1689 break;
1690 }
1691}
1692
1693static struct hda_input_mux ad1981_hp_capture_source = {
1694 .num_items = 3,
1695 .items = {
1696 { "Mic", 0x0 },
1697 { "Docking-Station", 0x1 },
1698 { "Mix", 0x2 },
1699 },
1700};
1701
1702static struct snd_kcontrol_new ad1981_hp_mixers[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02001703 HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
Takashi Iwai18a815d2006-03-01 19:54:39 +01001704 {
1705 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001706 .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
Takashi Iwai18a815d2006-03-01 19:54:39 +01001707 .name = "Master Playback Switch",
1708 .info = ad198x_eapd_info,
1709 .get = ad198x_eapd_get,
1710 .put = ad1981_hp_master_sw_put,
1711 .private_value = 0x05,
1712 },
1713 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1714 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1715#if 0
1716 /* FIXME: analog mic/line loopback doesn't work with my tests...
1717 * (although recording is OK)
1718 */
1719 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1720 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1721 HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1722 HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1723 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1724 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1725 /* FIXME: does this laptop have analog CD connection? */
1726 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1727 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1728#endif
1729 HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
1730 HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT),
1731 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1732 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1733 {
1734 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1735 .name = "Capture Source",
1736 .info = ad198x_mux_enum_info,
1737 .get = ad198x_mux_enum_get,
1738 .put = ad198x_mux_enum_put,
1739 },
1740 { } /* end */
1741};
1742
1743/* initialize jack-sensing, too */
1744static int ad1981_hp_init(struct hda_codec *codec)
1745{
1746 ad198x_init(codec);
1747 ad1981_hp_automute(codec);
1748 ad1981_hp_automic(codec);
1749 return 0;
1750}
1751
Tobin Davis18768992007-03-12 22:20:51 +01001752/* configuration for Toshiba Laptops */
1753static struct hda_verb ad1981_toshiba_init_verbs[] = {
1754 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
1755 /* pin sensing on HP and Mic jacks */
1756 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1757 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1758 {}
1759};
1760
1761static struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
1762 HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
1763 HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
1764 { }
1765};
1766
Takashi Iwai01686c5f2006-04-18 12:54:11 +02001767/* configuration for Lenovo Thinkpad T60 */
1768static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
1769 HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1770 HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1771 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1772 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1773 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1774 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1775 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1776 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1777 HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
1778 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1779 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1780 {
1781 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1782 .name = "Capture Source",
1783 .info = ad198x_mux_enum_info,
1784 .get = ad198x_mux_enum_get,
1785 .put = ad198x_mux_enum_put,
1786 },
Takashi Iwai6540dff2006-06-13 11:57:22 +02001787 /* identical with AD1983 */
1788 {
1789 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1790 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1791 .info = ad1983_spdif_route_info,
1792 .get = ad1983_spdif_route_get,
1793 .put = ad1983_spdif_route_put,
1794 },
Takashi Iwai01686c5f2006-04-18 12:54:11 +02001795 { } /* end */
1796};
1797
1798static struct hda_input_mux ad1981_thinkpad_capture_source = {
1799 .num_items = 3,
1800 .items = {
1801 { "Mic", 0x0 },
1802 { "Mix", 0x2 },
1803 { "CD", 0x4 },
1804 },
1805};
1806
Takashi Iwai18a815d2006-03-01 19:54:39 +01001807/* models */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001808enum {
1809 AD1981_BASIC,
1810 AD1981_HP,
1811 AD1981_THINKPAD,
Tobin Davis18768992007-03-12 22:20:51 +01001812 AD1981_TOSHIBA,
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001813 AD1981_MODELS
1814};
Takashi Iwai18a815d2006-03-01 19:54:39 +01001815
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001816static const char *ad1981_models[AD1981_MODELS] = {
1817 [AD1981_HP] = "hp",
1818 [AD1981_THINKPAD] = "thinkpad",
1819 [AD1981_BASIC] = "basic",
Tobin Davis18768992007-03-12 22:20:51 +01001820 [AD1981_TOSHIBA] = "toshiba"
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001821};
1822
1823static struct snd_pci_quirk ad1981_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01001824 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
Takashi Iwai470eaf62008-06-30 16:40:10 +02001825 SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
Takashi Iwai8970ccd2006-04-18 12:50:40 +02001826 /* All HP models */
Takashi Iwaidea0a502009-02-09 17:14:52 +01001827 SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01001828 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
Takashi Iwai01686c5f2006-04-18 12:54:11 +02001829 /* Lenovo Thinkpad T60/X60/Z6xx */
Takashi Iwaidea0a502009-02-09 17:14:52 +01001830 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01001831 /* HP nx6320 (reversed SSID, H/W bug) */
1832 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
Takashi Iwai18a815d2006-03-01 19:54:39 +01001833 {}
1834};
1835
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001836static int patch_ad1981(struct hda_codec *codec)
1837{
1838 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01001839 int err, board_config;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001840
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001841 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001842 if (spec == NULL)
1843 return -ENOMEM;
1844
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001845 codec->spec = spec;
1846
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01001847 err = snd_hda_attach_beep_device(codec, 0x10);
1848 if (err < 0) {
1849 ad198x_free(codec);
1850 return err;
1851 }
1852 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
1853
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001854 spec->multiout.max_channels = 2;
1855 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
1856 spec->multiout.dac_nids = ad1981_dac_nids;
1857 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +01001858 spec->num_adc_nids = 1;
1859 spec->adc_nids = ad1981_adc_nids;
Takashi Iwai18a815d2006-03-01 19:54:39 +01001860 spec->capsrc_nids = ad1981_capsrc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001861 spec->input_mux = &ad1981_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +01001862 spec->num_mixers = 1;
1863 spec->mixers[0] = ad1981_mixers;
1864 spec->num_init_verbs = 1;
1865 spec->init_verbs[0] = ad1981_init_verbs;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001866 spec->spdif_route = 0;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001867#ifdef CONFIG_SND_HDA_POWER_SAVE
1868 spec->loopback.amplist = ad1981_loopbacks;
1869#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01001870 spec->vmaster_nid = 0x05;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001871
1872 codec->patch_ops = ad198x_patch_ops;
1873
Takashi Iwai18a815d2006-03-01 19:54:39 +01001874 /* override some parameters */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001875 board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
1876 ad1981_models,
1877 ad1981_cfg_tbl);
Takashi Iwai18a815d2006-03-01 19:54:39 +01001878 switch (board_config) {
1879 case AD1981_HP:
1880 spec->mixers[0] = ad1981_hp_mixers;
1881 spec->num_init_verbs = 2;
1882 spec->init_verbs[1] = ad1981_hp_init_verbs;
1883 spec->multiout.dig_out_nid = 0;
1884 spec->input_mux = &ad1981_hp_capture_source;
1885
1886 codec->patch_ops.init = ad1981_hp_init;
1887 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
Daniel T Chen01f59662009-12-13 16:22:58 -05001888 /* set the upper-limit for mixer amp to 0dB for avoiding the
1889 * possible damage by overloading
1890 */
1891 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
1892 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
1893 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
1894 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
1895 (1 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai18a815d2006-03-01 19:54:39 +01001896 break;
Takashi Iwai01686c5f2006-04-18 12:54:11 +02001897 case AD1981_THINKPAD:
1898 spec->mixers[0] = ad1981_thinkpad_mixers;
Takashi Iwai01686c5f2006-04-18 12:54:11 +02001899 spec->input_mux = &ad1981_thinkpad_capture_source;
Daniel T Chenb8e80cf2010-03-30 13:29:28 -04001900 /* set the upper-limit for mixer amp to 0dB for avoiding the
1901 * possible damage by overloading
1902 */
1903 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
1904 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
1905 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
1906 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
1907 (1 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai01686c5f2006-04-18 12:54:11 +02001908 break;
Tobin Davis18768992007-03-12 22:20:51 +01001909 case AD1981_TOSHIBA:
1910 spec->mixers[0] = ad1981_hp_mixers;
1911 spec->mixers[1] = ad1981_toshiba_mixers;
1912 spec->num_init_verbs = 2;
1913 spec->init_verbs[1] = ad1981_toshiba_init_verbs;
1914 spec->multiout.dig_out_nid = 0;
1915 spec->input_mux = &ad1981_hp_capture_source;
1916 codec->patch_ops.init = ad1981_hp_init;
1917 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1918 break;
Takashi Iwai18a815d2006-03-01 19:54:39 +01001919 }
Takashi Iwai729d55b2009-12-25 22:49:01 +01001920
1921 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02001922 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01001923
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001924 return 0;
1925}
1926
1927
1928/*
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001929 * AD1988
1930 *
1931 * Output pins and routes
1932 *
Takashi Iwaid32410b12005-11-24 16:06:23 +01001933 * Pin Mix Sel DAC (*)
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001934 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
1935 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
1936 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
1937 * port-D 0x12 (mute/hp) <- 0x29 <- 04
1938 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
1939 * port-F 0x16 (mute) <- 0x2a <- 06
1940 * port-G 0x24 (mute) <- 0x27 <- 05
1941 * port-H 0x25 (mute) <- 0x28 <- 0a
1942 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
1943 *
Takashi Iwaid32410b12005-11-24 16:06:23 +01001944 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
1945 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001946 *
1947 * Input pins and routes
1948 *
1949 * pin boost mix input # / adc input #
1950 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
1951 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
1952 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
1953 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
1954 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
1955 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
1956 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
1957 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
1958 *
1959 *
1960 * DAC assignment
Takashi Iwaid32410b12005-11-24 16:06:23 +01001961 * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01001962 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001963 *
1964 * Inputs of Analog Mix (0x20)
1965 * 0:Port-B (front mic)
1966 * 1:Port-C/G/H (line-in)
1967 * 2:Port-A
1968 * 3:Port-D (line-in/2)
1969 * 4:Port-E/G/H (mic-in)
1970 * 5:Port-F (mic2-in)
1971 * 6:CD
1972 * 7:Beep
1973 *
1974 * ADC selection
1975 * 0:Port-A
1976 * 1:Port-B (front mic-in)
1977 * 2:Port-C (line-in)
1978 * 3:Port-F (mic2-in)
1979 * 4:Port-E (mic-in)
1980 * 5:CD
1981 * 6:Port-G
1982 * 7:Port-H
1983 * 8:Port-D (line-in/2)
1984 * 9:Mix
1985 *
1986 * Proposed pin assignments by the datasheet
1987 *
1988 * 6-stack
1989 * Port-A front headphone
1990 * B front mic-in
1991 * C rear line-in
1992 * D rear front-out
1993 * E rear mic-in
1994 * F rear surround
1995 * G rear CLFE
1996 * H rear side
1997 *
1998 * 3-stack
1999 * Port-A front headphone
2000 * B front mic
2001 * C rear line-in/surround
2002 * D rear front-out
2003 * E rear mic-in/CLFE
2004 *
2005 * laptop
2006 * Port-A headphone
2007 * B mic-in
2008 * C docking station
2009 * D internal speaker (with EAPD)
2010 * E/F quad mic array
2011 */
2012
2013
2014/* models */
2015enum {
2016 AD1988_6STACK,
2017 AD1988_6STACK_DIG,
2018 AD1988_3STACK,
2019 AD1988_3STACK_DIG,
2020 AD1988_LAPTOP,
2021 AD1988_LAPTOP_DIG,
Takashi Iwaid32410b12005-11-24 16:06:23 +01002022 AD1988_AUTO,
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002023 AD1988_MODEL_LAST,
2024};
2025
Takashi Iwaid32410b12005-11-24 16:06:23 +01002026/* reivision id to check workarounds */
2027#define AD1988A_REV2 0x100200
2028
Takashi Iwai1a806f42006-07-03 15:58:16 +02002029#define is_rev2(codec) \
2030 ((codec)->vendor_id == 0x11d41988 && \
2031 (codec)->revision_id == AD1988A_REV2)
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002032
2033/*
2034 * mixers
2035 */
2036
Takashi Iwaid32410b12005-11-24 16:06:23 +01002037static hda_nid_t ad1988_6stack_dac_nids[4] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002038 0x04, 0x06, 0x05, 0x0a
2039};
2040
Takashi Iwaid32410b12005-11-24 16:06:23 +01002041static hda_nid_t ad1988_3stack_dac_nids[3] = {
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002042 0x04, 0x05, 0x0a
Takashi Iwaid32410b12005-11-24 16:06:23 +01002043};
2044
2045/* for AD1988A revision-2, DAC2-4 are swapped */
2046static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
2047 0x04, 0x05, 0x0a, 0x06
2048};
2049
2050static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002051 0x04, 0x0a, 0x06
Takashi Iwaid32410b12005-11-24 16:06:23 +01002052};
2053
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002054static hda_nid_t ad1988_adc_nids[3] = {
2055 0x08, 0x09, 0x0f
2056};
2057
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002058static hda_nid_t ad1988_capsrc_nids[3] = {
2059 0x0c, 0x0d, 0x0e
2060};
2061
Robin H. Johnson9cae0c62008-09-13 16:54:58 -07002062#define AD1988_SPDIF_OUT 0x02
2063#define AD1988_SPDIF_OUT_HDMI 0x0b
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002064#define AD1988_SPDIF_IN 0x07
2065
Takashi Iwai3a08e302009-02-13 11:37:08 +01002066static hda_nid_t ad1989b_slave_dig_outs[] = {
2067 AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
Robin H. Johnson9cae0c62008-09-13 16:54:58 -07002068};
2069
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002070static struct hda_input_mux ad1988_6stack_capture_source = {
2071 .num_items = 5,
2072 .items = {
Takashi Iwaifb304ce2008-02-25 15:32:01 +01002073 { "Front Mic", 0x1 }, /* port-B */
2074 { "Line", 0x2 }, /* port-C */
2075 { "Mic", 0x4 }, /* port-E */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002076 { "CD", 0x5 },
2077 { "Mix", 0x9 },
2078 },
2079};
2080
2081static struct hda_input_mux ad1988_laptop_capture_source = {
2082 .num_items = 3,
2083 .items = {
Takashi Iwaifb304ce2008-02-25 15:32:01 +01002084 { "Mic/Line", 0x1 }, /* port-B */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002085 { "CD", 0x5 },
2086 { "Mix", 0x9 },
2087 },
2088};
2089
2090/*
2091 */
2092static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
2093 struct snd_ctl_elem_info *uinfo)
2094{
2095 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2096 struct ad198x_spec *spec = codec->spec;
2097 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
2098 spec->num_channel_mode);
2099}
2100
2101static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
2102 struct snd_ctl_elem_value *ucontrol)
2103{
2104 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2105 struct ad198x_spec *spec = codec->spec;
2106 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
2107 spec->num_channel_mode, spec->multiout.max_channels);
2108}
2109
2110static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
2111 struct snd_ctl_elem_value *ucontrol)
2112{
2113 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2114 struct ad198x_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +02002115 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
2116 spec->num_channel_mode,
2117 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +02002118 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai2125cad2006-03-27 12:52:22 +02002119 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
Takashi Iwai4e195a72006-07-28 14:47:34 +02002120 return err;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002121}
2122
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002123/* 6-stack mode */
Takashi Iwaid32410b12005-11-24 16:06:23 +01002124static struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002125 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2126 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2127 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2128 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2129 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
Takashi Iwai2ece5f422006-07-06 19:16:40 +02002130 { } /* end */
Takashi Iwaid32410b12005-11-24 16:06:23 +01002131};
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002132
Takashi Iwaid32410b12005-11-24 16:06:23 +01002133static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
2134 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2135 HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
2136 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2137 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
2138 HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
Takashi Iwai2ece5f422006-07-06 19:16:40 +02002139 { } /* end */
Takashi Iwaid32410b12005-11-24 16:06:23 +01002140};
2141
2142static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002143 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2144 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
2145 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
2146 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
2147 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
2148 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2149 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2150
2151 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2152 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2153 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2154 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2155 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2156 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2157 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2158 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2159
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002160 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002161 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2162
2163 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2164 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
2165
2166 { } /* end */
2167};
2168
2169/* 3-stack mode */
Takashi Iwaid32410b12005-11-24 16:06:23 +01002170static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002171 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
Takashi Iwaid32410b12005-11-24 16:06:23 +01002172 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002173 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2174 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
Takashi Iwai2ece5f422006-07-06 19:16:40 +02002175 { } /* end */
Takashi Iwaid32410b12005-11-24 16:06:23 +01002176};
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002177
Takashi Iwaid32410b12005-11-24 16:06:23 +01002178static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
2179 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002180 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2181 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
2182 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
Takashi Iwai2ece5f422006-07-06 19:16:40 +02002183 { } /* end */
Takashi Iwaid32410b12005-11-24 16:06:23 +01002184};
2185
2186static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002187 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
Takashi Iwaid32410b12005-11-24 16:06:23 +01002188 HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
2189 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
2190 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002191 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2192 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2193
2194 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2195 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2196 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2197 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2198 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2199 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2200 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2201 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2202
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002203 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002204 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2205
2206 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2207 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
2208 {
2209 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2210 .name = "Channel Mode",
2211 .info = ad198x_ch_mode_info,
2212 .get = ad198x_ch_mode_get,
2213 .put = ad198x_ch_mode_put,
2214 },
2215
2216 { } /* end */
2217};
2218
2219/* laptop mode */
2220static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
2221 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2222 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
2223 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2224
2225 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2226 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2227 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2228 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2229 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2230 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2231
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002232 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002233 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2234
2235 HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2236
2237 {
2238 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2239 .name = "External Amplifier",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002240 .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
Takashi Iwai18a815d2006-03-01 19:54:39 +01002241 .info = ad198x_eapd_info,
2242 .get = ad198x_eapd_get,
2243 .put = ad198x_eapd_put,
Takashi Iwaiee6e3652009-12-08 17:23:33 +01002244 .private_value = 0x12, /* port-D */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002245 },
2246
2247 { } /* end */
2248};
2249
2250/* capture */
2251static struct snd_kcontrol_new ad1988_capture_mixers[] = {
2252 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
2253 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
2254 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
2255 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
2256 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
2257 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
2258 {
2259 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2260 /* The multiple "Capture Source" controls confuse alsamixer
2261 * So call somewhat different..
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002262 */
2263 /* .name = "Capture Source", */
2264 .name = "Input Source",
2265 .count = 3,
2266 .info = ad198x_mux_enum_info,
2267 .get = ad198x_mux_enum_get,
2268 .put = ad198x_mux_enum_put,
2269 },
2270 { } /* end */
2271};
2272
2273static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
2274 struct snd_ctl_elem_info *uinfo)
2275{
2276 static char *texts[] = {
2277 "PCM", "ADC1", "ADC2", "ADC3"
2278 };
2279 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2280 uinfo->count = 1;
2281 uinfo->value.enumerated.items = 4;
2282 if (uinfo->value.enumerated.item >= 4)
2283 uinfo->value.enumerated.item = 3;
2284 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2285 return 0;
2286}
2287
2288static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
2289 struct snd_ctl_elem_value *ucontrol)
2290{
2291 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2292 unsigned int sel;
2293
Takashi Iwaibddcf542007-07-24 18:04:05 +02002294 sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
2295 AC_AMP_GET_INPUT);
2296 if (!(sel & 0x80))
2297 ucontrol->value.enumerated.item[0] = 0;
2298 else {
Takashi Iwai35b26722007-05-05 12:17:17 +02002299 sel = snd_hda_codec_read(codec, 0x0b, 0,
2300 AC_VERB_GET_CONNECT_SEL, 0);
2301 if (sel < 3)
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002302 sel++;
2303 else
2304 sel = 0;
Takashi Iwaibddcf542007-07-24 18:04:05 +02002305 ucontrol->value.enumerated.item[0] = sel;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002306 }
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002307 return 0;
2308}
2309
2310static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
2311 struct snd_ctl_elem_value *ucontrol)
2312{
2313 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai35b26722007-05-05 12:17:17 +02002314 unsigned int val, sel;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002315 int change;
2316
Takashi Iwai35b26722007-05-05 12:17:17 +02002317 val = ucontrol->value.enumerated.item[0];
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002318 if (val > 3)
2319 return -EINVAL;
Takashi Iwai35b26722007-05-05 12:17:17 +02002320 if (!val) {
Takashi Iwaibddcf542007-07-24 18:04:05 +02002321 sel = snd_hda_codec_read(codec, 0x1d, 0,
2322 AC_VERB_GET_AMP_GAIN_MUTE,
2323 AC_AMP_GET_INPUT);
2324 change = sel & 0x80;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002325 if (change) {
2326 snd_hda_codec_write_cache(codec, 0x1d, 0,
2327 AC_VERB_SET_AMP_GAIN_MUTE,
2328 AMP_IN_UNMUTE(0));
2329 snd_hda_codec_write_cache(codec, 0x1d, 0,
2330 AC_VERB_SET_AMP_GAIN_MUTE,
2331 AMP_IN_MUTE(1));
Takashi Iwaibddcf542007-07-24 18:04:05 +02002332 }
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002333 } else {
Takashi Iwaibddcf542007-07-24 18:04:05 +02002334 sel = snd_hda_codec_read(codec, 0x1d, 0,
2335 AC_VERB_GET_AMP_GAIN_MUTE,
2336 AC_AMP_GET_INPUT | 0x01);
2337 change = sel & 0x80;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002338 if (change) {
2339 snd_hda_codec_write_cache(codec, 0x1d, 0,
2340 AC_VERB_SET_AMP_GAIN_MUTE,
2341 AMP_IN_MUTE(0));
2342 snd_hda_codec_write_cache(codec, 0x1d, 0,
2343 AC_VERB_SET_AMP_GAIN_MUTE,
2344 AMP_IN_UNMUTE(1));
Takashi Iwaibddcf542007-07-24 18:04:05 +02002345 }
Takashi Iwai35b26722007-05-05 12:17:17 +02002346 sel = snd_hda_codec_read(codec, 0x0b, 0,
2347 AC_VERB_GET_CONNECT_SEL, 0) + 1;
2348 change |= sel != val;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002349 if (change)
2350 snd_hda_codec_write_cache(codec, 0x0b, 0,
2351 AC_VERB_SET_CONNECT_SEL,
2352 val - 1);
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002353 }
2354 return change;
2355}
2356
2357static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
2358 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2359 {
2360 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2361 .name = "IEC958 Playback Source",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002362 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002363 .info = ad1988_spdif_playback_source_info,
2364 .get = ad1988_spdif_playback_source_get,
2365 .put = ad1988_spdif_playback_source_put,
2366 },
2367 { } /* end */
2368};
2369
2370static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
2371 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
2372 { } /* end */
2373};
2374
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02002375static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
2376 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
Robin H. Johnson9cae0c62008-09-13 16:54:58 -07002377 HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02002378 { } /* end */
2379};
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002380
2381/*
2382 * initialization verbs
2383 */
2384
2385/*
2386 * for 6-stack (+dig)
2387 */
2388static struct hda_verb ad1988_6stack_init_verbs[] = {
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002389 /* Front, Surround, CLFE, side DAC; unmute as default */
2390 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2391 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2392 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2393 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002394 /* Port-A front headphon path */
2395 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2396 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2397 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2398 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2399 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2400 /* Port-D line-out path */
2401 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2402 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2403 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2404 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2405 /* Port-F surround path */
2406 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2407 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2408 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2409 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2410 /* Port-G CLFE path */
2411 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2412 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2413 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2414 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2415 /* Port-H side path */
2416 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2417 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2418 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2419 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2420 /* Mono out path */
2421 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2422 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2423 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2424 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2425 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2426 /* Port-B front mic-in path */
2427 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2428 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2429 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2430 /* Port-C line-in path */
2431 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2432 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2433 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2434 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2435 /* Port-E mic-in path */
2436 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2437 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2438 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2439 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
Johannes Stezenbach695005c2007-12-13 17:51:00 +01002440 /* Analog CD Input */
2441 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidb3da6c2008-08-11 18:08:54 +02002442 /* Analog Mix output amp */
2443 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002444
2445 { }
2446};
2447
2448static struct hda_verb ad1988_capture_init_verbs[] = {
2449 /* mute analog mix */
2450 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2451 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2452 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2453 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2454 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2455 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2456 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2457 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2458 /* select ADCs - front-mic */
2459 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2460 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2461 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002462
2463 { }
2464};
2465
2466static struct hda_verb ad1988_spdif_init_verbs[] = {
2467 /* SPDIF out sel */
2468 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
2469 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
2470 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaibddcf542007-07-24 18:04:05 +02002471 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002472 /* SPDIF out pin */
2473 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002474
2475 { }
2476};
2477
Jaroslav Kyselafd0b0922010-01-21 14:54:38 +01002478static struct hda_verb ad1988_spdif_in_init_verbs[] = {
2479 /* unmute SPDIF input pin */
2480 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2481 { }
2482};
2483
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02002484/* AD1989 has no ADC -> SPDIF route */
2485static struct hda_verb ad1989_spdif_init_verbs[] = {
Robin H. Johnsone8bfc6c2008-09-13 16:55:00 -07002486 /* SPDIF-1 out pin */
2487 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02002488 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
Robin H. Johnsone8bfc6c2008-09-13 16:55:00 -07002489 /* SPDIF-2/HDMI out pin */
2490 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2491 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02002492 { }
2493};
2494
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002495/*
2496 * verbs for 3stack (+dig)
2497 */
2498static struct hda_verb ad1988_3stack_ch2_init[] = {
2499 /* set port-C to line-in */
2500 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2501 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2502 /* set port-E to mic-in */
2503 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2504 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2505 { } /* end */
2506};
2507
2508static struct hda_verb ad1988_3stack_ch6_init[] = {
2509 /* set port-C to surround out */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002510 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
Takashi Iwaid32410b12005-11-24 16:06:23 +01002511 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002512 /* set port-E to CLFE out */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002513 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
Takashi Iwaid32410b12005-11-24 16:06:23 +01002514 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002515 { } /* end */
2516};
2517
2518static struct hda_channel_mode ad1988_3stack_modes[2] = {
2519 { 2, ad1988_3stack_ch2_init },
2520 { 6, ad1988_3stack_ch6_init },
2521};
2522
2523static struct hda_verb ad1988_3stack_init_verbs[] = {
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002524 /* Front, Surround, CLFE, side DAC; unmute as default */
2525 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2526 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2527 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2528 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002529 /* Port-A front headphon path */
2530 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2531 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2532 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2533 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2534 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2535 /* Port-D line-out path */
2536 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2537 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2538 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2539 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2540 /* Mono out path */
2541 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2542 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2543 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2544 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2545 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2546 /* Port-B front mic-in path */
2547 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2548 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2549 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwaid32410b12005-11-24 16:06:23 +01002550 /* Port-C line-in/surround path - 6ch mode as default */
2551 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2552 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002553 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwaid32410b12005-11-24 16:06:23 +01002554 {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002555 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
Takashi Iwaid32410b12005-11-24 16:06:23 +01002556 /* Port-E mic-in/CLFE path - 6ch mode as default */
2557 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2558 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002559 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002560 {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002561 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2562 /* mute analog mix */
2563 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2564 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2565 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2566 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2567 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2568 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2569 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2570 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2571 /* select ADCs - front-mic */
2572 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2573 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2574 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
Takashi Iwaidb3da6c2008-08-11 18:08:54 +02002575 /* Analog Mix output amp */
2576 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002577 { }
2578};
2579
2580/*
2581 * verbs for laptop mode (+dig)
2582 */
2583static struct hda_verb ad1988_laptop_hp_on[] = {
2584 /* unmute port-A and mute port-D */
2585 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2586 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2587 { } /* end */
2588};
2589static struct hda_verb ad1988_laptop_hp_off[] = {
2590 /* mute port-A and unmute port-D */
2591 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2592 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2593 { } /* end */
2594};
2595
2596#define AD1988_HP_EVENT 0x01
2597
2598static struct hda_verb ad1988_laptop_init_verbs[] = {
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002599 /* Front, Surround, CLFE, side DAC; unmute as default */
2600 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2601 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2602 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2603 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002604 /* Port-A front headphon path */
2605 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2606 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2607 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2608 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2609 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2610 /* unsolicited event for pin-sense */
2611 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
2612 /* Port-D line-out path + EAPD */
2613 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2614 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2615 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2616 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2617 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
2618 /* Mono out path */
2619 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2620 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2621 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2622 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2623 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2624 /* Port-B mic-in path */
2625 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2626 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2627 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2628 /* Port-C docking station - try to output */
2629 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2630 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2631 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2632 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2633 /* mute analog mix */
2634 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2635 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2636 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2637 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2638 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2639 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2640 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2641 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2642 /* select ADCs - mic */
2643 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2644 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2645 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
Takashi Iwaidb3da6c2008-08-11 18:08:54 +02002646 /* Analog Mix output amp */
2647 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002648 { }
2649};
2650
2651static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
2652{
2653 if ((res >> 26) != AD1988_HP_EVENT)
2654 return;
Takashi Iwaid56757a2009-11-18 08:00:14 +01002655 if (snd_hda_jack_detect(codec, 0x11))
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002656 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
2657 else
2658 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
2659}
2660
Takashi Iwaicb53c622007-08-10 17:21:45 +02002661#ifdef CONFIG_SND_HDA_POWER_SAVE
2662static struct hda_amp_list ad1988_loopbacks[] = {
2663 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
2664 { 0x20, HDA_INPUT, 1 }, /* Line */
2665 { 0x20, HDA_INPUT, 4 }, /* Mic */
2666 { 0x20, HDA_INPUT, 6 }, /* CD */
2667 { } /* end */
2668};
2669#endif
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002670
2671/*
Takashi Iwaid32410b12005-11-24 16:06:23 +01002672 * Automatic parse of I/O pins from the BIOS configuration
2673 */
2674
Takashi Iwaid32410b12005-11-24 16:06:23 +01002675enum {
2676 AD_CTL_WIDGET_VOL,
2677 AD_CTL_WIDGET_MUTE,
2678 AD_CTL_BIND_MUTE,
2679};
2680static struct snd_kcontrol_new ad1988_control_templates[] = {
2681 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2682 HDA_CODEC_MUTE(NULL, 0, 0, 0),
2683 HDA_BIND_MUTE(NULL, 0, 0, 0),
2684};
2685
2686/* add dynamic controls */
2687static int add_control(struct ad198x_spec *spec, int type, const char *name,
2688 unsigned long val)
2689{
2690 struct snd_kcontrol_new *knew;
2691
Takashi Iwai603c4012008-07-30 15:01:44 +02002692 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2693 knew = snd_array_new(&spec->kctls);
2694 if (!knew)
2695 return -ENOMEM;
Takashi Iwaid32410b12005-11-24 16:06:23 +01002696 *knew = ad1988_control_templates[type];
2697 knew->name = kstrdup(name, GFP_KERNEL);
2698 if (! knew->name)
2699 return -ENOMEM;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01002700 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01002701 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaid32410b12005-11-24 16:06:23 +01002702 knew->private_value = val;
Takashi Iwaid32410b12005-11-24 16:06:23 +01002703 return 0;
2704}
2705
2706#define AD1988_PIN_CD_NID 0x18
2707#define AD1988_PIN_BEEP_NID 0x10
2708
2709static hda_nid_t ad1988_mixer_nids[8] = {
2710 /* A B C D E F G H */
2711 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28
2712};
2713
2714static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
2715{
2716 static hda_nid_t idx_to_dac[8] = {
2717 /* A B C D E F G H */
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002718 0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
Takashi Iwaid32410b12005-11-24 16:06:23 +01002719 };
2720 static hda_nid_t idx_to_dac_rev2[8] = {
2721 /* A B C D E F G H */
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002722 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
Takashi Iwaid32410b12005-11-24 16:06:23 +01002723 };
Takashi Iwai1a806f42006-07-03 15:58:16 +02002724 if (is_rev2(codec))
Takashi Iwaid32410b12005-11-24 16:06:23 +01002725 return idx_to_dac_rev2[idx];
2726 else
2727 return idx_to_dac[idx];
2728}
2729
2730static hda_nid_t ad1988_boost_nids[8] = {
2731 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0
2732};
2733
2734static int ad1988_pin_idx(hda_nid_t nid)
2735{
2736 static hda_nid_t ad1988_io_pins[8] = {
2737 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25
2738 };
2739 int i;
2740 for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++)
2741 if (ad1988_io_pins[i] == nid)
2742 return i;
2743 return 0; /* should be -1 */
2744}
2745
2746static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
2747{
2748 static int loopback_idx[8] = {
2749 2, 0, 1, 3, 4, 5, 1, 4
2750 };
2751 switch (nid) {
2752 case AD1988_PIN_CD_NID:
2753 return 6;
2754 default:
2755 return loopback_idx[ad1988_pin_idx(nid)];
2756 }
2757}
2758
2759static int ad1988_pin_to_adc_idx(hda_nid_t nid)
2760{
2761 static int adc_idx[8] = {
2762 0, 1, 2, 8, 4, 3, 6, 7
2763 };
2764 switch (nid) {
2765 case AD1988_PIN_CD_NID:
2766 return 5;
2767 default:
2768 return adc_idx[ad1988_pin_idx(nid)];
2769 }
2770}
2771
2772/* fill in the dac_nids table from the parsed pin configuration */
2773static int ad1988_auto_fill_dac_nids(struct hda_codec *codec,
2774 const struct auto_pin_cfg *cfg)
2775{
2776 struct ad198x_spec *spec = codec->spec;
2777 int i, idx;
2778
2779 spec->multiout.dac_nids = spec->private_dac_nids;
2780
2781 /* check the pins hardwired to audio widget */
2782 for (i = 0; i < cfg->line_outs; i++) {
2783 idx = ad1988_pin_idx(cfg->line_out_pins[i]);
2784 spec->multiout.dac_nids[i] = ad1988_idx_to_dac(codec, idx);
2785 }
2786 spec->multiout.num_dacs = cfg->line_outs;
2787 return 0;
2788}
2789
2790/* add playback controls from the parsed DAC table */
2791static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec,
2792 const struct auto_pin_cfg *cfg)
2793{
2794 char name[32];
2795 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
2796 hda_nid_t nid;
2797 int i, err;
2798
2799 for (i = 0; i < cfg->line_outs; i++) {
2800 hda_nid_t dac = spec->multiout.dac_nids[i];
2801 if (! dac)
2802 continue;
2803 nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])];
2804 if (i == 2) {
2805 /* Center/LFE */
2806 err = add_control(spec, AD_CTL_WIDGET_VOL,
2807 "Center Playback Volume",
2808 HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT));
2809 if (err < 0)
2810 return err;
2811 err = add_control(spec, AD_CTL_WIDGET_VOL,
2812 "LFE Playback Volume",
2813 HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT));
2814 if (err < 0)
2815 return err;
2816 err = add_control(spec, AD_CTL_BIND_MUTE,
2817 "Center Playback Switch",
2818 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT));
2819 if (err < 0)
2820 return err;
2821 err = add_control(spec, AD_CTL_BIND_MUTE,
2822 "LFE Playback Switch",
2823 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT));
2824 if (err < 0)
2825 return err;
2826 } else {
2827 sprintf(name, "%s Playback Volume", chname[i]);
2828 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2829 HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT));
2830 if (err < 0)
2831 return err;
2832 sprintf(name, "%s Playback Switch", chname[i]);
2833 err = add_control(spec, AD_CTL_BIND_MUTE, name,
2834 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
2835 if (err < 0)
2836 return err;
2837 }
2838 }
2839 return 0;
2840}
2841
2842/* add playback controls for speaker and HP outputs */
2843static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
2844 const char *pfx)
2845{
2846 struct ad198x_spec *spec = codec->spec;
2847 hda_nid_t nid;
Takashi Iwai43785ea2008-06-16 15:47:26 +02002848 int i, idx, err;
Takashi Iwaid32410b12005-11-24 16:06:23 +01002849 char name[32];
2850
2851 if (! pin)
2852 return 0;
2853
2854 idx = ad1988_pin_idx(pin);
2855 nid = ad1988_idx_to_dac(codec, idx);
Takashi Iwai43785ea2008-06-16 15:47:26 +02002856 /* check whether the corresponding DAC was already taken */
2857 for (i = 0; i < spec->autocfg.line_outs; i++) {
2858 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2859 hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin));
2860 if (dac == nid)
2861 break;
2862 }
2863 if (i >= spec->autocfg.line_outs) {
2864 /* specify the DAC as the extra output */
2865 if (!spec->multiout.hp_nid)
2866 spec->multiout.hp_nid = nid;
2867 else
2868 spec->multiout.extra_out_nid[0] = nid;
2869 /* control HP volume/switch on the output mixer amp */
2870 sprintf(name, "%s Playback Volume", pfx);
2871 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2872 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2873 if (err < 0)
2874 return err;
2875 }
Takashi Iwaid32410b12005-11-24 16:06:23 +01002876 nid = ad1988_mixer_nids[idx];
2877 sprintf(name, "%s Playback Switch", pfx);
2878 if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,
2879 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
2880 return err;
2881 return 0;
2882}
2883
2884/* create input playback/capture controls for the given pin */
2885static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
Takashi Iwai9e042e72010-08-30 13:04:44 +02002886 const char *ctlname, int ctlidx, int boost)
Takashi Iwaid32410b12005-11-24 16:06:23 +01002887{
2888 char name[32];
2889 int err, idx;
2890
2891 sprintf(name, "%s Playback Volume", ctlname);
2892 idx = ad1988_pin_to_loopback_idx(pin);
2893 if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2894 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2895 return err;
2896 sprintf(name, "%s Playback Switch", ctlname);
2897 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name,
2898 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2899 return err;
2900 if (boost) {
2901 hda_nid_t bnid;
2902 idx = ad1988_pin_idx(pin);
2903 bnid = ad1988_boost_nids[idx];
2904 if (bnid) {
2905 sprintf(name, "%s Boost", ctlname);
2906 return add_control(spec, AD_CTL_WIDGET_VOL, name,
2907 HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));
2908
2909 }
2910 }
2911 return 0;
2912}
2913
2914/* create playback/capture controls for input pins */
Takashi Iwai10a20af2010-09-09 16:28:02 +02002915static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
Takashi Iwaid32410b12005-11-24 16:06:23 +01002916 const struct auto_pin_cfg *cfg)
2917{
Takashi Iwai10a20af2010-09-09 16:28:02 +02002918 struct ad198x_spec *spec = codec->spec;
Takashi Iwaid32410b12005-11-24 16:06:23 +01002919 struct hda_input_mux *imux = &spec->private_imux;
Takashi Iwai10a20af2010-09-09 16:28:02 +02002920 int i, err, type, type_idx;
Takashi Iwaid32410b12005-11-24 16:06:23 +01002921
Takashi Iwai9e042e72010-08-30 13:04:44 +02002922 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai10a20af2010-09-09 16:28:02 +02002923 const char *label;
Takashi Iwai9e042e72010-08-30 13:04:44 +02002924 type = cfg->inputs[i].type;
Takashi Iwai10a20af2010-09-09 16:28:02 +02002925 label = hda_get_autocfg_input_label(codec, cfg, i);
2926 snd_hda_add_imux_item(imux, label,
2927 ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
2928 &type_idx);
Takashi Iwai9e042e72010-08-30 13:04:44 +02002929 err = new_analog_input(spec, cfg->inputs[i].pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02002930 label, type_idx,
Takashi Iwai86e29592010-09-09 14:50:17 +02002931 type == AUTO_PIN_MIC);
Takashi Iwaid32410b12005-11-24 16:06:23 +01002932 if (err < 0)
2933 return err;
Takashi Iwaid32410b12005-11-24 16:06:23 +01002934 }
Takashi Iwai10a20af2010-09-09 16:28:02 +02002935 snd_hda_add_imux_item(imux, "Mix", 9, NULL);
Takashi Iwaid32410b12005-11-24 16:06:23 +01002936
2937 if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
2938 "Analog Mix Playback Volume",
2939 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
2940 return err;
2941 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE,
2942 "Analog Mix Playback Switch",
2943 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
2944 return err;
2945
2946 return 0;
2947}
2948
2949static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
2950 hda_nid_t nid, int pin_type,
2951 int dac_idx)
2952{
2953 /* set as output */
2954 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
2955 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
2956 switch (nid) {
2957 case 0x11: /* port-A - DAC 04 */
2958 snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2959 break;
2960 case 0x14: /* port-B - DAC 06 */
2961 snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02);
2962 break;
2963 case 0x15: /* port-C - DAC 05 */
2964 snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00);
2965 break;
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002966 case 0x17: /* port-E - DAC 0a */
Takashi Iwaid32410b12005-11-24 16:06:23 +01002967 snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2968 break;
2969 case 0x13: /* mono - DAC 04 */
2970 snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2971 break;
2972 }
2973}
2974
2975static void ad1988_auto_init_multi_out(struct hda_codec *codec)
2976{
2977 struct ad198x_spec *spec = codec->spec;
2978 int i;
2979
2980 for (i = 0; i < spec->autocfg.line_outs; i++) {
2981 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2982 ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
2983 }
2984}
2985
2986static void ad1988_auto_init_extra_out(struct hda_codec *codec)
2987{
2988 struct ad198x_spec *spec = codec->spec;
2989 hda_nid_t pin;
2990
Takashi Iwai82bc9552006-03-21 11:24:42 +01002991 pin = spec->autocfg.speaker_pins[0];
Takashi Iwaid32410b12005-11-24 16:06:23 +01002992 if (pin) /* connect to front */
2993 ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002994 pin = spec->autocfg.hp_pins[0];
Takashi Iwaid32410b12005-11-24 16:06:23 +01002995 if (pin) /* connect to front */
2996 ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
2997}
2998
2999static void ad1988_auto_init_analog_input(struct hda_codec *codec)
3000{
3001 struct ad198x_spec *spec = codec->spec;
Takashi Iwai9e042e72010-08-30 13:04:44 +02003002 const struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaid32410b12005-11-24 16:06:23 +01003003 int i, idx;
3004
Takashi Iwai9e042e72010-08-30 13:04:44 +02003005 for (i = 0; i < cfg->num_inputs; i++) {
3006 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwaid32410b12005-11-24 16:06:23 +01003007 switch (nid) {
3008 case 0x15: /* port-C */
3009 snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
3010 break;
3011 case 0x17: /* port-E */
3012 snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
3013 break;
3014 }
3015 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai86e29592010-09-09 14:50:17 +02003016 i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
Takashi Iwaid32410b12005-11-24 16:06:23 +01003017 if (nid != AD1988_PIN_CD_NID)
3018 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3019 AMP_OUT_MUTE);
3020 idx = ad1988_pin_idx(nid);
3021 if (ad1988_boost_nids[idx])
3022 snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0,
3023 AC_VERB_SET_AMP_GAIN_MUTE,
3024 AMP_OUT_ZERO);
3025 }
3026}
3027
3028/* parse the BIOS configuration and set up the alc_spec */
3029/* return 1 if successful, 0 if the proper config is not found, or a negative error code */
3030static int ad1988_parse_auto_config(struct hda_codec *codec)
3031{
3032 struct ad198x_spec *spec = codec->spec;
3033 int err;
3034
Kailang Yangdf694da2005-12-05 19:42:22 +01003035 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Takashi Iwaid32410b12005-11-24 16:06:23 +01003036 return err;
3037 if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3038 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003039 if (! spec->autocfg.line_outs)
Takashi Iwaid32410b12005-11-24 16:06:23 +01003040 return 0; /* can't find valid BIOS pin config */
3041 if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
Takashi Iwai82bc9552006-03-21 11:24:42 +01003042 (err = ad1988_auto_create_extra_out(codec,
3043 spec->autocfg.speaker_pins[0],
Takashi Iwaid32410b12005-11-24 16:06:23 +01003044 "Speaker")) < 0 ||
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003045 (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaid32410b12005-11-24 16:06:23 +01003046 "Headphone")) < 0 ||
Takashi Iwai10a20af2010-09-09 16:28:02 +02003047 (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
Takashi Iwaid32410b12005-11-24 16:06:23 +01003048 return err;
3049
3050 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3051
Takashi Iwai0852d7a2009-02-11 11:35:15 +01003052 if (spec->autocfg.dig_outs)
Takashi Iwaid32410b12005-11-24 16:06:23 +01003053 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3054 if (spec->autocfg.dig_in_pin)
3055 spec->dig_in_nid = AD1988_SPDIF_IN;
3056
Takashi Iwai603c4012008-07-30 15:01:44 +02003057 if (spec->kctls.list)
3058 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Takashi Iwaid32410b12005-11-24 16:06:23 +01003059
3060 spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
3061
3062 spec->input_mux = &spec->private_imux;
3063
3064 return 1;
3065}
3066
3067/* init callback for auto-configuration model -- overriding the default init */
3068static int ad1988_auto_init(struct hda_codec *codec)
3069{
3070 ad198x_init(codec);
3071 ad1988_auto_init_multi_out(codec);
3072 ad1988_auto_init_extra_out(codec);
3073 ad1988_auto_init_analog_input(codec);
3074 return 0;
3075}
3076
3077
3078/*
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003079 */
3080
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003081static const char *ad1988_models[AD1988_MODEL_LAST] = {
3082 [AD1988_6STACK] = "6stack",
3083 [AD1988_6STACK_DIG] = "6stack-dig",
3084 [AD1988_3STACK] = "3stack",
3085 [AD1988_3STACK_DIG] = "3stack-dig",
3086 [AD1988_LAPTOP] = "laptop",
3087 [AD1988_LAPTOP_DIG] = "laptop-dig",
3088 [AD1988_AUTO] = "auto",
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003089};
3090
Tobin Davisa64c8cd2007-03-12 11:36:00 +01003091static struct snd_pci_quirk ad1988_cfg_tbl[] = {
Tobin Davis18768992007-03-12 22:20:51 +01003092 SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003093 SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
Travis Placeb9e16bc2008-05-21 16:57:20 +02003094 SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
Robin H. Johnsonf51ff992008-09-13 16:55:01 -07003095 SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
Tobin Davisa64c8cd2007-03-12 11:36:00 +01003096 {}
3097};
3098
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003099static int patch_ad1988(struct hda_codec *codec)
3100{
3101 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01003102 int err, board_config;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003103
3104 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3105 if (spec == NULL)
3106 return -ENOMEM;
3107
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003108 codec->spec = spec;
3109
Takashi Iwai1a806f42006-07-03 15:58:16 +02003110 if (is_rev2(codec))
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01003111 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
3112
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003113 board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
Tobin Davisa64c8cd2007-03-12 11:36:00 +01003114 ad1988_models, ad1988_cfg_tbl);
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003115 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02003116 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
3117 codec->chip_name);
Takashi Iwaid32410b12005-11-24 16:06:23 +01003118 board_config = AD1988_AUTO;
3119 }
3120
3121 if (board_config == AD1988_AUTO) {
3122 /* automatic parse from the BIOS config */
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01003123 err = ad1988_parse_auto_config(codec);
Takashi Iwaid32410b12005-11-24 16:06:23 +01003124 if (err < 0) {
3125 ad198x_free(codec);
3126 return err;
3127 } else if (! err) {
3128 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n");
3129 board_config = AD1988_6STACK;
3130 }
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003131 }
3132
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01003133 err = snd_hda_attach_beep_device(codec, 0x10);
3134 if (err < 0) {
3135 ad198x_free(codec);
3136 return err;
3137 }
3138 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3139
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003140 switch (board_config) {
3141 case AD1988_6STACK:
3142 case AD1988_6STACK_DIG:
3143 spec->multiout.max_channels = 8;
3144 spec->multiout.num_dacs = 4;
Takashi Iwai1a806f42006-07-03 15:58:16 +02003145 if (is_rev2(codec))
Takashi Iwaid32410b12005-11-24 16:06:23 +01003146 spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
3147 else
3148 spec->multiout.dac_nids = ad1988_6stack_dac_nids;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003149 spec->input_mux = &ad1988_6stack_capture_source;
Takashi Iwaid32410b12005-11-24 16:06:23 +01003150 spec->num_mixers = 2;
Takashi Iwai1a806f42006-07-03 15:58:16 +02003151 if (is_rev2(codec))
Takashi Iwaid32410b12005-11-24 16:06:23 +01003152 spec->mixers[0] = ad1988_6stack_mixers1_rev2;
3153 else
3154 spec->mixers[0] = ad1988_6stack_mixers1;
3155 spec->mixers[1] = ad1988_6stack_mixers2;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003156 spec->num_init_verbs = 1;
3157 spec->init_verbs[0] = ad1988_6stack_init_verbs;
3158 if (board_config == AD1988_6STACK_DIG) {
3159 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3160 spec->dig_in_nid = AD1988_SPDIF_IN;
3161 }
3162 break;
3163 case AD1988_3STACK:
3164 case AD1988_3STACK_DIG:
3165 spec->multiout.max_channels = 6;
3166 spec->multiout.num_dacs = 3;
Takashi Iwai1a806f42006-07-03 15:58:16 +02003167 if (is_rev2(codec))
Takashi Iwaid32410b12005-11-24 16:06:23 +01003168 spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
3169 else
3170 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003171 spec->input_mux = &ad1988_6stack_capture_source;
3172 spec->channel_mode = ad1988_3stack_modes;
3173 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
Takashi Iwaid32410b12005-11-24 16:06:23 +01003174 spec->num_mixers = 2;
Takashi Iwai1a806f42006-07-03 15:58:16 +02003175 if (is_rev2(codec))
Takashi Iwaid32410b12005-11-24 16:06:23 +01003176 spec->mixers[0] = ad1988_3stack_mixers1_rev2;
3177 else
3178 spec->mixers[0] = ad1988_3stack_mixers1;
3179 spec->mixers[1] = ad1988_3stack_mixers2;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003180 spec->num_init_verbs = 1;
3181 spec->init_verbs[0] = ad1988_3stack_init_verbs;
3182 if (board_config == AD1988_3STACK_DIG)
3183 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3184 break;
3185 case AD1988_LAPTOP:
3186 case AD1988_LAPTOP_DIG:
3187 spec->multiout.max_channels = 2;
3188 spec->multiout.num_dacs = 1;
Takashi Iwaid32410b12005-11-24 16:06:23 +01003189 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003190 spec->input_mux = &ad1988_laptop_capture_source;
3191 spec->num_mixers = 1;
3192 spec->mixers[0] = ad1988_laptop_mixers;
Takashi Iwaiee6e3652009-12-08 17:23:33 +01003193 spec->inv_eapd = 1; /* inverted EAPD */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003194 spec->num_init_verbs = 1;
3195 spec->init_verbs[0] = ad1988_laptop_init_verbs;
3196 if (board_config == AD1988_LAPTOP_DIG)
3197 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3198 break;
3199 }
3200
Takashi Iwaid32410b12005-11-24 16:06:23 +01003201 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
3202 spec->adc_nids = ad1988_adc_nids;
3203 spec->capsrc_nids = ad1988_capsrc_nids;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003204 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
3205 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
3206 if (spec->multiout.dig_out_nid) {
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02003207 if (codec->vendor_id >= 0x11d4989a) {
3208 spec->mixers[spec->num_mixers++] =
3209 ad1989_spdif_out_mixers;
3210 spec->init_verbs[spec->num_init_verbs++] =
3211 ad1989_spdif_init_verbs;
Robin H. Johnson9cae0c62008-09-13 16:54:58 -07003212 codec->slave_dig_outs = ad1989b_slave_dig_outs;
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02003213 } else {
3214 spec->mixers[spec->num_mixers++] =
3215 ad1988_spdif_out_mixers;
3216 spec->init_verbs[spec->num_init_verbs++] =
3217 ad1988_spdif_init_verbs;
3218 }
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003219 }
Jaroslav Kyselafd0b0922010-01-21 14:54:38 +01003220 if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003221 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
Jaroslav Kyselafd0b0922010-01-21 14:54:38 +01003222 spec->init_verbs[spec->num_init_verbs++] =
3223 ad1988_spdif_in_init_verbs;
3224 }
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003225
3226 codec->patch_ops = ad198x_patch_ops;
3227 switch (board_config) {
Takashi Iwaid32410b12005-11-24 16:06:23 +01003228 case AD1988_AUTO:
3229 codec->patch_ops.init = ad1988_auto_init;
3230 break;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003231 case AD1988_LAPTOP:
3232 case AD1988_LAPTOP_DIG:
3233 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
3234 break;
3235 }
Takashi Iwaicb53c622007-08-10 17:21:45 +02003236#ifdef CONFIG_SND_HDA_POWER_SAVE
3237 spec->loopback.amplist = ad1988_loopbacks;
3238#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01003239 spec->vmaster_nid = 0x04;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003240
Takashi Iwai729d55b2009-12-25 22:49:01 +01003241 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02003242 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01003243
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003244 return 0;
3245}
3246
3247
3248/*
Takashi Iwai2bac6472007-05-18 18:21:41 +02003249 * AD1884 / AD1984
3250 *
3251 * port-B - front line/mic-in
3252 * port-E - aux in/out
3253 * port-F - aux in/out
3254 * port-C - rear line/mic-in
3255 * port-D - rear line/hp-out
3256 * port-A - front line/hp-out
3257 *
3258 * AD1984 = AD1884 + two digital mic-ins
3259 *
3260 * FIXME:
3261 * For simplicity, we share the single DAC for both HP and line-outs
3262 * right now. The inidividual playbacks could be easily implemented,
3263 * but no build-up framework is given, so far.
3264 */
3265
3266static hda_nid_t ad1884_dac_nids[1] = {
3267 0x04,
3268};
3269
3270static hda_nid_t ad1884_adc_nids[2] = {
3271 0x08, 0x09,
3272};
3273
3274static hda_nid_t ad1884_capsrc_nids[2] = {
3275 0x0c, 0x0d,
3276};
3277
3278#define AD1884_SPDIF_OUT 0x02
3279
3280static struct hda_input_mux ad1884_capture_source = {
3281 .num_items = 4,
3282 .items = {
3283 { "Front Mic", 0x0 },
3284 { "Mic", 0x1 },
3285 { "CD", 0x2 },
3286 { "Mix", 0x3 },
3287 },
3288};
3289
3290static struct snd_kcontrol_new ad1884_base_mixers[] = {
3291 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3292 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3293 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3294 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3295 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3296 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3297 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3298 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3299 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3300 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3301 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3302 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003303 HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
3304 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3305 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3306 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3307 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3308 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3309 {
3310 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3311 /* The multiple "Capture Source" controls confuse alsamixer
3312 * So call somewhat different..
Takashi Iwai2bac6472007-05-18 18:21:41 +02003313 */
3314 /* .name = "Capture Source", */
3315 .name = "Input Source",
3316 .count = 2,
3317 .info = ad198x_mux_enum_info,
3318 .get = ad198x_mux_enum_get,
3319 .put = ad198x_mux_enum_put,
3320 },
3321 /* SPDIF controls */
3322 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3323 {
3324 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3325 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3326 /* identical with ad1983 */
3327 .info = ad1983_spdif_route_info,
3328 .get = ad1983_spdif_route_get,
3329 .put = ad1983_spdif_route_put,
3330 },
3331 { } /* end */
3332};
3333
3334static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
3335 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
3336 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
3337 HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
Takashi Iwai538c49c2007-06-05 12:13:34 +02003338 HDA_INPUT),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003339 HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
Takashi Iwai538c49c2007-06-05 12:13:34 +02003340 HDA_INPUT),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003341 { } /* end */
3342};
3343
3344/*
3345 * initialization verbs
3346 */
3347static struct hda_verb ad1884_init_verbs[] = {
3348 /* DACs; mute as default */
Takashi Iwai3b194402007-06-04 18:32:23 +02003349 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3350 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2bac6472007-05-18 18:21:41 +02003351 /* Port-A (HP) mixer */
3352 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3353 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3354 /* Port-A pin */
3355 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3356 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3357 /* HP selector - select DAC2 */
3358 {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
3359 /* Port-D (Line-out) mixer */
3360 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3361 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3362 /* Port-D pin */
3363 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3364 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3365 /* Mono-out mixer */
3366 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3367 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3368 /* Mono-out pin */
3369 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3370 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3371 /* Mono selector */
3372 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
3373 /* Port-B (front mic) pin */
3374 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai60e388e2009-01-23 12:37:09 +01003375 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai2bac6472007-05-18 18:21:41 +02003376 /* Port-C (rear mic) pin */
3377 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai60e388e2009-01-23 12:37:09 +01003378 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai2bac6472007-05-18 18:21:41 +02003379 /* Analog mixer; mute as default */
3380 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3381 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3382 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3383 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3384 /* Analog Mix output amp */
3385 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
3386 /* SPDIF output selector */
3387 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
3388 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3389 { } /* end */
3390};
3391
Takashi Iwaicb53c622007-08-10 17:21:45 +02003392#ifdef CONFIG_SND_HDA_POWER_SAVE
3393static struct hda_amp_list ad1884_loopbacks[] = {
3394 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3395 { 0x20, HDA_INPUT, 1 }, /* Mic */
3396 { 0x20, HDA_INPUT, 2 }, /* CD */
3397 { 0x20, HDA_INPUT, 4 }, /* Docking */
3398 { } /* end */
3399};
3400#endif
3401
Takashi Iwai2134ea42008-01-10 16:53:55 +01003402static const char *ad1884_slave_vols[] = {
3403 "PCM Playback Volume",
3404 "Mic Playback Volume",
3405 "Mono Playback Volume",
3406 "Front Mic Playback Volume",
3407 "Mic Playback Volume",
3408 "CD Playback Volume",
3409 "Internal Mic Playback Volume",
Akinobu Mitabca68462009-04-06 18:42:42 +09003410 "Docking Mic Playback Volume",
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01003411 /* "Beep Playback Volume", */
Takashi Iwai4806ef02008-01-26 09:58:13 +01003412 "IEC958 Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003413 NULL
3414};
3415
Takashi Iwai2bac6472007-05-18 18:21:41 +02003416static int patch_ad1884(struct hda_codec *codec)
3417{
3418 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01003419 int err;
Takashi Iwai2bac6472007-05-18 18:21:41 +02003420
3421 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3422 if (spec == NULL)
3423 return -ENOMEM;
3424
Takashi Iwai2bac6472007-05-18 18:21:41 +02003425 codec->spec = spec;
3426
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01003427 err = snd_hda_attach_beep_device(codec, 0x10);
3428 if (err < 0) {
3429 ad198x_free(codec);
3430 return err;
3431 }
3432 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3433
Takashi Iwai2bac6472007-05-18 18:21:41 +02003434 spec->multiout.max_channels = 2;
3435 spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
3436 spec->multiout.dac_nids = ad1884_dac_nids;
3437 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3438 spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
3439 spec->adc_nids = ad1884_adc_nids;
3440 spec->capsrc_nids = ad1884_capsrc_nids;
3441 spec->input_mux = &ad1884_capture_source;
3442 spec->num_mixers = 1;
3443 spec->mixers[0] = ad1884_base_mixers;
3444 spec->num_init_verbs = 1;
3445 spec->init_verbs[0] = ad1884_init_verbs;
3446 spec->spdif_route = 0;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003447#ifdef CONFIG_SND_HDA_POWER_SAVE
3448 spec->loopback.amplist = ad1884_loopbacks;
3449#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01003450 spec->vmaster_nid = 0x04;
3451 /* we need to cover all playback volumes */
3452 spec->slave_vols = ad1884_slave_vols;
Takashi Iwai2bac6472007-05-18 18:21:41 +02003453
3454 codec->patch_ops = ad198x_patch_ops;
3455
Takashi Iwai729d55b2009-12-25 22:49:01 +01003456 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02003457 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01003458
Takashi Iwai2bac6472007-05-18 18:21:41 +02003459 return 0;
3460}
3461
3462/*
3463 * Lenovo Thinkpad T61/X61
3464 */
3465static struct hda_input_mux ad1984_thinkpad_capture_source = {
Takashi Iwaib26451c2008-02-26 11:56:35 +01003466 .num_items = 4,
Takashi Iwai2bac6472007-05-18 18:21:41 +02003467 .items = {
3468 { "Mic", 0x0 },
3469 { "Internal Mic", 0x1 },
3470 { "Mix", 0x3 },
Takashi Iwaib26451c2008-02-26 11:56:35 +01003471 { "Docking-Station", 0x4 },
Takashi Iwai2bac6472007-05-18 18:21:41 +02003472 },
3473};
3474
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003475
3476/*
3477 * Dell Precision T3400
3478 */
3479static struct hda_input_mux ad1984_dell_desktop_capture_source = {
3480 .num_items = 3,
3481 .items = {
3482 { "Front Mic", 0x0 },
3483 { "Line-In", 0x1 },
3484 { "Mix", 0x3 },
3485 },
3486};
3487
3488
Takashi Iwai2bac6472007-05-18 18:21:41 +02003489static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
3490 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3491 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3492 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3493 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3494 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3495 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3496 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3497 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +01003498 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3499 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003500 HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3501 HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003502 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3503 HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
Takashi Iwai0ba79622007-05-23 16:27:32 +02003504 HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003505 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3506 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3507 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3508 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3509 {
3510 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3511 /* The multiple "Capture Source" controls confuse alsamixer
3512 * So call somewhat different..
Takashi Iwai2bac6472007-05-18 18:21:41 +02003513 */
3514 /* .name = "Capture Source", */
3515 .name = "Input Source",
3516 .count = 2,
3517 .info = ad198x_mux_enum_info,
3518 .get = ad198x_mux_enum_get,
3519 .put = ad198x_mux_enum_put,
3520 },
Jerone Youngebf00c52008-01-07 12:22:18 +01003521 /* SPDIF controls */
3522 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3523 {
3524 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3525 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3526 /* identical with ad1983 */
3527 .info = ad1983_spdif_route_info,
3528 .get = ad1983_spdif_route_get,
3529 .put = ad1983_spdif_route_put,
3530 },
Takashi Iwai2bac6472007-05-18 18:21:41 +02003531 { } /* end */
3532};
3533
3534/* additional verbs */
3535static struct hda_verb ad1984_thinkpad_init_verbs[] = {
3536 /* Port-E (docking station mic) pin */
3537 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3538 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3539 /* docking mic boost */
Takashi Iwai70040c02009-01-23 14:18:11 +01003540 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +01003541 /* Analog PC Beeper - allow firmware/ACPI beeps */
3542 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a},
Takashi Iwai2bac6472007-05-18 18:21:41 +02003543 /* Analog mixer - docking mic; mute as default */
3544 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwaib959d1f2007-06-08 12:25:25 +02003545 /* enable EAPD bit */
3546 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
Takashi Iwai2bac6472007-05-18 18:21:41 +02003547 { } /* end */
3548};
3549
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003550/*
3551 * Dell Precision T3400
3552 */
3553static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
3554 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3555 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3556 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3557 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3558 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3559 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3560 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3561 HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
3562 HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003563 HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
3564 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3565 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3566 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3567 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3568 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3569 {
3570 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3571 /* The multiple "Capture Source" controls confuse alsamixer
3572 * So call somewhat different..
3573 */
3574 /* .name = "Capture Source", */
3575 .name = "Input Source",
3576 .count = 2,
3577 .info = ad198x_mux_enum_info,
3578 .get = ad198x_mux_enum_get,
3579 .put = ad198x_mux_enum_put,
3580 },
3581 { } /* end */
3582};
3583
Takashi Iwai2bac6472007-05-18 18:21:41 +02003584/* Digial MIC ADC NID 0x05 + 0x06 */
3585static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
3586 struct hda_codec *codec,
3587 unsigned int stream_tag,
3588 unsigned int format,
3589 struct snd_pcm_substream *substream)
3590{
3591 snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
3592 stream_tag, 0, format);
3593 return 0;
3594}
3595
3596static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
3597 struct hda_codec *codec,
3598 struct snd_pcm_substream *substream)
3599{
Takashi Iwai888afa12008-03-18 09:57:50 +01003600 snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
Takashi Iwai2bac6472007-05-18 18:21:41 +02003601 return 0;
3602}
3603
3604static struct hda_pcm_stream ad1984_pcm_dmic_capture = {
3605 .substreams = 2,
3606 .channels_min = 2,
3607 .channels_max = 2,
3608 .nid = 0x05,
3609 .ops = {
3610 .prepare = ad1984_pcm_dmic_prepare,
3611 .cleanup = ad1984_pcm_dmic_cleanup
3612 },
3613};
3614
3615static int ad1984_build_pcms(struct hda_codec *codec)
3616{
3617 struct ad198x_spec *spec = codec->spec;
3618 struct hda_pcm *info;
3619 int err;
3620
3621 err = ad198x_build_pcms(codec);
3622 if (err < 0)
3623 return err;
3624
3625 info = spec->pcm_rec + codec->num_pcms;
3626 codec->num_pcms++;
3627 info->name = "AD1984 Digital Mic";
3628 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
3629 return 0;
3630}
3631
3632/* models */
3633enum {
3634 AD1984_BASIC,
3635 AD1984_THINKPAD,
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003636 AD1984_DELL_DESKTOP,
Takashi Iwai2bac6472007-05-18 18:21:41 +02003637 AD1984_MODELS
3638};
3639
3640static const char *ad1984_models[AD1984_MODELS] = {
3641 [AD1984_BASIC] = "basic",
3642 [AD1984_THINKPAD] = "thinkpad",
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003643 [AD1984_DELL_DESKTOP] = "dell_desktop",
Takashi Iwai2bac6472007-05-18 18:21:41 +02003644};
3645
3646static struct snd_pci_quirk ad1984_cfg_tbl[] = {
3647 /* Lenovo Thinkpad T61/X61 */
Takashi Iwaidea0a502009-02-09 17:14:52 +01003648 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003649 SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
Luke Yelavich0f9f1ee92010-09-21 17:05:46 +10003650 SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003651 {}
3652};
3653
3654static int patch_ad1984(struct hda_codec *codec)
3655{
3656 struct ad198x_spec *spec;
3657 int board_config, err;
3658
3659 err = patch_ad1884(codec);
3660 if (err < 0)
3661 return err;
3662 spec = codec->spec;
3663 board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
3664 ad1984_models, ad1984_cfg_tbl);
3665 switch (board_config) {
3666 case AD1984_BASIC:
3667 /* additional digital mics */
3668 spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
3669 codec->patch_ops.build_pcms = ad1984_build_pcms;
3670 break;
3671 case AD1984_THINKPAD:
Jerone Young68c18692010-08-03 01:46:44 -05003672 if (codec->subsystem_id == 0x17aa20fb) {
3673 /* Thinpad X300 does not have the ability to do SPDIF,
3674 or attach to docking station to use SPDIF */
3675 spec->multiout.dig_out_nid = 0;
3676 } else
3677 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
Takashi Iwai2bac6472007-05-18 18:21:41 +02003678 spec->input_mux = &ad1984_thinkpad_capture_source;
3679 spec->mixers[0] = ad1984_thinkpad_mixers;
3680 spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +01003681 spec->analog_beep = 1;
Takashi Iwai2bac6472007-05-18 18:21:41 +02003682 break;
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003683 case AD1984_DELL_DESKTOP:
3684 spec->multiout.dig_out_nid = 0;
3685 spec->input_mux = &ad1984_dell_desktop_capture_source;
3686 spec->mixers[0] = ad1984_dell_desktop_mixers;
3687 break;
Takashi Iwai2bac6472007-05-18 18:21:41 +02003688 }
3689 return 0;
3690}
3691
3692
3693/*
Takashi Iwaic5059252008-02-16 09:43:56 +01003694 * AD1883 / AD1884A / AD1984A / AD1984B
3695 *
3696 * port-B (0x14) - front mic-in
3697 * port-E (0x1c) - rear mic-in
3698 * port-F (0x16) - CD / ext out
3699 * port-C (0x15) - rear line-in
3700 * port-D (0x12) - rear line-out
3701 * port-A (0x11) - front hp-out
3702 *
3703 * AD1984A = AD1884A + digital-mic
3704 * AD1883 = equivalent with AD1984A
3705 * AD1984B = AD1984A + extra SPDIF-out
3706 *
3707 * FIXME:
3708 * We share the single DAC for both HP and line-outs (see AD1884/1984).
3709 */
3710
3711static hda_nid_t ad1884a_dac_nids[1] = {
3712 0x03,
3713};
3714
3715#define ad1884a_adc_nids ad1884_adc_nids
3716#define ad1884a_capsrc_nids ad1884_capsrc_nids
3717
3718#define AD1884A_SPDIF_OUT 0x02
3719
3720static struct hda_input_mux ad1884a_capture_source = {
3721 .num_items = 5,
3722 .items = {
3723 { "Front Mic", 0x0 },
3724 { "Mic", 0x4 },
3725 { "Line", 0x1 },
3726 { "CD", 0x2 },
3727 { "Mix", 0x3 },
3728 },
3729};
3730
3731static struct snd_kcontrol_new ad1884a_base_mixers[] = {
3732 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3733 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3734 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3735 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3736 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3737 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3738 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3739 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3740 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3741 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3742 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
3743 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
3744 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3745 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3746 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3747 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
Takashi Iwaic5059252008-02-16 09:43:56 +01003748 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3749 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
3750 HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3751 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3752 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3753 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3754 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3755 {
3756 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3757 /* The multiple "Capture Source" controls confuse alsamixer
3758 * So call somewhat different..
3759 */
3760 /* .name = "Capture Source", */
3761 .name = "Input Source",
3762 .count = 2,
3763 .info = ad198x_mux_enum_info,
3764 .get = ad198x_mux_enum_get,
3765 .put = ad198x_mux_enum_put,
3766 },
3767 /* SPDIF controls */
3768 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3769 {
3770 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3771 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3772 /* identical with ad1983 */
3773 .info = ad1983_spdif_route_info,
3774 .get = ad1983_spdif_route_get,
3775 .put = ad1983_spdif_route_put,
3776 },
3777 { } /* end */
3778};
3779
3780/*
3781 * initialization verbs
3782 */
3783static struct hda_verb ad1884a_init_verbs[] = {
3784 /* DACs; unmute as default */
3785 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3786 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3787 /* Port-A (HP) mixer - route only from analog mixer */
3788 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3789 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3790 /* Port-A pin */
3791 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3792 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3793 /* Port-D (Line-out) mixer - route only from analog mixer */
3794 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3795 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3796 /* Port-D pin */
3797 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3798 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3799 /* Mono-out mixer - route only from analog mixer */
3800 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3801 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3802 /* Mono-out pin */
3803 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3804 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3805 /* Port-B (front mic) pin */
3806 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai60e388e2009-01-23 12:37:09 +01003807 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaic5059252008-02-16 09:43:56 +01003808 /* Port-C (rear line-in) pin */
3809 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai60e388e2009-01-23 12:37:09 +01003810 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaic5059252008-02-16 09:43:56 +01003811 /* Port-E (rear mic) pin */
3812 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3813 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3814 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
3815 /* Port-F (CD) pin */
3816 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3817 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3818 /* Analog mixer; mute as default */
3819 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3820 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3821 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3822 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3823 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
3824 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
3825 /* Analog Mix output amp */
3826 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3827 /* capture sources */
3828 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
3829 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3830 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
3831 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3832 /* SPDIF output amp */
3833 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3834 { } /* end */
3835};
3836
3837#ifdef CONFIG_SND_HDA_POWER_SAVE
3838static struct hda_amp_list ad1884a_loopbacks[] = {
3839 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3840 { 0x20, HDA_INPUT, 1 }, /* Mic */
3841 { 0x20, HDA_INPUT, 2 }, /* CD */
3842 { 0x20, HDA_INPUT, 4 }, /* Docking */
3843 { } /* end */
3844};
3845#endif
3846
3847/*
3848 * Laptop model
3849 *
3850 * Port A: Headphone jack
3851 * Port B: MIC jack
3852 * Port C: Internal MIC
3853 * Port D: Dock Line Out (if enabled)
3854 * Port E: Dock Line In (if enabled)
3855 * Port F: Internal speakers
3856 */
3857
Takashi Iwai17bbaa62009-08-30 12:15:59 +02003858static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
3859 struct snd_ctl_elem_value *ucontrol)
3860{
3861 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3862 int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
3863 int mute = (!ucontrol->value.integer.value[0] &&
3864 !ucontrol->value.integer.value[1]);
3865 /* toggle GPIO1 according to the mute state */
3866 snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
3867 mute ? 0x02 : 0x0);
3868 return ret;
3869}
Takashi Iwaic5059252008-02-16 09:43:56 +01003870
3871static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
3872 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwai17bbaa62009-08-30 12:15:59 +02003873 {
3874 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3875 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01003876 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai17bbaa62009-08-30 12:15:59 +02003877 .info = snd_hda_mixer_amp_switch_info,
3878 .get = snd_hda_mixer_amp_switch_get,
3879 .put = ad1884a_mobile_master_sw_put,
3880 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3881 },
Takashi Iwaic5059252008-02-16 09:43:56 +01003882 HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3883 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3884 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3885 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3886 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3887 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3888 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3889 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3890 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
Takashi Iwaic5059252008-02-16 09:43:56 +01003891 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3892 HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
3893 HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3894 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3895 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaic5059252008-02-16 09:43:56 +01003896 { } /* end */
3897};
3898
Takashi Iwaib40b04a2008-02-16 09:44:56 +01003899static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
3900 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwai099db17e2009-07-02 16:10:23 +02003901 /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
3902 {
3903 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3904 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01003905 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai099db17e2009-07-02 16:10:23 +02003906 .info = snd_hda_mixer_amp_switch_info,
3907 .get = snd_hda_mixer_amp_switch_get,
3908 .put = ad1884a_mobile_master_sw_put,
3909 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3910 },
Takashi Iwaib40b04a2008-02-16 09:44:56 +01003911 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3912 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
Takashi Iwai269ef192008-05-30 15:32:15 +02003913 HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
3914 HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
Takashi Iwaib40b04a2008-02-16 09:44:56 +01003915 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3916 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib40b04a2008-02-16 09:44:56 +01003917 { } /* end */
3918};
3919
Takashi Iwaic5059252008-02-16 09:43:56 +01003920/* mute internal speaker if HP is plugged */
3921static void ad1884a_hp_automute(struct hda_codec *codec)
3922{
3923 unsigned int present;
3924
Takashi Iwaid56757a2009-11-18 08:00:14 +01003925 present = snd_hda_jack_detect(codec, 0x11);
Takashi Iwaic5059252008-02-16 09:43:56 +01003926 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
3927 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
3928 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
3929 present ? 0x00 : 0x02);
3930}
3931
Takashi Iwai269ef192008-05-30 15:32:15 +02003932/* switch to external mic if plugged */
3933static void ad1884a_hp_automic(struct hda_codec *codec)
3934{
3935 unsigned int present;
3936
Takashi Iwaid56757a2009-11-18 08:00:14 +01003937 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai269ef192008-05-30 15:32:15 +02003938 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
3939 present ? 0 : 1);
3940}
3941
Takashi Iwaic5059252008-02-16 09:43:56 +01003942#define AD1884A_HP_EVENT 0x37
Takashi Iwai269ef192008-05-30 15:32:15 +02003943#define AD1884A_MIC_EVENT 0x36
Takashi Iwaic5059252008-02-16 09:43:56 +01003944
3945/* unsolicited event for HP jack sensing */
3946static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
3947{
Takashi Iwai269ef192008-05-30 15:32:15 +02003948 switch (res >> 26) {
3949 case AD1884A_HP_EVENT:
3950 ad1884a_hp_automute(codec);
3951 break;
3952 case AD1884A_MIC_EVENT:
3953 ad1884a_hp_automic(codec);
3954 break;
3955 }
Takashi Iwaic5059252008-02-16 09:43:56 +01003956}
3957
3958/* initialize jack-sensing, too */
3959static int ad1884a_hp_init(struct hda_codec *codec)
3960{
3961 ad198x_init(codec);
3962 ad1884a_hp_automute(codec);
Takashi Iwai269ef192008-05-30 15:32:15 +02003963 ad1884a_hp_automic(codec);
Takashi Iwaic5059252008-02-16 09:43:56 +01003964 return 0;
3965}
3966
Takashi Iwai17bbaa62009-08-30 12:15:59 +02003967/* mute internal speaker if HP or docking HP is plugged */
3968static void ad1884a_laptop_automute(struct hda_codec *codec)
3969{
3970 unsigned int present;
3971
Takashi Iwaid56757a2009-11-18 08:00:14 +01003972 present = snd_hda_jack_detect(codec, 0x11);
3973 if (!present)
3974 present = snd_hda_jack_detect(codec, 0x12);
Takashi Iwai17bbaa62009-08-30 12:15:59 +02003975 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
3976 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
3977 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
3978 present ? 0x00 : 0x02);
3979}
3980
3981/* switch to external mic if plugged */
3982static void ad1884a_laptop_automic(struct hda_codec *codec)
3983{
3984 unsigned int idx;
3985
Takashi Iwaid56757a2009-11-18 08:00:14 +01003986 if (snd_hda_jack_detect(codec, 0x14))
Takashi Iwai17bbaa62009-08-30 12:15:59 +02003987 idx = 0;
Takashi Iwaid56757a2009-11-18 08:00:14 +01003988 else if (snd_hda_jack_detect(codec, 0x1c))
Takashi Iwai17bbaa62009-08-30 12:15:59 +02003989 idx = 4;
3990 else
3991 idx = 1;
3992 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
3993}
3994
3995/* unsolicited event for HP jack sensing */
3996static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
3997 unsigned int res)
3998{
3999 switch (res >> 26) {
4000 case AD1884A_HP_EVENT:
4001 ad1884a_laptop_automute(codec);
4002 break;
4003 case AD1884A_MIC_EVENT:
4004 ad1884a_laptop_automic(codec);
4005 break;
4006 }
4007}
4008
4009/* initialize jack-sensing, too */
4010static int ad1884a_laptop_init(struct hda_codec *codec)
4011{
4012 ad198x_init(codec);
4013 ad1884a_laptop_automute(codec);
4014 ad1884a_laptop_automic(codec);
4015 return 0;
4016}
4017
Takashi Iwaic5059252008-02-16 09:43:56 +01004018/* additional verbs for laptop model */
4019static struct hda_verb ad1884a_laptop_verbs[] = {
4020 /* Port-A (HP) pin - always unmuted */
4021 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4022 /* Port-F (int speaker) mixer - route only from analog mixer */
4023 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4024 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Wu Fengguang150fe142009-08-19 16:58:59 +08004025 /* Port-F (int speaker) pin */
4026 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaic5059252008-02-16 09:43:56 +01004027 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Wu Fengguang150fe142009-08-19 16:58:59 +08004028 /* required for compaq 6530s/6531s speaker output */
4029 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai269ef192008-05-30 15:32:15 +02004030 /* Port-C pin - internal mic-in */
4031 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4032 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4033 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
Takashi Iwai2ad81ba2009-09-01 09:09:26 +02004034 /* Port-D (docking line-out) pin - default unmuted */
4035 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaic5059252008-02-16 09:43:56 +01004036 /* analog mix */
4037 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4038 /* unsolicited event for pin-sense */
4039 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004040 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
Takashi Iwai269ef192008-05-30 15:32:15 +02004041 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004042 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
Takashi Iwaife7e5682009-08-31 08:37:46 +02004043 /* allow to touch GPIO1 (for mute control) */
4044 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4045 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4046 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
Takashi Iwaic5059252008-02-16 09:43:56 +01004047 { } /* end */
4048};
4049
Takashi Iwai73156132009-04-23 08:24:48 +02004050static struct hda_verb ad1884a_mobile_verbs[] = {
4051 /* DACs; unmute as default */
4052 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4053 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4054 /* Port-A (HP) mixer - route only from analog mixer */
4055 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4056 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4057 /* Port-A pin */
4058 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4059 /* Port-A (HP) pin - always unmuted */
4060 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4061 /* Port-B (mic jack) pin */
4062 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4063 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4064 /* Port-C (int mic) pin */
4065 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4066 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4067 /* Port-F (int speaker) mixer - route only from analog mixer */
4068 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4069 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4070 /* Port-F pin */
4071 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4072 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4073 /* Analog mixer; mute as default */
4074 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4075 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4076 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4077 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4078 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4079 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4080 /* Analog Mix output amp */
4081 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4082 /* capture sources */
4083 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4084 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4085 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4086 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4087 /* unsolicited event for pin-sense */
4088 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4089 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
Takashi Iwai099db17e2009-07-02 16:10:23 +02004090 /* allow to touch GPIO1 (for mute control) */
4091 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4092 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4093 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
Takashi Iwai73156132009-04-23 08:24:48 +02004094 { } /* end */
4095};
4096
Takashi Iwaic5059252008-02-16 09:43:56 +01004097/*
Takashi Iwaif0813742008-03-18 12:13:03 +01004098 * Thinkpad X300
4099 * 0x11 - HP
4100 * 0x12 - speaker
4101 * 0x14 - mic-in
4102 * 0x17 - built-in mic
4103 */
4104
4105static struct hda_verb ad1984a_thinkpad_verbs[] = {
4106 /* HP unmute */
4107 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4108 /* analog mix */
4109 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4110 /* turn on EAPD */
4111 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4112 /* unsolicited event for pin-sense */
4113 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4114 /* internal mic - dmic */
4115 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai05808ec2008-04-23 13:50:08 +02004116 /* set magic COEFs for dmic */
4117 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4118 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
Takashi Iwaif0813742008-03-18 12:13:03 +01004119 { } /* end */
4120};
4121
4122static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
4123 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4124 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4125 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4126 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4127 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4128 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
Takashi Iwaif0813742008-03-18 12:13:03 +01004129 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
4130 HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
4131 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4132 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4133 {
4134 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4135 .name = "Capture Source",
4136 .info = ad198x_mux_enum_info,
4137 .get = ad198x_mux_enum_get,
4138 .put = ad198x_mux_enum_put,
4139 },
4140 { } /* end */
4141};
4142
4143static struct hda_input_mux ad1984a_thinkpad_capture_source = {
4144 .num_items = 3,
4145 .items = {
4146 { "Mic", 0x0 },
4147 { "Internal Mic", 0x5 },
4148 { "Mix", 0x3 },
4149 },
4150};
4151
4152/* mute internal speaker if HP is plugged */
4153static void ad1984a_thinkpad_automute(struct hda_codec *codec)
4154{
4155 unsigned int present;
4156
Takashi Iwaid56757a2009-11-18 08:00:14 +01004157 present = snd_hda_jack_detect(codec, 0x11);
Takashi Iwaif0813742008-03-18 12:13:03 +01004158 snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
4159 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4160}
4161
4162/* unsolicited event for HP jack sensing */
4163static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
4164 unsigned int res)
4165{
4166 if ((res >> 26) != AD1884A_HP_EVENT)
4167 return;
4168 ad1984a_thinkpad_automute(codec);
4169}
4170
4171/* initialize jack-sensing, too */
4172static int ad1984a_thinkpad_init(struct hda_codec *codec)
4173{
4174 ad198x_init(codec);
4175 ad1984a_thinkpad_automute(codec);
4176 return 0;
4177}
4178
4179/*
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004180 * HP Touchsmart
4181 * port-A (0x11) - front hp-out
4182 * port-B (0x14) - unused
4183 * port-C (0x15) - unused
4184 * port-D (0x12) - rear line out
4185 * port-E (0x1c) - front mic-in
4186 * port-F (0x16) - Internal speakers
4187 * digital-mic (0x17) - Internal mic
4188 */
4189
4190static struct hda_verb ad1984a_touchsmart_verbs[] = {
4191 /* DACs; unmute as default */
4192 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4193 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4194 /* Port-A (HP) mixer - route only from analog mixer */
4195 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4196 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4197 /* Port-A pin */
4198 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4199 /* Port-A (HP) pin - always unmuted */
4200 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4201 /* Port-E (int speaker) mixer - route only from analog mixer */
4202 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
4203 /* Port-E pin */
4204 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4205 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4206 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4207 /* Port-F (int speaker) mixer - route only from analog mixer */
4208 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4209 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4210 /* Port-F pin */
4211 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4212 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4213 /* Analog mixer; mute as default */
4214 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4215 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4216 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4217 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4218 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4219 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4220 /* Analog Mix output amp */
4221 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4222 /* capture sources */
4223 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4224 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4225 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4226 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4227 /* unsolicited event for pin-sense */
4228 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4229 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4230 /* allow to touch GPIO1 (for mute control) */
4231 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4232 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4233 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4234 /* internal mic - dmic */
4235 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4236 /* set magic COEFs for dmic */
4237 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4238 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4239 { } /* end */
4240};
4241
4242static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
4243 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4244/* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
4245 {
4246 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01004247 .subdevice = HDA_SUBDEV_AMP_FLAG,
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004248 .name = "Master Playback Switch",
4249 .info = snd_hda_mixer_amp_switch_info,
4250 .get = snd_hda_mixer_amp_switch_get,
4251 .put = ad1884a_mobile_master_sw_put,
4252 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4253 },
4254 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4255 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4256 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4257 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4258 HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
4259 HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
4260 { } /* end */
4261};
4262
4263/* switch to external mic if plugged */
4264static void ad1984a_touchsmart_automic(struct hda_codec *codec)
4265{
Takashi Iwaid56757a2009-11-18 08:00:14 +01004266 if (snd_hda_jack_detect(codec, 0x1c))
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004267 snd_hda_codec_write(codec, 0x0c, 0,
4268 AC_VERB_SET_CONNECT_SEL, 0x4);
Takashi Iwaid56757a2009-11-18 08:00:14 +01004269 else
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004270 snd_hda_codec_write(codec, 0x0c, 0,
4271 AC_VERB_SET_CONNECT_SEL, 0x5);
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004272}
4273
4274
4275/* unsolicited event for HP jack sensing */
4276static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
4277 unsigned int res)
4278{
4279 switch (res >> 26) {
4280 case AD1884A_HP_EVENT:
4281 ad1884a_hp_automute(codec);
4282 break;
4283 case AD1884A_MIC_EVENT:
4284 ad1984a_touchsmart_automic(codec);
4285 break;
4286 }
4287}
4288
4289/* initialize jack-sensing, too */
4290static int ad1984a_touchsmart_init(struct hda_codec *codec)
4291{
4292 ad198x_init(codec);
4293 ad1884a_hp_automute(codec);
4294 ad1984a_touchsmart_automic(codec);
4295 return 0;
4296}
4297
4298
4299/*
Takashi Iwaic5059252008-02-16 09:43:56 +01004300 */
4301
4302enum {
4303 AD1884A_DESKTOP,
4304 AD1884A_LAPTOP,
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004305 AD1884A_MOBILE,
Takashi Iwaif0813742008-03-18 12:13:03 +01004306 AD1884A_THINKPAD,
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004307 AD1984A_TOUCHSMART,
Takashi Iwaic5059252008-02-16 09:43:56 +01004308 AD1884A_MODELS
4309};
4310
4311static const char *ad1884a_models[AD1884A_MODELS] = {
4312 [AD1884A_DESKTOP] = "desktop",
4313 [AD1884A_LAPTOP] = "laptop",
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004314 [AD1884A_MOBILE] = "mobile",
Takashi Iwaif0813742008-03-18 12:13:03 +01004315 [AD1884A_THINKPAD] = "thinkpad",
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004316 [AD1984A_TOUCHSMART] = "touchsmart",
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004317};
4318
4319static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
4320 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
Takashi Iwaid5337de2009-01-07 11:41:57 +01004321 SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
Takashi Iwai5695ff42008-10-28 15:39:26 +01004322 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
Takashi Iwaic2312752009-02-16 15:20:41 +01004323 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
Takashi Iwaiff848472009-07-01 18:08:01 +02004324 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
Takashi Iwai873dc782009-02-25 18:12:13 +01004325 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
4326 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
Takashi Iwai286f5872009-08-27 14:37:51 +02004327 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
Takashi Iwaif0813742008-03-18 12:13:03 +01004328 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004329 SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004330 {}
Takashi Iwaic5059252008-02-16 09:43:56 +01004331};
4332
4333static int patch_ad1884a(struct hda_codec *codec)
4334{
4335 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01004336 int err, board_config;
Takashi Iwaic5059252008-02-16 09:43:56 +01004337
4338 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4339 if (spec == NULL)
4340 return -ENOMEM;
4341
Takashi Iwaic5059252008-02-16 09:43:56 +01004342 codec->spec = spec;
4343
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01004344 err = snd_hda_attach_beep_device(codec, 0x10);
4345 if (err < 0) {
4346 ad198x_free(codec);
4347 return err;
4348 }
4349 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4350
Takashi Iwaic5059252008-02-16 09:43:56 +01004351 spec->multiout.max_channels = 2;
4352 spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
4353 spec->multiout.dac_nids = ad1884a_dac_nids;
4354 spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
4355 spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
4356 spec->adc_nids = ad1884a_adc_nids;
4357 spec->capsrc_nids = ad1884a_capsrc_nids;
4358 spec->input_mux = &ad1884a_capture_source;
4359 spec->num_mixers = 1;
4360 spec->mixers[0] = ad1884a_base_mixers;
4361 spec->num_init_verbs = 1;
4362 spec->init_verbs[0] = ad1884a_init_verbs;
4363 spec->spdif_route = 0;
4364#ifdef CONFIG_SND_HDA_POWER_SAVE
4365 spec->loopback.amplist = ad1884a_loopbacks;
4366#endif
4367 codec->patch_ops = ad198x_patch_ops;
4368
4369 /* override some parameters */
4370 board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004371 ad1884a_models,
4372 ad1884a_cfg_tbl);
Takashi Iwaic5059252008-02-16 09:43:56 +01004373 switch (board_config) {
4374 case AD1884A_LAPTOP:
4375 spec->mixers[0] = ad1884a_laptop_mixers;
4376 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
4377 spec->multiout.dig_out_nid = 0;
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004378 codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
4379 codec->patch_ops.init = ad1884a_laptop_init;
Takashi Iwai4dc1f872009-04-16 14:19:19 +02004380 /* set the upper-limit for mixer amp to 0dB for avoiding the
4381 * possible damage by overloading
4382 */
4383 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4384 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4385 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4386 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4387 (1 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwaic5059252008-02-16 09:43:56 +01004388 break;
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004389 case AD1884A_MOBILE:
4390 spec->mixers[0] = ad1884a_mobile_mixers;
Takashi Iwai73156132009-04-23 08:24:48 +02004391 spec->init_verbs[0] = ad1884a_mobile_verbs;
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004392 spec->multiout.dig_out_nid = 0;
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004393 codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
4394 codec->patch_ops.init = ad1884a_hp_init;
Takashi Iwai13c989b2009-02-23 11:33:34 +01004395 /* set the upper-limit for mixer amp to 0dB for avoiding the
4396 * possible damage by overloading
4397 */
4398 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4399 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4400 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4401 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4402 (1 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004403 break;
Takashi Iwaif0813742008-03-18 12:13:03 +01004404 case AD1884A_THINKPAD:
4405 spec->mixers[0] = ad1984a_thinkpad_mixers;
4406 spec->init_verbs[spec->num_init_verbs++] =
4407 ad1984a_thinkpad_verbs;
4408 spec->multiout.dig_out_nid = 0;
4409 spec->input_mux = &ad1984a_thinkpad_capture_source;
4410 codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
4411 codec->patch_ops.init = ad1984a_thinkpad_init;
4412 break;
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004413 case AD1984A_TOUCHSMART:
4414 spec->mixers[0] = ad1984a_touchsmart_mixers;
4415 spec->init_verbs[0] = ad1984a_touchsmart_verbs;
4416 spec->multiout.dig_out_nid = 0;
4417 codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
4418 codec->patch_ops.init = ad1984a_touchsmart_init;
4419 /* set the upper-limit for mixer amp to 0dB for avoiding the
4420 * possible damage by overloading
4421 */
4422 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4423 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4424 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4425 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4426 (1 << AC_AMPCAP_MUTE_SHIFT));
4427 break;
Takashi Iwaic5059252008-02-16 09:43:56 +01004428 }
4429
Takashi Iwai729d55b2009-12-25 22:49:01 +01004430 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02004431 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01004432
Takashi Iwaic5059252008-02-16 09:43:56 +01004433 return 0;
4434}
4435
4436
4437/*
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004438 * AD1882 / AD1882A
Takashi Iwai0ac85512007-06-20 15:46:13 +02004439 *
4440 * port-A - front hp-out
4441 * port-B - front mic-in
4442 * port-C - rear line-in, shared surr-out (3stack)
4443 * port-D - rear line-out
4444 * port-E - rear mic-in, shared clfe-out (3stack)
4445 * port-F - rear surr-out (6stack)
4446 * port-G - rear clfe-out (6stack)
4447 */
4448
4449static hda_nid_t ad1882_dac_nids[3] = {
4450 0x04, 0x03, 0x05
4451};
4452
4453static hda_nid_t ad1882_adc_nids[2] = {
4454 0x08, 0x09,
4455};
4456
4457static hda_nid_t ad1882_capsrc_nids[2] = {
4458 0x0c, 0x0d,
4459};
4460
4461#define AD1882_SPDIF_OUT 0x02
4462
4463/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
4464static struct hda_input_mux ad1882_capture_source = {
4465 .num_items = 5,
4466 .items = {
4467 { "Front Mic", 0x1 },
4468 { "Mic", 0x4 },
4469 { "Line", 0x2 },
4470 { "CD", 0x3 },
4471 { "Mix", 0x7 },
4472 },
4473};
4474
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004475/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
4476static struct hda_input_mux ad1882a_capture_source = {
4477 .num_items = 5,
4478 .items = {
4479 { "Front Mic", 0x1 },
4480 { "Mic", 0x4},
4481 { "Line", 0x2 },
4482 { "Digital Mic", 0x06 },
4483 { "Mix", 0x7 },
4484 },
4485};
4486
Takashi Iwai0ac85512007-06-20 15:46:13 +02004487static struct snd_kcontrol_new ad1882_base_mixers[] = {
4488 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
4489 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
4490 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
4491 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
4492 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
4493 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4494 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
4495 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004496
Takashi Iwai0ac85512007-06-20 15:46:13 +02004497 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
4498 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
4499 HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
4500 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4501 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4502 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
4503 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
4504 {
4505 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4506 /* The multiple "Capture Source" controls confuse alsamixer
4507 * So call somewhat different..
Takashi Iwai0ac85512007-06-20 15:46:13 +02004508 */
4509 /* .name = "Capture Source", */
4510 .name = "Input Source",
4511 .count = 2,
4512 .info = ad198x_mux_enum_info,
4513 .get = ad198x_mux_enum_get,
4514 .put = ad198x_mux_enum_put,
4515 },
4516 /* SPDIF controls */
4517 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
4518 {
4519 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4520 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4521 /* identical with ad1983 */
4522 .info = ad1983_spdif_route_info,
4523 .get = ad1983_spdif_route_get,
4524 .put = ad1983_spdif_route_put,
4525 },
4526 { } /* end */
4527};
4528
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004529static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
4530 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4531 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4532 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4533 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4534 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
4535 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
4536 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4537 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004538 { } /* end */
4539};
4540
4541static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
4542 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4543 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4544 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4545 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4546 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
4547 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
4548 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4549 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004550 HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
4551 { } /* end */
4552};
4553
Takashi Iwai0ac85512007-06-20 15:46:13 +02004554static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
4555 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
4556 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
4557 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
4558 {
4559 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4560 .name = "Channel Mode",
4561 .info = ad198x_ch_mode_info,
4562 .get = ad198x_ch_mode_get,
4563 .put = ad198x_ch_mode_put,
4564 },
4565 { } /* end */
4566};
4567
4568static struct snd_kcontrol_new ad1882_6stack_mixers[] = {
4569 HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
4570 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
4571 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
4572 { } /* end */
4573};
4574
4575static struct hda_verb ad1882_ch2_init[] = {
4576 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4577 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4578 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4579 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4580 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4581 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4582 { } /* end */
4583};
4584
4585static struct hda_verb ad1882_ch4_init[] = {
4586 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4587 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4588 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4589 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4590 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4591 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4592 { } /* end */
4593};
4594
4595static struct hda_verb ad1882_ch6_init[] = {
4596 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4597 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4598 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4599 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4600 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4601 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4602 { } /* end */
4603};
4604
4605static struct hda_channel_mode ad1882_modes[3] = {
4606 { 2, ad1882_ch2_init },
4607 { 4, ad1882_ch4_init },
4608 { 6, ad1882_ch6_init },
4609};
4610
4611/*
4612 * initialization verbs
4613 */
4614static struct hda_verb ad1882_init_verbs[] = {
4615 /* DACs; mute as default */
4616 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4617 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4618 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4619 /* Port-A (HP) mixer */
4620 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4621 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4622 /* Port-A pin */
4623 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4624 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4625 /* HP selector - select DAC2 */
4626 {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
4627 /* Port-D (Line-out) mixer */
4628 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4629 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4630 /* Port-D pin */
4631 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4632 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4633 /* Mono-out mixer */
4634 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4635 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4636 /* Mono-out pin */
4637 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4638 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4639 /* Port-B (front mic) pin */
4640 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4641 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4642 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4643 /* Port-C (line-in) pin */
4644 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4645 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4646 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4647 /* Port-C mixer - mute as input */
4648 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4649 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4650 /* Port-E (mic-in) pin */
4651 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4652 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4653 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4654 /* Port-E mixer - mute as input */
4655 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4656 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4657 /* Port-F (surround) */
4658 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4659 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4660 /* Port-G (CLFE) */
4661 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4662 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4663 /* Analog mixer; mute as default */
4664 /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
4665 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4666 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4667 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4668 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4669 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4670 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4671 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
4672 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
4673 /* Analog Mix output amp */
4674 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
4675 /* SPDIF output selector */
4676 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4677 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
4678 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4679 { } /* end */
4680};
4681
Takashi Iwaicb53c622007-08-10 17:21:45 +02004682#ifdef CONFIG_SND_HDA_POWER_SAVE
4683static struct hda_amp_list ad1882_loopbacks[] = {
4684 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
4685 { 0x20, HDA_INPUT, 1 }, /* Mic */
4686 { 0x20, HDA_INPUT, 4 }, /* Line */
4687 { 0x20, HDA_INPUT, 6 }, /* CD */
4688 { } /* end */
4689};
4690#endif
4691
Takashi Iwai0ac85512007-06-20 15:46:13 +02004692/* models */
4693enum {
4694 AD1882_3STACK,
4695 AD1882_6STACK,
4696 AD1882_MODELS
4697};
4698
4699static const char *ad1882_models[AD1986A_MODELS] = {
4700 [AD1882_3STACK] = "3stack",
4701 [AD1882_6STACK] = "6stack",
4702};
4703
4704
4705static int patch_ad1882(struct hda_codec *codec)
4706{
4707 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01004708 int err, board_config;
Takashi Iwai0ac85512007-06-20 15:46:13 +02004709
4710 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4711 if (spec == NULL)
4712 return -ENOMEM;
4713
Takashi Iwai0ac85512007-06-20 15:46:13 +02004714 codec->spec = spec;
4715
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01004716 err = snd_hda_attach_beep_device(codec, 0x10);
4717 if (err < 0) {
4718 ad198x_free(codec);
4719 return err;
4720 }
4721 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4722
Takashi Iwai0ac85512007-06-20 15:46:13 +02004723 spec->multiout.max_channels = 6;
4724 spec->multiout.num_dacs = 3;
4725 spec->multiout.dac_nids = ad1882_dac_nids;
4726 spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
4727 spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
4728 spec->adc_nids = ad1882_adc_nids;
4729 spec->capsrc_nids = ad1882_capsrc_nids;
Clemens Fruhwirthc247ed62009-01-07 11:43:48 +01004730 if (codec->vendor_id == 0x11d41882)
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004731 spec->input_mux = &ad1882_capture_source;
4732 else
4733 spec->input_mux = &ad1882a_capture_source;
4734 spec->num_mixers = 2;
Takashi Iwai0ac85512007-06-20 15:46:13 +02004735 spec->mixers[0] = ad1882_base_mixers;
Clemens Fruhwirthc247ed62009-01-07 11:43:48 +01004736 if (codec->vendor_id == 0x11d41882)
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004737 spec->mixers[1] = ad1882_loopback_mixers;
4738 else
4739 spec->mixers[1] = ad1882a_loopback_mixers;
Takashi Iwai0ac85512007-06-20 15:46:13 +02004740 spec->num_init_verbs = 1;
4741 spec->init_verbs[0] = ad1882_init_verbs;
4742 spec->spdif_route = 0;
Takashi Iwaicb53c622007-08-10 17:21:45 +02004743#ifdef CONFIG_SND_HDA_POWER_SAVE
4744 spec->loopback.amplist = ad1882_loopbacks;
4745#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01004746 spec->vmaster_nid = 0x04;
Takashi Iwai0ac85512007-06-20 15:46:13 +02004747
4748 codec->patch_ops = ad198x_patch_ops;
4749
4750 /* override some parameters */
4751 board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
4752 ad1882_models, NULL);
4753 switch (board_config) {
4754 default:
4755 case AD1882_3STACK:
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004756 spec->num_mixers = 3;
4757 spec->mixers[2] = ad1882_3stack_mixers;
Takashi Iwai0ac85512007-06-20 15:46:13 +02004758 spec->channel_mode = ad1882_modes;
4759 spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
4760 spec->need_dac_fix = 1;
4761 spec->multiout.max_channels = 2;
4762 spec->multiout.num_dacs = 1;
4763 break;
4764 case AD1882_6STACK:
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004765 spec->num_mixers = 3;
4766 spec->mixers[2] = ad1882_6stack_mixers;
Takashi Iwai0ac85512007-06-20 15:46:13 +02004767 break;
4768 }
Takashi Iwai729d55b2009-12-25 22:49:01 +01004769
4770 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02004771 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01004772
Takashi Iwai0ac85512007-06-20 15:46:13 +02004773 return 0;
4774}
4775
4776
4777/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 * patch entries
4779 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +01004780static struct hda_codec_preset snd_hda_preset_analog[] = {
Takashi Iwaic5059252008-02-16 09:43:56 +01004781 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
Takashi Iwai0ac85512007-06-20 15:46:13 +02004782 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
Takashi Iwaic5059252008-02-16 09:43:56 +01004783 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
Takashi Iwai2bac6472007-05-18 18:21:41 +02004784 { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
Takashi Iwaic5059252008-02-16 09:43:56 +01004785 { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
4786 { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02004787 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
4788 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
Takashi Iwai2bac6472007-05-18 18:21:41 +02004789 { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01004791 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
Takashi Iwai71b2ccc2006-04-21 16:09:31 +02004792 { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004793 { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02004794 { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
4795 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 {} /* terminator */
4797};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01004798
4799MODULE_ALIAS("snd-hda-codec-id:11d4*");
4800
4801MODULE_LICENSE("GPL");
4802MODULE_DESCRIPTION("Analog Devices HD-audio codec");
4803
4804static struct hda_codec_preset_list analog_list = {
4805 .preset = snd_hda_preset_analog,
4806 .owner = THIS_MODULE,
4807};
4808
4809static int __init patch_analog_init(void)
4810{
4811 return snd_hda_add_codec_preset(&analog_list);
4812}
4813
4814static void __exit patch_analog_exit(void)
4815{
4816 snd_hda_delete_codec_preset(&analog_list);
4817}
4818
4819module_init(patch_analog_init)
4820module_exit(patch_analog_exit)