blob: 087cabbcf25c56b06a4b71fa7b84b2626a1a8201 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/init.h>
25#include <linux/delay.h>
26#include <linux/slab.h>
27#include <linux/pci.h>
Paul Gortmakerda155d52011-07-15 12:38:28 -040028#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <sound/core.h>
30#include "hda_codec.h"
31#include "hda_local.h"
Takashi Iwai128bc4b2012-05-07 17:42:31 +020032#include "hda_auto_parser.h"
Takashi Iwaib060fb02012-12-19 17:35:47 +010033#include "hda_jack.h"
34#include "hda_generic.h"
35
Takashi Iwaif953eff2005-04-08 15:05:13 +020036#define NUM_PINS 11
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
38
39/* board config type */
40enum {
41 CMI_MINIMAL, /* back 3-jack */
42 CMI_MIN_FP, /* back 3-jack + front-panel 2-jack */
43 CMI_FULL, /* back 6-jack + front-panel 2-jack */
44 CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */
45 CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */
Takashi Iwaif953eff2005-04-08 15:05:13 +020046 CMI_AUTO, /* let driver guess it */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010047 CMI_MODELS
Linus Torvalds1da177e2005-04-16 15:20:36 -070048};
49
50struct cmi_spec {
Takashi Iwaib060fb02012-12-19 17:35:47 +010051 struct hda_gen_spec gen;
52
53 /* below are only for static models */
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 int board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 unsigned int no_line_in: 1; /* no line-in (5-jack) */
57 unsigned int front_panel: 1; /* has front-panel 2-jack */
58
59 /* playback */
60 struct hda_multi_out multiout;
Takashi Iwai41923e42007-10-22 17:20:10 +020061 hda_nid_t dac_nids[AUTO_CFG_MAX_OUTS]; /* NID for each DAC */
Takashi Iwaie9edcee2005-06-13 14:16:38 +020062 int num_dacs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64 /* capture */
Takashi Iwai779d0652011-05-02 11:34:20 +020065 const hda_nid_t *adc_nids;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 hda_nid_t dig_in_nid;
67
68 /* capture source */
69 const struct hda_input_mux *input_mux;
70 unsigned int cur_mux[2];
71
72 /* channel mode */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +010073 int num_channel_modes;
74 const struct hda_channel_mode *channel_modes;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
76 struct hda_pcm pcm_rec[2]; /* PCM information */
Takashi Iwaif953eff2005-04-08 15:05:13 +020077
André Goddard Rosaaf901ca2009-11-14 13:09:05 -020078 /* pin default configuration */
Takashi Iwaif953eff2005-04-08 15:05:13 +020079 hda_nid_t pin_nid[NUM_PINS];
80 unsigned int def_conf[NUM_PINS];
81 unsigned int pin_def_confs;
82
83 /* multichannel pins */
Takashi Iwaif953eff2005-04-08 15:05:13 +020084 struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */
Linus Torvalds1da177e2005-04-16 15:20:36 -070085};
86
87/*
88 * input MUX
89 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010090static int cmi_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070091{
92 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
93 struct cmi_spec *spec = codec->spec;
94 return snd_hda_input_mux_info(spec->input_mux, uinfo);
95}
96
Takashi Iwaic8b6bf92005-11-17 14:57:47 +010097static int cmi_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
99 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
100 struct cmi_spec *spec = codec->spec;
101 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
102
103 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
104 return 0;
105}
106
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100107static int cmi_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108{
109 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
110 struct cmi_spec *spec = codec->spec;
111 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
112
113 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
114 spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
115}
116
117/*
118 * shared line-in, mic for surrounds
119 */
120
121/* 3-stack / 2 channel */
Takashi Iwai779d0652011-05-02 11:34:20 +0200122static const struct hda_verb cmi9880_ch2_init[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 /* set line-in PIN for input */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200124 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 /* set mic PIN for input, also enable vref */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200126 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 /* route front PCM (DAC1) to HP */
128 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
129 {}
130};
131
132/* 3-stack / 6 channel */
Takashi Iwai779d0652011-05-02 11:34:20 +0200133static const struct hda_verb cmi9880_ch6_init[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 /* set line-in PIN for output */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200135 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 /* set mic PIN for output */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200137 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 /* route front PCM (DAC1) to HP */
139 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
140 {}
141};
142
143/* 3-stack+front / 8 channel */
Takashi Iwai779d0652011-05-02 11:34:20 +0200144static const struct hda_verb cmi9880_ch8_init[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 /* set line-in PIN for output */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200146 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 /* set mic PIN for output */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200148 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 /* route rear-surround PCM (DAC4) to HP */
150 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 },
151 {}
152};
153
Takashi Iwai779d0652011-05-02 11:34:20 +0200154static const struct hda_channel_mode cmi9880_channel_modes[3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 { 2, cmi9880_ch2_init },
156 { 6, cmi9880_ch6_init },
157 { 8, cmi9880_ch8_init },
158};
159
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100160static int cmi_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161{
162 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
163 struct cmi_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100164 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_modes,
165 spec->num_channel_modes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166}
167
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100168static int cmi_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169{
170 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
171 struct cmi_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100172 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_modes,
173 spec->num_channel_modes, spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174}
175
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100176static int cmi_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177{
178 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
179 struct cmi_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100180 return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_modes,
181 spec->num_channel_modes, &spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182}
183
184/*
185 */
Takashi Iwai779d0652011-05-02 11:34:20 +0200186static const struct snd_kcontrol_new cmi9880_basic_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 /* CMI9880 has no playback volumes! */
188 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */
189 HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT),
190 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
191 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
192 HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT),
193 {
194 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
195 /* The multiple "Capture Source" controls confuse alsamixer
196 * So call somewhat different..
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 */
198 /* .name = "Capture Source", */
199 .name = "Input Source",
200 .count = 2,
201 .info = cmi_mux_enum_info,
202 .get = cmi_mux_enum_get,
203 .put = cmi_mux_enum_put,
204 },
205 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT),
206 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT),
207 HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT),
208 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT),
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +0100209 HDA_CODEC_VOLUME("Beep Playback Volume", 0x23, 0, HDA_OUTPUT),
210 HDA_CODEC_MUTE("Beep Playback Switch", 0x23, 0, HDA_OUTPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 { } /* end */
212};
213
214/*
215 * shared I/O pins
216 */
Takashi Iwai779d0652011-05-02 11:34:20 +0200217static const struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 {
219 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
220 .name = "Channel Mode",
221 .info = cmi_ch_mode_info,
222 .get = cmi_ch_mode_get,
223 .put = cmi_ch_mode_put,
224 },
225 { } /* end */
226};
227
228/* AUD-in selections:
229 * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20
230 */
Takashi Iwai779d0652011-05-02 11:34:20 +0200231static const struct hda_input_mux cmi9880_basic_mux = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 .num_items = 4,
233 .items = {
234 { "Front Mic", 0x5 },
235 { "Rear Mic", 0x2 },
236 { "Line", 0x1 },
237 { "CD", 0x7 },
238 }
239};
240
Takashi Iwai779d0652011-05-02 11:34:20 +0200241static const struct hda_input_mux cmi9880_no_line_mux = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 .num_items = 3,
243 .items = {
244 { "Front Mic", 0x5 },
245 { "Rear Mic", 0x2 },
246 { "CD", 0x7 },
247 }
248};
249
250/* front, rear, clfe, rear_surr */
Takashi Iwai779d0652011-05-02 11:34:20 +0200251static const hda_nid_t cmi9880_dac_nids[4] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 0x03, 0x04, 0x05, 0x06
253};
254/* ADC0, ADC1 */
Takashi Iwai779d0652011-05-02 11:34:20 +0200255static const hda_nid_t cmi9880_adc_nids[2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 0x08, 0x09
257};
258
259#define CMI_DIG_OUT_NID 0x07
260#define CMI_DIG_IN_NID 0x0a
261
262/*
263 */
Takashi Iwai779d0652011-05-02 11:34:20 +0200264static const struct hda_verb cmi9880_basic_init[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 /* port-D for line out (rear panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200266 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 /* port-E for HP out (front panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200268 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 /* route front PCM to HP */
270 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
271 /* port-A for surround (rear panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200272 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 /* port-G for CLFE (rear panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200274 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
ChenLi Tiend05b2812005-03-24 20:47:35 +0100275 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 /* port-H for side (rear panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200277 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
ChenLi Tiend05b2812005-03-24 20:47:35 +0100278 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 /* port-C for line-in (rear panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200280 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 /* port-B for mic-in (rear panel) with vref */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200282 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 /* port-F for mic-in (front panel) with vref */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200284 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 /* CD-in */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200286 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 /* route front mic to ADC1/2 */
288 { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },
289 { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },
290 {} /* terminator */
291};
292
Takashi Iwai779d0652011-05-02 11:34:20 +0200293static const struct hda_verb cmi9880_allout_init[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 /* port-D for line out (rear panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200295 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 /* port-E for HP out (front panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200297 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 /* route front PCM to HP */
299 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
300 /* port-A for side (rear panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200301 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 /* port-G for CLFE (rear panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200303 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
ChenLi Tiend05b2812005-03-24 20:47:35 +0100304 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 },
305 /* port-H for side (rear panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200306 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
ChenLi Tiend05b2812005-03-24 20:47:35 +0100307 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 /* port-C for surround (rear panel) */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200309 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 /* port-B for mic-in (rear panel) with vref */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200311 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 /* port-F for mic-in (front panel) with vref */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200313 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 /* CD-in */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200315 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 /* 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 */
324static int cmi9880_build_controls(struct hda_codec *codec)
325{
326 struct cmi_spec *spec = codec->spec;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100327 struct snd_kcontrol *kctl;
328 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer);
331 if (err < 0)
332 return err;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100333 if (spec->channel_modes) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer);
335 if (err < 0)
336 return err;
337 }
338 if (spec->multiout.dig_out_nid) {
Stephen Warren74b654c2011-06-01 11:14:18 -0600339 err = snd_hda_create_spdif_out_ctls(codec,
340 spec->multiout.dig_out_nid,
341 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 if (err < 0)
343 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100344 err = snd_hda_create_spdif_share_sw(codec,
345 &spec->multiout);
346 if (err < 0)
347 return err;
348 spec->multiout.share_spdif = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 }
350 if (spec->dig_in_nid) {
351 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
352 if (err < 0)
353 return err;
354 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100355
356 /* assign Capture Source enums to NID */
357 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
358 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwai21949f02009-12-23 08:31:59 +0100359 err = snd_hda_add_nid(codec, kctl, i, spec->adc_nids[i]);
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100360 if (err < 0)
361 return err;
362 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 return 0;
364}
365
366static int cmi9880_init(struct hda_codec *codec)
367{
368 struct cmi_spec *spec = codec->spec;
369 if (spec->board_config == CMI_ALLOUT)
370 snd_hda_sequence_write(codec, cmi9880_allout_init);
371 else
372 snd_hda_sequence_write(codec, cmi9880_basic_init);
Takashi Iwaif953eff2005-04-08 15:05:13 +0200373 if (spec->board_config == CMI_AUTO)
374 snd_hda_sequence_write(codec, spec->multi_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 return 0;
376}
377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378/*
379 * Analog playback callbacks
380 */
381static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo,
382 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100383 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 struct cmi_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +0100386 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
387 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388}
389
390static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
391 struct hda_codec *codec,
392 unsigned int stream_tag,
393 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100394 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
396 struct cmi_spec *spec = codec->spec;
397 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
398 format, substream);
399}
400
401static int cmi9880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
402 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100403 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
405 struct cmi_spec *spec = codec->spec;
406 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
407}
408
409/*
410 * Digital out
411 */
412static int cmi9880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
413 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100414 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 struct cmi_spec *spec = codec->spec;
417 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
418}
419
420static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
421 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100422 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
424 struct cmi_spec *spec = codec->spec;
425 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
426}
427
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200428static int cmi9880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
429 struct hda_codec *codec,
430 unsigned int stream_tag,
431 unsigned int format,
432 struct snd_pcm_substream *substream)
433{
434 struct cmi_spec *spec = codec->spec;
435 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
436 format, substream);
437}
438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439/*
440 * Analog capture
441 */
442static int cmi9880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
443 struct hda_codec *codec,
444 unsigned int stream_tag,
445 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100446 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
448 struct cmi_spec *spec = codec->spec;
449
450 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
451 stream_tag, 0, format);
452 return 0;
453}
454
455static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
456 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100457 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
459 struct cmi_spec *spec = codec->spec;
460
Takashi Iwai888afa12008-03-18 09:57:50 +0100461 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 return 0;
463}
464
465
466/*
467 */
Takashi Iwai779d0652011-05-02 11:34:20 +0200468static const struct hda_pcm_stream cmi9880_pcm_analog_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 .substreams = 1,
470 .channels_min = 2,
471 .channels_max = 8,
472 .nid = 0x03, /* NID to query formats and rates */
473 .ops = {
474 .open = cmi9880_playback_pcm_open,
475 .prepare = cmi9880_playback_pcm_prepare,
476 .cleanup = cmi9880_playback_pcm_cleanup
477 },
478};
479
Takashi Iwai779d0652011-05-02 11:34:20 +0200480static const struct hda_pcm_stream cmi9880_pcm_analog_capture = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 .substreams = 2,
482 .channels_min = 2,
483 .channels_max = 2,
484 .nid = 0x08, /* NID to query formats and rates */
485 .ops = {
486 .prepare = cmi9880_capture_pcm_prepare,
487 .cleanup = cmi9880_capture_pcm_cleanup
488 },
489};
490
Takashi Iwai779d0652011-05-02 11:34:20 +0200491static const struct hda_pcm_stream cmi9880_pcm_digital_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 .substreams = 1,
493 .channels_min = 2,
494 .channels_max = 2,
495 /* NID is set in cmi9880_build_pcms */
496 .ops = {
497 .open = cmi9880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200498 .close = cmi9880_dig_playback_pcm_close,
499 .prepare = cmi9880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 },
501};
502
Takashi Iwai779d0652011-05-02 11:34:20 +0200503static const struct hda_pcm_stream cmi9880_pcm_digital_capture = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 .substreams = 1,
505 .channels_min = 2,
506 .channels_max = 2,
507 /* NID is set in cmi9880_build_pcms */
508};
509
510static int cmi9880_build_pcms(struct hda_codec *codec)
511{
512 struct cmi_spec *spec = codec->spec;
513 struct hda_pcm *info = spec->pcm_rec;
514
515 codec->num_pcms = 1;
516 codec->pcm_info = info;
517
518 info->name = "CMI9880";
519 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_analog_playback;
520 info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_analog_capture;
521
522 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
523 codec->num_pcms++;
524 info++;
525 info->name = "CMI9880 Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +0100526 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 if (spec->multiout.dig_out_nid) {
528 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback;
529 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
530 }
531 if (spec->dig_in_nid) {
532 info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_digital_capture;
533 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
534 }
535 }
536
537 return 0;
538}
539
540static void cmi9880_free(struct hda_codec *codec)
541{
542 kfree(codec->spec);
543}
544
545/*
546 */
547
Takashi Iwaiea734962011-01-17 11:29:34 +0100548static const char * const cmi9880_models[CMI_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100549 [CMI_MINIMAL] = "minimal",
550 [CMI_MIN_FP] = "min_fp",
551 [CMI_FULL] = "full",
552 [CMI_FULL_DIG] = "full_dig",
553 [CMI_ALLOUT] = "allout",
554 [CMI_AUTO] = "auto",
555};
556
Takashi Iwai779d0652011-05-02 11:34:20 +0200557static const struct snd_pci_quirk cmi9880_cfg_tbl[] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100558 SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG),
Takashi Iwai79d06432008-05-30 16:54:49 +0200559 SND_PCI_QUIRK(0x1854, 0x002b, "LG LS75", CMI_MINIMAL),
Jiang zhe5b030382008-04-14 13:26:53 +0200560 SND_PCI_QUIRK(0x1854, 0x0032, "LG", CMI_FULL_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 {} /* terminator */
562};
563
Takashi Iwai779d0652011-05-02 11:34:20 +0200564static const struct hda_codec_ops cmi9880_patch_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 .build_controls = cmi9880_build_controls,
566 .build_pcms = cmi9880_build_pcms,
567 .init = cmi9880_init,
568 .free = cmi9880_free,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569};
570
Takashi Iwaib060fb02012-12-19 17:35:47 +0100571/*
572 * stuff for auto-parser
573 */
574static const struct hda_codec_ops cmi_auto_patch_ops = {
575 .build_controls = snd_hda_gen_build_controls,
576 .build_pcms = snd_hda_gen_build_pcms,
577 .init = snd_hda_gen_init,
578 .free = snd_hda_gen_free,
Takashi Iwai8a6c21a2013-01-18 07:51:17 +0100579 .unsol_event = snd_hda_jack_unsol_event,
Takashi Iwaib060fb02012-12-19 17:35:47 +0100580};
581
582static int cmi_parse_auto_config(struct hda_codec *codec)
583{
584 struct cmi_spec *spec = codec->spec;
585 struct auto_pin_cfg *cfg = &spec->gen.autocfg;
586 int err;
587
588 snd_hda_gen_spec_init(&spec->gen);
589
590 err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
591 if (err < 0)
592 return err;
593 err = snd_hda_gen_parse_auto_config(codec, cfg);
594 if (err < 0)
595 return err;
596
597 codec->patch_ops = cmi_auto_patch_ops;
598 return 0;
599}
600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601static int patch_cmi9880(struct hda_codec *codec)
602{
603 struct cmi_spec *spec;
604
Takashi Iwaie560d8d2005-09-09 14:21:46 +0200605 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 if (spec == NULL)
607 return -ENOMEM;
608
609 codec->spec = spec;
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100610 spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS,
611 cmi9880_models,
612 cmi9880_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 if (spec->board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +0200614 snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
615 codec->chip_name);
Takashi Iwaif953eff2005-04-08 15:05:13 +0200616 spec->board_config = CMI_AUTO; /* try everything */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
618
Takashi Iwaib060fb02012-12-19 17:35:47 +0100619 if (spec->board_config == CMI_AUTO) {
620 int err = cmi_parse_auto_config(codec);
621 if (err < 0) {
622 snd_hda_gen_free(codec);
623 return err;
624 }
625 return 0;
626 }
627
Takashi Iwaif953eff2005-04-08 15:05:13 +0200628 /* copy default DAC NIDs */
629 memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids));
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200630 spec->num_dacs = 4;
Takashi Iwaif953eff2005-04-08 15:05:13 +0200631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 switch (spec->board_config) {
633 case CMI_MINIMAL:
634 case CMI_MIN_FP:
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100635 spec->channel_modes = cmi9880_channel_modes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 if (spec->board_config == CMI_MINIMAL)
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100637 spec->num_channel_modes = 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 else {
639 spec->front_panel = 1;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100640 spec->num_channel_modes = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 spec->multiout.max_channels = cmi9880_channel_modes[0].channels;
643 spec->input_mux = &cmi9880_basic_mux;
644 break;
645 case CMI_FULL:
646 case CMI_FULL_DIG:
647 spec->front_panel = 1;
648 spec->multiout.max_channels = 8;
649 spec->input_mux = &cmi9880_basic_mux;
650 if (spec->board_config == CMI_FULL_DIG) {
651 spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
652 spec->dig_in_nid = CMI_DIG_IN_NID;
653 }
654 break;
655 case CMI_ALLOUT:
Takashi Iwaib060fb02012-12-19 17:35:47 +0100656 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 spec->front_panel = 1;
658 spec->multiout.max_channels = 8;
659 spec->no_line_in = 1;
660 spec->input_mux = &cmi9880_no_line_mux;
661 spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
662 break;
663 }
664
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200665 spec->multiout.num_dacs = spec->num_dacs;
Takashi Iwaif953eff2005-04-08 15:05:13 +0200666 spec->multiout.dac_nids = spec->dac_nids;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
668 spec->adc_nids = cmi9880_adc_nids;
669
670 codec->patch_ops = cmi9880_patch_ops;
671
672 return 0;
673}
674
675/*
676 * patch entries
677 */
Takashi Iwai779d0652011-05-02 11:34:20 +0200678static const struct hda_codec_preset snd_hda_preset_cmedia[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
680 { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
681 {} /* terminator */
682};
Takashi Iwai1289e9e2008-11-27 15:47:11 +0100683
684MODULE_ALIAS("snd-hda-codec-id:13f69880");
685MODULE_ALIAS("snd-hda-codec-id:434d4980");
686
687MODULE_LICENSE("GPL");
688MODULE_DESCRIPTION("C-Media HD-audio codec");
689
690static struct hda_codec_preset_list cmedia_list = {
691 .preset = snd_hda_preset_cmedia,
692 .owner = THIS_MODULE,
693};
694
695static int __init patch_cmedia_init(void)
696{
697 return snd_hda_add_codec_preset(&cmedia_list);
698}
699
700static void __exit patch_cmedia_exit(void)
701{
702 snd_hda_delete_codec_preset(&cmedia_list);
703}
704
705module_init(patch_cmedia_init)
706module_exit(patch_cmedia_exit)