blob: 3799d8a1afae988137c221bd8aec9d52a2c8f0f4 [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 Iwai2e5b9562005-11-21 16:36:15 +010053 hda_nid_t *capsrc_nids;
Takashi Iwai985be542005-11-02 18:26:49 +010054 unsigned int cur_mux[3];
55
56 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +010057 const struct hda_channel_mode *channel_mode;
Takashi Iwai985be542005-11-02 18:26:49 +010058 int num_channel_mode;
59
60 /* PCM information */
61 struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */
62
63 struct semaphore amp_mutex; /* PCM volume/mute control mutex */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020064 unsigned int spdif_route;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065};
66
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020067/*
68 * input MUX handling (common part)
69 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010070static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020071{
72 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
73 struct ad198x_spec *spec = codec->spec;
74
75 return snd_hda_input_mux_info(spec->input_mux, uinfo);
76}
77
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010078static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020079{
80 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
81 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +010082 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020083
Takashi Iwai985be542005-11-02 18:26:49 +010084 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020085 return 0;
86}
87
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010088static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020089{
90 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
91 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +010092 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020093
94 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Takashi Iwai2e5b9562005-11-21 16:36:15 +010095 spec->capsrc_nids[adc_idx],
96 &spec->cur_mux[adc_idx]);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020097}
98
99/*
100 * initialization (common callbacks)
101 */
102static int ad198x_init(struct hda_codec *codec)
103{
104 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100105 int i;
106
107 for (i = 0; i < spec->num_init_verbs; i++)
108 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200109 return 0;
110}
111
112static int ad198x_build_controls(struct hda_codec *codec)
113{
114 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100115 unsigned int i;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200116 int err;
117
Takashi Iwai985be542005-11-02 18:26:49 +0100118 for (i = 0; i < spec->num_mixers; i++) {
119 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
120 if (err < 0)
121 return err;
122 }
123 if (spec->multiout.dig_out_nid) {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200124 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
Takashi Iwai985be542005-11-02 18:26:49 +0100125 if (err < 0)
126 return err;
127 }
128 if (spec->dig_in_nid) {
129 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
130 if (err < 0)
131 return err;
132 }
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200133 return 0;
134}
135
136/*
137 * Analog playback callbacks
138 */
139static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
140 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100141 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200142{
143 struct ad198x_spec *spec = codec->spec;
144 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
145}
146
147static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
148 struct hda_codec *codec,
149 unsigned int stream_tag,
150 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100151 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200152{
153 struct ad198x_spec *spec = codec->spec;
154 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
155 format, substream);
156}
157
158static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
159 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100160 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200161{
162 struct ad198x_spec *spec = codec->spec;
163 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
164}
165
166/*
167 * Digital out
168 */
169static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
170 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100171 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200172{
173 struct ad198x_spec *spec = codec->spec;
174 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
175}
176
177static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
178 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100179 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200180{
181 struct ad198x_spec *spec = codec->spec;
182 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
183}
184
185/*
186 * Analog capture
187 */
188static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
189 struct hda_codec *codec,
190 unsigned int stream_tag,
191 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100192 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200193{
194 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100195 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
196 stream_tag, 0, format);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200197 return 0;
198}
199
200static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
201 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100202 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200203{
204 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100205 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
206 0, 0, 0);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200207 return 0;
208}
209
210
211/*
212 */
213static struct hda_pcm_stream ad198x_pcm_analog_playback = {
214 .substreams = 1,
215 .channels_min = 2,
Takashi Iwai985be542005-11-02 18:26:49 +0100216 .channels_max = 6, /* changed later */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200217 .nid = 0, /* fill later */
218 .ops = {
219 .open = ad198x_playback_pcm_open,
220 .prepare = ad198x_playback_pcm_prepare,
221 .cleanup = ad198x_playback_pcm_cleanup
222 },
223};
224
225static struct hda_pcm_stream ad198x_pcm_analog_capture = {
Takashi Iwai985be542005-11-02 18:26:49 +0100226 .substreams = 1,
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200227 .channels_min = 2,
228 .channels_max = 2,
229 .nid = 0, /* fill later */
230 .ops = {
231 .prepare = ad198x_capture_pcm_prepare,
232 .cleanup = ad198x_capture_pcm_cleanup
233 },
234};
235
236static struct hda_pcm_stream ad198x_pcm_digital_playback = {
237 .substreams = 1,
238 .channels_min = 2,
239 .channels_max = 2,
240 .nid = 0, /* fill later */
241 .ops = {
242 .open = ad198x_dig_playback_pcm_open,
243 .close = ad198x_dig_playback_pcm_close
244 },
245};
246
Takashi Iwai985be542005-11-02 18:26:49 +0100247static struct hda_pcm_stream ad198x_pcm_digital_capture = {
248 .substreams = 1,
249 .channels_min = 2,
250 .channels_max = 2,
251 /* NID is set in alc_build_pcms */
252};
253
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200254static int ad198x_build_pcms(struct hda_codec *codec)
255{
256 struct ad198x_spec *spec = codec->spec;
257 struct hda_pcm *info = spec->pcm_rec;
258
259 codec->num_pcms = 1;
260 codec->pcm_info = info;
261
262 info->name = "AD198x Analog";
263 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
264 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
265 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
266 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
Takashi Iwai985be542005-11-02 18:26:49 +0100267 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
268 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200269
270 if (spec->multiout.dig_out_nid) {
271 info++;
272 codec->num_pcms++;
273 info->name = "AD198x Digital";
274 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
275 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
Takashi Iwai985be542005-11-02 18:26:49 +0100276 if (spec->dig_in_nid) {
277 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
278 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
279 }
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200280 }
281
282 return 0;
283}
284
285static void ad198x_free(struct hda_codec *codec)
286{
287 kfree(codec->spec);
288}
289
290#ifdef CONFIG_PM
291static int ad198x_resume(struct hda_codec *codec)
292{
293 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100294 int i;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200295
296 ad198x_init(codec);
Takashi Iwai985be542005-11-02 18:26:49 +0100297 for (i = 0; i < spec->num_mixers; i++)
298 snd_hda_resume_ctls(codec, spec->mixers[i]);
299 if (spec->multiout.dig_out_nid)
300 snd_hda_resume_spdif_out(codec);
301 if (spec->dig_in_nid)
302 snd_hda_resume_spdif_in(codec);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200303 return 0;
304}
305#endif
306
307static struct hda_codec_ops ad198x_patch_ops = {
308 .build_controls = ad198x_build_controls,
309 .build_pcms = ad198x_build_pcms,
310 .init = ad198x_init,
311 .free = ad198x_free,
312#ifdef CONFIG_PM
313 .resume = ad198x_resume,
314#endif
315};
316
317
318/*
319 * AD1986A specific
320 */
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322#define AD1986A_SPDIF_OUT 0x02
323#define AD1986A_FRONT_DAC 0x03
324#define AD1986A_SURR_DAC 0x04
325#define AD1986A_CLFE_DAC 0x05
326#define AD1986A_ADC 0x06
327
328static hda_nid_t ad1986a_dac_nids[3] = {
329 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
330};
Takashi Iwai985be542005-11-02 18:26:49 +0100331static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333static struct hda_input_mux ad1986a_capture_source = {
334 .num_items = 7,
335 .items = {
336 { "Mic", 0x0 },
337 { "CD", 0x1 },
338 { "Aux", 0x3 },
339 { "Line", 0x4 },
340 { "Mix", 0x5 },
341 { "Mono", 0x6 },
342 { "Phone", 0x7 },
343 },
344};
345
346/*
347 * PCM control
348 *
349 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
350 */
351
352#define ad1986a_pcm_amp_vol_info snd_hda_mixer_amp_volume_info
353
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100354static int ad1986a_pcm_amp_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
356 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200357 struct ad198x_spec *ad = codec->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359 down(&ad->amp_mutex);
360 snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
361 up(&ad->amp_mutex);
362 return 0;
363}
364
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100365static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
367 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200368 struct ad198x_spec *ad = codec->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 int i, change = 0;
370
371 down(&ad->amp_mutex);
372 for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) {
373 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT);
374 change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
375 }
376 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT);
377 up(&ad->amp_mutex);
378 return change;
379}
380
Takashi Iwaiead9b7c2005-06-08 14:48:19 +0200381#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100383static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200386 struct ad198x_spec *ad = codec->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
388 down(&ad->amp_mutex);
389 snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
390 up(&ad->amp_mutex);
391 return 0;
392}
393
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100394static int ad1986a_pcm_amp_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
396 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200397 struct ad198x_spec *ad = codec->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 int i, change = 0;
399
400 down(&ad->amp_mutex);
401 for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) {
402 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT);
403 change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
404 }
405 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT);
406 up(&ad->amp_mutex);
407 return change;
408}
409
410/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 * mixers
412 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100413static struct snd_kcontrol_new ad1986a_mixers[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 {
415 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
416 .name = "PCM Playback Volume",
417 .info = ad1986a_pcm_amp_vol_info,
418 .get = ad1986a_pcm_amp_vol_get,
419 .put = ad1986a_pcm_amp_vol_put,
420 .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT)
421 },
422 {
423 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
424 .name = "PCM Playback Switch",
425 .info = ad1986a_pcm_amp_sw_info,
426 .get = ad1986a_pcm_amp_sw_get,
427 .put = ad1986a_pcm_amp_sw_put,
428 .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT)
429 },
430 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
431 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
432 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
433 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
434 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
435 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
436 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
437 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
438 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
439 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
440 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
441 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
442 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
443 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
444 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
445 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
446 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
447 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
448 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT),
449 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT),
450 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
451 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
452 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
453 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
454 {
455 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
456 .name = "Capture Source",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200457 .info = ad198x_mux_enum_info,
458 .get = ad198x_mux_enum_get,
459 .put = ad198x_mux_enum_put,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 },
461 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
462 { } /* end */
463};
464
465/*
466 * initialization verbs
467 */
468static struct hda_verb ad1986a_init_verbs[] = {
469 /* Front, Surround, CLFE DAC; mute as default */
470 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
471 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
472 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
473 /* Downmix - off */
474 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
475 /* HP, Line-Out, Surround, CLFE selectors */
476 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
477 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
478 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
479 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
480 /* Mono selector */
481 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
482 /* Mic selector: Mic 1/2 pin */
483 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
484 /* Line-in selector: Line-in */
485 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
486 /* Mic 1/2 swap */
487 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
488 /* Record selector: mic */
489 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
490 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
491 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
492 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
493 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
494 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
495 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
496 /* PC beep */
497 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
498 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
499 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
500 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
501 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
502 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
503 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200504 /* HP Pin */
505 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
506 /* Front, Surround, CLFE Pins */
507 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
508 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
509 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
510 /* Mono Pin */
511 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
512 /* Mic Pin */
513 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
514 /* Line, Aux, CD, Beep-In Pin */
515 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
516 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
517 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
518 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
519 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 { } /* end */
521};
522
523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524static int patch_ad1986a(struct hda_codec *codec)
525{
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200526 struct ad198x_spec *spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Takashi Iwaie560d8d2005-09-09 14:21:46 +0200528 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 if (spec == NULL)
530 return -ENOMEM;
531
532 init_MUTEX(&spec->amp_mutex);
533 codec->spec = spec;
534
535 spec->multiout.max_channels = 6;
536 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
537 spec->multiout.dac_nids = ad1986a_dac_nids;
538 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +0100539 spec->num_adc_nids = 1;
540 spec->adc_nids = ad1986a_adc_nids;
Takashi Iwai2e5b9562005-11-21 16:36:15 +0100541 spec->capsrc_nids = ad1986a_adc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200542 spec->input_mux = &ad1986a_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +0100543 spec->num_mixers = 1;
544 spec->mixers[0] = ad1986a_mixers;
545 spec->num_init_verbs = 1;
546 spec->init_verbs[0] = ad1986a_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200548 codec->patch_ops = ad198x_patch_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
550 return 0;
551}
552
553/*
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200554 * AD1983 specific
555 */
556
557#define AD1983_SPDIF_OUT 0x02
558#define AD1983_DAC 0x03
559#define AD1983_ADC 0x04
560
561static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
Takashi Iwai985be542005-11-02 18:26:49 +0100562static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200563
564static struct hda_input_mux ad1983_capture_source = {
565 .num_items = 4,
566 .items = {
567 { "Mic", 0x0 },
568 { "Line", 0x1 },
569 { "Mix", 0x2 },
570 { "Mix Mono", 0x3 },
571 },
572};
573
574/*
575 * SPDIF playback route
576 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100577static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200578{
579 static char *texts[] = { "PCM", "ADC" };
580
581 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
582 uinfo->count = 1;
583 uinfo->value.enumerated.items = 2;
584 if (uinfo->value.enumerated.item > 1)
585 uinfo->value.enumerated.item = 1;
586 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
587 return 0;
588}
589
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100590static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200591{
592 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
593 struct ad198x_spec *spec = codec->spec;
594
595 ucontrol->value.enumerated.item[0] = spec->spdif_route;
596 return 0;
597}
598
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100599static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200600{
601 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
602 struct ad198x_spec *spec = codec->spec;
603
604 if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
605 spec->spdif_route = ucontrol->value.enumerated.item[0];
606 snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0,
607 AC_VERB_SET_CONNECT_SEL, spec->spdif_route);
608 return 1;
609 }
610 return 0;
611}
612
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100613static struct snd_kcontrol_new ad1983_mixers[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200614 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
615 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
616 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
617 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
618 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
619 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
620 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
621 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
622 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
623 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
624 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
625 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
626 HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x10, 1, 0x0, HDA_OUTPUT),
627 HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x10, 1, 0x0, HDA_OUTPUT),
628 HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
629 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
630 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
631 {
632 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
633 .name = "Capture Source",
634 .info = ad198x_mux_enum_info,
635 .get = ad198x_mux_enum_get,
636 .put = ad198x_mux_enum_put,
637 },
638 {
639 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Clemens Ladisch10e8d782005-08-03 13:40:08 +0200640 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200641 .info = ad1983_spdif_route_info,
642 .get = ad1983_spdif_route_get,
643 .put = ad1983_spdif_route_put,
644 },
645 { } /* end */
646};
647
648static struct hda_verb ad1983_init_verbs[] = {
649 /* Front, HP, Mono; mute as default */
650 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
651 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
652 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
653 /* Beep, PCM, Mic, Line-In: mute */
654 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
655 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
656 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
657 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
658 /* Front, HP selectors; from Mix */
659 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
660 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
661 /* Mono selector; from Mix */
662 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
663 /* Mic selector; Mic */
664 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
665 /* Line-in selector: Line-in */
666 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
667 /* Mic boost: 0dB */
668 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
669 /* Record selector: mic */
670 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
671 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
672 /* SPDIF route: PCM */
673 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
674 /* Front Pin */
675 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
676 /* HP Pin */
677 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
678 /* Mono Pin */
679 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
680 /* Mic Pin */
681 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
682 /* Line Pin */
683 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
684 { } /* end */
685};
686
Takashi Iwai985be542005-11-02 18:26:49 +0100687
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200688static int patch_ad1983(struct hda_codec *codec)
689{
690 struct ad198x_spec *spec;
691
Takashi Iwaie560d8d2005-09-09 14:21:46 +0200692 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200693 if (spec == NULL)
694 return -ENOMEM;
695
696 init_MUTEX(&spec->amp_mutex);
697 codec->spec = spec;
698
699 spec->multiout.max_channels = 2;
700 spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
701 spec->multiout.dac_nids = ad1983_dac_nids;
702 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +0100703 spec->num_adc_nids = 1;
704 spec->adc_nids = ad1983_adc_nids;
Takashi Iwai2e5b9562005-11-21 16:36:15 +0100705 spec->capsrc_nids = ad1983_adc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200706 spec->input_mux = &ad1983_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +0100707 spec->num_mixers = 1;
708 spec->mixers[0] = ad1983_mixers;
709 spec->num_init_verbs = 1;
710 spec->init_verbs[0] = ad1983_init_verbs;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200711 spec->spdif_route = 0;
712
713 codec->patch_ops = ad198x_patch_ops;
714
715 return 0;
716}
717
718
719/*
720 * AD1981 HD specific
721 */
722
723#define AD1981_SPDIF_OUT 0x02
724#define AD1981_DAC 0x03
725#define AD1981_ADC 0x04
726
727static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
Takashi Iwai985be542005-11-02 18:26:49 +0100728static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200729
730/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
731static struct hda_input_mux ad1981_capture_source = {
732 .num_items = 7,
733 .items = {
734 { "Front Mic", 0x0 },
735 { "Line", 0x1 },
736 { "Mix", 0x2 },
737 { "Mix Mono", 0x3 },
738 { "CD", 0x4 },
739 { "Mic", 0x6 },
740 { "Aux", 0x7 },
741 },
742};
743
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100744static struct snd_kcontrol_new ad1981_mixers[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200745 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
746 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
747 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
748 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
749 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
750 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
751 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
752 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
753 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
754 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
755 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
756 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
757 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
758 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
759 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
760 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
761 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
762 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
763 HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
764 HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x0d, 1, 0x0, HDA_OUTPUT),
765 HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
766 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
767 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
768 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
769 {
770 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
771 .name = "Capture Source",
772 .info = ad198x_mux_enum_info,
773 .get = ad198x_mux_enum_get,
774 .put = ad198x_mux_enum_put,
775 },
776 /* identical with AD1983 */
777 {
778 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Clemens Ladisch10e8d782005-08-03 13:40:08 +0200779 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200780 .info = ad1983_spdif_route_info,
781 .get = ad1983_spdif_route_get,
782 .put = ad1983_spdif_route_put,
783 },
784 { } /* end */
785};
786
787static struct hda_verb ad1981_init_verbs[] = {
788 /* Front, HP, Mono; mute as default */
789 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
790 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
791 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
792 /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
793 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
794 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
795 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
796 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
797 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
798 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
799 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
800 /* Front, HP selectors; from Mix */
801 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
802 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
803 /* Mono selector; from Mix */
804 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
805 /* Mic Mixer; select Front Mic */
806 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
807 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
808 /* Mic boost: 0dB */
809 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
810 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
811 /* Record selector: Front mic */
812 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
813 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
814 /* SPDIF route: PCM */
815 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
816 /* Front Pin */
817 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
818 /* HP Pin */
819 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
820 /* Mono Pin */
821 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
822 /* Front & Rear Mic Pins */
823 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
824 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
825 /* Line Pin */
826 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
827 /* Digital Beep */
828 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
829 /* Line-Out as Input: disabled */
830 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
831 { } /* end */
832};
833
834static int patch_ad1981(struct hda_codec *codec)
835{
836 struct ad198x_spec *spec;
837
Takashi Iwaie560d8d2005-09-09 14:21:46 +0200838 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200839 if (spec == NULL)
840 return -ENOMEM;
841
842 init_MUTEX(&spec->amp_mutex);
843 codec->spec = spec;
844
845 spec->multiout.max_channels = 2;
846 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
847 spec->multiout.dac_nids = ad1981_dac_nids;
848 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +0100849 spec->num_adc_nids = 1;
850 spec->adc_nids = ad1981_adc_nids;
Takashi Iwai2e5b9562005-11-21 16:36:15 +0100851 spec->capsrc_nids = ad1981_adc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200852 spec->input_mux = &ad1981_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +0100853 spec->num_mixers = 1;
854 spec->mixers[0] = ad1981_mixers;
855 spec->num_init_verbs = 1;
856 spec->init_verbs[0] = ad1981_init_verbs;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200857 spec->spdif_route = 0;
858
859 codec->patch_ops = ad198x_patch_ops;
860
861 return 0;
862}
863
864
865/*
Takashi Iwaifd66e0d2005-11-17 15:31:34 +0100866 * AD1988
867 *
868 * Output pins and routes
869 *
870 * Pin Mix Sel DAC
871 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
872 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
873 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
874 * port-D 0x12 (mute/hp) <- 0x29 <- 04
875 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
876 * port-F 0x16 (mute) <- 0x2a <- 06
877 * port-G 0x24 (mute) <- 0x27 <- 05
878 * port-H 0x25 (mute) <- 0x28 <- 0a
879 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
880 *
881 *
882 * Input pins and routes
883 *
884 * pin boost mix input # / adc input #
885 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
886 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
887 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
888 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
889 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
890 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
891 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
892 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
893 *
894 *
895 * DAC assignment
896 * front DAC - 04
897 * surr DAC - 06
898 * CLFE DAC - 05
899 * side DAC - 0a
900 * opt DAC - 03
901 *
902 * Inputs of Analog Mix (0x20)
903 * 0:Port-B (front mic)
904 * 1:Port-C/G/H (line-in)
905 * 2:Port-A
906 * 3:Port-D (line-in/2)
907 * 4:Port-E/G/H (mic-in)
908 * 5:Port-F (mic2-in)
909 * 6:CD
910 * 7:Beep
911 *
912 * ADC selection
913 * 0:Port-A
914 * 1:Port-B (front mic-in)
915 * 2:Port-C (line-in)
916 * 3:Port-F (mic2-in)
917 * 4:Port-E (mic-in)
918 * 5:CD
919 * 6:Port-G
920 * 7:Port-H
921 * 8:Port-D (line-in/2)
922 * 9:Mix
923 *
924 * Proposed pin assignments by the datasheet
925 *
926 * 6-stack
927 * Port-A front headphone
928 * B front mic-in
929 * C rear line-in
930 * D rear front-out
931 * E rear mic-in
932 * F rear surround
933 * G rear CLFE
934 * H rear side
935 *
936 * 3-stack
937 * Port-A front headphone
938 * B front mic
939 * C rear line-in/surround
940 * D rear front-out
941 * E rear mic-in/CLFE
942 *
943 * laptop
944 * Port-A headphone
945 * B mic-in
946 * C docking station
947 * D internal speaker (with EAPD)
948 * E/F quad mic array
949 */
950
951
952/* models */
953enum {
954 AD1988_6STACK,
955 AD1988_6STACK_DIG,
956 AD1988_3STACK,
957 AD1988_3STACK_DIG,
958 AD1988_LAPTOP,
959 AD1988_LAPTOP_DIG,
960 AD1988_MODEL_LAST,
961};
962
963
964/*
965 * mixers
966 */
967
968static hda_nid_t ad1988_dac_nids[4] = {
969 0x04, 0x06, 0x05, 0x0a
970};
971
972static hda_nid_t ad1988_adc_nids[3] = {
973 0x08, 0x09, 0x0f
974};
975
Takashi Iwai2e5b9562005-11-21 16:36:15 +0100976static hda_nid_t ad1988_capsrc_nids[3] = {
977 0x0c, 0x0d, 0x0e
978};
979
Takashi Iwaifd66e0d2005-11-17 15:31:34 +0100980#define AD1988_SPDIF_OUT 0x02
981#define AD1988_SPDIF_IN 0x07
982
983static struct hda_input_mux ad1988_6stack_capture_source = {
984 .num_items = 5,
985 .items = {
986 { "Front Mic", 0x0 },
987 { "Line", 0x1 },
988 { "Mic", 0x4 },
989 { "CD", 0x5 },
990 { "Mix", 0x9 },
991 },
992};
993
994static struct hda_input_mux ad1988_laptop_capture_source = {
995 .num_items = 3,
996 .items = {
997 { "Mic/Line", 0x0 },
998 { "CD", 0x5 },
999 { "Mix", 0x9 },
1000 },
1001};
1002
1003/*
1004 */
1005static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
1006 struct snd_ctl_elem_info *uinfo)
1007{
1008 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1009 struct ad198x_spec *spec = codec->spec;
1010 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
1011 spec->num_channel_mode);
1012}
1013
1014static int ad198x_ch_mode_get(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_get(codec, ucontrol, spec->channel_mode,
1020 spec->num_channel_mode, spec->multiout.max_channels);
1021}
1022
1023static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
1024 struct snd_ctl_elem_value *ucontrol)
1025{
1026 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1027 struct ad198x_spec *spec = codec->spec;
1028 return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
1029 spec->num_channel_mode, &spec->multiout.max_channels);
1030}
1031
1032/*
1033 * EAPD control
1034 */
1035static int ad1988_eapd_info(struct snd_kcontrol *kcontrol,
1036 struct snd_ctl_elem_info *uinfo)
1037{
1038 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1039 uinfo->count = 1;
1040 uinfo->value.integer.min = 0;
1041 uinfo->value.integer.max = 1;
1042 return 0;
1043}
1044
1045static int ad1988_eapd_get(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 ucontrol->value.enumerated.item[0] = ! spec->cur_eapd;
1051 return 0;
1052}
1053
1054static int ad1988_eapd_put(struct snd_kcontrol *kcontrol,
1055 struct snd_ctl_elem_value *ucontrol)
1056{
1057 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1058 struct ad198x_spec *spec = codec->spec;
1059 unsigned int eapd;
1060 eapd = ! ucontrol->value.enumerated.item[0];
1061 if (eapd == spec->cur_eapd && ! codec->in_resume)
1062 return 0;
1063 spec->cur_eapd = eapd;
1064 snd_hda_codec_write(codec, 0x12 /* port-D */,
1065 0, AC_VERB_SET_EAPD_BTLENABLE,
1066 eapd ? 0x02 : 0x00);
1067 return 0;
1068}
1069
1070/* 6-stack mode */
1071static struct snd_kcontrol_new ad1988_6stack_mixers[] = {
1072 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
1073 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1074 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
1075 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
1076 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
1077
1078 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
1079 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
1080 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
1081 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
1082 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
1083 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
1084 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
1085
1086 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
1087 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
1088 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
1089 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
1090 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
1091 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
1092 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
1093 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
1094
1095 HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
1096 HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
1097
Takashi Iwai2e5b9562005-11-21 16:36:15 +01001098 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001099 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
1100
1101 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
1102 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
1103
1104 { } /* end */
1105};
1106
1107/* 3-stack mode */
1108static struct snd_kcontrol_new ad1988_3stack_mixers[] = {
1109 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
1110 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1111 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
1112 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
1113
1114 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
1115 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
1116 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
1117 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
1118 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
1119 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
1120
1121 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
1122 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
1123 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
1124 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
1125 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
1126 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
1127 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
1128 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
1129
1130 HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
1131 HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
1132
Takashi Iwai2e5b9562005-11-21 16:36:15 +01001133 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001134 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
1135
1136 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
1137 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
1138 {
1139 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1140 .name = "Channel Mode",
1141 .info = ad198x_ch_mode_info,
1142 .get = ad198x_ch_mode_get,
1143 .put = ad198x_ch_mode_put,
1144 },
1145
1146 { } /* end */
1147};
1148
1149/* laptop mode */
1150static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
1151 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
1152 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
1153 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
1154
1155 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
1156 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
1157 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
1158 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
1159 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
1160 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
1161
1162 HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
1163 HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
1164
Takashi Iwai2e5b9562005-11-21 16:36:15 +01001165 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001166 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
1167
1168 HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT),
1169
1170 {
1171 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1172 .name = "External Amplifier",
1173 .info = ad1988_eapd_info,
1174 .get = ad1988_eapd_get,
1175 .put = ad1988_eapd_put,
1176 },
1177
1178 { } /* end */
1179};
1180
1181/* capture */
1182static struct snd_kcontrol_new ad1988_capture_mixers[] = {
1183 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
1184 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
1185 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
1186 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
1187 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
1188 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
1189 {
1190 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1191 /* The multiple "Capture Source" controls confuse alsamixer
1192 * So call somewhat different..
1193 * FIXME: the controls appear in the "playback" view!
1194 */
1195 /* .name = "Capture Source", */
1196 .name = "Input Source",
1197 .count = 3,
1198 .info = ad198x_mux_enum_info,
1199 .get = ad198x_mux_enum_get,
1200 .put = ad198x_mux_enum_put,
1201 },
1202 { } /* end */
1203};
1204
1205static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
1206 struct snd_ctl_elem_info *uinfo)
1207{
1208 static char *texts[] = {
1209 "PCM", "ADC1", "ADC2", "ADC3"
1210 };
1211 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1212 uinfo->count = 1;
1213 uinfo->value.enumerated.items = 4;
1214 if (uinfo->value.enumerated.item >= 4)
1215 uinfo->value.enumerated.item = 3;
1216 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1217 return 0;
1218}
1219
1220static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
1221 struct snd_ctl_elem_value *ucontrol)
1222{
1223 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1224 unsigned int sel;
1225
1226 sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0);
1227 if (sel > 0) {
1228 sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0);
1229 if (sel <= 3)
1230 sel++;
1231 else
1232 sel = 0;
1233 }
1234 ucontrol->value.enumerated.item[0] = sel;
1235 return 0;
1236}
1237
1238static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
1239 struct snd_ctl_elem_value *ucontrol)
1240{
1241 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1242 unsigned int sel;
1243 int change;
1244
1245 sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0);
1246 if (! ucontrol->value.enumerated.item[0]) {
1247 change = sel != 0;
1248 if (change)
1249 snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL, 0);
1250 } else {
1251 change = sel == 0;
1252 if (change)
1253 snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL, 1);
1254 sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0) + 1;
1255 change |= sel == ucontrol->value.enumerated.item[0];
1256 if (change)
1257 snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL,
1258 ucontrol->value.enumerated.item[0] - 1);
1259 }
1260 return change;
1261}
1262
1263static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
1264 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1265 {
1266 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1267 .name = "IEC958 Playback Source",
1268 .info = ad1988_spdif_playback_source_info,
1269 .get = ad1988_spdif_playback_source_get,
1270 .put = ad1988_spdif_playback_source_put,
1271 },
1272 { } /* end */
1273};
1274
1275static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
1276 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
1277 { } /* end */
1278};
1279
1280
1281/*
1282 * initialization verbs
1283 */
1284
1285/*
1286 * for 6-stack (+dig)
1287 */
1288static struct hda_verb ad1988_6stack_init_verbs[] = {
Takashi Iwai2e5b9562005-11-21 16:36:15 +01001289 /* Front, Surround, CLFE, side DAC; unmute as default */
1290 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1291 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1292 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1293 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001294 /* Port-A front headphon path */
1295 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
1296 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1297 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1298 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1299 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1300 /* Port-D line-out path */
1301 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1302 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1303 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1304 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1305 /* Port-F surround path */
1306 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1307 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1308 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1309 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1310 /* Port-G CLFE path */
1311 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1312 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1313 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1314 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1315 /* Port-H side path */
1316 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1317 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1318 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1319 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1320 /* Mono out path */
1321 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
1322 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1323 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1324 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1325 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
1326 /* Port-B front mic-in path */
1327 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1328 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1329 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1330 /* Port-C line-in path */
1331 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1332 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1333 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1334 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
1335 /* Port-E mic-in path */
1336 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1337 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1338 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1339 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
1340
1341 { }
1342};
1343
1344static struct hda_verb ad1988_capture_init_verbs[] = {
1345 /* mute analog mix */
1346 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1347 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1348 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1349 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1350 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1351 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
1352 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1353 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
1354 /* select ADCs - front-mic */
1355 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
1356 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
1357 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
1358 /* ADCs; muted */
1359 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1360 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1361 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1362
1363 { }
1364};
1365
1366static struct hda_verb ad1988_spdif_init_verbs[] = {
1367 /* SPDIF out sel */
1368 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
1369 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
1370 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1371 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1372 /* SPDIF out pin */
1373 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
1374 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x17}, /* 0dB */
1375
1376 { }
1377};
1378
1379/*
1380 * verbs for 3stack (+dig)
1381 */
1382static struct hda_verb ad1988_3stack_ch2_init[] = {
1383 /* set port-C to line-in */
1384 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1385 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1386 /* set port-E to mic-in */
1387 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1388 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1389 { } /* end */
1390};
1391
1392static struct hda_verb ad1988_3stack_ch6_init[] = {
1393 /* set port-C to surround out */
1394 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1395 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1396 /* set port-E to CLFE out */
1397 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1398 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1399 { } /* end */
1400};
1401
1402static struct hda_channel_mode ad1988_3stack_modes[2] = {
1403 { 2, ad1988_3stack_ch2_init },
1404 { 6, ad1988_3stack_ch6_init },
1405};
1406
1407static struct hda_verb ad1988_3stack_init_verbs[] = {
Takashi Iwai2e5b9562005-11-21 16:36:15 +01001408 /* Front, Surround, CLFE, side DAC; unmute as default */
1409 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1410 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1411 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1412 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001413 /* Port-A front headphon path */
1414 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
1415 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1416 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1417 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1418 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1419 /* Port-D line-out path */
1420 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1421 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1422 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1423 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1424 /* Mono out path */
1425 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
1426 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1427 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1428 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1429 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
1430 /* Port-B front mic-in path */
1431 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1432 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1433 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1434 /* Port-C line-in/surround path */
1435 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1436 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1437 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1438 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
1439 /* Port-E mic-in/CLFE path */
1440 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1441 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1442 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1443 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
1444 /* mute analog mix */
1445 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1446 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1447 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1448 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1449 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1450 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
1451 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1452 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
1453 /* select ADCs - front-mic */
1454 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
1455 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
1456 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
1457 /* ADCs; muted */
1458 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1459 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1460 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1461 { }
1462};
1463
1464/*
1465 * verbs for laptop mode (+dig)
1466 */
1467static struct hda_verb ad1988_laptop_hp_on[] = {
1468 /* unmute port-A and mute port-D */
1469 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1470 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1471 { } /* end */
1472};
1473static struct hda_verb ad1988_laptop_hp_off[] = {
1474 /* mute port-A and unmute port-D */
1475 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1476 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1477 { } /* end */
1478};
1479
1480#define AD1988_HP_EVENT 0x01
1481
1482static struct hda_verb ad1988_laptop_init_verbs[] = {
Takashi Iwai2e5b9562005-11-21 16:36:15 +01001483 /* Front, Surround, CLFE, side DAC; unmute as default */
1484 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1485 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1486 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1487 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001488 /* Port-A front headphon path */
1489 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
1490 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1491 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1492 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1493 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1494 /* unsolicited event for pin-sense */
1495 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
1496 /* Port-D line-out path + EAPD */
1497 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1498 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1499 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1500 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1501 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
1502 /* Mono out path */
1503 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
1504 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1505 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1506 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1507 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
1508 /* Port-B mic-in path */
1509 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1510 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1511 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1512 /* Port-C docking station - try to output */
1513 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1514 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1515 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1516 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
1517 /* mute analog mix */
1518 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1519 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1520 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1521 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1522 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1523 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
1524 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1525 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
1526 /* select ADCs - mic */
1527 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
1528 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
1529 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
1530 /* ADCs; muted */
1531 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1532 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1533 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1534 { }
1535};
1536
1537static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
1538{
1539 if ((res >> 26) != AD1988_HP_EVENT)
1540 return;
1541 if (snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & (1 << 31))
1542 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
1543 else
1544 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
1545}
1546
1547
1548/*
1549 */
1550
1551static struct hda_board_config ad1988_cfg_tbl[] = {
1552 { .modelname = "6stack", .config = AD1988_6STACK },
1553 { .modelname = "6stack-dig", .config = AD1988_6STACK_DIG },
1554 { .modelname = "3stack", .config = AD1988_3STACK },
1555 { .modelname = "3stack-dig", .config = AD1988_3STACK_DIG },
1556 { .modelname = "laptop", .config = AD1988_LAPTOP },
1557 { .modelname = "laptop-dig", .config = AD1988_LAPTOP_DIG },
1558 {}
1559};
1560
1561static int patch_ad1988(struct hda_codec *codec)
1562{
1563 struct ad198x_spec *spec;
1564 int board_config;
1565
1566 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1567 if (spec == NULL)
1568 return -ENOMEM;
1569
1570 init_MUTEX(&spec->amp_mutex);
1571 codec->spec = spec;
1572
1573 board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl);
1574 if (board_config < 0 || board_config >= AD1988_MODEL_LAST) {
Takashi Iwai2e5b9562005-11-21 16:36:15 +01001575 printk(KERN_INFO "hda_codec: Unknown model for AD1988, using 6stack model...\n");
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001576 board_config = AD1988_6STACK;
1577 }
1578
1579 switch (board_config) {
1580 case AD1988_6STACK:
1581 case AD1988_6STACK_DIG:
1582 spec->multiout.max_channels = 8;
1583 spec->multiout.num_dacs = 4;
1584 spec->multiout.dac_nids = ad1988_dac_nids;
1585 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
1586 spec->adc_nids = ad1988_adc_nids;
Takashi Iwai2e5b9562005-11-21 16:36:15 +01001587 spec->capsrc_nids = ad1988_capsrc_nids;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001588 spec->input_mux = &ad1988_6stack_capture_source;
1589 spec->num_mixers = 1;
1590 spec->mixers[0] = ad1988_6stack_mixers;
1591 spec->num_init_verbs = 1;
1592 spec->init_verbs[0] = ad1988_6stack_init_verbs;
1593 if (board_config == AD1988_6STACK_DIG) {
1594 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
1595 spec->dig_in_nid = AD1988_SPDIF_IN;
1596 }
1597 break;
1598 case AD1988_3STACK:
1599 case AD1988_3STACK_DIG:
1600 spec->multiout.max_channels = 6;
1601 spec->multiout.num_dacs = 3;
1602 spec->multiout.dac_nids = ad1988_dac_nids;
1603 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
1604 spec->adc_nids = ad1988_adc_nids;
Takashi Iwai2e5b9562005-11-21 16:36:15 +01001605 spec->capsrc_nids = ad1988_capsrc_nids;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001606 spec->input_mux = &ad1988_6stack_capture_source;
1607 spec->channel_mode = ad1988_3stack_modes;
1608 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
1609 spec->num_mixers = 1;
1610 spec->mixers[0] = ad1988_3stack_mixers;
1611 spec->num_init_verbs = 1;
1612 spec->init_verbs[0] = ad1988_3stack_init_verbs;
1613 if (board_config == AD1988_3STACK_DIG)
1614 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
1615 break;
1616 case AD1988_LAPTOP:
1617 case AD1988_LAPTOP_DIG:
1618 spec->multiout.max_channels = 2;
1619 spec->multiout.num_dacs = 1;
1620 spec->multiout.dac_nids = ad1988_dac_nids;
1621 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
1622 spec->adc_nids = ad1988_adc_nids;
Takashi Iwai2e5b9562005-11-21 16:36:15 +01001623 spec->capsrc_nids = ad1988_capsrc_nids;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001624 spec->input_mux = &ad1988_laptop_capture_source;
1625 spec->num_mixers = 1;
1626 spec->mixers[0] = ad1988_laptop_mixers;
1627 spec->num_init_verbs = 1;
1628 spec->init_verbs[0] = ad1988_laptop_init_verbs;
1629 if (board_config == AD1988_LAPTOP_DIG)
1630 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
1631 break;
1632 }
1633
1634 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
1635 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
1636 if (spec->multiout.dig_out_nid) {
1637 spec->mixers[spec->num_mixers++] = ad1988_spdif_out_mixers;
1638 spec->init_verbs[spec->num_init_verbs++] = ad1988_spdif_init_verbs;
1639 }
1640 if (spec->dig_in_nid)
1641 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
1642
1643 codec->patch_ops = ad198x_patch_ops;
1644 switch (board_config) {
1645 case AD1988_LAPTOP:
1646 case AD1988_LAPTOP_DIG:
1647 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
1648 break;
1649 }
1650
1651 return 0;
1652}
1653
1654
1655/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 * patch entries
1657 */
1658struct hda_codec_preset snd_hda_preset_analog[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001659 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
1660 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01001662 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 {} /* terminator */
1664};