diff options
author | Matt Porter <mporter@embeddedalley.com> | 2005-11-29 09:00:51 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-01-03 06:29:58 -0500 |
commit | 403d19446bd0cabee70110415d2f3bc466f46448 (patch) | |
tree | d2ddf51bd4a1274e6469272143a052566944d1ae /sound | |
parent | 9056412f21bb6b76ceb98329409a958198b2d591 (diff) |
[ALSA] hda-codec - update sigmatel support and bug fixes
Modules: HDA Codec driver
- Explictly set pin control as input for all input pins
- Fix bug in 922x mixer (no mute on adc0vol)
- Remove broken ch_mode control
- Add support for jack retasking mixer controls to use rear line and
mic as surround outputs
- Add board tables to support autodetect and pin config defaults for
systems with broken bioses
- Add support for several Intel mobos
- Add support for DFI mobo with reference boards attached
(gets rid of compile time switch to use reference boards)
Signed-off-by: Matt Porter <mporter@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 356 |
1 files changed, 200 insertions, 156 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c8c539cb4a8f..78662d3539e2 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * HD audio interface patch for SigmaTel STAC92xx | 4 | * HD audio interface patch for SigmaTel STAC92xx |
5 | * | 5 | * |
6 | * Copyright (c) 2005 Embedded Alley Solutions, Inc. | 6 | * Copyright (c) 2005 Embedded Alley Solutions, Inc. |
7 | * <matt@embeddedalley.com> | 7 | * Matt Porter <mporter@embeddedalley.com> |
8 | * | 8 | * |
9 | * Based on patch_cmedia.c and patch_realtek.c | 9 | * Based on patch_cmedia.c and patch_realtek.c |
10 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | 10 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> |
@@ -34,17 +34,22 @@ | |||
34 | #include "hda_codec.h" | 34 | #include "hda_codec.h" |
35 | #include "hda_local.h" | 35 | #include "hda_local.h" |
36 | 36 | ||
37 | #undef STAC_TEST | ||
38 | |||
39 | #define NUM_CONTROL_ALLOC 32 | 37 | #define NUM_CONTROL_ALLOC 32 |
40 | #define STAC_HP_EVENT 0x37 | 38 | #define STAC_HP_EVENT 0x37 |
41 | #define STAC_UNSOL_ENABLE (AC_USRSP_EN | STAC_HP_EVENT) | 39 | #define STAC_UNSOL_ENABLE (AC_USRSP_EN | STAC_HP_EVENT) |
42 | 40 | ||
41 | #define STAC_REF 0 | ||
42 | #define STAC_D945GTP3 1 | ||
43 | #define STAC_D945GTP5 2 | ||
44 | |||
43 | struct sigmatel_spec { | 45 | struct sigmatel_spec { |
44 | struct snd_kcontrol_new *mixers[4]; | 46 | struct snd_kcontrol_new *mixers[4]; |
45 | unsigned int num_mixers; | 47 | unsigned int num_mixers; |
46 | 48 | ||
49 | int board_config; | ||
47 | unsigned int surr_switch: 1; | 50 | unsigned int surr_switch: 1; |
51 | unsigned int line_switch: 1; | ||
52 | unsigned int mic_switch: 1; | ||
48 | 53 | ||
49 | /* playback */ | 54 | /* playback */ |
50 | struct hda_multi_out multiout; | 55 | struct hda_multi_out multiout; |
@@ -57,12 +62,10 @@ struct sigmatel_spec { | |||
57 | unsigned int num_muxes; | 62 | unsigned int num_muxes; |
58 | hda_nid_t dig_in_nid; | 63 | hda_nid_t dig_in_nid; |
59 | 64 | ||
60 | #ifdef STAC_TEST | ||
61 | /* pin widgets */ | 65 | /* pin widgets */ |
62 | hda_nid_t *pin_nids; | 66 | hda_nid_t *pin_nids; |
63 | unsigned int num_pins; | 67 | unsigned int num_pins; |
64 | unsigned int *pin_configs; | 68 | unsigned int *pin_configs; |
65 | #endif | ||
66 | 69 | ||
67 | /* codec specific stuff */ | 70 | /* codec specific stuff */ |
68 | struct hda_verb *init; | 71 | struct hda_verb *init; |
@@ -72,9 +75,8 @@ struct sigmatel_spec { | |||
72 | struct hda_input_mux *input_mux; | 75 | struct hda_input_mux *input_mux; |
73 | unsigned int cur_mux[2]; | 76 | unsigned int cur_mux[2]; |
74 | 77 | ||
75 | /* channel mode */ | 78 | /* i/o switches */ |
76 | unsigned int num_ch_modes; | 79 | unsigned int io_switch[2]; |
77 | unsigned int cur_ch_mode; | ||
78 | 80 | ||
79 | struct hda_pcm pcm_rec[2]; /* PCM information */ | 81 | struct hda_pcm pcm_rec[2]; /* PCM information */ |
80 | 82 | ||
@@ -105,7 +107,6 @@ static hda_nid_t stac922x_mux_nids[2] = { | |||
105 | 0x12, 0x13, | 107 | 0x12, 0x13, |
106 | }; | 108 | }; |
107 | 109 | ||
108 | #ifdef STAC_TEST | ||
109 | static hda_nid_t stac9200_pin_nids[8] = { | 110 | static hda_nid_t stac9200_pin_nids[8] = { |
110 | 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, | 111 | 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, |
111 | }; | 112 | }; |
@@ -114,7 +115,6 @@ static hda_nid_t stac922x_pin_nids[10] = { | |||
114 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | 115 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, |
115 | 0x0f, 0x10, 0x11, 0x15, 0x1b, | 116 | 0x0f, 0x10, 0x11, 0x15, 0x1b, |
116 | }; | 117 | }; |
117 | #endif | ||
118 | 118 | ||
119 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 119 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
120 | { | 120 | { |
@@ -155,49 +155,6 @@ static struct hda_verb stac922x_core_init[] = { | |||
155 | {} | 155 | {} |
156 | }; | 156 | }; |
157 | 157 | ||
158 | static int stac922x_channel_modes[3] = {2, 6, 8}; | ||
159 | |||
160 | static int stac922x_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
161 | { | ||
162 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
163 | struct sigmatel_spec *spec = codec->spec; | ||
164 | |||
165 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
166 | uinfo->count = 1; | ||
167 | uinfo->value.enumerated.items = spec->num_ch_modes; | ||
168 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
169 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
170 | sprintf(uinfo->value.enumerated.name, "%dch", | ||
171 | stac922x_channel_modes[uinfo->value.enumerated.item]); | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static int stac922x_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
176 | { | ||
177 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
178 | struct sigmatel_spec *spec = codec->spec; | ||
179 | |||
180 | ucontrol->value.enumerated.item[0] = spec->cur_ch_mode; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int stac922x_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
185 | { | ||
186 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
187 | struct sigmatel_spec *spec = codec->spec; | ||
188 | |||
189 | if (ucontrol->value.enumerated.item[0] >= spec->num_ch_modes) | ||
190 | ucontrol->value.enumerated.item[0] = spec->num_ch_modes; | ||
191 | if (ucontrol->value.enumerated.item[0] == spec->cur_ch_mode && | ||
192 | ! codec->in_resume) | ||
193 | return 0; | ||
194 | |||
195 | spec->cur_ch_mode = ucontrol->value.enumerated.item[0]; | ||
196 | spec->multiout.max_channels = stac922x_channel_modes[spec->cur_ch_mode]; | ||
197 | |||
198 | return 1; | ||
199 | } | ||
200 | |||
201 | static struct snd_kcontrol_new stac9200_mixer[] = { | 158 | static struct snd_kcontrol_new stac9200_mixer[] = { |
202 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), | 159 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), |
203 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), | 160 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), |
@@ -226,22 +183,10 @@ static struct snd_kcontrol_new stac922x_mixer[] = { | |||
226 | .put = stac92xx_mux_enum_put, | 183 | .put = stac92xx_mux_enum_put, |
227 | }, | 184 | }, |
228 | HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), | 185 | HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), |
229 | HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), | ||
230 | HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), | 186 | HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), |
231 | { } /* end */ | 187 | { } /* end */ |
232 | }; | 188 | }; |
233 | 189 | ||
234 | static struct snd_kcontrol_new stac922x_ch_mode_mixer[] = { | ||
235 | { | ||
236 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
237 | .name = "Channel Mode", | ||
238 | .info = stac922x_ch_mode_info, | ||
239 | .get = stac922x_ch_mode_get, | ||
240 | .put = stac922x_ch_mode_put, | ||
241 | }, | ||
242 | { } /* end */ | ||
243 | }; | ||
244 | |||
245 | static int stac92xx_build_controls(struct hda_codec *codec) | 190 | static int stac92xx_build_controls(struct hda_codec *codec) |
246 | { | 191 | { |
247 | struct sigmatel_spec *spec = codec->spec; | 192 | struct sigmatel_spec *spec = codec->spec; |
@@ -258,11 +203,6 @@ static int stac92xx_build_controls(struct hda_codec *codec) | |||
258 | return err; | 203 | return err; |
259 | } | 204 | } |
260 | 205 | ||
261 | if (spec->surr_switch) { | ||
262 | err = snd_hda_add_new_ctls(codec, stac922x_ch_mode_mixer); | ||
263 | if (err < 0) | ||
264 | return err; | ||
265 | } | ||
266 | if (spec->multiout.dig_out_nid) { | 206 | if (spec->multiout.dig_out_nid) { |
267 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | 207 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); |
268 | if (err < 0) | 208 | if (err < 0) |
@@ -276,18 +216,67 @@ static int stac92xx_build_controls(struct hda_codec *codec) | |||
276 | return 0; | 216 | return 0; |
277 | } | 217 | } |
278 | 218 | ||
279 | #ifdef STAC_TEST | 219 | static unsigned int ref9200_pin_configs[8] = { |
280 | static unsigned int stac9200_pin_configs[8] = { | ||
281 | 0x01c47010, 0x01447010, 0x0221401f, 0x01114010, | 220 | 0x01c47010, 0x01447010, 0x0221401f, 0x01114010, |
282 | 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, | 221 | 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, |
283 | }; | 222 | }; |
284 | 223 | ||
285 | static unsigned int stac922x_pin_configs[10] = { | 224 | static unsigned int *stac9200_brd_tbl[] = { |
286 | 0x01014010, 0x01014011, 0x01014012, 0x0221401f, | 225 | ref9200_pin_configs, |
287 | 0x01813122, 0x01014014, 0x01441030, 0x01c41030, | 226 | }; |
227 | |||
228 | static struct hda_board_config stac9200_cfg_tbl[] = { | ||
229 | { .modelname = "ref", | ||
230 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
231 | .pci_subdevice = 0x2668, /* DFI LanParty */ | ||
232 | .config = STAC_REF }, | ||
233 | {} /* terminator */ | ||
234 | }; | ||
235 | |||
236 | static unsigned int ref922x_pin_configs[10] = { | ||
237 | 0x01014010, 0x01016011, 0x01012012, 0x0221401f, | ||
238 | 0x01813122, 0x01011014, 0x01441030, 0x01c41030, | ||
288 | 0x40000100, 0x40000100, | 239 | 0x40000100, 0x40000100, |
289 | }; | 240 | }; |
290 | 241 | ||
242 | static unsigned int d945gtp3_pin_configs[10] = { | ||
243 | 0x0221401f, 0x01a19022, 0x01813021, 0x01114010, | ||
244 | 0x40000100, 0x40000100, 0x40000100, 0x40000100, | ||
245 | 0x02a19120, 0x40000100, | ||
246 | }; | ||
247 | |||
248 | static unsigned int d945gtp5_pin_configs[10] = { | ||
249 | 0x0221401f, 0x01111012, 0x01813024, 0x01114010, | ||
250 | 0x01a19021, 0x01116011, 0x01452130, 0x40000100, | ||
251 | 0x02a19320, 0x40000100, | ||
252 | }; | ||
253 | |||
254 | static unsigned int *stac922x_brd_tbl[] = { | ||
255 | ref922x_pin_configs, | ||
256 | d945gtp3_pin_configs, | ||
257 | d945gtp5_pin_configs, | ||
258 | }; | ||
259 | |||
260 | static struct hda_board_config stac922x_cfg_tbl[] = { | ||
261 | { .modelname = "ref", | ||
262 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
263 | .pci_subdevice = 0x2668, /* DFI LanParty */ | ||
264 | .config = STAC_REF }, /* SigmaTel reference board */ | ||
265 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
266 | .pci_subdevice = 0x0101, | ||
267 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ | ||
268 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
269 | .pci_subdevice = 0x0404, | ||
270 | .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */ | ||
271 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
272 | .pci_subdevice = 0x0303, | ||
273 | .config = STAC_D945GTP5 }, /* Intel D945GNT - 5 Stack */ | ||
274 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
275 | .pci_subdevice = 0x0013, | ||
276 | .config = STAC_D945GTP5 }, /* Intel D955XBK - 5 Stack */ | ||
277 | {} /* terminator */ | ||
278 | }; | ||
279 | |||
291 | static void stac92xx_set_config_regs(struct hda_codec *codec) | 280 | static void stac92xx_set_config_regs(struct hda_codec *codec) |
292 | { | 281 | { |
293 | int i; | 282 | int i; |
@@ -310,10 +299,9 @@ static void stac92xx_set_config_regs(struct hda_codec *codec) | |||
310 | pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0, | 299 | pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0, |
311 | AC_VERB_GET_CONFIG_DEFAULT, | 300 | AC_VERB_GET_CONFIG_DEFAULT, |
312 | 0x00); | 301 | 0x00); |
313 | printk("pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], pin_cfg); | 302 | snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], pin_cfg); |
314 | } | 303 | } |
315 | } | 304 | } |
316 | #endif | ||
317 | 305 | ||
318 | /* | 306 | /* |
319 | * Analog playback callbacks | 307 | * Analog playback callbacks |
@@ -326,56 +314,6 @@ static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo, | |||
326 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); | 314 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); |
327 | } | 315 | } |
328 | 316 | ||
329 | /* | ||
330 | * set up the i/o for analog out | ||
331 | * when the digital out is available, copy the front out to digital out, too. | ||
332 | */ | ||
333 | static int stac92xx_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, | ||
334 | unsigned int stream_tag, | ||
335 | unsigned int format, | ||
336 | struct snd_pcm_substream *substream) | ||
337 | { | ||
338 | hda_nid_t *nids = mout->dac_nids; | ||
339 | int chs = substream->runtime->channels; | ||
340 | int i; | ||
341 | |||
342 | down(&codec->spdif_mutex); | ||
343 | if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { | ||
344 | if (chs == 2 && | ||
345 | snd_hda_is_supported_format(codec, mout->dig_out_nid, format) && | ||
346 | ! (codec->spdif_status & IEC958_AES0_NONAUDIO)) { | ||
347 | mout->dig_out_used = HDA_DIG_ANALOG_DUP; | ||
348 | /* setup digital receiver */ | ||
349 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, | ||
350 | stream_tag, 0, format); | ||
351 | } else { | ||
352 | mout->dig_out_used = 0; | ||
353 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0); | ||
354 | } | ||
355 | } | ||
356 | up(&codec->spdif_mutex); | ||
357 | |||
358 | /* front */ | ||
359 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format); | ||
360 | if (mout->hp_nid) | ||
361 | /* headphone out will just decode front left/right (stereo) */ | ||
362 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); | ||
363 | /* surrounds */ | ||
364 | if (mout->max_channels > 2) | ||
365 | for (i = 1; i < mout->num_dacs; i++) { | ||
366 | if ((mout->max_channels == 6) && (i == 3)) | ||
367 | break; | ||
368 | if (chs >= (i + 1) * 2) /* independent out */ | ||
369 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2, | ||
370 | format); | ||
371 | else /* copy front */ | ||
372 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, | ||
373 | format); | ||
374 | } | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | |||
379 | static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 317 | static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo, |
380 | struct hda_codec *codec, | 318 | struct hda_codec *codec, |
381 | unsigned int stream_tag, | 319 | unsigned int stream_tag, |
@@ -383,8 +321,7 @@ static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
383 | struct snd_pcm_substream *substream) | 321 | struct snd_pcm_substream *substream) |
384 | { | 322 | { |
385 | struct sigmatel_spec *spec = codec->spec; | 323 | struct sigmatel_spec *spec = codec->spec; |
386 | return stac92xx_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, | 324 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream); |
387 | format, substream); | ||
388 | } | 325 | } |
389 | 326 | ||
390 | static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | 327 | static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, |
@@ -511,14 +448,70 @@ static int stac92xx_build_pcms(struct hda_codec *codec) | |||
511 | return 0; | 448 | return 0; |
512 | } | 449 | } |
513 | 450 | ||
451 | static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) | ||
452 | |||
453 | { | ||
454 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); | ||
455 | } | ||
456 | |||
457 | static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
458 | { | ||
459 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
460 | uinfo->count = 1; | ||
461 | uinfo->value.integer.min = 0; | ||
462 | uinfo->value.integer.max = 1; | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
467 | { | ||
468 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
469 | struct sigmatel_spec *spec = codec->spec; | ||
470 | int io_idx = kcontrol-> private_value & 0xff; | ||
471 | |||
472 | ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; | ||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
477 | { | ||
478 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
479 | struct sigmatel_spec *spec = codec->spec; | ||
480 | hda_nid_t nid = kcontrol->private_value >> 8; | ||
481 | int io_idx = kcontrol-> private_value & 0xff; | ||
482 | unsigned short val = ucontrol->value.integer.value[0]; | ||
483 | |||
484 | spec->io_switch[io_idx] = val; | ||
485 | |||
486 | if (val) | ||
487 | stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); | ||
488 | else | ||
489 | stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_IN_EN); | ||
490 | |||
491 | return 1; | ||
492 | } | ||
493 | |||
494 | #define STAC_CODEC_IO_SWITCH(xname, xpval) \ | ||
495 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
496 | .name = xname, \ | ||
497 | .index = 0, \ | ||
498 | .info = stac92xx_io_switch_info, \ | ||
499 | .get = stac92xx_io_switch_get, \ | ||
500 | .put = stac92xx_io_switch_put, \ | ||
501 | .private_value = xpval, \ | ||
502 | } | ||
503 | |||
504 | |||
514 | enum { | 505 | enum { |
515 | STAC_CTL_WIDGET_VOL, | 506 | STAC_CTL_WIDGET_VOL, |
516 | STAC_CTL_WIDGET_MUTE, | 507 | STAC_CTL_WIDGET_MUTE, |
508 | STAC_CTL_WIDGET_IO_SWITCH, | ||
517 | }; | 509 | }; |
518 | 510 | ||
519 | static struct snd_kcontrol_new stac92xx_control_templates[] = { | 511 | static struct snd_kcontrol_new stac92xx_control_templates[] = { |
520 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | 512 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), |
521 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | 513 | HDA_CODEC_MUTE(NULL, 0, 0, 0), |
514 | STAC_CODEC_IO_SWITCH(NULL, 0), | ||
522 | }; | 515 | }; |
523 | 516 | ||
524 | /* add dynamic controls */ | 517 | /* add dynamic controls */ |
@@ -550,6 +543,51 @@ static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char | |||
550 | return 0; | 543 | return 0; |
551 | } | 544 | } |
552 | 545 | ||
546 | /* flag inputs as additional dynamic lineouts */ | ||
547 | static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg) | ||
548 | { | ||
549 | struct sigmatel_spec *spec = codec->spec; | ||
550 | |||
551 | switch (cfg->line_outs) { | ||
552 | case 3: | ||
553 | /* add line-in as side */ | ||
554 | if (cfg->input_pins[AUTO_PIN_LINE]) { | ||
555 | cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_LINE]; | ||
556 | spec->line_switch = 1; | ||
557 | cfg->line_outs++; | ||
558 | } | ||
559 | break; | ||
560 | case 2: | ||
561 | /* add line-in as clfe and mic as side */ | ||
562 | if (cfg->input_pins[AUTO_PIN_LINE]) { | ||
563 | cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_LINE]; | ||
564 | spec->line_switch = 1; | ||
565 | cfg->line_outs++; | ||
566 | } | ||
567 | if (cfg->input_pins[AUTO_PIN_MIC]) { | ||
568 | cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_MIC]; | ||
569 | spec->mic_switch = 1; | ||
570 | cfg->line_outs++; | ||
571 | } | ||
572 | break; | ||
573 | case 1: | ||
574 | /* add line-in as surr and mic as clfe */ | ||
575 | if (cfg->input_pins[AUTO_PIN_LINE]) { | ||
576 | cfg->line_out_pins[1] = cfg->input_pins[AUTO_PIN_LINE]; | ||
577 | spec->line_switch = 1; | ||
578 | cfg->line_outs++; | ||
579 | } | ||
580 | if (cfg->input_pins[AUTO_PIN_MIC]) { | ||
581 | cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_MIC]; | ||
582 | spec->mic_switch = 1; | ||
583 | cfg->line_outs++; | ||
584 | } | ||
585 | break; | ||
586 | } | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
553 | /* fill in the dac_nids table from the parsed pin configuration */ | 591 | /* fill in the dac_nids table from the parsed pin configuration */ |
554 | static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) | 592 | static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) |
555 | { | 593 | { |
@@ -578,7 +616,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, const | |||
578 | int i, err; | 616 | int i, err; |
579 | 617 | ||
580 | for (i = 0; i < cfg->line_outs; i++) { | 618 | for (i = 0; i < cfg->line_outs; i++) { |
581 | if (! spec->multiout.dac_nids[i]) | 619 | if (!spec->multiout.dac_nids[i]) |
582 | continue; | 620 | continue; |
583 | 621 | ||
584 | nid = spec->multiout.dac_nids[i]; | 622 | nid = spec->multiout.dac_nids[i]; |
@@ -609,6 +647,14 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, const | |||
609 | } | 647 | } |
610 | } | 648 | } |
611 | 649 | ||
650 | if (spec->line_switch) | ||
651 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0) | ||
652 | return err; | ||
653 | |||
654 | if (spec->mic_switch) | ||
655 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", (cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0) | ||
656 | return err; | ||
657 | |||
612 | return 0; | 658 | return 0; |
613 | } | 659 | } |
614 | 660 | ||
@@ -666,6 +712,9 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const | |||
666 | for (i = 0; i < AUTO_PIN_LAST; i++) { | 712 | for (i = 0; i < AUTO_PIN_LAST; i++) { |
667 | int index = -1; | 713 | int index = -1; |
668 | if (cfg->input_pins[i]) { | 714 | if (cfg->input_pins[i]) { |
715 | /* Enable active pin widget as an input */ | ||
716 | stac92xx_auto_set_pinctl(codec, cfg->input_pins[i], AC_PINCTL_IN_EN); | ||
717 | |||
669 | imux->items[imux->num_items].label = labels[i]; | 718 | imux->items[imux->num_items].label = labels[i]; |
670 | 719 | ||
671 | for (j=0; j<spec->num_muxes; j++) { | 720 | for (j=0; j<spec->num_muxes; j++) { |
@@ -686,12 +735,6 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const | |||
686 | return 0; | 735 | return 0; |
687 | } | 736 | } |
688 | 737 | ||
689 | static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) | ||
690 | |||
691 | { | ||
692 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); | ||
693 | } | ||
694 | |||
695 | static void stac92xx_auto_init_multi_out(struct hda_codec *codec) | 738 | static void stac92xx_auto_init_multi_out(struct hda_codec *codec) |
696 | { | 739 | { |
697 | struct sigmatel_spec *spec = codec->spec; | 740 | struct sigmatel_spec *spec = codec->spec; |
@@ -720,6 +763,8 @@ static int stac922x_parse_auto_config(struct hda_codec *codec) | |||
720 | 763 | ||
721 | if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0) | 764 | if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0) |
722 | return err; | 765 | return err; |
766 | if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) | ||
767 | return err; | ||
723 | if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) | 768 | if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) |
724 | return err; | 769 | return err; |
725 | if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin) | 770 | if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin) |
@@ -731,15 +776,8 @@ static int stac922x_parse_auto_config(struct hda_codec *codec) | |||
731 | return err; | 776 | return err; |
732 | 777 | ||
733 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 778 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
734 | if (spec->multiout.max_channels > 2) { | 779 | if (spec->multiout.max_channels > 2) |
735 | spec->surr_switch = 1; | 780 | spec->surr_switch = 1; |
736 | spec->cur_ch_mode = 1; | ||
737 | spec->num_ch_modes = 2; | ||
738 | if (spec->multiout.max_channels == 8) { | ||
739 | spec->cur_ch_mode++; | ||
740 | spec->num_ch_modes++; | ||
741 | } | ||
742 | } | ||
743 | 781 | ||
744 | if (spec->autocfg.dig_out_pin) { | 782 | if (spec->autocfg.dig_out_pin) { |
745 | spec->multiout.dig_out_nid = 0x08; | 783 | spec->multiout.dig_out_nid = 0x08; |
@@ -901,13 +939,16 @@ static int patch_stac9200(struct hda_codec *codec) | |||
901 | return -ENOMEM; | 939 | return -ENOMEM; |
902 | 940 | ||
903 | codec->spec = spec; | 941 | codec->spec = spec; |
942 | spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl); | ||
943 | if (spec->board_config < 0) | ||
944 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); | ||
945 | else { | ||
946 | spec->num_pins = 8; | ||
947 | spec->pin_nids = stac9200_pin_nids; | ||
948 | spec->pin_configs = stac9200_brd_tbl[spec->board_config]; | ||
949 | stac92xx_set_config_regs(codec); | ||
950 | } | ||
904 | 951 | ||
905 | #ifdef STAC_TEST | ||
906 | spec->pin_nids = stac9200_pin_nids; | ||
907 | spec->num_pins = 8; | ||
908 | spec->pin_configs = stac9200_pin_configs; | ||
909 | stac92xx_set_config_regs(codec); | ||
910 | #endif | ||
911 | spec->multiout.max_channels = 2; | 952 | spec->multiout.max_channels = 2; |
912 | spec->multiout.num_dacs = 1; | 953 | spec->multiout.num_dacs = 1; |
913 | spec->multiout.dac_nids = stac9200_dac_nids; | 954 | spec->multiout.dac_nids = stac9200_dac_nids; |
@@ -939,13 +980,16 @@ static int patch_stac922x(struct hda_codec *codec) | |||
939 | return -ENOMEM; | 980 | return -ENOMEM; |
940 | 981 | ||
941 | codec->spec = spec; | 982 | codec->spec = spec; |
983 | spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl); | ||
984 | if (spec->board_config < 0) | ||
985 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, using BIOS defaults\n"); | ||
986 | else { | ||
987 | spec->num_pins = 10; | ||
988 | spec->pin_nids = stac922x_pin_nids; | ||
989 | spec->pin_configs = stac922x_brd_tbl[spec->board_config]; | ||
990 | stac92xx_set_config_regs(codec); | ||
991 | } | ||
942 | 992 | ||
943 | #ifdef STAC_TEST | ||
944 | spec->num_pins = 10; | ||
945 | spec->pin_nids = stac922x_pin_nids; | ||
946 | spec->pin_configs = stac922x_pin_configs; | ||
947 | stac92xx_set_config_regs(codec); | ||
948 | #endif | ||
949 | spec->adc_nids = stac922x_adc_nids; | 993 | spec->adc_nids = stac922x_adc_nids; |
950 | spec->mux_nids = stac922x_mux_nids; | 994 | spec->mux_nids = stac922x_mux_nids; |
951 | spec->num_muxes = 2; | 995 | spec->num_muxes = 2; |