Linux-2.6.12-rc2
[linux-2.6.git] / sound / pci / hda / patch_cmedia.c
1 /*
2  * Universal Interface for Intel High Definition Audio Codec
3  *
4  * HD audio interface patch for C-Media CMI9880
5  *
6  * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
7  *
8  *
9  *  This driver is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This driver is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22  */
23
24 #include <sound/driver.h>
25 #include <linux/init.h>
26 #include <linux/delay.h>
27 #include <linux/slab.h>
28 #include <linux/pci.h>
29 #include <sound/core.h>
30 #include "hda_codec.h"
31 #include "hda_local.h"
32
33
34 /* board config type */
35 enum {
36         CMI_MINIMAL,    /* back 3-jack */
37         CMI_MIN_FP,     /* back 3-jack + front-panel 2-jack */
38         CMI_FULL,       /* back 6-jack + front-panel 2-jack */
39         CMI_FULL_DIG,   /* back 6-jack + front-panel 2-jack + digital I/O */
40         CMI_ALLOUT,     /* back 5-jack + front-panel 2-jack + digital out */
41 };
42
43 struct cmi_spec {
44         int board_config;
45         unsigned int surr_switch: 1;    /* switchable line,mic */
46         unsigned int no_line_in: 1;     /* no line-in (5-jack) */
47         unsigned int front_panel: 1;    /* has front-panel 2-jack */
48
49         /* playback */
50         struct hda_multi_out multiout;
51
52         /* capture */
53         hda_nid_t *adc_nids;
54         hda_nid_t dig_in_nid;
55
56         /* capture source */
57         const struct hda_input_mux *input_mux;
58         unsigned int cur_mux[2];
59
60         /* channel mode */
61         unsigned int num_ch_modes;
62         unsigned int cur_ch_mode;
63         const struct cmi_channel_mode *channel_modes;
64
65         struct hda_pcm pcm_rec[2];      /* PCM information */
66 };
67
68 /*
69  * input MUX
70  */
71 static int cmi_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
72 {
73         struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
74         struct cmi_spec *spec = codec->spec;
75         return snd_hda_input_mux_info(spec->input_mux, uinfo);
76 }
77
78 static int cmi_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
79 {
80         struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
81         struct cmi_spec *spec = codec->spec;
82         unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
83
84         ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
85         return 0;
86 }
87
88 static int cmi_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
89 {
90         struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
91         struct cmi_spec *spec = codec->spec;
92         unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
93
94         return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
95                                      spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
96 }
97
98 /*
99  * shared line-in, mic for surrounds
100  */
101
102 /* 3-stack / 2 channel */
103 static struct hda_verb cmi9880_ch2_init[] = {
104         /* set line-in PIN for input */
105         { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
106         /* set mic PIN for input, also enable vref */
107         { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
108         /* route front PCM (DAC1) to HP */
109         { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
110         {}
111 };
112
113 /* 3-stack / 6 channel */
114 static struct hda_verb cmi9880_ch6_init[] = {
115         /* set line-in PIN for output */
116         { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
117         /* set mic PIN for output */
118         { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
119         /* route front PCM (DAC1) to HP */
120         { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
121         {}
122 };
123
124 /* 3-stack+front / 8 channel */
125 static struct hda_verb cmi9880_ch8_init[] = {
126         /* set line-in PIN for output */
127         { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
128         /* set mic PIN for output */
129         { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
130         /* route rear-surround PCM (DAC4) to HP */
131         { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 },
132         {}
133 };
134
135 struct cmi_channel_mode {
136         unsigned int channels;
137         const struct hda_verb *sequence;
138 };
139
140 static struct cmi_channel_mode cmi9880_channel_modes[3] = {
141         { 2, cmi9880_ch2_init },
142         { 6, cmi9880_ch6_init },
143         { 8, cmi9880_ch8_init },
144 };
145
146 static int cmi_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
147 {
148         struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
149         struct cmi_spec *spec = codec->spec;
150
151         snd_assert(spec->channel_modes, return -EINVAL);
152         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
153         uinfo->count = 1;
154         uinfo->value.enumerated.items = spec->num_ch_modes;
155         if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
156                 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
157         sprintf(uinfo->value.enumerated.name, "%dch",
158                 spec->channel_modes[uinfo->value.enumerated.item].channels);
159         return 0;
160 }
161
162 static int cmi_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
163 {
164         struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
165         struct cmi_spec *spec = codec->spec;
166
167         ucontrol->value.enumerated.item[0] = spec->cur_ch_mode;
168         return 0;
169 }
170
171 static int cmi_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
172 {
173         struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
174         struct cmi_spec *spec = codec->spec;
175
176         snd_assert(spec->channel_modes, return -EINVAL);
177         if (ucontrol->value.enumerated.item[0] >= spec->num_ch_modes)
178                 ucontrol->value.enumerated.item[0] = spec->num_ch_modes;
179         if (ucontrol->value.enumerated.item[0] == spec->cur_ch_mode &&
180             ! codec->in_resume)
181                 return 0;
182
183         spec->cur_ch_mode = ucontrol->value.enumerated.item[0];
184         snd_hda_sequence_write(codec, spec->channel_modes[spec->cur_ch_mode].sequence);
185         spec->multiout.max_channels = spec->channel_modes[spec->cur_ch_mode].channels;
186         return 1;
187 }
188
189 /*
190  */
191 static snd_kcontrol_new_t cmi9880_basic_mixer[] = {
192         /* CMI9880 has no playback volumes! */
193         HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */
194         HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT),
195         HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
196         HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
197         HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT),
198         {
199                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
200                 /* The multiple "Capture Source" controls confuse alsamixer
201                  * So call somewhat different..
202                  * FIXME: the controls appear in the "playback" view!
203                  */
204                 /* .name = "Capture Source", */
205                 .name = "Input Source",
206                 .count = 2,
207                 .info = cmi_mux_enum_info,
208                 .get = cmi_mux_enum_get,
209                 .put = cmi_mux_enum_put,
210         },
211         HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT),
212         HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT),
213         HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT),
214         HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT),
215         HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x23, 0, HDA_OUTPUT),
216         HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x23, 0, HDA_OUTPUT),
217         { } /* end */
218 };
219
220 /*
221  * shared I/O pins
222  */
223 static snd_kcontrol_new_t cmi9880_ch_mode_mixer[] = {
224         {
225                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
226                 .name = "Channel Mode",
227                 .info = cmi_ch_mode_info,
228                 .get = cmi_ch_mode_get,
229                 .put = cmi_ch_mode_put,
230         },
231         { } /* end */
232 };
233
234 /* AUD-in selections:
235  * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20
236  */
237 static struct hda_input_mux cmi9880_basic_mux = {
238         .num_items = 4,
239         .items = {
240                 { "Front Mic", 0x5 },
241                 { "Rear Mic", 0x2 },
242                 { "Line", 0x1 },
243                 { "CD", 0x7 },
244         }
245 };
246
247 static struct hda_input_mux cmi9880_no_line_mux = {
248         .num_items = 3,
249         .items = {
250                 { "Front Mic", 0x5 },
251                 { "Rear Mic", 0x2 },
252                 { "CD", 0x7 },
253         }
254 };
255
256 /* front, rear, clfe, rear_surr */
257 static hda_nid_t cmi9880_dac_nids[4] = {
258         0x03, 0x04, 0x05, 0x06
259 };
260 /* ADC0, ADC1 */
261 static hda_nid_t cmi9880_adc_nids[2] = {
262         0x08, 0x09
263 };
264
265 #define CMI_DIG_OUT_NID 0x07
266 #define CMI_DIG_IN_NID  0x0a
267
268 /*
269  */
270 static struct hda_verb cmi9880_basic_init[] = {
271         /* port-D for line out (rear panel) */
272         { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
273         /* port-E for HP out (front panel) */
274         { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
275         /* route front PCM to HP */
276         { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
277         /* port-A for surround (rear panel) */
278         { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
279         /* port-G for CLFE (rear panel) */
280         { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
281         /* port-H for side (rear panel) */
282         { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
283         /* port-C for line-in (rear panel) */
284         { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
285         /* port-B for mic-in (rear panel) with vref */
286         { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
287         /* port-F for mic-in (front panel) with vref */
288         { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
289         /* CD-in */
290         { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
291         /* route front mic to ADC1/2 */
292         { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },
293         { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },
294         {} /* terminator */
295 };
296
297 static struct hda_verb cmi9880_allout_init[] = {
298         /* port-D for line out (rear panel) */
299         { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
300         /* port-E for HP out (front panel) */
301         { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
302         /* route front PCM to HP */
303         { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
304         /* port-A for side (rear panel) */
305         { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
306         /* port-G for CLFE (rear panel) */
307         { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
308         /* port-C for surround (rear panel) */
309         { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
310         /* port-B for mic-in (rear panel) with vref */
311         { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
312         /* port-F for mic-in (front panel) with vref */
313         { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
314         /* CD-in */
315         { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
316         /* route front mic to ADC1/2 */
317         { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },
318         { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },
319         {} /* terminator */
320 };
321
322 /*
323  */
324 static int cmi9880_build_controls(struct hda_codec *codec)
325 {
326         struct cmi_spec *spec = codec->spec;
327         int err;
328
329         err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer);
330         if (err < 0)
331                 return err;
332         if (spec->surr_switch) {
333                 err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer);
334                 if (err < 0)
335                         return err;
336         }
337         if (spec->multiout.dig_out_nid) {
338                 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
339                 if (err < 0)
340                         return err;
341         }
342         if (spec->dig_in_nid) {
343                 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
344                 if (err < 0)
345                         return err;
346         }
347         return 0;
348 }
349
350 static int cmi9880_init(struct hda_codec *codec)
351 {
352         struct cmi_spec *spec = codec->spec;
353         if (spec->board_config == CMI_ALLOUT)
354                 snd_hda_sequence_write(codec, cmi9880_allout_init);
355         else
356                 snd_hda_sequence_write(codec, cmi9880_basic_init);
357         return 0;
358 }
359
360 #ifdef CONFIG_PM
361 /*
362  * resume
363  */
364 static int cmi9880_resume(struct hda_codec *codec)
365 {
366         struct cmi_spec *spec = codec->spec;
367
368         cmi9880_init(codec);
369         snd_hda_resume_ctls(codec, cmi9880_basic_mixer);
370         if (spec->surr_switch)
371                 snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer);
372         if (spec->multiout.dig_out_nid)
373                 snd_hda_resume_spdif_out(codec);
374         if (spec->dig_in_nid)
375                 snd_hda_resume_spdif_in(codec);
376
377         return 0;
378 }
379 #endif
380
381 /*
382  * Analog playback callbacks
383  */
384 static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo,
385                                      struct hda_codec *codec,
386                                      snd_pcm_substream_t *substream)
387 {
388         struct cmi_spec *spec = codec->spec;
389         return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
390 }
391
392 static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
393                                         struct hda_codec *codec,
394                                         unsigned int stream_tag,
395                                         unsigned int format,
396                                         snd_pcm_substream_t *substream)
397 {
398         struct cmi_spec *spec = codec->spec;
399         return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
400                                                 format, substream);
401 }
402
403 static int cmi9880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
404                                        struct hda_codec *codec,
405                                        snd_pcm_substream_t *substream)
406 {
407         struct cmi_spec *spec = codec->spec;
408         return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
409 }
410
411 /*
412  * Digital out
413  */
414 static int cmi9880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
415                                          struct hda_codec *codec,
416                                          snd_pcm_substream_t *substream)
417 {
418         struct cmi_spec *spec = codec->spec;
419         return snd_hda_multi_out_dig_open(codec, &spec->multiout);
420 }
421
422 static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
423                                           struct hda_codec *codec,
424                                           snd_pcm_substream_t *substream)
425 {
426         struct cmi_spec *spec = codec->spec;
427         return snd_hda_multi_out_dig_close(codec, &spec->multiout);
428 }
429
430 /*
431  * Analog capture
432  */
433 static int cmi9880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
434                                       struct hda_codec *codec,
435                                       unsigned int stream_tag,
436                                       unsigned int format,
437                                       snd_pcm_substream_t *substream)
438 {
439         struct cmi_spec *spec = codec->spec;
440
441         snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
442                                    stream_tag, 0, format);
443         return 0;
444 }
445
446 static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
447                                       struct hda_codec *codec,
448                                       snd_pcm_substream_t *substream)
449 {
450         struct cmi_spec *spec = codec->spec;
451
452         snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
453         return 0;
454 }
455
456
457 /*
458  */
459 static struct hda_pcm_stream cmi9880_pcm_analog_playback = {
460         .substreams = 1,
461         .channels_min = 2,
462         .channels_max = 8,
463         .nid = 0x03, /* NID to query formats and rates */
464         .ops = {
465                 .open = cmi9880_playback_pcm_open,
466                 .prepare = cmi9880_playback_pcm_prepare,
467                 .cleanup = cmi9880_playback_pcm_cleanup
468         },
469 };
470
471 static struct hda_pcm_stream cmi9880_pcm_analog_capture = {
472         .substreams = 2,
473         .channels_min = 2,
474         .channels_max = 2,
475         .nid = 0x08, /* NID to query formats and rates */
476         .ops = {
477                 .prepare = cmi9880_capture_pcm_prepare,
478                 .cleanup = cmi9880_capture_pcm_cleanup
479         },
480 };
481
482 static struct hda_pcm_stream cmi9880_pcm_digital_playback = {
483         .substreams = 1,
484         .channels_min = 2,
485         .channels_max = 2,
486         /* NID is set in cmi9880_build_pcms */
487         .ops = {
488                 .open = cmi9880_dig_playback_pcm_open,
489                 .close = cmi9880_dig_playback_pcm_close
490         },
491 };
492
493 static struct hda_pcm_stream cmi9880_pcm_digital_capture = {
494         .substreams = 1,
495         .channels_min = 2,
496         .channels_max = 2,
497         /* NID is set in cmi9880_build_pcms */
498 };
499
500 static int cmi9880_build_pcms(struct hda_codec *codec)
501 {
502         struct cmi_spec *spec = codec->spec;
503         struct hda_pcm *info = spec->pcm_rec;
504
505         codec->num_pcms = 1;
506         codec->pcm_info = info;
507
508         info->name = "CMI9880";
509         info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_analog_playback;
510         info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_analog_capture;
511
512         if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
513                 codec->num_pcms++;
514                 info++;
515                 info->name = "CMI9880 Digital";
516                 if (spec->multiout.dig_out_nid) {
517                         info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback;
518                         info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
519                 }
520                 if (spec->dig_in_nid) {
521                         info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_digital_capture;
522                         info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
523                 }
524         }
525
526         return 0;
527 }
528
529 static void cmi9880_free(struct hda_codec *codec)
530 {
531         kfree(codec->spec);
532 }
533
534 /*
535  */
536
537 static struct hda_board_config cmi9880_cfg_tbl[] = {
538         { .modelname = "minimal", .config = CMI_MINIMAL },
539         { .modelname = "min_fp", .config = CMI_MIN_FP },
540         { .modelname = "full", .config = CMI_FULL },
541         { .modelname = "full_dig", .config = CMI_FULL_DIG },
542         { .modelname = "allout", .config = CMI_ALLOUT },
543         {} /* terminator */
544 };
545
546 static struct hda_codec_ops cmi9880_patch_ops = {
547         .build_controls = cmi9880_build_controls,
548         .build_pcms = cmi9880_build_pcms,
549         .init = cmi9880_init,
550         .free = cmi9880_free,
551 #ifdef CONFIG_PM
552         .resume = cmi9880_resume,
553 #endif
554 };
555
556 static int patch_cmi9880(struct hda_codec *codec)
557 {
558         struct cmi_spec *spec;
559
560         spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
561         if (spec == NULL)
562                 return -ENOMEM;
563
564         codec->spec = spec;
565         spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl);
566         if (spec->board_config < 0) {
567                 snd_printd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
568                 spec->board_config = CMI_FULL_DIG; /* try everything */
569         }
570
571         switch (spec->board_config) {
572         case CMI_MINIMAL:
573         case CMI_MIN_FP:
574                 spec->surr_switch = 1;
575                 if (spec->board_config == CMI_MINIMAL)
576                         spec->num_ch_modes = 2;
577                 else {
578                         spec->front_panel = 1;
579                         spec->num_ch_modes = 3;
580                 }
581                 spec->channel_modes = cmi9880_channel_modes;
582                 spec->multiout.max_channels = cmi9880_channel_modes[0].channels;
583                 spec->input_mux = &cmi9880_basic_mux;
584                 break;
585         case CMI_FULL:
586         case CMI_FULL_DIG:
587                 spec->front_panel = 1;
588                 spec->multiout.max_channels = 8;
589                 spec->input_mux = &cmi9880_basic_mux;
590                 if (spec->board_config == CMI_FULL_DIG) {
591                         spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
592                         spec->dig_in_nid = CMI_DIG_IN_NID;
593                 }
594                 break;
595         case CMI_ALLOUT:
596                 spec->front_panel = 1;
597                 spec->multiout.max_channels = 8;
598                 spec->no_line_in = 1;
599                 spec->input_mux = &cmi9880_no_line_mux;
600                 spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
601                 break;
602         }
603
604         spec->multiout.num_dacs = 4;
605         spec->multiout.dac_nids = cmi9880_dac_nids;
606
607         spec->adc_nids = cmi9880_adc_nids;
608
609         codec->patch_ops = cmi9880_patch_ops;
610
611         return 0;
612 }
613
614 /*
615  * patch entries
616  */
617 struct hda_codec_preset snd_hda_preset_cmedia[] = {
618         { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
619         { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
620         {} /* terminator */
621 };