blob: 25116a883ca613811ee41e0da6c5de78d9e6b0ef [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02002 * HD audio interface patch for AD1981HD, AD1983, AD1986A
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de>
5 *
6 * This driver is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This driver is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <sound/driver.h>
22#include <linux/init.h>
23#include <linux/delay.h>
24#include <linux/slab.h>
25#include <linux/pci.h>
26#include <sound/core.h>
27#include "hda_codec.h"
28#include "hda_local.h"
29
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020030struct ad198x_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010031 struct snd_kcontrol_new *mixers[5];
Takashi Iwai985be542005-11-02 18:26:49 +010032 int num_mixers;
33
34 const struct hda_verb *init_verbs[3]; /* initialization verbs
35 * don't forget NULL termination!
36 */
37 unsigned int num_init_verbs;
38
39 /* playback */
40 struct hda_multi_out multiout; /* playback set-up
41 * max_channels, dacs must be set
42 * dig_out_nid and hp_nid are optional
43 */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +010044 unsigned int cur_eapd;
Takashi Iwai985be542005-11-02 18:26:49 +010045
46 /* capture */
47 unsigned int num_adc_nids;
48 hda_nid_t *adc_nids;
49 hda_nid_t dig_in_nid; /* digital-in NID; optional */
50
51 /* capture source */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020052 const struct hda_input_mux *input_mux;
Takashi Iwai985be542005-11-02 18:26:49 +010053 unsigned int cur_mux[3];
54
55 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +010056 const struct hda_channel_mode *channel_mode;
Takashi Iwai985be542005-11-02 18:26:49 +010057 int num_channel_mode;
58
59 /* PCM information */
60 struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */
61
62 struct semaphore amp_mutex; /* PCM volume/mute control mutex */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020063 unsigned int spdif_route;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064};
65
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020066/*
67 * input MUX handling (common part)
68 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010069static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020070{
71 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
72 struct ad198x_spec *spec = codec->spec;
73
74 return snd_hda_input_mux_info(spec->input_mux, uinfo);
75}
76
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010077static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020078{
79 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
80 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +010081 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020082
Takashi Iwai985be542005-11-02 18:26:49 +010083 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020084 return 0;
85}
86
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010087static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020088{
89 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
90 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +010091 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020092
93 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Takashi Iwai985be542005-11-02 18:26:49 +010094 spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020095}
96
97/*
98 * initialization (common callbacks)
99 */
100static int ad198x_init(struct hda_codec *codec)
101{
102 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100103 int i;
104
105 for (i = 0; i < spec->num_init_verbs; i++)
106 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200107 return 0;
108}
109
110static int ad198x_build_controls(struct hda_codec *codec)
111{
112 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100113 unsigned int i;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200114 int err;
115
Takashi Iwai985be542005-11-02 18:26:49 +0100116 for (i = 0; i < spec->num_mixers; i++) {
117 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
118 if (err < 0)
119 return err;
120 }
121 if (spec->multiout.dig_out_nid) {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200122 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
Takashi Iwai985be542005-11-02 18:26:49 +0100123 if (err < 0)
124 return err;
125 }
126 if (spec->dig_in_nid) {
127 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
128 if (err < 0)
129 return err;
130 }
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200131 return 0;
132}
133
134/*
135 * Analog playback callbacks
136 */
137static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
138 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100139 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200140{
141 struct ad198x_spec *spec = codec->spec;
142 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
143}
144
145static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
146 struct hda_codec *codec,
147 unsigned int stream_tag,
148 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100149 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200150{
151 struct ad198x_spec *spec = codec->spec;
152 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
153 format, substream);
154}
155
156static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
157 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100158 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200159{
160 struct ad198x_spec *spec = codec->spec;
161 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
162}
163
164/*
165 * Digital out
166 */
167static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
168 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100169 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200170{
171 struct ad198x_spec *spec = codec->spec;
172 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
173}
174
175static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
176 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100177 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200178{
179 struct ad198x_spec *spec = codec->spec;
180 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
181}
182
183/*
184 * Analog capture
185 */
186static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
187 struct hda_codec *codec,
188 unsigned int stream_tag,
189 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100190 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200191{
192 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100193 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
194 stream_tag, 0, format);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200195 return 0;
196}
197
198static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
199 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100200 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200201{
202 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100203 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
204 0, 0, 0);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200205 return 0;
206}
207
208
209/*
210 */
211static struct hda_pcm_stream ad198x_pcm_analog_playback = {
212 .substreams = 1,
213 .channels_min = 2,
Takashi Iwai985be542005-11-02 18:26:49 +0100214 .channels_max = 6, /* changed later */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200215 .nid = 0, /* fill later */
216 .ops = {
217 .open = ad198x_playback_pcm_open,
218 .prepare = ad198x_playback_pcm_prepare,
219 .cleanup = ad198x_playback_pcm_cleanup
220 },
221};
222
223static struct hda_pcm_stream ad198x_pcm_analog_capture = {
Takashi Iwai985be542005-11-02 18:26:49 +0100224 .substreams = 1,
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200225 .channels_min = 2,
226 .channels_max = 2,
227 .nid = 0, /* fill later */
228 .ops = {
229 .prepare = ad198x_capture_pcm_prepare,
230 .cleanup = ad198x_capture_pcm_cleanup
231 },
232};
233
234static struct hda_pcm_stream ad198x_pcm_digital_playback = {
235 .substreams = 1,
236 .channels_min = 2,
237 .channels_max = 2,
238 .nid = 0, /* fill later */
239 .ops = {
240 .open = ad198x_dig_playback_pcm_open,
241 .close = ad198x_dig_playback_pcm_close
242 },
243};
244
Takashi Iwai985be542005-11-02 18:26:49 +0100245static struct hda_pcm_stream ad198x_pcm_digital_capture = {
246 .substreams = 1,
247 .channels_min = 2,
248 .channels_max = 2,
249 /* NID is set in alc_build_pcms */
250};
251
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200252static int ad198x_build_pcms(struct hda_codec *codec)
253{
254 struct ad198x_spec *spec = codec->spec;
255 struct hda_pcm *info = spec->pcm_rec;
256
257 codec->num_pcms = 1;
258 codec->pcm_info = info;
259
260 info->name = "AD198x Analog";
261 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
262 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
263 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
264 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
Takashi Iwai985be542005-11-02 18:26:49 +0100265 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
266 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200267
268 if (spec->multiout.dig_out_nid) {
269 info++;
270 codec->num_pcms++;
271 info->name = "AD198x Digital";
272 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
273 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
Takashi Iwai985be542005-11-02 18:26:49 +0100274 if (spec->dig_in_nid) {
275 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
276 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
277 }
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200278 }
279
280 return 0;
281}
282
283static void ad198x_free(struct hda_codec *codec)
284{
285 kfree(codec->spec);
286}
287
288#ifdef CONFIG_PM
289static int ad198x_resume(struct hda_codec *codec)
290{
291 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100292 int i;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200293
294 ad198x_init(codec);
Takashi Iwai985be542005-11-02 18:26:49 +0100295 for (i = 0; i < spec->num_mixers; i++)
296 snd_hda_resume_ctls(codec, spec->mixers[i]);
297 if (spec->multiout.dig_out_nid)
298 snd_hda_resume_spdif_out(codec);
299 if (spec->dig_in_nid)
300 snd_hda_resume_spdif_in(codec);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200301 return 0;
302}
303#endif
304
305static struct hda_codec_ops ad198x_patch_ops = {
306 .build_controls = ad198x_build_controls,
307 .build_pcms = ad198x_build_pcms,
308 .init = ad198x_init,
309 .free = ad198x_free,
310#ifdef CONFIG_PM
311 .resume = ad198x_resume,
312#endif
313};
314
315
316/*
317 * AD1986A specific
318 */
319
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320#define AD1986A_SPDIF_OUT 0x02
321#define AD1986A_FRONT_DAC 0x03
322#define AD1986A_SURR_DAC 0x04
323#define AD1986A_CLFE_DAC 0x05
324#define AD1986A_ADC 0x06
325
326static hda_nid_t ad1986a_dac_nids[3] = {
327 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
328};
Takashi Iwai985be542005-11-02 18:26:49 +0100329static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331static struct hda_input_mux ad1986a_capture_source = {
332 .num_items = 7,
333 .items = {
334 { "Mic", 0x0 },
335 { "CD", 0x1 },
336 { "Aux", 0x3 },
337 { "Line", 0x4 },
338 { "Mix", 0x5 },
339 { "Mono", 0x6 },
340 { "Phone", 0x7 },
341 },
342};
343
344/*
345 * PCM control
346 *
347 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
348 */
349
350#define ad1986a_pcm_amp_vol_info snd_hda_mixer_amp_volume_info
351
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100352static int ad1986a_pcm_amp_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
354 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200355 struct ad198x_spec *ad = codec->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357 down(&ad->amp_mutex);
358 snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
359 up(&ad->amp_mutex);
360 return 0;
361}
362
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100363static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200366 struct ad198x_spec *ad = codec->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 int i, change = 0;
368
369 down(&ad->amp_mutex);
370 for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) {
371 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT);
372 change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
373 }
374 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT);
375 up(&ad->amp_mutex);
376 return change;
377}
378
Takashi Iwaiead9b7c2005-06-08 14:48:19 +0200379#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100381static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382{
383 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200384 struct ad198x_spec *ad = codec->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
386 down(&ad->amp_mutex);
387 snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
388 up(&ad->amp_mutex);
389 return 0;
390}
391
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100392static int ad1986a_pcm_amp_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393{
394 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200395 struct ad198x_spec *ad = codec->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 int i, change = 0;
397
398 down(&ad->amp_mutex);
399 for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) {
400 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT);
401 change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
402 }
403 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT);
404 up(&ad->amp_mutex);
405 return change;
406}
407
408/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 * mixers
410 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100411static struct snd_kcontrol_new ad1986a_mixers[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 {
413 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
414 .name = "PCM Playback Volume",
415 .info = ad1986a_pcm_amp_vol_info,
416 .get = ad1986a_pcm_amp_vol_get,
417 .put = ad1986a_pcm_amp_vol_put,
418 .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT)
419 },
420 {
421 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
422 .name = "PCM Playback Switch",
423 .info = ad1986a_pcm_amp_sw_info,
424 .get = ad1986a_pcm_amp_sw_get,
425 .put = ad1986a_pcm_amp_sw_put,
426 .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT)
427 },
428 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
429 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
430 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
431 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
432 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
433 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
434 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
435 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
436 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
437 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
438 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
439 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
440 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
441 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
442 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
443 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
444 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
445 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
446 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT),
447 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT),
448 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
449 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
450 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
451 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
452 {
453 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
454 .name = "Capture Source",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200455 .info = ad198x_mux_enum_info,
456 .get = ad198x_mux_enum_get,
457 .put = ad198x_mux_enum_put,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 },
459 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
460 { } /* end */
461};
462
463/*
464 * initialization verbs
465 */
466static struct hda_verb ad1986a_init_verbs[] = {
467 /* Front, Surround, CLFE DAC; mute as default */
468 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
469 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
470 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
471 /* Downmix - off */
472 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
473 /* HP, Line-Out, Surround, CLFE selectors */
474 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
475 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
476 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
477 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
478 /* Mono selector */
479 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
480 /* Mic selector: Mic 1/2 pin */
481 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
482 /* Line-in selector: Line-in */
483 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
484 /* Mic 1/2 swap */
485 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
486 /* Record selector: mic */
487 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
488 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
489 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
490 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
491 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
492 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
493 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
494 /* PC beep */
495 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
496 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
497 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
498 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
499 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
500 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
501 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200502 /* HP Pin */
503 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
504 /* Front, Surround, CLFE Pins */
505 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
506 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
507 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
508 /* Mono Pin */
509 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
510 /* Mic Pin */
511 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
512 /* Line, Aux, CD, Beep-In Pin */
513 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
514 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
515 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
516 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
517 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 { } /* end */
519};
520
521
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522static int patch_ad1986a(struct hda_codec *codec)
523{
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200524 struct ad198x_spec *spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Takashi Iwaie560d8d2005-09-09 14:21:46 +0200526 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 if (spec == NULL)
528 return -ENOMEM;
529
530 init_MUTEX(&spec->amp_mutex);
531 codec->spec = spec;
532
533 spec->multiout.max_channels = 6;
534 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
535 spec->multiout.dac_nids = ad1986a_dac_nids;
536 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +0100537 spec->num_adc_nids = 1;
538 spec->adc_nids = ad1986a_adc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200539 spec->input_mux = &ad1986a_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +0100540 spec->num_mixers = 1;
541 spec->mixers[0] = ad1986a_mixers;
542 spec->num_init_verbs = 1;
543 spec->init_verbs[0] = ad1986a_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200545 codec->patch_ops = ad198x_patch_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
547 return 0;
548}
549
550/*
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200551 * AD1983 specific
552 */
553
554#define AD1983_SPDIF_OUT 0x02
555#define AD1983_DAC 0x03
556#define AD1983_ADC 0x04
557
558static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
Takashi Iwai985be542005-11-02 18:26:49 +0100559static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200560
561static struct hda_input_mux ad1983_capture_source = {
562 .num_items = 4,
563 .items = {
564 { "Mic", 0x0 },
565 { "Line", 0x1 },
566 { "Mix", 0x2 },
567 { "Mix Mono", 0x3 },
568 },
569};
570
571/*
572 * SPDIF playback route
573 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100574static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200575{
576 static char *texts[] = { "PCM", "ADC" };
577
578 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
579 uinfo->count = 1;
580 uinfo->value.enumerated.items = 2;
581 if (uinfo->value.enumerated.item > 1)
582 uinfo->value.enumerated.item = 1;
583 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
584 return 0;
585}
586
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100587static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200588{
589 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
590 struct ad198x_spec *spec = codec->spec;
591
592 ucontrol->value.enumerated.item[0] = spec->spdif_route;
593 return 0;
594}
595
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100596static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200597{
598 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
599 struct ad198x_spec *spec = codec->spec;
600
601 if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
602 spec->spdif_route = ucontrol->value.enumerated.item[0];
603 snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0,
604 AC_VERB_SET_CONNECT_SEL, spec->spdif_route);
605 return 1;
606 }
607 return 0;
608}
609
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100610static struct snd_kcontrol_new ad1983_mixers[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200611 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
612 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
613 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
614 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
615 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
616 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
617 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
618 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
619 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
620 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
621 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
622 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
623 HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x10, 1, 0x0, HDA_OUTPUT),
624 HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x10, 1, 0x0, HDA_OUTPUT),
625 HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
626 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
627 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
628 {
629 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
630 .name = "Capture Source",
631 .info = ad198x_mux_enum_info,
632 .get = ad198x_mux_enum_get,
633 .put = ad198x_mux_enum_put,
634 },
635 {
636 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Clemens Ladisch10e8d782005-08-03 13:40:08 +0200637 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200638 .info = ad1983_spdif_route_info,
639 .get = ad1983_spdif_route_get,
640 .put = ad1983_spdif_route_put,
641 },
642 { } /* end */
643};
644
645static struct hda_verb ad1983_init_verbs[] = {
646 /* Front, HP, Mono; mute as default */
647 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
648 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
649 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
650 /* Beep, PCM, Mic, Line-In: mute */
651 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
652 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
653 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
654 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
655 /* Front, HP selectors; from Mix */
656 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
657 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
658 /* Mono selector; from Mix */
659 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
660 /* Mic selector; Mic */
661 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
662 /* Line-in selector: Line-in */
663 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
664 /* Mic boost: 0dB */
665 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
666 /* Record selector: mic */
667 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
668 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
669 /* SPDIF route: PCM */
670 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
671 /* Front Pin */
672 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
673 /* HP Pin */
674 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
675 /* Mono Pin */
676 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
677 /* Mic Pin */
678 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
679 /* Line Pin */
680 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
681 { } /* end */
682};
683
Takashi Iwai985be542005-11-02 18:26:49 +0100684
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200685static int patch_ad1983(struct hda_codec *codec)
686{
687 struct ad198x_spec *spec;
688
Takashi Iwaie560d8d2005-09-09 14:21:46 +0200689 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200690 if (spec == NULL)
691 return -ENOMEM;
692
693 init_MUTEX(&spec->amp_mutex);
694 codec->spec = spec;
695
696 spec->multiout.max_channels = 2;
697 spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
698 spec->multiout.dac_nids = ad1983_dac_nids;
699 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +0100700 spec->num_adc_nids = 1;
701 spec->adc_nids = ad1983_adc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200702 spec->input_mux = &ad1983_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +0100703 spec->num_mixers = 1;
704 spec->mixers[0] = ad1983_mixers;
705 spec->num_init_verbs = 1;
706 spec->init_verbs[0] = ad1983_init_verbs;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200707 spec->spdif_route = 0;
708
709 codec->patch_ops = ad198x_patch_ops;
710
711 return 0;
712}
713
714
715/*
716 * AD1981 HD specific
717 */
718
719#define AD1981_SPDIF_OUT 0x02
720#define AD1981_DAC 0x03
721#define AD1981_ADC 0x04
722
723static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
Takashi Iwai985be542005-11-02 18:26:49 +0100724static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200725
726/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
727static struct hda_input_mux ad1981_capture_source = {
728 .num_items = 7,
729 .items = {
730 { "Front Mic", 0x0 },
731 { "Line", 0x1 },
732 { "Mix", 0x2 },
733 { "Mix Mono", 0x3 },
734 { "CD", 0x4 },
735 { "Mic", 0x6 },
736 { "Aux", 0x7 },
737 },
738};
739
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100740static struct snd_kcontrol_new ad1981_mixers[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200741 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
742 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
743 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
744 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
745 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
746 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
747 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
748 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
749 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
750 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
751 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
752 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
753 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
754 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
755 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
756 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
757 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
758 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
759 HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
760 HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x0d, 1, 0x0, HDA_OUTPUT),
761 HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
762 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
763 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
764 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
765 {
766 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
767 .name = "Capture Source",
768 .info = ad198x_mux_enum_info,
769 .get = ad198x_mux_enum_get,
770 .put = ad198x_mux_enum_put,
771 },
772 /* identical with AD1983 */
773 {
774 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Clemens Ladisch10e8d782005-08-03 13:40:08 +0200775 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200776 .info = ad1983_spdif_route_info,
777 .get = ad1983_spdif_route_get,
778 .put = ad1983_spdif_route_put,
779 },
780 { } /* end */
781};
782
783static struct hda_verb ad1981_init_verbs[] = {
784 /* Front, HP, Mono; mute as default */
785 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
786 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
787 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
788 /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
789 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
790 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
791 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
792 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
793 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
794 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
795 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
796 /* Front, HP selectors; from Mix */
797 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
798 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
799 /* Mono selector; from Mix */
800 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
801 /* Mic Mixer; select Front Mic */
802 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
803 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
804 /* Mic boost: 0dB */
805 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
806 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
807 /* Record selector: Front mic */
808 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
809 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
810 /* SPDIF route: PCM */
811 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
812 /* Front Pin */
813 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
814 /* HP Pin */
815 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
816 /* Mono Pin */
817 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
818 /* Front & Rear Mic Pins */
819 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
820 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
821 /* Line Pin */
822 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
823 /* Digital Beep */
824 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
825 /* Line-Out as Input: disabled */
826 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
827 { } /* end */
828};
829
830static int patch_ad1981(struct hda_codec *codec)
831{
832 struct ad198x_spec *spec;
833
Takashi Iwaie560d8d2005-09-09 14:21:46 +0200834 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200835 if (spec == NULL)
836 return -ENOMEM;
837
838 init_MUTEX(&spec->amp_mutex);
839 codec->spec = spec;
840
841 spec->multiout.max_channels = 2;
842 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
843 spec->multiout.dac_nids = ad1981_dac_nids;
844 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +0100845 spec->num_adc_nids = 1;
846 spec->adc_nids = ad1981_adc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200847 spec->input_mux = &ad1981_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +0100848 spec->num_mixers = 1;
849 spec->mixers[0] = ad1981_mixers;
850 spec->num_init_verbs = 1;
851 spec->init_verbs[0] = ad1981_init_verbs;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200852 spec->spdif_route = 0;
853
854 codec->patch_ops = ad198x_patch_ops;
855
856 return 0;
857}
858
859
860/*
Takashi Iwaifd66e0d2005-11-17 15:31:34 +0100861 * AD1988
862 *
863 * Output pins and routes
864 *
865 * Pin Mix Sel DAC
866 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
867 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
868 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
869 * port-D 0x12 (mute/hp) <- 0x29 <- 04
870 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
871 * port-F 0x16 (mute) <- 0x2a <- 06
872 * port-G 0x24 (mute) <- 0x27 <- 05
873 * port-H 0x25 (mute) <- 0x28 <- 0a
874 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
875 *
876 *
877 * Input pins and routes
878 *
879 * pin boost mix input # / adc input #
880 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
881 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
882 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
883 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
884 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
885 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
886 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
887 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
888 *
889 *
890 * DAC assignment
891 * front DAC - 04
892 * surr DAC - 06
893 * CLFE DAC - 05
894 * side DAC - 0a
895 * opt DAC - 03
896 *
897 * Inputs of Analog Mix (0x20)
898 * 0:Port-B (front mic)
899 * 1:Port-C/G/H (line-in)
900 * 2:Port-A
901 * 3:Port-D (line-in/2)
902 * 4:Port-E/G/H (mic-in)
903 * 5:Port-F (mic2-in)
904 * 6:CD
905 * 7:Beep
906 *
907 * ADC selection
908 * 0:Port-A
909 * 1:Port-B (front mic-in)
910 * 2:Port-C (line-in)
911 * 3:Port-F (mic2-in)
912 * 4:Port-E (mic-in)
913 * 5:CD
914 * 6:Port-G
915 * 7:Port-H
916 * 8:Port-D (line-in/2)
917 * 9:Mix
918 *
919 * Proposed pin assignments by the datasheet
920 *
921 * 6-stack
922 * Port-A front headphone
923 * B front mic-in
924 * C rear line-in
925 * D rear front-out
926 * E rear mic-in
927 * F rear surround
928 * G rear CLFE
929 * H rear side
930 *
931 * 3-stack
932 * Port-A front headphone
933 * B front mic
934 * C rear line-in/surround
935 * D rear front-out
936 * E rear mic-in/CLFE
937 *
938 * laptop
939 * Port-A headphone
940 * B mic-in
941 * C docking station
942 * D internal speaker (with EAPD)
943 * E/F quad mic array
944 */
945
946
947/* models */
948enum {
949 AD1988_6STACK,
950 AD1988_6STACK_DIG,
951 AD1988_3STACK,
952 AD1988_3STACK_DIG,
953 AD1988_LAPTOP,
954 AD1988_LAPTOP_DIG,
955 AD1988_MODEL_LAST,
956};
957
958
959/*
960 * mixers
961 */
962
963static hda_nid_t ad1988_dac_nids[4] = {
964 0x04, 0x06, 0x05, 0x0a
965};
966
967static hda_nid_t ad1988_adc_nids[3] = {
968 0x08, 0x09, 0x0f
969};
970
971#define AD1988_SPDIF_OUT 0x02
972#define AD1988_SPDIF_IN 0x07
973
974static struct hda_input_mux ad1988_6stack_capture_source = {
975 .num_items = 5,
976 .items = {
977 { "Front Mic", 0x0 },
978 { "Line", 0x1 },
979 { "Mic", 0x4 },
980 { "CD", 0x5 },
981 { "Mix", 0x9 },
982 },
983};
984
985static struct hda_input_mux ad1988_laptop_capture_source = {
986 .num_items = 3,
987 .items = {
988 { "Mic/Line", 0x0 },
989 { "CD", 0x5 },
990 { "Mix", 0x9 },
991 },
992};
993
994/*
995 */
996static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
997 struct snd_ctl_elem_info *uinfo)
998{
999 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1000 struct ad198x_spec *spec = codec->spec;
1001 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
1002 spec->num_channel_mode);
1003}
1004
1005static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
1006 struct snd_ctl_elem_value *ucontrol)
1007{
1008 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1009 struct ad198x_spec *spec = codec->spec;
1010 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
1011 spec->num_channel_mode, spec->multiout.max_channels);
1012}
1013
1014static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
1015 struct snd_ctl_elem_value *ucontrol)
1016{
1017 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1018 struct ad198x_spec *spec = codec->spec;
1019 return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
1020 spec->num_channel_mode, &spec->multiout.max_channels);
1021}
1022
1023/*
1024 * EAPD control
1025 */
1026static int ad1988_eapd_info(struct snd_kcontrol *kcontrol,
1027 struct snd_ctl_elem_info *uinfo)
1028{
1029 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1030 uinfo->count = 1;
1031 uinfo->value.integer.min = 0;
1032 uinfo->value.integer.max = 1;
1033 return 0;
1034}
1035
1036static int ad1988_eapd_get(struct snd_kcontrol *kcontrol,
1037 struct snd_ctl_elem_value *ucontrol)
1038{
1039 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1040 struct ad198x_spec *spec = codec->spec;
1041 ucontrol->value.enumerated.item[0] = ! spec->cur_eapd;
1042 return 0;
1043}
1044
1045static int ad1988_eapd_put(struct snd_kcontrol *kcontrol,
1046 struct snd_ctl_elem_value *ucontrol)
1047{
1048 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1049 struct ad198x_spec *spec = codec->spec;
1050 unsigned int eapd;
1051 eapd = ! ucontrol->value.enumerated.item[0];
1052 if (eapd == spec->cur_eapd && ! codec->in_resume)
1053 return 0;
1054 spec->cur_eapd = eapd;
1055 snd_hda_codec_write(codec, 0x12 /* port-D */,
1056 0, AC_VERB_SET_EAPD_BTLENABLE,
1057 eapd ? 0x02 : 0x00);
1058 return 0;
1059}
1060
1061/* 6-stack mode */
1062static struct snd_kcontrol_new ad1988_6stack_mixers[] = {
1063 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
1064 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1065 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
1066 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
1067 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
1068
1069 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
1070 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
1071 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
1072 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
1073 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
1074 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
1075 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
1076
1077 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
1078 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
1079 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
1080 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
1081 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
1082 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
1083 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
1084 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
1085
1086 HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
1087 HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
1088
1089 HDA_CODEC_VOLUME("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
1090 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
1091
1092 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
1093 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
1094
1095 { } /* end */
1096};
1097
1098/* 3-stack mode */
1099static struct snd_kcontrol_new ad1988_3stack_mixers[] = {
1100 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
1101 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1102 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
1103 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
1104
1105 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
1106 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
1107 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
1108 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
1109 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
1110 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
1111
1112 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
1113 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
1114 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
1115 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
1116 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
1117 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
1118 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
1119 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
1120
1121 HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
1122 HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
1123
1124 HDA_CODEC_VOLUME("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
1125 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
1126
1127 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
1128 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
1129 {
1130 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1131 .name = "Channel Mode",
1132 .info = ad198x_ch_mode_info,
1133 .get = ad198x_ch_mode_get,
1134 .put = ad198x_ch_mode_put,
1135 },
1136
1137 { } /* end */
1138};
1139
1140/* laptop mode */
1141static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
1142 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
1143 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
1144 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
1145
1146 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
1147 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
1148 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
1149 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
1150 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
1151 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
1152
1153 HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
1154 HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
1155
1156 HDA_CODEC_VOLUME("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
1157 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
1158
1159 HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT),
1160
1161 {
1162 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1163 .name = "External Amplifier",
1164 .info = ad1988_eapd_info,
1165 .get = ad1988_eapd_get,
1166 .put = ad1988_eapd_put,
1167 },
1168
1169 { } /* end */
1170};
1171
1172/* capture */
1173static struct snd_kcontrol_new ad1988_capture_mixers[] = {
1174 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
1175 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
1176 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
1177 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
1178 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
1179 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
1180 {
1181 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1182 /* The multiple "Capture Source" controls confuse alsamixer
1183 * So call somewhat different..
1184 * FIXME: the controls appear in the "playback" view!
1185 */
1186 /* .name = "Capture Source", */
1187 .name = "Input Source",
1188 .count = 3,
1189 .info = ad198x_mux_enum_info,
1190 .get = ad198x_mux_enum_get,
1191 .put = ad198x_mux_enum_put,
1192 },
1193 { } /* end */
1194};
1195
1196static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
1197 struct snd_ctl_elem_info *uinfo)
1198{
1199 static char *texts[] = {
1200 "PCM", "ADC1", "ADC2", "ADC3"
1201 };
1202 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1203 uinfo->count = 1;
1204 uinfo->value.enumerated.items = 4;
1205 if (uinfo->value.enumerated.item >= 4)
1206 uinfo->value.enumerated.item = 3;
1207 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1208 return 0;
1209}
1210
1211static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
1212 struct snd_ctl_elem_value *ucontrol)
1213{
1214 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1215 unsigned int sel;
1216
1217 sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0);
1218 if (sel > 0) {
1219 sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0);
1220 if (sel <= 3)
1221 sel++;
1222 else
1223 sel = 0;
1224 }
1225 ucontrol->value.enumerated.item[0] = sel;
1226 return 0;
1227}
1228
1229static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
1230 struct snd_ctl_elem_value *ucontrol)
1231{
1232 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1233 unsigned int sel;
1234 int change;
1235
1236 sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0);
1237 if (! ucontrol->value.enumerated.item[0]) {
1238 change = sel != 0;
1239 if (change)
1240 snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL, 0);
1241 } else {
1242 change = sel == 0;
1243 if (change)
1244 snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL, 1);
1245 sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0) + 1;
1246 change |= sel == ucontrol->value.enumerated.item[0];
1247 if (change)
1248 snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL,
1249 ucontrol->value.enumerated.item[0] - 1);
1250 }
1251 return change;
1252}
1253
1254static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
1255 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1256 {
1257 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1258 .name = "IEC958 Playback Source",
1259 .info = ad1988_spdif_playback_source_info,
1260 .get = ad1988_spdif_playback_source_get,
1261 .put = ad1988_spdif_playback_source_put,
1262 },
1263 { } /* end */
1264};
1265
1266static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
1267 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
1268 { } /* end */
1269};
1270
1271
1272/*
1273 * initialization verbs
1274 */
1275
1276/*
1277 * for 6-stack (+dig)
1278 */
1279static struct hda_verb ad1988_6stack_init_verbs[] = {
1280 /* Front, Surround, CLFE, side DAC; mute as default */
1281 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1282 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1283 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1284 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1285 /* Port-A front headphon path */
1286 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
1287 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1288 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1289 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1290 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1291 /* Port-D line-out path */
1292 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1293 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1294 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1295 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1296 /* Port-F surround path */
1297 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1298 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1299 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1300 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1301 /* Port-G CLFE path */
1302 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1303 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1304 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1305 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1306 /* Port-H side path */
1307 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1308 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1309 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1310 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1311 /* Mono out path */
1312 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
1313 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1314 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1315 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1316 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
1317 /* Port-B front mic-in path */
1318 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1319 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1320 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1321 /* Port-C line-in path */
1322 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1323 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1324 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1325 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
1326 /* Port-E mic-in path */
1327 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1328 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1329 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1330 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
1331
1332 { }
1333};
1334
1335static struct hda_verb ad1988_capture_init_verbs[] = {
1336 /* mute analog mix */
1337 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1338 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1339 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1340 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1341 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1342 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
1343 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1344 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
1345 /* select ADCs - front-mic */
1346 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
1347 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
1348 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
1349 /* ADCs; muted */
1350 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1351 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1352 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1353
1354 { }
1355};
1356
1357static struct hda_verb ad1988_spdif_init_verbs[] = {
1358 /* SPDIF out sel */
1359 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
1360 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
1361 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1362 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1363 /* SPDIF out pin */
1364 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
1365 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x17}, /* 0dB */
1366
1367 { }
1368};
1369
1370/*
1371 * verbs for 3stack (+dig)
1372 */
1373static struct hda_verb ad1988_3stack_ch2_init[] = {
1374 /* set port-C to line-in */
1375 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1376 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1377 /* set port-E to mic-in */
1378 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1379 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1380 { } /* end */
1381};
1382
1383static struct hda_verb ad1988_3stack_ch6_init[] = {
1384 /* set port-C to surround out */
1385 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1386 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1387 /* set port-E to CLFE out */
1388 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1389 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1390 { } /* end */
1391};
1392
1393static struct hda_channel_mode ad1988_3stack_modes[2] = {
1394 { 2, ad1988_3stack_ch2_init },
1395 { 6, ad1988_3stack_ch6_init },
1396};
1397
1398static struct hda_verb ad1988_3stack_init_verbs[] = {
1399 /* Front, Surround, CLFE, side DAC; mute as default */
1400 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1401 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1402 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1403 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1404 /* Port-A front headphon path */
1405 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
1406 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1407 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1408 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1409 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1410 /* Port-D line-out path */
1411 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1412 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1413 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1414 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1415 /* Mono out path */
1416 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
1417 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1418 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1419 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1420 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
1421 /* Port-B front mic-in path */
1422 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1423 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1424 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1425 /* Port-C line-in/surround path */
1426 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1427 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1428 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1429 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
1430 /* Port-E mic-in/CLFE path */
1431 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1432 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1433 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1434 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
1435 /* mute analog mix */
1436 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1437 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1438 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1439 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1440 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1441 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
1442 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1443 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
1444 /* select ADCs - front-mic */
1445 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
1446 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
1447 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
1448 /* ADCs; muted */
1449 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1450 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1451 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1452 { }
1453};
1454
1455/*
1456 * verbs for laptop mode (+dig)
1457 */
1458static struct hda_verb ad1988_laptop_hp_on[] = {
1459 /* unmute port-A and mute port-D */
1460 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1461 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1462 { } /* end */
1463};
1464static struct hda_verb ad1988_laptop_hp_off[] = {
1465 /* mute port-A and unmute port-D */
1466 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1467 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1468 { } /* end */
1469};
1470
1471#define AD1988_HP_EVENT 0x01
1472
1473static struct hda_verb ad1988_laptop_init_verbs[] = {
1474 /* Front, Surround, CLFE, side DAC; mute as default */
1475 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1476 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1477 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1478 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1479 /* Port-A front headphon path */
1480 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
1481 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1482 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1483 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1484 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1485 /* unsolicited event for pin-sense */
1486 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
1487 /* Port-D line-out path + EAPD */
1488 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1489 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1490 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1491 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1492 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
1493 /* Mono out path */
1494 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
1495 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1496 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1497 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1498 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
1499 /* Port-B mic-in path */
1500 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1501 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1502 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1503 /* Port-C docking station - try to output */
1504 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1505 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1506 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1507 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
1508 /* mute analog mix */
1509 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1510 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1511 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1512 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1513 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1514 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
1515 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1516 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
1517 /* select ADCs - mic */
1518 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
1519 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
1520 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
1521 /* ADCs; muted */
1522 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1523 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1524 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1525 { }
1526};
1527
1528static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
1529{
1530 if ((res >> 26) != AD1988_HP_EVENT)
1531 return;
1532 if (snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & (1 << 31))
1533 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
1534 else
1535 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
1536}
1537
1538
1539/*
1540 */
1541
1542static struct hda_board_config ad1988_cfg_tbl[] = {
1543 { .modelname = "6stack", .config = AD1988_6STACK },
1544 { .modelname = "6stack-dig", .config = AD1988_6STACK_DIG },
1545 { .modelname = "3stack", .config = AD1988_3STACK },
1546 { .modelname = "3stack-dig", .config = AD1988_3STACK_DIG },
1547 { .modelname = "laptop", .config = AD1988_LAPTOP },
1548 { .modelname = "laptop-dig", .config = AD1988_LAPTOP_DIG },
1549 {}
1550};
1551
1552static int patch_ad1988(struct hda_codec *codec)
1553{
1554 struct ad198x_spec *spec;
1555 int board_config;
1556
1557 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1558 if (spec == NULL)
1559 return -ENOMEM;
1560
1561 init_MUTEX(&spec->amp_mutex);
1562 codec->spec = spec;
1563
1564 board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl);
1565 if (board_config < 0 || board_config >= AD1988_MODEL_LAST) {
1566 printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n");
1567 board_config = AD1988_6STACK;
1568 }
1569
1570 switch (board_config) {
1571 case AD1988_6STACK:
1572 case AD1988_6STACK_DIG:
1573 spec->multiout.max_channels = 8;
1574 spec->multiout.num_dacs = 4;
1575 spec->multiout.dac_nids = ad1988_dac_nids;
1576 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
1577 spec->adc_nids = ad1988_adc_nids;
1578 spec->input_mux = &ad1988_6stack_capture_source;
1579 spec->num_mixers = 1;
1580 spec->mixers[0] = ad1988_6stack_mixers;
1581 spec->num_init_verbs = 1;
1582 spec->init_verbs[0] = ad1988_6stack_init_verbs;
1583 if (board_config == AD1988_6STACK_DIG) {
1584 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
1585 spec->dig_in_nid = AD1988_SPDIF_IN;
1586 }
1587 break;
1588 case AD1988_3STACK:
1589 case AD1988_3STACK_DIG:
1590 spec->multiout.max_channels = 6;
1591 spec->multiout.num_dacs = 3;
1592 spec->multiout.dac_nids = ad1988_dac_nids;
1593 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
1594 spec->adc_nids = ad1988_adc_nids;
1595 spec->input_mux = &ad1988_6stack_capture_source;
1596 spec->channel_mode = ad1988_3stack_modes;
1597 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
1598 spec->num_mixers = 1;
1599 spec->mixers[0] = ad1988_3stack_mixers;
1600 spec->num_init_verbs = 1;
1601 spec->init_verbs[0] = ad1988_3stack_init_verbs;
1602 if (board_config == AD1988_3STACK_DIG)
1603 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
1604 break;
1605 case AD1988_LAPTOP:
1606 case AD1988_LAPTOP_DIG:
1607 spec->multiout.max_channels = 2;
1608 spec->multiout.num_dacs = 1;
1609 spec->multiout.dac_nids = ad1988_dac_nids;
1610 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
1611 spec->adc_nids = ad1988_adc_nids;
1612 spec->input_mux = &ad1988_laptop_capture_source;
1613 spec->num_mixers = 1;
1614 spec->mixers[0] = ad1988_laptop_mixers;
1615 spec->num_init_verbs = 1;
1616 spec->init_verbs[0] = ad1988_laptop_init_verbs;
1617 if (board_config == AD1988_LAPTOP_DIG)
1618 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
1619 break;
1620 }
1621
1622 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
1623 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
1624 if (spec->multiout.dig_out_nid) {
1625 spec->mixers[spec->num_mixers++] = ad1988_spdif_out_mixers;
1626 spec->init_verbs[spec->num_init_verbs++] = ad1988_spdif_init_verbs;
1627 }
1628 if (spec->dig_in_nid)
1629 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
1630
1631 codec->patch_ops = ad198x_patch_ops;
1632 switch (board_config) {
1633 case AD1988_LAPTOP:
1634 case AD1988_LAPTOP_DIG:
1635 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
1636 break;
1637 }
1638
1639 return 0;
1640}
1641
1642
1643/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 * patch entries
1645 */
1646struct hda_codec_preset snd_hda_preset_analog[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001647 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
1648 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001650 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 {} /* terminator */
1652};