patch_realtek.c revision a3bcba384c2f2448ad204ea52baa15f1227d0d40
1/* 2 * Universal Interface for Intel High Definition Audio Codec 3 * 4 * HD audio interface patch for ALC 260/880/882 codecs 5 * 6 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw> 7 * PeiSen Hou <pshou@realtek.com.tw> 8 * Takashi Iwai <tiwai@suse.de> 9 * 10 * This driver is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This driver is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 */ 24 25#include <sound/driver.h> 26#include <linux/init.h> 27#include <linux/delay.h> 28#include <linux/slab.h> 29#include <linux/pci.h> 30#include <sound/core.h> 31#include "hda_codec.h" 32#include "hda_local.h" 33 34 35/* ALC880 board config type */ 36enum { 37 ALC880_3ST, 38 ALC880_3ST_DIG, 39 ALC880_5ST, 40 ALC880_5ST_DIG, 41 ALC880_W810, 42 ALC880_Z71V, 43 ALC880_6ST, 44 ALC880_6ST_DIG, 45 ALC880_F1734, 46 ALC880_ASUS, 47 ALC880_ASUS_DIG, 48 ALC880_ASUS_W1V, 49 ALC880_ASUS_DIG2, 50 ALC880_UNIWILL_DIG, 51 ALC880_CLEVO, 52 ALC880_TCL_S700, 53#ifdef CONFIG_SND_DEBUG 54 ALC880_TEST, 55#endif 56 ALC880_AUTO, 57 ALC880_MODEL_LAST /* last tag */ 58}; 59 60/* ALC260 models */ 61enum { 62 ALC260_BASIC, 63 ALC260_HP, 64 ALC260_HP_3013, 65 ALC260_FUJITSU_S702X, 66 ALC260_AUTO, 67 ALC260_MODEL_LAST /* last tag */ 68}; 69 70/* ALC262 models */ 71enum { 72 ALC262_BASIC, 73 ALC262_AUTO, 74 ALC262_MODEL_LAST /* last tag */ 75}; 76 77/* ALC861 models */ 78enum { 79 ALC861_3ST, 80 ALC861_3ST_DIG, 81 ALC861_6ST_DIG, 82 ALC861_AUTO, 83 ALC861_MODEL_LAST, 84}; 85 86/* ALC882 models */ 87enum { 88 ALC882_3ST_DIG, 89 ALC882_6ST_DIG, 90 ALC882_AUTO, 91 ALC882_MODEL_LAST, 92}; 93 94/* for GPIO Poll */ 95#define GPIO_MASK 0x03 96 97struct alc_spec { 98 /* codec parameterization */ 99 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ 100 unsigned int num_mixers; 101 102 const struct hda_verb *init_verbs[5]; /* initialization verbs 103 * don't forget NULL termination! 104 */ 105 unsigned int num_init_verbs; 106 107 char *stream_name_analog; /* analog PCM stream */ 108 struct hda_pcm_stream *stream_analog_playback; 109 struct hda_pcm_stream *stream_analog_capture; 110 111 char *stream_name_digital; /* digital PCM stream */ 112 struct hda_pcm_stream *stream_digital_playback; 113 struct hda_pcm_stream *stream_digital_capture; 114 115 /* playback */ 116 struct hda_multi_out multiout; /* playback set-up 117 * max_channels, dacs must be set 118 * dig_out_nid and hp_nid are optional 119 */ 120 121 /* capture */ 122 unsigned int num_adc_nids; 123 hda_nid_t *adc_nids; 124 hda_nid_t dig_in_nid; /* digital-in NID; optional */ 125 126 /* capture source */ 127 const struct hda_input_mux *input_mux; 128 unsigned int cur_mux[3]; 129 130 /* channel model */ 131 const struct hda_channel_mode *channel_mode; 132 int num_channel_mode; 133 134 /* PCM information */ 135 struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ 136 137 /* dynamic controls, init_verbs and input_mux */ 138 struct auto_pin_cfg autocfg; 139 unsigned int num_kctl_alloc, num_kctl_used; 140 struct snd_kcontrol_new *kctl_alloc; 141 struct hda_input_mux private_imux; 142 hda_nid_t private_dac_nids[5]; 143}; 144 145/* 146 * configuration template - to be copied to the spec instance 147 */ 148struct alc_config_preset { 149 struct snd_kcontrol_new *mixers[5]; /* should be identical size with spec */ 150 const struct hda_verb *init_verbs[5]; 151 unsigned int num_dacs; 152 hda_nid_t *dac_nids; 153 hda_nid_t dig_out_nid; /* optional */ 154 hda_nid_t hp_nid; /* optional */ 155 unsigned int num_adc_nids; 156 hda_nid_t *adc_nids; 157 hda_nid_t dig_in_nid; 158 unsigned int num_channel_mode; 159 const struct hda_channel_mode *channel_mode; 160 const struct hda_input_mux *input_mux; 161}; 162 163 164/* 165 * input MUX handling 166 */ 167static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 168{ 169 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 170 struct alc_spec *spec = codec->spec; 171 return snd_hda_input_mux_info(spec->input_mux, uinfo); 172} 173 174static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 175{ 176 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 177 struct alc_spec *spec = codec->spec; 178 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 179 180 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 181 return 0; 182} 183 184static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 185{ 186 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 187 struct alc_spec *spec = codec->spec; 188 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 189 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 190 spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); 191} 192 193 194/* 195 * channel mode setting 196 */ 197static int alc_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 198{ 199 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 200 struct alc_spec *spec = codec->spec; 201 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, 202 spec->num_channel_mode); 203} 204 205static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 206{ 207 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 208 struct alc_spec *spec = codec->spec; 209 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, 210 spec->num_channel_mode, spec->multiout.max_channels); 211} 212 213static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 214{ 215 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 216 struct alc_spec *spec = codec->spec; 217 return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, 218 spec->num_channel_mode, &spec->multiout.max_channels); 219} 220 221 222/* 223 * Control of pin widget settings via the mixer. Only boolean settings are 224 * supported, so VrefEn can't be controlled using these functions as they 225 * stand. 226 */ 227static int alc_pinctl_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 228{ 229 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 230 uinfo->count = 1; 231 uinfo->value.integer.min = 0; 232 uinfo->value.integer.max = 1; 233 return 0; 234} 235 236static int alc_pinctl_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 237{ 238 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 239 hda_nid_t nid = kcontrol->private_value & 0xffff; 240 long mask = (kcontrol->private_value >> 16) & 0xff; 241 long *valp = ucontrol->value.integer.value; 242 243 *valp = 0; 244 if (snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00) & mask) 245 *valp = 1; 246 return 0; 247} 248 249static int alc_pinctl_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 250{ 251 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 252 hda_nid_t nid = kcontrol->private_value & 0xffff; 253 long mask = (kcontrol->private_value >> 16) & 0xff; 254 long *valp = ucontrol->value.integer.value; 255 unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00); 256 int change = ((pinctl & mask)!=0) != *valp; 257 258 if (change) 259 snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL, 260 *valp?(pinctl|mask):(pinctl&~mask)); 261 return change; 262} 263 264#define ALC_PINCTL_SWITCH(xname, nid, mask) \ 265 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ 266 .info = alc_pinctl_switch_info, \ 267 .get = alc_pinctl_switch_get, \ 268 .put = alc_pinctl_switch_put, \ 269 .private_value = (nid) | (mask<<16) } 270 271 272/* 273 * set up from the preset table 274 */ 275static void setup_preset(struct alc_spec *spec, const struct alc_config_preset *preset) 276{ 277 int i; 278 279 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) 280 spec->mixers[spec->num_mixers++] = preset->mixers[i]; 281 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; i++) 282 spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i]; 283 284 spec->channel_mode = preset->channel_mode; 285 spec->num_channel_mode = preset->num_channel_mode; 286 287 spec->multiout.max_channels = spec->channel_mode[0].channels; 288 289 spec->multiout.num_dacs = preset->num_dacs; 290 spec->multiout.dac_nids = preset->dac_nids; 291 spec->multiout.dig_out_nid = preset->dig_out_nid; 292 spec->multiout.hp_nid = preset->hp_nid; 293 294 spec->input_mux = preset->input_mux; 295 296 spec->num_adc_nids = preset->num_adc_nids; 297 spec->adc_nids = preset->adc_nids; 298 spec->dig_in_nid = preset->dig_in_nid; 299} 300 301/* 302 * ALC880 3-stack model 303 * 304 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) 305 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, F-Mic = 0x1b 306 * HP = 0x19 307 */ 308 309static hda_nid_t alc880_dac_nids[4] = { 310 /* front, rear, clfe, rear_surr */ 311 0x02, 0x05, 0x04, 0x03 312}; 313 314static hda_nid_t alc880_adc_nids[3] = { 315 /* ADC0-2 */ 316 0x07, 0x08, 0x09, 317}; 318 319/* The datasheet says the node 0x07 is connected from inputs, 320 * but it shows zero connection in the real implementation on some devices. 321 * Note: this is a 915GAV bug, fixed on 915GLV 322 */ 323static hda_nid_t alc880_adc_nids_alt[2] = { 324 /* ADC1-2 */ 325 0x08, 0x09, 326}; 327 328#define ALC880_DIGOUT_NID 0x06 329#define ALC880_DIGIN_NID 0x0a 330 331static struct hda_input_mux alc880_capture_source = { 332 .num_items = 4, 333 .items = { 334 { "Mic", 0x0 }, 335 { "Front Mic", 0x3 }, 336 { "Line", 0x2 }, 337 { "CD", 0x4 }, 338 }, 339}; 340 341/* channel source setting (2/6 channel selection for 3-stack) */ 342/* 2ch mode */ 343static struct hda_verb alc880_threestack_ch2_init[] = { 344 /* set line-in to input, mute it */ 345 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, 346 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, 347 /* set mic-in to input vref 80%, mute it */ 348 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, 349 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, 350 { } /* end */ 351}; 352 353/* 6ch mode */ 354static struct hda_verb alc880_threestack_ch6_init[] = { 355 /* set line-in to output, unmute it */ 356 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 357 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, 358 /* set mic-in to output, unmute it */ 359 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 360 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, 361 { } /* end */ 362}; 363 364static struct hda_channel_mode alc880_threestack_modes[2] = { 365 { 2, alc880_threestack_ch2_init }, 366 { 6, alc880_threestack_ch6_init }, 367}; 368 369static struct snd_kcontrol_new alc880_three_stack_mixer[] = { 370 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 371 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 372 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), 373 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), 374 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 375 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 376 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 377 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), 378 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 379 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 380 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 381 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 382 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 383 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 384 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), 385 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), 386 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 387 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 388 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), 389 { 390 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 391 .name = "Channel Mode", 392 .info = alc_ch_mode_info, 393 .get = alc_ch_mode_get, 394 .put = alc_ch_mode_put, 395 }, 396 { } /* end */ 397}; 398 399/* capture mixer elements */ 400static struct snd_kcontrol_new alc880_capture_mixer[] = { 401 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), 402 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), 403 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), 404 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), 405 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), 406 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), 407 { 408 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 409 /* The multiple "Capture Source" controls confuse alsamixer 410 * So call somewhat different.. 411 * FIXME: the controls appear in the "playback" view! 412 */ 413 /* .name = "Capture Source", */ 414 .name = "Input Source", 415 .count = 3, 416 .info = alc_mux_enum_info, 417 .get = alc_mux_enum_get, 418 .put = alc_mux_enum_put, 419 }, 420 { } /* end */ 421}; 422 423/* capture mixer elements (in case NID 0x07 not available) */ 424static struct snd_kcontrol_new alc880_capture_alt_mixer[] = { 425 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 426 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 427 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), 428 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), 429 { 430 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 431 /* The multiple "Capture Source" controls confuse alsamixer 432 * So call somewhat different.. 433 * FIXME: the controls appear in the "playback" view! 434 */ 435 /* .name = "Capture Source", */ 436 .name = "Input Source", 437 .count = 2, 438 .info = alc_mux_enum_info, 439 .get = alc_mux_enum_get, 440 .put = alc_mux_enum_put, 441 }, 442 { } /* end */ 443}; 444 445 446 447/* 448 * ALC880 5-stack model 449 * 450 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), Side = 0x02 (0xd) 451 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 452 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 453 */ 454 455/* additional mixers to alc880_three_stack_mixer */ 456static struct snd_kcontrol_new alc880_five_stack_mixer[] = { 457 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 458 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), 459 { } /* end */ 460}; 461 462/* channel source setting (6/8 channel selection for 5-stack) */ 463/* 6ch mode */ 464static struct hda_verb alc880_fivestack_ch6_init[] = { 465 /* set line-in to input, mute it */ 466 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, 467 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, 468 { } /* end */ 469}; 470 471/* 8ch mode */ 472static struct hda_verb alc880_fivestack_ch8_init[] = { 473 /* set line-in to output, unmute it */ 474 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 475 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, 476 { } /* end */ 477}; 478 479static struct hda_channel_mode alc880_fivestack_modes[2] = { 480 { 6, alc880_fivestack_ch6_init }, 481 { 8, alc880_fivestack_ch8_init }, 482}; 483 484 485/* 486 * ALC880 6-stack model 487 * 488 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), Side = 0x05 (0x0f) 489 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, 490 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b 491 */ 492 493static hda_nid_t alc880_6st_dac_nids[4] = { 494 /* front, rear, clfe, rear_surr */ 495 0x02, 0x03, 0x04, 0x05 496}; 497 498static struct hda_input_mux alc880_6stack_capture_source = { 499 .num_items = 4, 500 .items = { 501 { "Mic", 0x0 }, 502 { "Front Mic", 0x1 }, 503 { "Line", 0x2 }, 504 { "CD", 0x4 }, 505 }, 506}; 507 508/* fixed 8-channels */ 509static struct hda_channel_mode alc880_sixstack_modes[1] = { 510 { 8, NULL }, 511}; 512 513static struct snd_kcontrol_new alc880_six_stack_mixer[] = { 514 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 515 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 516 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 517 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 518 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 519 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 520 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 521 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), 522 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), 523 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), 524 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 525 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 526 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 527 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 528 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 529 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 530 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), 531 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), 532 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 533 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 534 { 535 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 536 .name = "Channel Mode", 537 .info = alc_ch_mode_info, 538 .get = alc_ch_mode_get, 539 .put = alc_ch_mode_put, 540 }, 541 { } /* end */ 542}; 543 544 545/* 546 * ALC880 W810 model 547 * 548 * W810 has rear IO for: 549 * Front (DAC 02) 550 * Surround (DAC 03) 551 * Center/LFE (DAC 04) 552 * Digital out (06) 553 * 554 * The system also has a pair of internal speakers, and a headphone jack. 555 * These are both connected to Line2 on the codec, hence to DAC 02. 556 * 557 * There is a variable resistor to control the speaker or headphone 558 * volume. This is a hardware-only device without a software API. 559 * 560 * Plugging headphones in will disable the internal speakers. This is 561 * implemented in hardware, not via the driver using jack sense. In 562 * a similar fashion, plugging into the rear socket marked "front" will 563 * disable both the speakers and headphones. 564 * 565 * For input, there's a microphone jack, and an "audio in" jack. 566 * These may not do anything useful with this driver yet, because I 567 * haven't setup any initialization verbs for these yet... 568 */ 569 570static hda_nid_t alc880_w810_dac_nids[3] = { 571 /* front, rear/surround, clfe */ 572 0x02, 0x03, 0x04 573}; 574 575/* fixed 6 channels */ 576static struct hda_channel_mode alc880_w810_modes[1] = { 577 { 6, NULL } 578}; 579 580/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ 581static struct snd_kcontrol_new alc880_w810_base_mixer[] = { 582 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 583 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 584 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 585 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 586 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 587 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 588 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 589 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), 590 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), 591 { } /* end */ 592}; 593 594 595/* 596 * Z710V model 597 * 598 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) 599 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), Line = 0x1a 600 */ 601 602static hda_nid_t alc880_z71v_dac_nids[1] = { 603 0x02 604}; 605#define ALC880_Z71V_HP_DAC 0x03 606 607/* fixed 2 channels */ 608static struct hda_channel_mode alc880_2_jack_modes[1] = { 609 { 2, NULL } 610}; 611 612static struct snd_kcontrol_new alc880_z71v_mixer[] = { 613 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 614 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 615 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 616 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), 617 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 618 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 619 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 620 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 621 { } /* end */ 622}; 623 624 625/* FIXME! */ 626/* 627 * ALC880 F1734 model 628 * 629 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) 630 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 631 */ 632 633static hda_nid_t alc880_f1734_dac_nids[1] = { 634 0x03 635}; 636#define ALC880_F1734_HP_DAC 0x02 637 638static struct snd_kcontrol_new alc880_f1734_mixer[] = { 639 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 640 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), 641 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 642 HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), 643 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 644 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 645 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 646 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 647 { } /* end */ 648}; 649 650 651/* FIXME! */ 652/* 653 * ALC880 ASUS model 654 * 655 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) 656 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, 657 * Mic = 0x18, Line = 0x1a 658 */ 659 660#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ 661#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ 662 663static struct snd_kcontrol_new alc880_asus_mixer[] = { 664 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 665 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 666 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 667 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 668 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 669 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 670 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 671 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), 672 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 673 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 674 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 675 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 676 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 677 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 678 { 679 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 680 .name = "Channel Mode", 681 .info = alc_ch_mode_info, 682 .get = alc_ch_mode_get, 683 .put = alc_ch_mode_put, 684 }, 685 { } /* end */ 686}; 687 688/* FIXME! */ 689/* 690 * ALC880 ASUS W1V model 691 * 692 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) 693 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, 694 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b 695 */ 696 697/* additional mixers to alc880_asus_mixer */ 698static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = { 699 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), 700 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), 701 { } /* end */ 702}; 703 704/* additional mixers to alc880_asus_mixer */ 705static struct snd_kcontrol_new alc880_pcbeep_mixer[] = { 706 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 707 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 708 { } /* end */ 709}; 710 711/* TCL S700 */ 712static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { 713 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 714 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), 715 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), 716 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT), 717 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT), 718 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT), 719 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), 720 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 721 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 722 { 723 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 724 /* The multiple "Capture Source" controls confuse alsamixer 725 * So call somewhat different.. 726 * FIXME: the controls appear in the "playback" view! 727 */ 728 /* .name = "Capture Source", */ 729 .name = "Input Source", 730 .count = 1, 731 .info = alc_mux_enum_info, 732 .get = alc_mux_enum_get, 733 .put = alc_mux_enum_put, 734 }, 735 { } /* end */ 736}; 737 738/* 739 * build control elements 740 */ 741static int alc_build_controls(struct hda_codec *codec) 742{ 743 struct alc_spec *spec = codec->spec; 744 int err; 745 int i; 746 747 for (i = 0; i < spec->num_mixers; i++) { 748 err = snd_hda_add_new_ctls(codec, spec->mixers[i]); 749 if (err < 0) 750 return err; 751 } 752 753 if (spec->multiout.dig_out_nid) { 754 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); 755 if (err < 0) 756 return err; 757 } 758 if (spec->dig_in_nid) { 759 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 760 if (err < 0) 761 return err; 762 } 763 return 0; 764} 765 766 767/* 768 * initialize the codec volumes, etc 769 */ 770 771/* 772 * generic initialization of ADC, input mixers and output mixers 773 */ 774static struct hda_verb alc880_volume_init_verbs[] = { 775 /* 776 * Unmute ADC0-2 and set the default input to mic-in 777 */ 778 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 779 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 780 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 781 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 782 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 783 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 784 785 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 786 * mixer widget 787 * Note: PASD motherboards uses the Line In 2 as the input for front panel 788 * mic (mic 2) 789 */ 790 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ 791 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 792 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 793 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 794 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 795 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 796 797 /* 798 * Set up output mixers (0x0c - 0x0f) 799 */ 800 /* set vol=0 to output mixers */ 801 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 802 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 803 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 804 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 805 /* set up input amps for analog loopback */ 806 /* Amp Indices: DAC = 0, mixer = 1 */ 807 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 808 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 809 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 810 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 811 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 812 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 813 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 814 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 815 816 { } 817}; 818 819/* 820 * 3-stack pin configuration: 821 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b 822 */ 823static struct hda_verb alc880_pin_3stack_init_verbs[] = { 824 /* 825 * preset connection lists of input pins 826 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround 827 */ 828 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ 829 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ 830 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ 831 832 /* 833 * Set pin mode and muting 834 */ 835 /* set front pin widgets 0x14 for output */ 836 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 837 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 838 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 839 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 840 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 841 /* Mic2 (as headphone out) for HP output */ 842 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 843 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 844 /* Line In pin widget for input */ 845 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 846 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 847 /* Line2 (as front mic) pin widget for input and vref at 80% */ 848 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 849 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 850 /* CD pin widget for input */ 851 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 852 853 { } 854}; 855 856/* 857 * 5-stack pin configuration: 858 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, 859 * line-in/side = 0x1a, f-mic = 0x1b 860 */ 861static struct hda_verb alc880_pin_5stack_init_verbs[] = { 862 /* 863 * preset connection lists of input pins 864 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround 865 */ 866 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ 867 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ 868 869 /* 870 * Set pin mode and muting 871 */ 872 /* set pin widgets 0x14-0x17 for output */ 873 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 874 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 875 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 876 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 877 /* unmute pins for output (no gain on this amp) */ 878 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 879 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 880 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 881 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 882 883 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 884 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 885 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 886 /* Mic2 (as headphone out) for HP output */ 887 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 888 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 889 /* Line In pin widget for input */ 890 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 891 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 892 /* Line2 (as front mic) pin widget for input and vref at 80% */ 893 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 894 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 895 /* CD pin widget for input */ 896 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 897 898 { } 899}; 900 901/* 902 * W810 pin configuration: 903 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b 904 */ 905static struct hda_verb alc880_pin_w810_init_verbs[] = { 906 /* hphone/speaker input selector: front DAC */ 907 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, 908 909 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 910 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 911 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 912 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 913 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 914 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 915 916 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 917 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 918 919 { } 920}; 921 922/* 923 * Z71V pin configuration: 924 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) 925 */ 926static struct hda_verb alc880_pin_z71v_init_verbs[] = { 927 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 928 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 929 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 930 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 931 932 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 933 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 934 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 935 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 936 937 { } 938}; 939 940/* 941 * 6-stack pin configuration: 942 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, f-mic = 0x19, 943 * line = 0x1a, HP = 0x1b 944 */ 945static struct hda_verb alc880_pin_6stack_init_verbs[] = { 946 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ 947 948 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 949 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 950 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 951 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 952 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 953 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 954 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 955 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 956 957 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 958 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 959 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 960 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 961 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 962 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 963 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 964 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 965 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 966 967 { } 968}; 969 970/* FIXME! */ 971/* 972 * F1734 pin configuration: 973 * HP = 0x14, speaker-out = 0x15, mic = 0x18 974 */ 975static struct hda_verb alc880_pin_f1734_init_verbs[] = { 976 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, 977 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, 978 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, 979 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, 980 981 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 982 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 983 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 984 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 985 986 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 987 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 988 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 989 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 990 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 991 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 992 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 993 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 994 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 995 996 { } 997}; 998 999/* FIXME! */ 1000/* 1001 * ASUS pin configuration: 1002 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a 1003 */ 1004static struct hda_verb alc880_pin_asus_init_verbs[] = { 1005 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, 1006 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, 1007 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, 1008 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, 1009 1010 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 1011 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1012 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1013 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1014 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1015 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1016 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1017 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1018 1019 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1020 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1021 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1022 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1023 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1024 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1025 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1026 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1027 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1028 1029 { } 1030}; 1031 1032/* Enable GPIO mask and set output */ 1033static struct hda_verb alc880_gpio1_init_verbs[] = { 1034 {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, 1035 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, 1036 {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, 1037 1038 { } 1039}; 1040 1041/* Enable GPIO mask and set output */ 1042static struct hda_verb alc880_gpio2_init_verbs[] = { 1043 {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, 1044 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, 1045 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, 1046 1047 { } 1048}; 1049 1050/* Clevo m520g init */ 1051static struct hda_verb alc880_pin_clevo_init_verbs[] = { 1052 /* headphone output */ 1053 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, 1054 /* line-out */ 1055 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1056 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1057 /* Line-in */ 1058 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1059 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1060 /* CD */ 1061 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1062 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1063 /* Mic1 (rear panel) */ 1064 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1065 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1066 /* Mic2 (front panel) */ 1067 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1068 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1069 /* headphone */ 1070 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 1071 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1072 /* change to EAPD mode */ 1073 {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, 1074 {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, 1075 1076 { } 1077}; 1078 1079static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { 1080 /* Headphone output */ 1081 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 1082 /* Front output*/ 1083 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1084 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, 1085 1086 /* Line In pin widget for input */ 1087 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1088 /* CD pin widget for input */ 1089 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1090 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 1091 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1092 1093 /* change to EAPD mode */ 1094 {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, 1095 {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, 1096 1097 { } 1098}; 1099 1100/* 1101 */ 1102 1103static int alc_init(struct hda_codec *codec) 1104{ 1105 struct alc_spec *spec = codec->spec; 1106 unsigned int i; 1107 1108 for (i = 0; i < spec->num_init_verbs; i++) 1109 snd_hda_sequence_write(codec, spec->init_verbs[i]); 1110 return 0; 1111} 1112 1113#ifdef CONFIG_PM 1114/* 1115 * resume 1116 */ 1117static int alc_resume(struct hda_codec *codec) 1118{ 1119 struct alc_spec *spec = codec->spec; 1120 int i; 1121 1122 alc_init(codec); 1123 for (i = 0; i < spec->num_mixers; i++) 1124 snd_hda_resume_ctls(codec, spec->mixers[i]); 1125 if (spec->multiout.dig_out_nid) 1126 snd_hda_resume_spdif_out(codec); 1127 if (spec->dig_in_nid) 1128 snd_hda_resume_spdif_in(codec); 1129 1130 return 0; 1131} 1132#endif 1133 1134/* 1135 * Analog playback callbacks 1136 */ 1137static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo, 1138 struct hda_codec *codec, 1139 struct snd_pcm_substream *substream) 1140{ 1141 struct alc_spec *spec = codec->spec; 1142 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); 1143} 1144 1145static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 1146 struct hda_codec *codec, 1147 unsigned int stream_tag, 1148 unsigned int format, 1149 struct snd_pcm_substream *substream) 1150{ 1151 struct alc_spec *spec = codec->spec; 1152 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, 1153 format, substream); 1154} 1155 1156static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 1157 struct hda_codec *codec, 1158 struct snd_pcm_substream *substream) 1159{ 1160 struct alc_spec *spec = codec->spec; 1161 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 1162} 1163 1164/* 1165 * Digital out 1166 */ 1167static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 1168 struct hda_codec *codec, 1169 struct snd_pcm_substream *substream) 1170{ 1171 struct alc_spec *spec = codec->spec; 1172 return snd_hda_multi_out_dig_open(codec, &spec->multiout); 1173} 1174 1175static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 1176 struct hda_codec *codec, 1177 struct snd_pcm_substream *substream) 1178{ 1179 struct alc_spec *spec = codec->spec; 1180 return snd_hda_multi_out_dig_close(codec, &spec->multiout); 1181} 1182 1183/* 1184 * Analog capture 1185 */ 1186static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 1187 struct hda_codec *codec, 1188 unsigned int stream_tag, 1189 unsigned int format, 1190 struct snd_pcm_substream *substream) 1191{ 1192 struct alc_spec *spec = codec->spec; 1193 1194 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 1195 stream_tag, 0, format); 1196 return 0; 1197} 1198 1199static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 1200 struct hda_codec *codec, 1201 struct snd_pcm_substream *substream) 1202{ 1203 struct alc_spec *spec = codec->spec; 1204 1205 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); 1206 return 0; 1207} 1208 1209 1210/* 1211 */ 1212static struct hda_pcm_stream alc880_pcm_analog_playback = { 1213 .substreams = 1, 1214 .channels_min = 2, 1215 .channels_max = 8, 1216 /* NID is set in alc_build_pcms */ 1217 .ops = { 1218 .open = alc880_playback_pcm_open, 1219 .prepare = alc880_playback_pcm_prepare, 1220 .cleanup = alc880_playback_pcm_cleanup 1221 }, 1222}; 1223 1224static struct hda_pcm_stream alc880_pcm_analog_capture = { 1225 .substreams = 2, 1226 .channels_min = 2, 1227 .channels_max = 2, 1228 /* NID is set in alc_build_pcms */ 1229 .ops = { 1230 .prepare = alc880_capture_pcm_prepare, 1231 .cleanup = alc880_capture_pcm_cleanup 1232 }, 1233}; 1234 1235static struct hda_pcm_stream alc880_pcm_digital_playback = { 1236 .substreams = 1, 1237 .channels_min = 2, 1238 .channels_max = 2, 1239 /* NID is set in alc_build_pcms */ 1240 .ops = { 1241 .open = alc880_dig_playback_pcm_open, 1242 .close = alc880_dig_playback_pcm_close 1243 }, 1244}; 1245 1246static struct hda_pcm_stream alc880_pcm_digital_capture = { 1247 .substreams = 1, 1248 .channels_min = 2, 1249 .channels_max = 2, 1250 /* NID is set in alc_build_pcms */ 1251}; 1252 1253static int alc_build_pcms(struct hda_codec *codec) 1254{ 1255 struct alc_spec *spec = codec->spec; 1256 struct hda_pcm *info = spec->pcm_rec; 1257 int i; 1258 1259 codec->num_pcms = 1; 1260 codec->pcm_info = info; 1261 1262 snd_assert(spec->stream_analog_playback, return -EINVAL); 1263 snd_assert(spec->stream_analog_capture, return -EINVAL); 1264 info->name = spec->stream_name_analog; 1265 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); 1266 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; 1267 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); 1268 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 1269 1270 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; 1271 for (i = 0; i < spec->num_channel_mode; i++) { 1272 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) { 1273 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels; 1274 } 1275 } 1276 1277 if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 1278 codec->num_pcms++; 1279 info++; 1280 info->name = spec->stream_name_digital; 1281 if (spec->multiout.dig_out_nid) { 1282 snd_assert(spec->stream_digital_playback, return -EINVAL); 1283 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback); 1284 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; 1285 } 1286 if (spec->dig_in_nid) { 1287 snd_assert(spec->stream_digital_capture, return -EINVAL); 1288 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture); 1289 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; 1290 } 1291 } 1292 1293 return 0; 1294} 1295 1296static void alc_free(struct hda_codec *codec) 1297{ 1298 struct alc_spec *spec = codec->spec; 1299 unsigned int i; 1300 1301 if (! spec) 1302 return; 1303 1304 if (spec->kctl_alloc) { 1305 for (i = 0; i < spec->num_kctl_used; i++) 1306 kfree(spec->kctl_alloc[i].name); 1307 kfree(spec->kctl_alloc); 1308 } 1309 kfree(spec); 1310} 1311 1312/* 1313 */ 1314static struct hda_codec_ops alc_patch_ops = { 1315 .build_controls = alc_build_controls, 1316 .build_pcms = alc_build_pcms, 1317 .init = alc_init, 1318 .free = alc_free, 1319#ifdef CONFIG_PM 1320 .resume = alc_resume, 1321#endif 1322}; 1323 1324 1325/* 1326 * Test configuration for debugging 1327 * 1328 * Almost all inputs/outputs are enabled. I/O pins can be configured via 1329 * enum controls. 1330 */ 1331#ifdef CONFIG_SND_DEBUG 1332static hda_nid_t alc880_test_dac_nids[4] = { 1333 0x02, 0x03, 0x04, 0x05 1334}; 1335 1336static struct hda_input_mux alc880_test_capture_source = { 1337 .num_items = 5, 1338 .items = { 1339 { "In-1", 0x0 }, 1340 { "In-2", 0x1 }, 1341 { "In-3", 0x2 }, 1342 { "In-4", 0x3 }, 1343 { "CD", 0x4 }, 1344 }, 1345}; 1346 1347static struct hda_channel_mode alc880_test_modes[4] = { 1348 { 2, NULL }, 1349 { 4, NULL }, 1350 { 6, NULL }, 1351 { 8, NULL }, 1352}; 1353 1354static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 1355{ 1356 static char *texts[] = { 1357 "N/A", "Line Out", "HP Out", 1358 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" 1359 }; 1360 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1361 uinfo->count = 1; 1362 uinfo->value.enumerated.items = 8; 1363 if (uinfo->value.enumerated.item >= 8) 1364 uinfo->value.enumerated.item = 7; 1365 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 1366 return 0; 1367} 1368 1369static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1370{ 1371 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1372 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1373 unsigned int pin_ctl, item = 0; 1374 1375 pin_ctl = snd_hda_codec_read(codec, nid, 0, 1376 AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 1377 if (pin_ctl & AC_PINCTL_OUT_EN) { 1378 if (pin_ctl & AC_PINCTL_HP_EN) 1379 item = 2; 1380 else 1381 item = 1; 1382 } else if (pin_ctl & AC_PINCTL_IN_EN) { 1383 switch (pin_ctl & AC_PINCTL_VREFEN) { 1384 case AC_PINCTL_VREF_HIZ: item = 3; break; 1385 case AC_PINCTL_VREF_50: item = 4; break; 1386 case AC_PINCTL_VREF_GRD: item = 5; break; 1387 case AC_PINCTL_VREF_80: item = 6; break; 1388 case AC_PINCTL_VREF_100: item = 7; break; 1389 } 1390 } 1391 ucontrol->value.enumerated.item[0] = item; 1392 return 0; 1393} 1394 1395static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1396{ 1397 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1398 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1399 static unsigned int ctls[] = { 1400 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, 1401 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, 1402 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, 1403 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, 1404 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, 1405 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, 1406 }; 1407 unsigned int old_ctl, new_ctl; 1408 1409 old_ctl = snd_hda_codec_read(codec, nid, 0, 1410 AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 1411 new_ctl = ctls[ucontrol->value.enumerated.item[0]]; 1412 if (old_ctl != new_ctl) { 1413 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); 1414 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 1415 ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000); 1416 return 1; 1417 } 1418 return 0; 1419} 1420 1421static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 1422{ 1423 static char *texts[] = { 1424 "Front", "Surround", "CLFE", "Side" 1425 }; 1426 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1427 uinfo->count = 1; 1428 uinfo->value.enumerated.items = 4; 1429 if (uinfo->value.enumerated.item >= 4) 1430 uinfo->value.enumerated.item = 3; 1431 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 1432 return 0; 1433} 1434 1435static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1436{ 1437 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1438 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1439 unsigned int sel; 1440 1441 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); 1442 ucontrol->value.enumerated.item[0] = sel & 3; 1443 return 0; 1444} 1445 1446static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1447{ 1448 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1449 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1450 unsigned int sel; 1451 1452 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; 1453 if (ucontrol->value.enumerated.item[0] != sel) { 1454 sel = ucontrol->value.enumerated.item[0] & 3; 1455 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); 1456 return 1; 1457 } 1458 return 0; 1459} 1460 1461#define PIN_CTL_TEST(xname,nid) { \ 1462 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 1463 .name = xname, \ 1464 .info = alc_test_pin_ctl_info, \ 1465 .get = alc_test_pin_ctl_get, \ 1466 .put = alc_test_pin_ctl_put, \ 1467 .private_value = nid \ 1468 } 1469 1470#define PIN_SRC_TEST(xname,nid) { \ 1471 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 1472 .name = xname, \ 1473 .info = alc_test_pin_src_info, \ 1474 .get = alc_test_pin_src_get, \ 1475 .put = alc_test_pin_src_put, \ 1476 .private_value = nid \ 1477 } 1478 1479static struct snd_kcontrol_new alc880_test_mixer[] = { 1480 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 1481 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 1482 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), 1483 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), 1484 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 1485 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 1486 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT), 1487 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), 1488 PIN_CTL_TEST("Front Pin Mode", 0x14), 1489 PIN_CTL_TEST("Surround Pin Mode", 0x15), 1490 PIN_CTL_TEST("CLFE Pin Mode", 0x16), 1491 PIN_CTL_TEST("Side Pin Mode", 0x17), 1492 PIN_CTL_TEST("In-1 Pin Mode", 0x18), 1493 PIN_CTL_TEST("In-2 Pin Mode", 0x19), 1494 PIN_CTL_TEST("In-3 Pin Mode", 0x1a), 1495 PIN_CTL_TEST("In-4 Pin Mode", 0x1b), 1496 PIN_SRC_TEST("In-1 Pin Source", 0x18), 1497 PIN_SRC_TEST("In-2 Pin Source", 0x19), 1498 PIN_SRC_TEST("In-3 Pin Source", 0x1a), 1499 PIN_SRC_TEST("In-4 Pin Source", 0x1b), 1500 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), 1501 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), 1502 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), 1503 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), 1504 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), 1505 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), 1506 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), 1507 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), 1508 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), 1509 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), 1510 { 1511 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1512 .name = "Channel Mode", 1513 .info = alc_ch_mode_info, 1514 .get = alc_ch_mode_get, 1515 .put = alc_ch_mode_put, 1516 }, 1517 { } /* end */ 1518}; 1519 1520static struct hda_verb alc880_test_init_verbs[] = { 1521 /* Unmute inputs of 0x0c - 0x0f */ 1522 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1523 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1524 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1525 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1526 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1527 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1528 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1529 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1530 /* Vol output for 0x0c-0x0f */ 1531 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1532 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1533 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1534 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1535 /* Set output pins 0x14-0x17 */ 1536 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1537 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1538 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1539 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1540 /* Unmute output pins 0x14-0x17 */ 1541 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1542 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1543 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1544 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1545 /* Set input pins 0x18-0x1c */ 1546 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1547 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1548 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1549 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1550 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1551 /* Mute input pins 0x18-0x1b */ 1552 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1553 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1554 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1555 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1556 /* ADC set up */ 1557 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1558 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 1559 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1560 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 1561 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1562 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 1563 /* Analog input/passthru */ 1564 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1565 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 1566 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 1567 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 1568 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 1569 { } 1570}; 1571#endif 1572 1573/* 1574 */ 1575 1576static struct hda_board_config alc880_cfg_tbl[] = { 1577 /* Back 3 jack, front 2 jack */ 1578 { .modelname = "3stack", .config = ALC880_3ST }, 1579 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST }, 1580 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST }, 1581 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST }, 1582 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST }, 1583 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST }, 1584 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST }, 1585 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST }, 1586 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST }, 1587 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST }, 1588 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST }, 1589 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST }, 1590 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST }, 1591 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST }, 1592 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST }, 1593 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST }, 1594 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, 1595 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, 1596 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, 1597 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, 1598 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, 1599 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, 1600 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, 1601 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST }, 1602 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST }, 1603 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST }, 1604 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST }, 1605 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST }, 1606 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST }, 1607 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST }, 1608 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST }, 1609 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, 1610 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, 1611 /* TCL S700 */ 1612 { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 }, 1613 1614 /* Back 3 jack, front 2 jack (Internal add Aux-In) */ 1615 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, 1616 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST }, 1617 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST }, 1618 1619 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ 1620 { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, 1621 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, 1622 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG }, 1623 /* Clevo m520G NB */ 1624 { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, .config = ALC880_CLEVO }, 1625 1626 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ 1627 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, 1628 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG }, 1629 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG }, 1630 1631 /* Back 5 jack, front 2 jack */ 1632 { .modelname = "5stack", .config = ALC880_5ST }, 1633 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST }, 1634 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST }, 1635 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST }, 1636 { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST }, 1637 { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST }, 1638 1639 /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ 1640 { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, 1641 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG }, 1642 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG }, 1643 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG }, 1644 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG }, 1645 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG }, 1646 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG }, 1647 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG }, 1648 { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG }, 1649 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG }, 1650 /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */ 1651 { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG }, 1652 /* note subvendor = 0 below */ 1653 /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */ 1654 1655 { .modelname = "w810", .config = ALC880_W810 }, 1656 { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 }, 1657 1658 { .modelname = "z71v", .config = ALC880_Z71V }, 1659 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, 1660 1661 { .modelname = "6stack", .config = ALC880_6ST }, 1662 { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b4, .config = ALC880_6ST }, 1663 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */ 1664 1665 { .modelname = "6stack-digout", .config = ALC880_6ST_DIG }, 1666 { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG }, 1667 { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG }, 1668 { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, 1669 { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, 1670 { .pci_subvendor = 0x1039, .pci_subdevice = 0x1234, .config = ALC880_6ST_DIG }, 1671 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0077, .config = ALC880_6ST_DIG }, 1672 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG }, 1673 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG }, 1674 1675 { .modelname = "asus", .config = ALC880_ASUS }, 1676 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, 1677 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG }, 1678 { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG }, 1679 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, 1680 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG }, 1681 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, 1682 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, 1683 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, 1684 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, 1685 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, 1686 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, 1687 { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 }, 1688 1689 { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, 1690 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, 1691 1692 { .modelname = "F1734", .config = ALC880_F1734 }, 1693 { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, 1694 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 }, 1695 1696#ifdef CONFIG_SND_DEBUG 1697 { .modelname = "test", .config = ALC880_TEST }, 1698#endif 1699 { .modelname = "auto", .config = ALC880_AUTO }, 1700 1701 {} 1702}; 1703 1704/* 1705 * ALC880 codec presets 1706 */ 1707static struct alc_config_preset alc880_presets[] = { 1708 [ALC880_3ST] = { 1709 .mixers = { alc880_three_stack_mixer }, 1710 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, 1711 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1712 .dac_nids = alc880_dac_nids, 1713 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), 1714 .channel_mode = alc880_threestack_modes, 1715 .input_mux = &alc880_capture_source, 1716 }, 1717 [ALC880_3ST_DIG] = { 1718 .mixers = { alc880_three_stack_mixer }, 1719 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, 1720 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1721 .dac_nids = alc880_dac_nids, 1722 .dig_out_nid = ALC880_DIGOUT_NID, 1723 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), 1724 .channel_mode = alc880_threestack_modes, 1725 .input_mux = &alc880_capture_source, 1726 }, 1727 [ALC880_TCL_S700] = { 1728 .mixers = { alc880_tcl_s700_mixer }, 1729 .init_verbs = { alc880_volume_init_verbs, 1730 alc880_pin_tcl_S700_init_verbs, 1731 alc880_gpio2_init_verbs }, 1732 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1733 .dac_nids = alc880_dac_nids, 1734 .hp_nid = 0x03, 1735 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), 1736 .channel_mode = alc880_2_jack_modes, 1737 .input_mux = &alc880_capture_source, 1738 }, 1739 [ALC880_5ST] = { 1740 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer}, 1741 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, 1742 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1743 .dac_nids = alc880_dac_nids, 1744 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), 1745 .channel_mode = alc880_fivestack_modes, 1746 .input_mux = &alc880_capture_source, 1747 }, 1748 [ALC880_5ST_DIG] = { 1749 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer }, 1750 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, 1751 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1752 .dac_nids = alc880_dac_nids, 1753 .dig_out_nid = ALC880_DIGOUT_NID, 1754 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), 1755 .channel_mode = alc880_fivestack_modes, 1756 .input_mux = &alc880_capture_source, 1757 }, 1758 [ALC880_6ST] = { 1759 .mixers = { alc880_six_stack_mixer }, 1760 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs }, 1761 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), 1762 .dac_nids = alc880_6st_dac_nids, 1763 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), 1764 .channel_mode = alc880_sixstack_modes, 1765 .input_mux = &alc880_6stack_capture_source, 1766 }, 1767 [ALC880_6ST_DIG] = { 1768 .mixers = { alc880_six_stack_mixer }, 1769 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs }, 1770 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), 1771 .dac_nids = alc880_6st_dac_nids, 1772 .dig_out_nid = ALC880_DIGOUT_NID, 1773 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), 1774 .channel_mode = alc880_sixstack_modes, 1775 .input_mux = &alc880_6stack_capture_source, 1776 }, 1777 [ALC880_W810] = { 1778 .mixers = { alc880_w810_base_mixer }, 1779 .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs, 1780 alc880_gpio2_init_verbs }, 1781 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), 1782 .dac_nids = alc880_w810_dac_nids, 1783 .dig_out_nid = ALC880_DIGOUT_NID, 1784 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), 1785 .channel_mode = alc880_w810_modes, 1786 .input_mux = &alc880_capture_source, 1787 }, 1788 [ALC880_Z71V] = { 1789 .mixers = { alc880_z71v_mixer }, 1790 .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs }, 1791 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), 1792 .dac_nids = alc880_z71v_dac_nids, 1793 .dig_out_nid = ALC880_DIGOUT_NID, 1794 .hp_nid = 0x03, 1795 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), 1796 .channel_mode = alc880_2_jack_modes, 1797 .input_mux = &alc880_capture_source, 1798 }, 1799 [ALC880_F1734] = { 1800 .mixers = { alc880_f1734_mixer }, 1801 .init_verbs = { alc880_volume_init_verbs, alc880_pin_f1734_init_verbs }, 1802 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), 1803 .dac_nids = alc880_f1734_dac_nids, 1804 .hp_nid = 0x02, 1805 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), 1806 .channel_mode = alc880_2_jack_modes, 1807 .input_mux = &alc880_capture_source, 1808 }, 1809 [ALC880_ASUS] = { 1810 .mixers = { alc880_asus_mixer }, 1811 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, 1812 alc880_gpio1_init_verbs }, 1813 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 1814 .dac_nids = alc880_asus_dac_nids, 1815 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1816 .channel_mode = alc880_asus_modes, 1817 .input_mux = &alc880_capture_source, 1818 }, 1819 [ALC880_ASUS_DIG] = { 1820 .mixers = { alc880_asus_mixer }, 1821 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, 1822 alc880_gpio1_init_verbs }, 1823 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 1824 .dac_nids = alc880_asus_dac_nids, 1825 .dig_out_nid = ALC880_DIGOUT_NID, 1826 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1827 .channel_mode = alc880_asus_modes, 1828 .input_mux = &alc880_capture_source, 1829 }, 1830 [ALC880_ASUS_DIG2] = { 1831 .mixers = { alc880_asus_mixer }, 1832 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, 1833 alc880_gpio2_init_verbs }, /* use GPIO2 */ 1834 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 1835 .dac_nids = alc880_asus_dac_nids, 1836 .dig_out_nid = ALC880_DIGOUT_NID, 1837 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1838 .channel_mode = alc880_asus_modes, 1839 .input_mux = &alc880_capture_source, 1840 }, 1841 [ALC880_ASUS_W1V] = { 1842 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, 1843 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, 1844 alc880_gpio1_init_verbs }, 1845 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 1846 .dac_nids = alc880_asus_dac_nids, 1847 .dig_out_nid = ALC880_DIGOUT_NID, 1848 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1849 .channel_mode = alc880_asus_modes, 1850 .input_mux = &alc880_capture_source, 1851 }, 1852 [ALC880_UNIWILL_DIG] = { 1853 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer }, 1854 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs }, 1855 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 1856 .dac_nids = alc880_asus_dac_nids, 1857 .dig_out_nid = ALC880_DIGOUT_NID, 1858 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1859 .channel_mode = alc880_asus_modes, 1860 .input_mux = &alc880_capture_source, 1861 }, 1862 [ALC880_CLEVO] = { 1863 .mixers = { alc880_three_stack_mixer }, 1864 .init_verbs = { alc880_volume_init_verbs, 1865 alc880_pin_clevo_init_verbs }, 1866 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1867 .dac_nids = alc880_dac_nids, 1868 .hp_nid = 0x03, 1869 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), 1870 .channel_mode = alc880_threestack_modes, 1871 .input_mux = &alc880_capture_source, 1872 }, 1873#ifdef CONFIG_SND_DEBUG 1874 [ALC880_TEST] = { 1875 .mixers = { alc880_test_mixer }, 1876 .init_verbs = { alc880_test_init_verbs }, 1877 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), 1878 .dac_nids = alc880_test_dac_nids, 1879 .dig_out_nid = ALC880_DIGOUT_NID, 1880 .num_channel_mode = ARRAY_SIZE(alc880_test_modes), 1881 .channel_mode = alc880_test_modes, 1882 .input_mux = &alc880_test_capture_source, 1883 }, 1884#endif 1885}; 1886 1887/* 1888 * Automatic parse of I/O pins from the BIOS configuration 1889 */ 1890 1891#define NUM_CONTROL_ALLOC 32 1892#define NUM_VERB_ALLOC 32 1893 1894enum { 1895 ALC_CTL_WIDGET_VOL, 1896 ALC_CTL_WIDGET_MUTE, 1897 ALC_CTL_BIND_MUTE, 1898}; 1899static struct snd_kcontrol_new alc880_control_templates[] = { 1900 HDA_CODEC_VOLUME(NULL, 0, 0, 0), 1901 HDA_CODEC_MUTE(NULL, 0, 0, 0), 1902 HDA_BIND_MUTE(NULL, 0, 0, 0), 1903}; 1904 1905/* add dynamic controls */ 1906static int add_control(struct alc_spec *spec, int type, const char *name, unsigned long val) 1907{ 1908 struct snd_kcontrol_new *knew; 1909 1910 if (spec->num_kctl_used >= spec->num_kctl_alloc) { 1911 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; 1912 1913 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ 1914 if (! knew) 1915 return -ENOMEM; 1916 if (spec->kctl_alloc) { 1917 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); 1918 kfree(spec->kctl_alloc); 1919 } 1920 spec->kctl_alloc = knew; 1921 spec->num_kctl_alloc = num; 1922 } 1923 1924 knew = &spec->kctl_alloc[spec->num_kctl_used]; 1925 *knew = alc880_control_templates[type]; 1926 knew->name = kstrdup(name, GFP_KERNEL); 1927 if (! knew->name) 1928 return -ENOMEM; 1929 knew->private_value = val; 1930 spec->num_kctl_used++; 1931 return 0; 1932} 1933 1934#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) 1935#define alc880_fixed_pin_idx(nid) ((nid) - 0x14) 1936#define alc880_is_multi_pin(nid) ((nid) >= 0x18) 1937#define alc880_multi_pin_idx(nid) ((nid) - 0x18) 1938#define alc880_is_input_pin(nid) ((nid) >= 0x18) 1939#define alc880_input_pin_idx(nid) ((nid) - 0x18) 1940#define alc880_idx_to_dac(nid) ((nid) + 0x02) 1941#define alc880_dac_to_idx(nid) ((nid) - 0x02) 1942#define alc880_idx_to_mixer(nid) ((nid) + 0x0c) 1943#define alc880_idx_to_selector(nid) ((nid) + 0x10) 1944#define ALC880_PIN_CD_NID 0x1c 1945 1946/* fill in the dac_nids table from the parsed pin configuration */ 1947static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 1948{ 1949 hda_nid_t nid; 1950 int assigned[4]; 1951 int i, j; 1952 1953 memset(assigned, 0, sizeof(assigned)); 1954 spec->multiout.dac_nids = spec->private_dac_nids; 1955 1956 /* check the pins hardwired to audio widget */ 1957 for (i = 0; i < cfg->line_outs; i++) { 1958 nid = cfg->line_out_pins[i]; 1959 if (alc880_is_fixed_pin(nid)) { 1960 int idx = alc880_fixed_pin_idx(nid); 1961 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx); 1962 assigned[idx] = 1; 1963 } 1964 } 1965 /* left pins can be connect to any audio widget */ 1966 for (i = 0; i < cfg->line_outs; i++) { 1967 nid = cfg->line_out_pins[i]; 1968 if (alc880_is_fixed_pin(nid)) 1969 continue; 1970 /* search for an empty channel */ 1971 for (j = 0; j < cfg->line_outs; j++) { 1972 if (! assigned[j]) { 1973 spec->multiout.dac_nids[i] = alc880_idx_to_dac(j); 1974 assigned[j] = 1; 1975 break; 1976 } 1977 } 1978 } 1979 spec->multiout.num_dacs = cfg->line_outs; 1980 return 0; 1981} 1982 1983/* add playback controls from the parsed DAC table */ 1984static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, 1985 const struct auto_pin_cfg *cfg) 1986{ 1987 char name[32]; 1988 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; 1989 hda_nid_t nid; 1990 int i, err; 1991 1992 for (i = 0; i < cfg->line_outs; i++) { 1993 if (! spec->multiout.dac_nids[i]) 1994 continue; 1995 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); 1996 if (i == 2) { 1997 /* Center/LFE */ 1998 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Center Playback Volume", 1999 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) 2000 return err; 2001 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "LFE Playback Volume", 2002 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) 2003 return err; 2004 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch", 2005 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT))) < 0) 2006 return err; 2007 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch", 2008 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT))) < 0) 2009 return err; 2010 } else { 2011 sprintf(name, "%s Playback Volume", chname[i]); 2012 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, 2013 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 2014 return err; 2015 sprintf(name, "%s Playback Switch", chname[i]); 2016 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, 2017 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) 2018 return err; 2019 } 2020 } 2021 return 0; 2022} 2023 2024/* add playback controls for speaker and HP outputs */ 2025static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, 2026 const char *pfx) 2027{ 2028 hda_nid_t nid; 2029 int err; 2030 char name[32]; 2031 2032 if (! pin) 2033 return 0; 2034 2035 if (alc880_is_fixed_pin(pin)) { 2036 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); 2037 if (! spec->multiout.dac_nids[0]) { 2038 /* use this as the primary output */ 2039 spec->multiout.dac_nids[0] = nid; 2040 if (! spec->multiout.num_dacs) 2041 spec->multiout.num_dacs = 1; 2042 } else 2043 /* specify the DAC as the extra output */ 2044 spec->multiout.hp_nid = nid; 2045 /* control HP volume/switch on the output mixer amp */ 2046 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); 2047 sprintf(name, "%s Playback Volume", pfx); 2048 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, 2049 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 2050 return err; 2051 sprintf(name, "%s Playback Switch", pfx); 2052 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, 2053 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) 2054 return err; 2055 } else if (alc880_is_multi_pin(pin)) { 2056 /* set manual connection */ 2057 if (! spec->multiout.dac_nids[0]) { 2058 /* use this as the primary output */ 2059 spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin)); 2060 if (! spec->multiout.num_dacs) 2061 spec->multiout.num_dacs = 1; 2062 } 2063 /* we have only a switch on HP-out PIN */ 2064 sprintf(name, "%s Playback Switch", pfx); 2065 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, 2066 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT))) < 0) 2067 return err; 2068 } 2069 return 0; 2070} 2071 2072/* create input playback/capture controls for the given pin */ 2073static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname, 2074 int idx, hda_nid_t mix_nid) 2075{ 2076 char name[32]; 2077 int err; 2078 2079 sprintf(name, "%s Playback Volume", ctlname); 2080 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, 2081 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT))) < 0) 2082 return err; 2083 sprintf(name, "%s Playback Switch", ctlname); 2084 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, 2085 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT))) < 0) 2086 return err; 2087 return 0; 2088} 2089 2090/* create playback/capture controls for input pins */ 2091static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, 2092 const struct auto_pin_cfg *cfg) 2093{ 2094 static char *labels[AUTO_PIN_LAST] = { 2095 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" 2096 }; 2097 struct hda_input_mux *imux = &spec->private_imux; 2098 int i, err, idx; 2099 2100 for (i = 0; i < AUTO_PIN_LAST; i++) { 2101 if (alc880_is_input_pin(cfg->input_pins[i])) { 2102 idx = alc880_input_pin_idx(cfg->input_pins[i]); 2103 err = new_analog_input(spec, cfg->input_pins[i], labels[i], 2104 idx, 0x0b); 2105 if (err < 0) 2106 return err; 2107 imux->items[imux->num_items].label = labels[i]; 2108 imux->items[imux->num_items].index = alc880_input_pin_idx(cfg->input_pins[i]); 2109 imux->num_items++; 2110 } 2111 } 2112 return 0; 2113} 2114 2115static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, 2116 hda_nid_t nid, int pin_type, 2117 int dac_idx) 2118{ 2119 /* set as output */ 2120 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); 2121 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 2122 /* need the manual connection? */ 2123 if (alc880_is_multi_pin(nid)) { 2124 struct alc_spec *spec = codec->spec; 2125 int idx = alc880_multi_pin_idx(nid); 2126 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, 2127 AC_VERB_SET_CONNECT_SEL, 2128 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); 2129 } 2130} 2131 2132static void alc880_auto_init_multi_out(struct hda_codec *codec) 2133{ 2134 struct alc_spec *spec = codec->spec; 2135 int i; 2136 2137 for (i = 0; i < spec->autocfg.line_outs; i++) { 2138 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 2139 alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); 2140 } 2141} 2142 2143static void alc880_auto_init_extra_out(struct hda_codec *codec) 2144{ 2145 struct alc_spec *spec = codec->spec; 2146 hda_nid_t pin; 2147 2148 pin = spec->autocfg.speaker_pin; 2149 if (pin) /* connect to front */ 2150 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); 2151 pin = spec->autocfg.hp_pin; 2152 if (pin) /* connect to front */ 2153 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); 2154} 2155 2156static void alc880_auto_init_analog_input(struct hda_codec *codec) 2157{ 2158 struct alc_spec *spec = codec->spec; 2159 int i; 2160 2161 for (i = 0; i < AUTO_PIN_LAST; i++) { 2162 hda_nid_t nid = spec->autocfg.input_pins[i]; 2163 if (alc880_is_input_pin(nid)) { 2164 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 2165 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); 2166 if (nid != ALC880_PIN_CD_NID) 2167 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 2168 AMP_OUT_MUTE); 2169 } 2170 } 2171} 2172 2173/* parse the BIOS configuration and set up the alc_spec */ 2174/* return 1 if successful, 0 if the proper config is not found, or a negative error code */ 2175static int alc880_parse_auto_config(struct hda_codec *codec) 2176{ 2177 struct alc_spec *spec = codec->spec; 2178 int err; 2179 static hda_nid_t alc880_ignore[] = { 0x1d, 0 }; 2180 2181 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, 2182 alc880_ignore)) < 0) 2183 return err; 2184 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && 2185 ! spec->autocfg.hp_pin) 2186 return 0; /* can't find valid BIOS pin config */ 2187 2188 if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || 2189 (err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || 2190 (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin, 2191 "Speaker")) < 0 || 2192 (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin, 2193 "Headphone")) < 0 || 2194 (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) 2195 return err; 2196 2197 spec->multiout.max_channels = spec->multiout.num_dacs * 2; 2198 2199 if (spec->autocfg.dig_out_pin) 2200 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; 2201 if (spec->autocfg.dig_in_pin) 2202 spec->dig_in_nid = ALC880_DIGIN_NID; 2203 2204 if (spec->kctl_alloc) 2205 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 2206 2207 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; 2208 2209 spec->input_mux = &spec->private_imux; 2210 2211 return 1; 2212} 2213 2214/* init callback for auto-configuration model -- overriding the default init */ 2215static int alc880_auto_init(struct hda_codec *codec) 2216{ 2217 alc_init(codec); 2218 alc880_auto_init_multi_out(codec); 2219 alc880_auto_init_extra_out(codec); 2220 alc880_auto_init_analog_input(codec); 2221 return 0; 2222} 2223 2224/* 2225 * OK, here we have finally the patch for ALC880 2226 */ 2227 2228static int patch_alc880(struct hda_codec *codec) 2229{ 2230 struct alc_spec *spec; 2231 int board_config; 2232 int err; 2233 2234 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 2235 if (spec == NULL) 2236 return -ENOMEM; 2237 2238 codec->spec = spec; 2239 2240 board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); 2241 if (board_config < 0 || board_config >= ALC880_MODEL_LAST) { 2242 printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n"); 2243 board_config = ALC880_AUTO; 2244 } 2245 2246 if (board_config == ALC880_AUTO) { 2247 /* automatic parse from the BIOS config */ 2248 err = alc880_parse_auto_config(codec); 2249 if (err < 0) { 2250 alc_free(codec); 2251 return err; 2252 } else if (! err) { 2253 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 3-stack mode...\n"); 2254 board_config = ALC880_3ST; 2255 } 2256 } 2257 2258 if (board_config != ALC880_AUTO) 2259 setup_preset(spec, &alc880_presets[board_config]); 2260 2261 spec->stream_name_analog = "ALC880 Analog"; 2262 spec->stream_analog_playback = &alc880_pcm_analog_playback; 2263 spec->stream_analog_capture = &alc880_pcm_analog_capture; 2264 2265 spec->stream_name_digital = "ALC880 Digital"; 2266 spec->stream_digital_playback = &alc880_pcm_digital_playback; 2267 spec->stream_digital_capture = &alc880_pcm_digital_capture; 2268 2269 if (! spec->adc_nids && spec->input_mux) { 2270 /* check whether NID 0x07 is valid */ 2271 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]); 2272 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ 2273 if (wcap != AC_WID_AUD_IN) { 2274 spec->adc_nids = alc880_adc_nids_alt; 2275 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); 2276 spec->mixers[spec->num_mixers] = alc880_capture_alt_mixer; 2277 spec->num_mixers++; 2278 } else { 2279 spec->adc_nids = alc880_adc_nids; 2280 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); 2281 spec->mixers[spec->num_mixers] = alc880_capture_mixer; 2282 spec->num_mixers++; 2283 } 2284 } 2285 2286 codec->patch_ops = alc_patch_ops; 2287 if (board_config == ALC880_AUTO) 2288 codec->patch_ops.init = alc880_auto_init; 2289 2290 return 0; 2291} 2292 2293 2294/* 2295 * ALC260 support 2296 */ 2297 2298static hda_nid_t alc260_dac_nids[1] = { 2299 /* front */ 2300 0x02, 2301}; 2302 2303static hda_nid_t alc260_adc_nids[1] = { 2304 /* ADC0 */ 2305 0x04, 2306}; 2307 2308static hda_nid_t alc260_adc_nids_alt[1] = { 2309 /* ADC1 */ 2310 0x05, 2311}; 2312 2313static hda_nid_t alc260_hp_adc_nids[2] = { 2314 /* ADC1, 0 */ 2315 0x05, 0x04 2316}; 2317 2318#define ALC260_DIGOUT_NID 0x03 2319#define ALC260_DIGIN_NID 0x06 2320 2321static struct hda_input_mux alc260_capture_source = { 2322 .num_items = 4, 2323 .items = { 2324 { "Mic", 0x0 }, 2325 { "Front Mic", 0x1 }, 2326 { "Line", 0x2 }, 2327 { "CD", 0x4 }, 2328 }, 2329}; 2330 2331/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack 2332 * and the internal CD lines. 2333 */ 2334static struct hda_input_mux alc260_fujitsu_capture_source = { 2335 .num_items = 2, 2336 .items = { 2337 { "Mic/Line", 0x0 }, 2338 { "CD", 0x4 }, 2339 }, 2340}; 2341 2342/* 2343 * This is just place-holder, so there's something for alc_build_pcms to look 2344 * at when it calculates the maximum number of channels. ALC260 has no mixer 2345 * element which allows changing the channel mode, so the verb list is 2346 * never used. 2347 */ 2348static struct hda_channel_mode alc260_modes[1] = { 2349 { 2, NULL }, 2350}; 2351 2352 2353/* Mixer combinations 2354 * 2355 * basic: base_output + input + pc_beep + capture 2356 * HP: base_output + input + capture_alt 2357 * HP_3013: hp_3013 + input + capture 2358 * fujitsu: fujitsu + capture 2359 */ 2360 2361static struct snd_kcontrol_new alc260_base_output_mixer[] = { 2362 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), 2363 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), 2364 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), 2365 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), 2366 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), 2367 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), 2368 { } /* end */ 2369}; 2370 2371static struct snd_kcontrol_new alc260_input_mixer[] = { 2372 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), 2373 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), 2374 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), 2375 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), 2376 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), 2377 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), 2378 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), 2379 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), 2380 { } /* end */ 2381}; 2382 2383static struct snd_kcontrol_new alc260_pc_beep_mixer[] = { 2384 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), 2385 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), 2386 { } /* end */ 2387}; 2388 2389static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { 2390 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), 2391 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), 2392 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), 2393 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), 2394 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), 2395 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), 2396 HDA_CODEC_VOLUME_MONO("iSpeaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), 2397 HDA_CODEC_MUTE_MONO("iSpeaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), 2398 { } /* end */ 2399}; 2400 2401static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { 2402 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), 2403 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), 2404 ALC_PINCTL_SWITCH("Headphone Amp Switch", 0x14, PIN_HP_AMP), 2405 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), 2406 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), 2407 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), 2408 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), 2409 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), 2410 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), 2411 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), 2412 HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT), 2413 { } /* end */ 2414}; 2415 2416/* capture mixer elements */ 2417static struct snd_kcontrol_new alc260_capture_mixer[] = { 2418 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), 2419 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), 2420 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT), 2421 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT), 2422 { 2423 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2424 /* The multiple "Capture Source" controls confuse alsamixer 2425 * So call somewhat different.. 2426 * FIXME: the controls appear in the "playback" view! 2427 */ 2428 /* .name = "Capture Source", */ 2429 .name = "Input Source", 2430 .count = 2, 2431 .info = alc_mux_enum_info, 2432 .get = alc_mux_enum_get, 2433 .put = alc_mux_enum_put, 2434 }, 2435 { } /* end */ 2436}; 2437 2438static struct snd_kcontrol_new alc260_capture_alt_mixer[] = { 2439 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), 2440 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), 2441 { 2442 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2443 /* The multiple "Capture Source" controls confuse alsamixer 2444 * So call somewhat different.. 2445 * FIXME: the controls appear in the "playback" view! 2446 */ 2447 /* .name = "Capture Source", */ 2448 .name = "Input Source", 2449 .count = 1, 2450 .info = alc_mux_enum_info, 2451 .get = alc_mux_enum_get, 2452 .put = alc_mux_enum_put, 2453 }, 2454 { } /* end */ 2455}; 2456 2457/* 2458 * initialization verbs 2459 */ 2460static struct hda_verb alc260_init_verbs[] = { 2461 /* Line In pin widget for input */ 2462 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2463 /* CD pin widget for input */ 2464 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2465 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 2466 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2467 /* Mic2 (front panel) pin widget for input and vref at 80% */ 2468 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2469 /* LINE-2 is used for line-out in rear */ 2470 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2471 /* select line-out */ 2472 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, 2473 /* LINE-OUT pin */ 2474 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2475 /* enable HP */ 2476 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 2477 /* enable Mono */ 2478 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2479 /* mute capture amp left and right */ 2480 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2481 /* set connection select to line in (default select for this ADC) */ 2482 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, 2483 /* mute capture amp left and right */ 2484 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2485 /* set connection select to line in (default select for this ADC) */ 2486 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, 2487 /* set vol=0 Line-Out mixer amp left and right */ 2488 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2489 /* unmute pin widget amp left and right (no gain on this amp) */ 2490 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2491 /* set vol=0 HP mixer amp left and right */ 2492 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2493 /* unmute pin widget amp left and right (no gain on this amp) */ 2494 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2495 /* set vol=0 Mono mixer amp left and right */ 2496 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2497 /* unmute pin widget amp left and right (no gain on this amp) */ 2498 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2499 /* unmute LINE-2 out pin */ 2500 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2501 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ 2502 /* mute CD */ 2503 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 2504 /* mute Line In */ 2505 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 2506 /* mute Mic */ 2507 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2508 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ 2509 /* mute Front out path */ 2510 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2511 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2512 /* mute Headphone out path */ 2513 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2514 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2515 /* mute Mono out path */ 2516 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2517 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2518 { } 2519}; 2520 2521static struct hda_verb alc260_hp_init_verbs[] = { 2522 /* Headphone and output */ 2523 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, 2524 /* mono output */ 2525 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, 2526 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 2527 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, 2528 /* Mic2 (front panel) pin widget for input and vref at 80% */ 2529 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, 2530 /* Line In pin widget for input */ 2531 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, 2532 /* Line-2 pin widget for output */ 2533 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, 2534 /* CD pin widget for input */ 2535 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, 2536 /* unmute amp left and right */ 2537 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, 2538 /* set connection select to line in (default select for this ADC) */ 2539 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, 2540 /* unmute Line-Out mixer amp left and right (volume = 0) */ 2541 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, 2542 /* mute pin widget amp left and right (no gain on this amp) */ 2543 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 2544 /* unmute HP mixer amp left and right (volume = 0) */ 2545 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, 2546 /* mute pin widget amp left and right (no gain on this amp) */ 2547 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 2548 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ 2549 /* unmute CD */ 2550 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, 2551 /* unmute Line In */ 2552 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, 2553 /* unmute Mic */ 2554 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 2555 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ 2556 /* Unmute Front out path */ 2557 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 2558 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, 2559 /* Unmute Headphone out path */ 2560 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 2561 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, 2562 /* Unmute Mono out path */ 2563 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 2564 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, 2565 { } 2566}; 2567 2568static struct hda_verb alc260_hp_3013_init_verbs[] = { 2569 /* Line out and output */ 2570 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, 2571 /* mono output */ 2572 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, 2573 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 2574 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, 2575 /* Mic2 (front panel) pin widget for input and vref at 80% */ 2576 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, 2577 /* Line In pin widget for input */ 2578 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, 2579 /* Headphone pin widget for output */ 2580 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, 2581 /* CD pin widget for input */ 2582 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, 2583 /* unmute amp left and right */ 2584 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, 2585 /* set connection select to line in (default select for this ADC) */ 2586 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, 2587 /* unmute Line-Out mixer amp left and right (volume = 0) */ 2588 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, 2589 /* mute pin widget amp left and right (no gain on this amp) */ 2590 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 2591 /* unmute HP mixer amp left and right (volume = 0) */ 2592 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, 2593 /* mute pin widget amp left and right (no gain on this amp) */ 2594 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 2595 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ 2596 /* unmute CD */ 2597 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, 2598 /* unmute Line In */ 2599 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, 2600 /* unmute Mic */ 2601 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 2602 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ 2603 /* Unmute Front out path */ 2604 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 2605 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, 2606 /* Unmute Headphone out path */ 2607 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 2608 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, 2609 /* Unmute Mono out path */ 2610 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 2611 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, 2612 { } 2613}; 2614 2615/* Initialisation sequence for ALC260 as configured in Fujitsu S702x 2616 * laptops. 2617 */ 2618static struct hda_verb alc260_fujitsu_init_verbs[] = { 2619 /* Disable all GPIOs */ 2620 {0x01, AC_VERB_SET_GPIO_MASK, 0}, 2621 /* Internal speaker is connected to headphone pin */ 2622 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 2623 /* Headphone/Line-out jack connects to Line1 pin; make it an output */ 2624 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2625 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ 2626 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2627 /* Ensure all other unused pins are disabled and muted. 2628 * Note: trying to set widget 0x15 to anything blocks all audio 2629 * output for some reason, so just leave that at the default. 2630 */ 2631 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2632 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2633 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2634 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2635 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2636 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2637 /* Disable digital (SPDIF) pins */ 2638 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, 2639 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, 2640 2641 /* Start with mixer outputs muted */ 2642 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 2643 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 2644 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 2645 2646 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ 2647 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2648 /* Unmute Line1 pin widget amp left and right (no equiv mixer ctrl) */ 2649 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2650 /* Unmute pin widget used for Line-in (no equiv mixer ctrl) */ 2651 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2652 2653 /* Mute capture amp left and right */ 2654 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2655 /* Set ADC connection select to line in (on mic1 pin) */ 2656 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, 2657 2658 /* Mute all inputs to mixer widget (even unconnected ones) */ 2659 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ 2660 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ 2661 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ 2662 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ 2663 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ 2664 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ 2665 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ 2666 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ 2667}; 2668 2669static struct hda_pcm_stream alc260_pcm_analog_playback = { 2670 .substreams = 1, 2671 .channels_min = 2, 2672 .channels_max = 2, 2673}; 2674 2675static struct hda_pcm_stream alc260_pcm_analog_capture = { 2676 .substreams = 1, 2677 .channels_min = 2, 2678 .channels_max = 2, 2679}; 2680 2681#define alc260_pcm_digital_playback alc880_pcm_digital_playback 2682#define alc260_pcm_digital_capture alc880_pcm_digital_capture 2683 2684/* 2685 * for BIOS auto-configuration 2686 */ 2687 2688static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid, 2689 const char *pfx) 2690{ 2691 hda_nid_t nid_vol; 2692 unsigned long vol_val, sw_val; 2693 char name[32]; 2694 int err; 2695 2696 if (nid >= 0x0f && nid < 0x11) { 2697 nid_vol = nid - 0x7; 2698 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); 2699 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2700 } else if (nid == 0x11) { 2701 nid_vol = nid - 0x7; 2702 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT); 2703 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); 2704 } else if (nid >= 0x12 && nid <= 0x15) { 2705 nid_vol = 0x08; 2706 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); 2707 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2708 } else 2709 return 0; /* N/A */ 2710 2711 snprintf(name, sizeof(name), "%s Playback Volume", pfx); 2712 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val)) < 0) 2713 return err; 2714 snprintf(name, sizeof(name), "%s Playback Switch", pfx); 2715 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val)) < 0) 2716 return err; 2717 return 1; 2718} 2719 2720/* add playback controls from the parsed DAC table */ 2721static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, 2722 const struct auto_pin_cfg *cfg) 2723{ 2724 hda_nid_t nid; 2725 int err; 2726 2727 spec->multiout.num_dacs = 1; 2728 spec->multiout.dac_nids = spec->private_dac_nids; 2729 spec->multiout.dac_nids[0] = 0x02; 2730 2731 nid = cfg->line_out_pins[0]; 2732 if (nid) { 2733 err = alc260_add_playback_controls(spec, nid, "Front"); 2734 if (err < 0) 2735 return err; 2736 } 2737 2738 nid = cfg->speaker_pin; 2739 if (nid) { 2740 err = alc260_add_playback_controls(spec, nid, "Speaker"); 2741 if (err < 0) 2742 return err; 2743 } 2744 2745 nid = cfg->hp_pin; 2746 if (nid) { 2747 err = alc260_add_playback_controls(spec, nid, "Headphone"); 2748 if (err < 0) 2749 return err; 2750 } 2751 return 0; 2752} 2753 2754/* create playback/capture controls for input pins */ 2755static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec, 2756 const struct auto_pin_cfg *cfg) 2757{ 2758 static char *labels[AUTO_PIN_LAST] = { 2759 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" 2760 }; 2761 struct hda_input_mux *imux = &spec->private_imux; 2762 int i, err, idx; 2763 2764 for (i = 0; i < AUTO_PIN_LAST; i++) { 2765 if (cfg->input_pins[i] >= 0x12) { 2766 idx = cfg->input_pins[i] - 0x12; 2767 err = new_analog_input(spec, cfg->input_pins[i], labels[i], idx, 0x07); 2768 if (err < 0) 2769 return err; 2770 imux->items[imux->num_items].label = labels[i]; 2771 imux->items[imux->num_items].index = idx; 2772 imux->num_items++; 2773 } 2774 if ((cfg->input_pins[i] >= 0x0f) && (cfg->input_pins[i] <= 0x10)){ 2775 idx = cfg->input_pins[i] - 0x09; 2776 err = new_analog_input(spec, cfg->input_pins[i], labels[i], idx, 0x07); 2777 if (err < 0) 2778 return err; 2779 imux->items[imux->num_items].label = labels[i]; 2780 imux->items[imux->num_items].index = idx; 2781 imux->num_items++; 2782 } 2783 } 2784 return 0; 2785} 2786 2787static void alc260_auto_set_output_and_unmute(struct hda_codec *codec, 2788 hda_nid_t nid, int pin_type, 2789 int sel_idx) 2790{ 2791 /* set as output */ 2792 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); 2793 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 2794 /* need the manual connection? */ 2795 if (nid >= 0x12) { 2796 int idx = nid - 0x12; 2797 snd_hda_codec_write(codec, idx + 0x0b, 0, 2798 AC_VERB_SET_CONNECT_SEL, sel_idx); 2799 2800 } 2801} 2802 2803static void alc260_auto_init_multi_out(struct hda_codec *codec) 2804{ 2805 struct alc_spec *spec = codec->spec; 2806 hda_nid_t nid; 2807 2808 nid = spec->autocfg.line_out_pins[0]; 2809 if (nid) 2810 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); 2811 2812 nid = spec->autocfg.speaker_pin; 2813 if (nid) 2814 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); 2815 2816 nid = spec->autocfg.hp_pin; 2817 if (nid) 2818 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); 2819} 2820 2821#define ALC260_PIN_CD_NID 0x16 2822static void alc260_auto_init_analog_input(struct hda_codec *codec) 2823{ 2824 struct alc_spec *spec = codec->spec; 2825 int i; 2826 2827 for (i = 0; i < AUTO_PIN_LAST; i++) { 2828 hda_nid_t nid = spec->autocfg.input_pins[i]; 2829 if (nid >= 0x12) { 2830 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 2831 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); 2832 if (nid != ALC260_PIN_CD_NID) 2833 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 2834 AMP_OUT_MUTE); 2835 } 2836 } 2837} 2838 2839/* 2840 * generic initialization of ADC, input mixers and output mixers 2841 */ 2842static struct hda_verb alc260_volume_init_verbs[] = { 2843 /* 2844 * Unmute ADC0-1 and set the default input to mic-in 2845 */ 2846 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, 2847 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2848 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, 2849 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2850 2851 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 2852 * mixer widget 2853 * Note: PASD motherboards uses the Line In 2 as the input for front panel 2854 * mic (mic 2) 2855 */ 2856 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ 2857 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2858 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 2859 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 2860 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 2861 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 2862 2863 /* 2864 * Set up output mixers (0x08 - 0x0a) 2865 */ 2866 /* set vol=0 to output mixers */ 2867 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2868 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2869 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2870 /* set up input amps for analog loopback */ 2871 /* Amp Indices: DAC = 0, mixer = 1 */ 2872 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2873 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 2874 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2875 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 2876 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2877 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 2878 2879 { } 2880}; 2881 2882static int alc260_parse_auto_config(struct hda_codec *codec) 2883{ 2884 struct alc_spec *spec = codec->spec; 2885 unsigned int wcap; 2886 int err; 2887 static hda_nid_t alc260_ignore[] = { 0x17, 0 }; 2888 2889 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, 2890 alc260_ignore)) < 0) 2891 return err; 2892 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && 2893 ! spec->autocfg.hp_pin) 2894 return 0; /* can't find valid BIOS pin config */ 2895 if ((err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || 2896 (err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) 2897 return err; 2898 2899 spec->multiout.max_channels = 2; 2900 2901 if (spec->autocfg.dig_out_pin) 2902 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; 2903 if (spec->kctl_alloc) 2904 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 2905 2906 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs; 2907 2908 spec->input_mux = &spec->private_imux; 2909 2910 /* check whether NID 0x04 is valid */ 2911 wcap = snd_hda_param_read(codec, alc260_adc_nids[0], AC_PAR_AUDIO_WIDGET_CAP); 2912 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ 2913 if (wcap != AC_WID_AUD_IN) { 2914 spec->adc_nids = alc260_adc_nids_alt; 2915 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); 2916 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer; 2917 spec->num_mixers++; 2918 } else { 2919 spec->adc_nids = alc260_adc_nids; 2920 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); 2921 spec->mixers[spec->num_mixers] = alc260_capture_mixer; 2922 spec->num_mixers++; 2923 } 2924 2925 return 1; 2926} 2927 2928/* init callback for auto-configuration model -- overriding the default init */ 2929static int alc260_auto_init(struct hda_codec *codec) 2930{ 2931 alc_init(codec); 2932 alc260_auto_init_multi_out(codec); 2933 alc260_auto_init_analog_input(codec); 2934 return 0; 2935} 2936 2937/* 2938 * ALC260 configurations 2939 */ 2940static struct hda_board_config alc260_cfg_tbl[] = { 2941 { .modelname = "basic", .config = ALC260_BASIC }, 2942 { .modelname = "hp", .config = ALC260_HP }, 2943 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP }, 2944 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, 2945 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP }, 2946 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 }, 2947 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP }, 2948 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP }, 2949 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP }, 2950 { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X }, 2951 { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X }, 2952 { .modelname = "auto", .config = ALC260_AUTO }, 2953 {} 2954}; 2955 2956static struct alc_config_preset alc260_presets[] = { 2957 [ALC260_BASIC] = { 2958 .mixers = { alc260_base_output_mixer, 2959 alc260_input_mixer, 2960 alc260_pc_beep_mixer, 2961 alc260_capture_mixer }, 2962 .init_verbs = { alc260_init_verbs }, 2963 .num_dacs = ARRAY_SIZE(alc260_dac_nids), 2964 .dac_nids = alc260_dac_nids, 2965 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), 2966 .adc_nids = alc260_adc_nids, 2967 .num_channel_mode = ARRAY_SIZE(alc260_modes), 2968 .channel_mode = alc260_modes, 2969 .input_mux = &alc260_capture_source, 2970 }, 2971 [ALC260_HP] = { 2972 .mixers = { alc260_base_output_mixer, 2973 alc260_input_mixer, 2974 alc260_capture_alt_mixer }, 2975 .init_verbs = { alc260_hp_init_verbs }, 2976 .num_dacs = ARRAY_SIZE(alc260_dac_nids), 2977 .dac_nids = alc260_dac_nids, 2978 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), 2979 .adc_nids = alc260_hp_adc_nids, 2980 .num_channel_mode = ARRAY_SIZE(alc260_modes), 2981 .channel_mode = alc260_modes, 2982 .input_mux = &alc260_capture_source, 2983 }, 2984 [ALC260_HP_3013] = { 2985 .mixers = { alc260_hp_3013_mixer, 2986 alc260_input_mixer, 2987 alc260_capture_alt_mixer }, 2988 .init_verbs = { alc260_hp_3013_init_verbs }, 2989 .num_dacs = ARRAY_SIZE(alc260_dac_nids), 2990 .dac_nids = alc260_dac_nids, 2991 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), 2992 .adc_nids = alc260_hp_adc_nids, 2993 .num_channel_mode = ARRAY_SIZE(alc260_modes), 2994 .channel_mode = alc260_modes, 2995 .input_mux = &alc260_capture_source, 2996 }, 2997 [ALC260_FUJITSU_S702X] = { 2998 .mixers = { alc260_fujitsu_mixer, 2999 alc260_capture_mixer }, 3000 .init_verbs = { alc260_fujitsu_init_verbs }, 3001 .num_dacs = ARRAY_SIZE(alc260_dac_nids), 3002 .dac_nids = alc260_dac_nids, 3003 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), 3004 .adc_nids = alc260_adc_nids, 3005 .num_channel_mode = ARRAY_SIZE(alc260_modes), 3006 .channel_mode = alc260_modes, 3007 .input_mux = &alc260_fujitsu_capture_source, 3008 }, 3009}; 3010 3011static int patch_alc260(struct hda_codec *codec) 3012{ 3013 struct alc_spec *spec; 3014 int err, board_config; 3015 3016 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 3017 if (spec == NULL) 3018 return -ENOMEM; 3019 3020 codec->spec = spec; 3021 3022 board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); 3023 if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { 3024 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n"); 3025 board_config = ALC260_AUTO; 3026 } 3027 3028 if (board_config == ALC260_AUTO) { 3029 /* automatic parse from the BIOS config */ 3030 err = alc260_parse_auto_config(codec); 3031 if (err < 0) { 3032 alc_free(codec); 3033 return err; 3034 } else if (! err) { 3035 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); 3036 board_config = ALC260_BASIC; 3037 } 3038 } 3039 3040 if (board_config != ALC260_AUTO) 3041 setup_preset(spec, &alc260_presets[board_config]); 3042 3043 spec->stream_name_analog = "ALC260 Analog"; 3044 spec->stream_analog_playback = &alc260_pcm_analog_playback; 3045 spec->stream_analog_capture = &alc260_pcm_analog_capture; 3046 3047 spec->stream_name_digital = "ALC260 Digital"; 3048 spec->stream_digital_playback = &alc260_pcm_digital_playback; 3049 spec->stream_digital_capture = &alc260_pcm_digital_capture; 3050 3051 codec->patch_ops = alc_patch_ops; 3052 if (board_config == ALC260_AUTO) 3053 codec->patch_ops.init = alc260_auto_init; 3054 3055 return 0; 3056} 3057 3058 3059/* 3060 * ALC882 support 3061 * 3062 * ALC882 is almost identical with ALC880 but has cleaner and more flexible 3063 * configuration. Each pin widget can choose any input DACs and a mixer. 3064 * Each ADC is connected from a mixer of all inputs. This makes possible 3065 * 6-channel independent captures. 3066 * 3067 * In addition, an independent DAC for the multi-playback (not used in this 3068 * driver yet). 3069 */ 3070#define ALC882_DIGOUT_NID 0x06 3071#define ALC882_DIGIN_NID 0x0a 3072 3073static struct hda_channel_mode alc882_ch_modes[1] = { 3074 { 8, NULL } 3075}; 3076 3077static hda_nid_t alc882_dac_nids[4] = { 3078 /* front, rear, clfe, rear_surr */ 3079 0x02, 0x03, 0x04, 0x05 3080}; 3081 3082/* identical with ALC880 */ 3083#define alc882_adc_nids alc880_adc_nids 3084#define alc882_adc_nids_alt alc880_adc_nids_alt 3085 3086/* input MUX */ 3087/* FIXME: should be a matrix-type input source selection */ 3088 3089static struct hda_input_mux alc882_capture_source = { 3090 .num_items = 4, 3091 .items = { 3092 { "Mic", 0x0 }, 3093 { "Front Mic", 0x1 }, 3094 { "Line", 0x2 }, 3095 { "CD", 0x4 }, 3096 }, 3097}; 3098 3099#define alc882_mux_enum_info alc_mux_enum_info 3100#define alc882_mux_enum_get alc_mux_enum_get 3101 3102static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 3103{ 3104 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3105 struct alc_spec *spec = codec->spec; 3106 const struct hda_input_mux *imux = spec->input_mux; 3107 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3108 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; 3109 hda_nid_t nid = capture_mixers[adc_idx]; 3110 unsigned int *cur_val = &spec->cur_mux[adc_idx]; 3111 unsigned int i, idx; 3112 3113 idx = ucontrol->value.enumerated.item[0]; 3114 if (idx >= imux->num_items) 3115 idx = imux->num_items - 1; 3116 if (*cur_val == idx && ! codec->in_resume) 3117 return 0; 3118 for (i = 0; i < imux->num_items; i++) { 3119 unsigned int v = (i == idx) ? 0x7000 : 0x7080; 3120 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 3121 v | (imux->items[i].index << 8)); 3122 } 3123 *cur_val = idx; 3124 return 1; 3125} 3126 3127/* 3128 * 6ch mode 3129 */ 3130static struct hda_verb alc882_sixstack_ch6_init[] = { 3131 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, 3132 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3133 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3134 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3135 { } /* end */ 3136}; 3137 3138/* 3139 * 8ch mode 3140 */ 3141static struct hda_verb alc882_sixstack_ch8_init[] = { 3142 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3143 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3144 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3145 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3146 { } /* end */ 3147}; 3148 3149static struct hda_channel_mode alc882_sixstack_modes[2] = { 3150 { 6, alc882_sixstack_ch6_init }, 3151 { 8, alc882_sixstack_ch8_init }, 3152}; 3153 3154/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 3155 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b 3156 */ 3157static struct snd_kcontrol_new alc882_base_mixer[] = { 3158 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 3159 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 3160 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 3161 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 3162 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 3163 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 3164 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 3165 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), 3166 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), 3167 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), 3168 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), 3169 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 3170 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 3171 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 3172 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 3173 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 3174 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 3175 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), 3176 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), 3177 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 3178 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 3179 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), 3180 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), 3181 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), 3182 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), 3183 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), 3184 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), 3185 { 3186 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3187 /* .name = "Capture Source", */ 3188 .name = "Input Source", 3189 .count = 3, 3190 .info = alc882_mux_enum_info, 3191 .get = alc882_mux_enum_get, 3192 .put = alc882_mux_enum_put, 3193 }, 3194 { } /* end */ 3195}; 3196 3197static struct snd_kcontrol_new alc882_chmode_mixer[] = { 3198 { 3199 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3200 .name = "Channel Mode", 3201 .info = alc_ch_mode_info, 3202 .get = alc_ch_mode_get, 3203 .put = alc_ch_mode_put, 3204 }, 3205 { } /* end */ 3206}; 3207 3208static struct hda_verb alc882_init_verbs[] = { 3209 /* Front mixer: unmute input/output amp left and right (volume = 0) */ 3210 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3211 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3212 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 3213 /* Rear mixer */ 3214 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3215 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3216 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 3217 /* CLFE mixer */ 3218 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3219 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3220 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 3221 /* Side mixer */ 3222 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3223 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3224 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 3225 3226 /* Front Pin: output 0 (0x0c) */ 3227 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 3228 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 3229 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, 3230 /* Rear Pin: output 1 (0x0d) */ 3231 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 3232 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 3233 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, 3234 /* CLFE Pin: output 2 (0x0e) */ 3235 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 3236 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 3237 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, 3238 /* Side Pin: output 3 (0x0f) */ 3239 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 3240 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 3241 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, 3242 /* Mic (rear) pin: input vref at 80% */ 3243 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 3244 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 3245 /* Front Mic pin: input vref at 80% */ 3246 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 3247 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 3248 /* Line In pin: input */ 3249 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 3250 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 3251 /* Line-2 In: Headphone output (output 0 - 0x0c) */ 3252 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 3253 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 3254 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, 3255 /* CD pin widget for input */ 3256 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 3257 3258 /* FIXME: use matrix-type input source selection */ 3259 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ 3260 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ 3261 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3262 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 3263 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 3264 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 3265 /* Input mixer2 */ 3266 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3267 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 3268 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 3269 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 3270 /* Input mixer3 */ 3271 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3272 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 3273 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 3274 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 3275 /* ADC1: mute amp left and right */ 3276 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3277 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 3278 /* ADC2: mute amp left and right */ 3279 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3280 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 3281 /* ADC3: mute amp left and right */ 3282 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3283 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 3284 3285 { } 3286}; 3287 3288/* 3289 * generic initialization of ADC, input mixers and output mixers 3290 */ 3291static struct hda_verb alc882_auto_init_verbs[] = { 3292 /* 3293 * Unmute ADC0-2 and set the default input to mic-in 3294 */ 3295 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 3296 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3297 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 3298 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3299 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 3300 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3301 3302 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 3303 * mixer widget 3304 * Note: PASD motherboards uses the Line In 2 as the input for front panel 3305 * mic (mic 2) 3306 */ 3307 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ 3308 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3309 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3310 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 3311 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 3312 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 3313 3314 /* 3315 * Set up output mixers (0x0c - 0x0f) 3316 */ 3317 /* set vol=0 to output mixers */ 3318 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3319 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3320 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3321 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3322 /* set up input amps for analog loopback */ 3323 /* Amp Indices: DAC = 0, mixer = 1 */ 3324 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3325 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3326 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3327 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3328 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3329 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3330 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3331 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3332 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3333 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3334 3335 /* FIXME: use matrix-type input source selection */ 3336 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ 3337 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ 3338 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3339 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3340 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3341 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3342 /* Input mixer2 */ 3343 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3344 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3345 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3346 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3347 /* Input mixer3 */ 3348 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3349 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3350 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3351 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3352 3353 { } 3354}; 3355 3356/* capture mixer elements */ 3357static struct snd_kcontrol_new alc882_capture_alt_mixer[] = { 3358 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 3359 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 3360 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), 3361 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), 3362 { 3363 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3364 /* The multiple "Capture Source" controls confuse alsamixer 3365 * So call somewhat different.. 3366 * FIXME: the controls appear in the "playback" view! 3367 */ 3368 /* .name = "Capture Source", */ 3369 .name = "Input Source", 3370 .count = 2, 3371 .info = alc882_mux_enum_info, 3372 .get = alc882_mux_enum_get, 3373 .put = alc882_mux_enum_put, 3374 }, 3375 { } /* end */ 3376}; 3377 3378static struct snd_kcontrol_new alc882_capture_mixer[] = { 3379 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), 3380 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), 3381 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), 3382 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), 3383 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), 3384 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), 3385 { 3386 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3387 /* The multiple "Capture Source" controls confuse alsamixer 3388 * So call somewhat different.. 3389 * FIXME: the controls appear in the "playback" view! 3390 */ 3391 /* .name = "Capture Source", */ 3392 .name = "Input Source", 3393 .count = 3, 3394 .info = alc882_mux_enum_info, 3395 .get = alc882_mux_enum_get, 3396 .put = alc882_mux_enum_put, 3397 }, 3398 { } /* end */ 3399}; 3400 3401/* pcm configuration: identiacal with ALC880 */ 3402#define alc882_pcm_analog_playback alc880_pcm_analog_playback 3403#define alc882_pcm_analog_capture alc880_pcm_analog_capture 3404#define alc882_pcm_digital_playback alc880_pcm_digital_playback 3405#define alc882_pcm_digital_capture alc880_pcm_digital_capture 3406 3407/* 3408 * configuration and preset 3409 */ 3410static struct hda_board_config alc882_cfg_tbl[] = { 3411 { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, 3412 { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, 3413 { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* MSI */ 3414 { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* Foxconn */ 3415 { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* ECS */ 3416 { .modelname = "auto", .config = ALC861_AUTO }, 3417 {} 3418}; 3419 3420static struct alc_config_preset alc882_presets[] = { 3421 [ALC882_3ST_DIG] = { 3422 .mixers = { alc882_base_mixer }, 3423 .init_verbs = { alc882_init_verbs }, 3424 .num_dacs = ARRAY_SIZE(alc882_dac_nids), 3425 .dac_nids = alc882_dac_nids, 3426 .dig_out_nid = ALC882_DIGOUT_NID, 3427 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), 3428 .adc_nids = alc882_adc_nids, 3429 .dig_in_nid = ALC882_DIGIN_NID, 3430 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), 3431 .channel_mode = alc882_ch_modes, 3432 .input_mux = &alc882_capture_source, 3433 }, 3434 [ALC882_6ST_DIG] = { 3435 .mixers = { alc882_base_mixer, alc882_chmode_mixer }, 3436 .init_verbs = { alc882_init_verbs }, 3437 .num_dacs = ARRAY_SIZE(alc882_dac_nids), 3438 .dac_nids = alc882_dac_nids, 3439 .dig_out_nid = ALC882_DIGOUT_NID, 3440 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), 3441 .adc_nids = alc882_adc_nids, 3442 .dig_in_nid = ALC882_DIGIN_NID, 3443 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), 3444 .channel_mode = alc882_sixstack_modes, 3445 .input_mux = &alc882_capture_source, 3446 }, 3447}; 3448 3449 3450/* 3451 * BIOS auto configuration 3452 */ 3453static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, 3454 hda_nid_t nid, int pin_type, 3455 int dac_idx) 3456{ 3457 /* set as output */ 3458 struct alc_spec *spec = codec->spec; 3459 int idx; 3460 3461 if (spec->multiout.dac_nids[dac_idx] == 0x25) 3462 idx = 4; 3463 else 3464 idx = spec->multiout.dac_nids[dac_idx] - 2; 3465 3466 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); 3467 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 3468 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); 3469 3470} 3471 3472static void alc882_auto_init_multi_out(struct hda_codec *codec) 3473{ 3474 struct alc_spec *spec = codec->spec; 3475 int i; 3476 3477 for (i = 0; i <= HDA_SIDE; i++) { 3478 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 3479 if (nid) 3480 alc882_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); 3481 } 3482} 3483 3484static void alc882_auto_init_hp_out(struct hda_codec *codec) 3485{ 3486 struct alc_spec *spec = codec->spec; 3487 hda_nid_t pin; 3488 3489 pin = spec->autocfg.hp_pin; 3490 if (pin) /* connect to front */ 3491 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */ 3492} 3493 3494#define alc882_is_input_pin(nid) alc880_is_input_pin(nid) 3495#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID 3496 3497static void alc882_auto_init_analog_input(struct hda_codec *codec) 3498{ 3499 struct alc_spec *spec = codec->spec; 3500 int i; 3501 3502 for (i = 0; i < AUTO_PIN_LAST; i++) { 3503 hda_nid_t nid = spec->autocfg.input_pins[i]; 3504 if (alc882_is_input_pin(nid)) { 3505 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 3506 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); 3507 if (nid != ALC882_PIN_CD_NID) 3508 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 3509 AMP_OUT_MUTE); 3510 } 3511 } 3512} 3513 3514/* almost identical with ALC880 parser... */ 3515static int alc882_parse_auto_config(struct hda_codec *codec) 3516{ 3517 struct alc_spec *spec = codec->spec; 3518 int err = alc880_parse_auto_config(codec); 3519 3520 if (err < 0) 3521 return err; 3522 else if (err > 0) 3523 /* hack - override the init verbs */ 3524 spec->init_verbs[0] = alc882_auto_init_verbs; 3525 return err; 3526} 3527 3528/* init callback for auto-configuration model -- overriding the default init */ 3529static int alc882_auto_init(struct hda_codec *codec) 3530{ 3531 alc_init(codec); 3532 alc882_auto_init_multi_out(codec); 3533 alc882_auto_init_hp_out(codec); 3534 alc882_auto_init_analog_input(codec); 3535 return 0; 3536} 3537 3538/* 3539 * ALC882 Headphone poll in 3.5.1a or 3.5.2 3540 */ 3541 3542static int patch_alc882(struct hda_codec *codec) 3543{ 3544 struct alc_spec *spec; 3545 int err, board_config; 3546 3547 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 3548 if (spec == NULL) 3549 return -ENOMEM; 3550 3551 codec->spec = spec; 3552 3553 board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl); 3554 3555 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { 3556 printk(KERN_INFO "hda_codec: Unknown model for ALC882, trying auto-probe from BIOS...\n"); 3557 board_config = ALC882_AUTO; 3558 } 3559 3560 if (board_config == ALC882_AUTO) { 3561 /* automatic parse from the BIOS config */ 3562 err = alc882_parse_auto_config(codec); 3563 if (err < 0) { 3564 alc_free(codec); 3565 return err; 3566 } else if (! err) { 3567 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); 3568 board_config = ALC882_3ST_DIG; 3569 } 3570 } 3571 3572 if (board_config != ALC882_AUTO) 3573 setup_preset(spec, &alc882_presets[board_config]); 3574 3575 spec->stream_name_analog = "ALC882 Analog"; 3576 spec->stream_analog_playback = &alc882_pcm_analog_playback; 3577 spec->stream_analog_capture = &alc882_pcm_analog_capture; 3578 3579 spec->stream_name_digital = "ALC882 Digital"; 3580 spec->stream_digital_playback = &alc882_pcm_digital_playback; 3581 spec->stream_digital_capture = &alc882_pcm_digital_capture; 3582 3583 if (! spec->adc_nids && spec->input_mux) { 3584 /* check whether NID 0x07 is valid */ 3585 unsigned int wcap = snd_hda_param_read(codec, 0x07, 3586 AC_PAR_AUDIO_WIDGET_CAP); 3587 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ 3588 if (wcap != AC_WID_AUD_IN) { 3589 spec->adc_nids = alc882_adc_nids_alt; 3590 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt); 3591 spec->mixers[spec->num_mixers] = alc882_capture_alt_mixer; 3592 spec->num_mixers++; 3593 } else { 3594 spec->adc_nids = alc882_adc_nids; 3595 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); 3596 spec->mixers[spec->num_mixers] = alc882_capture_mixer; 3597 spec->num_mixers++; 3598 } 3599 } 3600 3601 codec->patch_ops = alc_patch_ops; 3602 if (board_config == ALC882_AUTO) 3603 codec->patch_ops.init = alc882_auto_init; 3604 3605 return 0; 3606} 3607 3608/* 3609 * ALC262 support 3610 */ 3611 3612#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID 3613#define ALC262_DIGIN_NID ALC880_DIGIN_NID 3614 3615#define alc262_dac_nids alc260_dac_nids 3616#define alc262_adc_nids alc882_adc_nids 3617#define alc262_adc_nids_alt alc882_adc_nids_alt 3618 3619#define alc262_modes alc260_modes 3620#define alc262_capture_source alc882_capture_source 3621 3622static struct snd_kcontrol_new alc262_base_mixer[] = { 3623 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 3624 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), 3625 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 3626 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 3627 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 3628 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 3629 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 3630 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 3631 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), 3632 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), 3633 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), 3634 HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */ 3635 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT), 3636 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), 3637 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 3638 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), 3639 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 3640 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 3641 { 3642 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3643 .name = "Capture Source", 3644 .count = 1, 3645 .info = alc882_mux_enum_info, 3646 .get = alc882_mux_enum_get, 3647 .put = alc882_mux_enum_put, 3648 }, 3649 { } /* end */ 3650}; 3651 3652#define alc262_capture_mixer alc882_capture_mixer 3653#define alc262_capture_alt_mixer alc882_capture_alt_mixer 3654 3655/* 3656 * generic initialization of ADC, input mixers and output mixers 3657 */ 3658static struct hda_verb alc262_init_verbs[] = { 3659 /* 3660 * Unmute ADC0-2 and set the default input to mic-in 3661 */ 3662 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 3663 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3664 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 3665 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3666 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 3667 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3668 3669 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 3670 * mixer widget 3671 * Note: PASD motherboards uses the Line In 2 as the input for front panel 3672 * mic (mic 2) 3673 */ 3674 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ 3675 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3676 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3677 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 3678 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 3679 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 3680 3681 /* 3682 * Set up output mixers (0x0c - 0x0e) 3683 */ 3684 /* set vol=0 to output mixers */ 3685 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3686 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3687 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3688 /* set up input amps for analog loopback */ 3689 /* Amp Indices: DAC = 0, mixer = 1 */ 3690 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3691 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3692 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3693 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3694 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3695 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3696 3697 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, 3698 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, 3699 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, 3700 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, 3701 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, 3702 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, 3703 3704 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 3705 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 3706 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 3707 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 3708 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 3709 3710 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, 3711 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, 3712 3713 /* FIXME: use matrix-type input source selection */ 3714 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ 3715 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ 3716 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3717 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3718 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3719 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3720 /* Input mixer2 */ 3721 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3722 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3723 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3724 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3725 /* Input mixer3 */ 3726 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3727 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3728 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3729 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3730 3731 { } 3732}; 3733 3734/* add playback controls from the parsed DAC table */ 3735static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 3736{ 3737 hda_nid_t nid; 3738 int err; 3739 3740 spec->multiout.num_dacs = 1; /* only use one dac */ 3741 spec->multiout.dac_nids = spec->private_dac_nids; 3742 spec->multiout.dac_nids[0] = 2; 3743 3744 nid = cfg->line_out_pins[0]; 3745 if (nid) { 3746 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Front Playback Volume", 3747 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0) 3748 return err; 3749 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Front Playback Switch", 3750 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 3751 return err; 3752 } 3753 3754 nid = cfg->speaker_pin; 3755 if (nid) { 3756 if (nid == 0x16) { 3757 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume", 3758 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT))) < 0) 3759 return err; 3760 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch", 3761 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) 3762 return err; 3763 } else { 3764 if (! cfg->line_out_pins[0]) 3765 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume", 3766 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0) 3767 return err; 3768 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch", 3769 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 3770 return err; 3771 } 3772 } 3773 nid = cfg->hp_pin; 3774 if (nid) { 3775 /* spec->multiout.hp_nid = 2; */ 3776 if (nid == 0x16) { 3777 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", 3778 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT))) < 0) 3779 return err; 3780 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", 3781 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) 3782 return err; 3783 } else { 3784 if (! cfg->line_out_pins[0]) 3785 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", 3786 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0) 3787 return err; 3788 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", 3789 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 3790 return err; 3791 } 3792 } 3793 return 0; 3794} 3795 3796/* identical with ALC880 */ 3797#define alc262_auto_create_analog_input_ctls alc880_auto_create_analog_input_ctls 3798 3799/* 3800 * generic initialization of ADC, input mixers and output mixers 3801 */ 3802static struct hda_verb alc262_volume_init_verbs[] = { 3803 /* 3804 * Unmute ADC0-2 and set the default input to mic-in 3805 */ 3806 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 3807 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3808 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 3809 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3810 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 3811 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3812 3813 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 3814 * mixer widget 3815 * Note: PASD motherboards uses the Line In 2 as the input for front panel 3816 * mic (mic 2) 3817 */ 3818 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ 3819 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3820 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3821 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 3822 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 3823 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 3824 3825 /* 3826 * Set up output mixers (0x0c - 0x0f) 3827 */ 3828 /* set vol=0 to output mixers */ 3829 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3830 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3831 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3832 3833 /* set up input amps for analog loopback */ 3834 /* Amp Indices: DAC = 0, mixer = 1 */ 3835 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3836 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3837 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3838 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3839 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3840 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3841 3842 /* FIXME: use matrix-type input source selection */ 3843 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ 3844 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ 3845 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3846 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3847 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3848 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3849 /* Input mixer2 */ 3850 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3851 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3852 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3853 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3854 /* Input mixer3 */ 3855 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3856 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3857 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3858 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3859 3860 { } 3861}; 3862 3863/* pcm configuration: identiacal with ALC880 */ 3864#define alc262_pcm_analog_playback alc880_pcm_analog_playback 3865#define alc262_pcm_analog_capture alc880_pcm_analog_capture 3866#define alc262_pcm_digital_playback alc880_pcm_digital_playback 3867#define alc262_pcm_digital_capture alc880_pcm_digital_capture 3868 3869/* 3870 * BIOS auto configuration 3871 */ 3872static int alc262_parse_auto_config(struct hda_codec *codec) 3873{ 3874 struct alc_spec *spec = codec->spec; 3875 int err; 3876 static hda_nid_t alc262_ignore[] = { 0x1d, 0 }; 3877 3878 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, 3879 alc262_ignore)) < 0) 3880 return err; 3881 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && 3882 ! spec->autocfg.hp_pin) 3883 return 0; /* can't find valid BIOS pin config */ 3884 if ((err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || 3885 (err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) 3886 return err; 3887 3888 spec->multiout.max_channels = spec->multiout.num_dacs * 2; 3889 3890 if (spec->autocfg.dig_out_pin) 3891 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID; 3892 if (spec->autocfg.dig_in_pin) 3893 spec->dig_in_nid = ALC262_DIGIN_NID; 3894 3895 if (spec->kctl_alloc) 3896 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 3897 3898 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs; 3899 spec->input_mux = &spec->private_imux; 3900 3901 return 1; 3902} 3903 3904#define alc262_auto_init_multi_out alc882_auto_init_multi_out 3905#define alc262_auto_init_hp_out alc882_auto_init_hp_out 3906#define alc262_auto_init_analog_input alc882_auto_init_analog_input 3907 3908 3909/* init callback for auto-configuration model -- overriding the default init */ 3910static int alc262_auto_init(struct hda_codec *codec) 3911{ 3912 alc_init(codec); 3913 alc262_auto_init_multi_out(codec); 3914 alc262_auto_init_hp_out(codec); 3915 alc262_auto_init_analog_input(codec); 3916 return 0; 3917} 3918 3919/* 3920 * configuration and preset 3921 */ 3922static struct hda_board_config alc262_cfg_tbl[] = { 3923 { .modelname = "basic", .config = ALC262_BASIC }, 3924 { .modelname = "auto", .config = ALC262_AUTO }, 3925 {} 3926}; 3927 3928static struct alc_config_preset alc262_presets[] = { 3929 [ALC262_BASIC] = { 3930 .mixers = { alc262_base_mixer }, 3931 .init_verbs = { alc262_init_verbs }, 3932 .num_dacs = ARRAY_SIZE(alc262_dac_nids), 3933 .dac_nids = alc262_dac_nids, 3934 .hp_nid = 0x03, 3935 .num_channel_mode = ARRAY_SIZE(alc262_modes), 3936 .channel_mode = alc262_modes, 3937 .input_mux = &alc262_capture_source, 3938 }, 3939}; 3940 3941static int patch_alc262(struct hda_codec *codec) 3942{ 3943 struct alc_spec *spec; 3944 int board_config; 3945 int err; 3946 3947 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 3948 if (spec == NULL) 3949 return -ENOMEM; 3950 3951 codec->spec = spec; 3952#if 0 3953 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is under-run */ 3954 { 3955 int tmp; 3956 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); 3957 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); 3958 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); 3959 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); 3960 } 3961#endif 3962 3963 board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl); 3964 if (board_config < 0 || board_config >= ALC262_MODEL_LAST) { 3965 printk(KERN_INFO "hda_codec: Unknown model for ALC262, trying auto-probe from BIOS...\n"); 3966 board_config = ALC262_AUTO; 3967 } 3968 3969 if (board_config == ALC262_AUTO) { 3970 /* automatic parse from the BIOS config */ 3971 err = alc262_parse_auto_config(codec); 3972 if (err < 0) { 3973 alc_free(codec); 3974 return err; 3975 } else if (! err) { 3976 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); 3977 board_config = ALC262_BASIC; 3978 } 3979 } 3980 3981 if (board_config != ALC262_AUTO) 3982 setup_preset(spec, &alc262_presets[board_config]); 3983 3984 spec->stream_name_analog = "ALC262 Analog"; 3985 spec->stream_analog_playback = &alc262_pcm_analog_playback; 3986 spec->stream_analog_capture = &alc262_pcm_analog_capture; 3987 3988 spec->stream_name_digital = "ALC262 Digital"; 3989 spec->stream_digital_playback = &alc262_pcm_digital_playback; 3990 spec->stream_digital_capture = &alc262_pcm_digital_capture; 3991 3992 if (! spec->adc_nids && spec->input_mux) { 3993 /* check whether NID 0x07 is valid */ 3994 unsigned int wcap = snd_hda_param_read(codec, 0x07, 3995 AC_PAR_AUDIO_WIDGET_CAP); 3996 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ 3997 if (wcap != AC_WID_AUD_IN) { 3998 spec->adc_nids = alc262_adc_nids_alt; 3999 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt); 4000 spec->mixers[spec->num_mixers] = alc262_capture_alt_mixer; 4001 spec->num_mixers++; 4002 } else { 4003 spec->adc_nids = alc262_adc_nids; 4004 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids); 4005 spec->mixers[spec->num_mixers] = alc262_capture_mixer; 4006 spec->num_mixers++; 4007 } 4008 } 4009 4010 codec->patch_ops = alc_patch_ops; 4011 if (board_config == ALC262_AUTO) 4012 codec->patch_ops.init = alc262_auto_init; 4013 4014 return 0; 4015} 4016 4017 4018/* 4019 * ALC861 channel source setting (2/6 channel selection for 3-stack) 4020 */ 4021 4022/* 4023 * set the path ways for 2 channel output 4024 * need to set the codec line out and mic 1 pin widgets to inputs 4025 */ 4026static struct hda_verb alc861_threestack_ch2_init[] = { 4027 /* set pin widget 1Ah (line in) for input */ 4028 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, 4029 /* set pin widget 18h (mic1/2) for input, for mic also enable the vref */ 4030 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 4031 4032 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, 4033 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, //mic 4034 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, //line in 4035 { } /* end */ 4036}; 4037/* 4038 * 6ch mode 4039 * need to set the codec line out and mic 1 pin widgets to outputs 4040 */ 4041static struct hda_verb alc861_threestack_ch6_init[] = { 4042 /* set pin widget 1Ah (line in) for output (Back Surround)*/ 4043 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4044 /* set pin widget 18h (mic1) for output (CLFE)*/ 4045 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4046 4047 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4048 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4049 4050 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, 4051 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, //mic 4052 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, //line in 4053 { } /* end */ 4054}; 4055 4056static struct hda_channel_mode alc861_threestack_modes[2] = { 4057 { 2, alc861_threestack_ch2_init }, 4058 { 6, alc861_threestack_ch6_init }, 4059}; 4060 4061/* patch-ALC861 */ 4062 4063static struct snd_kcontrol_new alc861_base_mixer[] = { 4064 /* output mixer control */ 4065 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), 4066 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), 4067 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), 4068 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), 4069 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), 4070 4071 /*Input mixer control */ 4072 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), 4073 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ 4074 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), 4075 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), 4076 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), 4077 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), 4078 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), 4079 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), 4080 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), 4081 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), 4082 4083 /* Capture mixer control */ 4084 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 4085 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 4086 { 4087 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4088 .name = "Capture Source", 4089 .count = 1, 4090 .info = alc_mux_enum_info, 4091 .get = alc_mux_enum_get, 4092 .put = alc_mux_enum_put, 4093 }, 4094 { } /* end */ 4095}; 4096 4097static struct snd_kcontrol_new alc861_3ST_mixer[] = { 4098 /* output mixer control */ 4099 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), 4100 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), 4101 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), 4102 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), 4103 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ 4104 4105 /* Input mixer control */ 4106 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), 4107 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ 4108 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), 4109 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), 4110 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), 4111 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), 4112 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), 4113 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), 4114 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), 4115 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), 4116 4117 /* Capture mixer control */ 4118 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 4119 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 4120 { 4121 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4122 .name = "Capture Source", 4123 .count = 1, 4124 .info = alc_mux_enum_info, 4125 .get = alc_mux_enum_get, 4126 .put = alc_mux_enum_put, 4127 }, 4128 { 4129 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4130 .name = "Channel Mode", 4131 .info = alc_ch_mode_info, 4132 .get = alc_ch_mode_get, 4133 .put = alc_ch_mode_put, 4134 .private_value = ARRAY_SIZE(alc861_threestack_modes), 4135 }, 4136 { } /* end */ 4137}; 4138 4139/* 4140 * generic initialization of ADC, input mixers and output mixers 4141 */ 4142static struct hda_verb alc861_base_init_verbs[] = { 4143 /* 4144 * Unmute ADC0 and set the default input to mic-in 4145 */ 4146 /* port-A for surround (rear panel) */ 4147 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4148 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4149 /* port-B for mic-in (rear panel) with vref */ 4150 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 4151 /* port-C for line-in (rear panel) */ 4152 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, 4153 /* port-D for Front */ 4154 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4155 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4156 /* port-E for HP out (front panel) */ 4157 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, 4158 /* route front PCM to HP */ 4159 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, 4160 /* port-F for mic-in (front panel) with vref */ 4161 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 4162 /* port-G for CLFE (rear panel) */ 4163 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4164 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4165 /* port-H for side (rear panel) */ 4166 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4167 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4168 /* CD-in */ 4169 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, 4170 /* route front mic to ADC1*/ 4171 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 4172 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4173 4174 /* Unmute DAC0~3 & spdif out*/ 4175 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4176 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4177 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4178 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4179 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4180 4181 /* Unmute Mixer 14 (mic) 1c (Line in)*/ 4182 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4183 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4184 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4185 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4186 4187 /* Unmute Stereo Mixer 15 */ 4188 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4189 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4190 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4191 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step 4192 4193 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4194 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4195 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4196 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4197 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4198 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4199 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4200 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4201 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front) 4202 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4203 4204 { } 4205}; 4206 4207static struct hda_verb alc861_threestack_init_verbs[] = { 4208 /* 4209 * Unmute ADC0 and set the default input to mic-in 4210 */ 4211 /* port-A for surround (rear panel) */ 4212 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, 4213 /* port-B for mic-in (rear panel) with vref */ 4214 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 4215 /* port-C for line-in (rear panel) */ 4216 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, 4217 /* port-D for Front */ 4218 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4219 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4220 /* port-E for HP out (front panel) */ 4221 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, 4222 /* route front PCM to HP */ 4223 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, 4224 /* port-F for mic-in (front panel) with vref */ 4225 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 4226 /* port-G for CLFE (rear panel) */ 4227 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, 4228 /* port-H for side (rear panel) */ 4229 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, 4230 /* CD-in */ 4231 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, 4232 /* route front mic to ADC1*/ 4233 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 4234 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4235 /* Unmute DAC0~3 & spdif out*/ 4236 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4237 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4238 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4239 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4240 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4241 4242 /* Unmute Mixer 14 (mic) 1c (Line in)*/ 4243 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4244 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4245 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4246 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4247 4248 /* Unmute Stereo Mixer 15 */ 4249 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4250 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4251 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4252 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step 4253 4254 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4255 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4256 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4257 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4258 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4259 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4260 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4261 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4262 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front) 4263 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4264 { } 4265}; 4266/* 4267 * generic initialization of ADC, input mixers and output mixers 4268 */ 4269static struct hda_verb alc861_auto_init_verbs[] = { 4270 /* 4271 * Unmute ADC0 and set the default input to mic-in 4272 */ 4273// {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 4274 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4275 4276 /* Unmute DAC0~3 & spdif out*/ 4277 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 4278 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 4279 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 4280 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 4281 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4282 4283 /* Unmute Mixer 14 (mic) 1c (Line in)*/ 4284 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4285 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4286 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4287 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4288 4289 /* Unmute Stereo Mixer 15 */ 4290 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4291 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4292 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4293 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, 4294 4295 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4296 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4297 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4298 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4299 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4300 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4301 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4302 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4303 4304 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 4305 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 4306 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4307 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 4308 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 4309 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 4310 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4311 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 4312 4313 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, // set Mic 1 4314 4315 { } 4316}; 4317 4318/* pcm configuration: identiacal with ALC880 */ 4319#define alc861_pcm_analog_playback alc880_pcm_analog_playback 4320#define alc861_pcm_analog_capture alc880_pcm_analog_capture 4321#define alc861_pcm_digital_playback alc880_pcm_digital_playback 4322#define alc861_pcm_digital_capture alc880_pcm_digital_capture 4323 4324 4325#define ALC861_DIGOUT_NID 0x07 4326 4327static struct hda_channel_mode alc861_8ch_modes[1] = { 4328 { 8, NULL } 4329}; 4330 4331static hda_nid_t alc861_dac_nids[4] = { 4332 /* front, surround, clfe, side */ 4333 0x03, 0x06, 0x05, 0x04 4334}; 4335 4336static hda_nid_t alc861_adc_nids[1] = { 4337 /* ADC0-2 */ 4338 0x08, 4339}; 4340 4341static struct hda_input_mux alc861_capture_source = { 4342 .num_items = 5, 4343 .items = { 4344 { "Mic", 0x0 }, 4345 { "Front Mic", 0x3 }, 4346 { "Line", 0x1 }, 4347 { "CD", 0x4 }, 4348 { "Mixer", 0x5 }, 4349 }, 4350}; 4351 4352/* fill in the dac_nids table from the parsed pin configuration */ 4353static int alc861_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 4354{ 4355 int i; 4356 hda_nid_t nid; 4357 4358 spec->multiout.dac_nids = spec->private_dac_nids; 4359 for (i = 0; i < cfg->line_outs; i++) { 4360 nid = cfg->line_out_pins[i]; 4361 if (nid) { 4362 if (i >= ARRAY_SIZE(alc861_dac_nids)) 4363 continue; 4364 spec->multiout.dac_nids[i] = alc861_dac_nids[i]; 4365 } 4366 } 4367 spec->multiout.num_dacs = cfg->line_outs; 4368 return 0; 4369} 4370 4371/* add playback controls from the parsed DAC table */ 4372static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec, 4373 const struct auto_pin_cfg *cfg) 4374{ 4375 char name[32]; 4376 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; 4377 hda_nid_t nid; 4378 int i, idx, err; 4379 4380 for (i = 0; i < cfg->line_outs; i++) { 4381 nid = spec->multiout.dac_nids[i]; 4382 if (! nid) 4383 continue; 4384 if (nid == 0x05) { 4385 /* Center/LFE */ 4386 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch", 4387 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) 4388 return err; 4389 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch", 4390 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) 4391 return err; 4392 } else { 4393 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1; idx++) 4394 if (nid == alc861_dac_nids[idx]) 4395 break; 4396 sprintf(name, "%s Playback Switch", chname[idx]); 4397 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, 4398 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 4399 return err; 4400 } 4401 } 4402 return 0; 4403} 4404 4405static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) 4406{ 4407 int err; 4408 hda_nid_t nid; 4409 4410 if (! pin) 4411 return 0; 4412 4413 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) { 4414 nid = 0x03; 4415 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", 4416 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 4417 return err; 4418 spec->multiout.hp_nid = nid; 4419 } 4420 return 0; 4421} 4422 4423/* create playback/capture controls for input pins */ 4424static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 4425{ 4426 static char *labels[AUTO_PIN_LAST] = { 4427 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" 4428 }; 4429 struct hda_input_mux *imux = &spec->private_imux; 4430 int i, err, idx, idx1; 4431 4432 for (i = 0; i < AUTO_PIN_LAST; i++) { 4433 switch(cfg->input_pins[i]) { 4434 case 0x0c: 4435 idx1 = 1; 4436 idx = 2; // Line In 4437 break; 4438 case 0x0f: 4439 idx1 = 2; 4440 idx = 2; // Line In 4441 break; 4442 case 0x0d: 4443 idx1 = 0; 4444 idx = 1; // Mic In 4445 break; 4446 case 0x10: 4447 idx1 = 3; 4448 idx = 1; // Mic In 4449 break; 4450 case 0x11: 4451 idx1 = 4; 4452 idx = 0; // CD 4453 break; 4454 default: 4455 continue; 4456 } 4457 4458 err = new_analog_input(spec, cfg->input_pins[i], labels[i], idx, 0x15); 4459 if (err < 0) 4460 return err; 4461 4462 imux->items[imux->num_items].label = labels[i]; 4463 imux->items[imux->num_items].index = idx1; 4464 imux->num_items++; 4465 } 4466 return 0; 4467} 4468 4469static struct snd_kcontrol_new alc861_capture_mixer[] = { 4470 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 4471 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 4472 4473 { 4474 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4475 /* The multiple "Capture Source" controls confuse alsamixer 4476 * So call somewhat different.. 4477 *FIXME: the controls appear in the "playback" view! 4478 */ 4479 /* .name = "Capture Source", */ 4480 .name = "Input Source", 4481 .count = 1, 4482 .info = alc_mux_enum_info, 4483 .get = alc_mux_enum_get, 4484 .put = alc_mux_enum_put, 4485 }, 4486 { } /* end */ 4487}; 4488 4489static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, 4490 int pin_type, int dac_idx) 4491{ 4492 /* set as output */ 4493 4494 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); 4495 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 4496 4497} 4498 4499static void alc861_auto_init_multi_out(struct hda_codec *codec) 4500{ 4501 struct alc_spec *spec = codec->spec; 4502 int i; 4503 4504 for (i = 0; i < spec->autocfg.line_outs; i++) { 4505 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 4506 if (nid) 4507 alc861_auto_set_output_and_unmute(codec, nid, PIN_OUT, spec->multiout.dac_nids[i]); 4508 } 4509} 4510 4511static void alc861_auto_init_hp_out(struct hda_codec *codec) 4512{ 4513 struct alc_spec *spec = codec->spec; 4514 hda_nid_t pin; 4515 4516 pin = spec->autocfg.hp_pin; 4517 if (pin) /* connect to front */ 4518 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]); 4519} 4520 4521static void alc861_auto_init_analog_input(struct hda_codec *codec) 4522{ 4523 struct alc_spec *spec = codec->spec; 4524 int i; 4525 4526 for (i = 0; i < AUTO_PIN_LAST; i++) { 4527 hda_nid_t nid = spec->autocfg.input_pins[i]; 4528 if ((nid>=0x0c) && (nid <=0x11)) { 4529 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 4530 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); 4531 } 4532 } 4533} 4534 4535/* parse the BIOS configuration and set up the alc_spec */ 4536/* return 1 if successful, 0 if the proper config is not found, or a negative error code */ 4537static int alc861_parse_auto_config(struct hda_codec *codec) 4538{ 4539 struct alc_spec *spec = codec->spec; 4540 int err; 4541 static hda_nid_t alc861_ignore[] = { 0x1d, 0 }; 4542 4543 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, 4544 alc861_ignore)) < 0) 4545 return err; 4546 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && 4547 ! spec->autocfg.hp_pin) 4548 return 0; /* can't find valid BIOS pin config */ 4549 4550 if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || 4551 (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || 4552 (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || 4553 (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) 4554 return err; 4555 4556 spec->multiout.max_channels = spec->multiout.num_dacs * 2; 4557 4558 if (spec->autocfg.dig_out_pin) 4559 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; 4560 4561 if (spec->kctl_alloc) 4562 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 4563 4564 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs; 4565 4566 spec->input_mux = &spec->private_imux; 4567 4568 spec->adc_nids = alc861_adc_nids; 4569 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); 4570 spec->mixers[spec->num_mixers] = alc861_capture_mixer; 4571 spec->num_mixers++; 4572 4573 return 1; 4574} 4575 4576/* init callback for auto-configuration model -- overriding the default init */ 4577static int alc861_auto_init(struct hda_codec *codec) 4578{ 4579 alc_init(codec); 4580 alc861_auto_init_multi_out(codec); 4581 alc861_auto_init_hp_out(codec); 4582 alc861_auto_init_analog_input(codec); 4583 4584 return 0; 4585} 4586 4587 4588/* 4589 * configuration and preset 4590 */ 4591static struct hda_board_config alc861_cfg_tbl[] = { 4592 { .modelname = "3stack", .config = ALC861_3ST }, 4593 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, .config = ALC861_3ST }, 4594 { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, 4595 { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, 4596 { .modelname = "auto", .config = ALC861_AUTO }, 4597 {} 4598}; 4599 4600static struct alc_config_preset alc861_presets[] = { 4601 [ALC861_3ST] = { 4602 .mixers = { alc861_3ST_mixer }, 4603 .init_verbs = { alc861_threestack_init_verbs }, 4604 .num_dacs = ARRAY_SIZE(alc861_dac_nids), 4605 .dac_nids = alc861_dac_nids, 4606 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), 4607 .channel_mode = alc861_threestack_modes, 4608 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), 4609 .adc_nids = alc861_adc_nids, 4610 .input_mux = &alc861_capture_source, 4611 }, 4612 [ALC861_3ST_DIG] = { 4613 .mixers = { alc861_base_mixer }, 4614 .init_verbs = { alc861_threestack_init_verbs }, 4615 .num_dacs = ARRAY_SIZE(alc861_dac_nids), 4616 .dac_nids = alc861_dac_nids, 4617 .dig_out_nid = ALC861_DIGOUT_NID, 4618 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), 4619 .channel_mode = alc861_threestack_modes, 4620 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), 4621 .adc_nids = alc861_adc_nids, 4622 .input_mux = &alc861_capture_source, 4623 }, 4624 [ALC861_6ST_DIG] = { 4625 .mixers = { alc861_base_mixer }, 4626 .init_verbs = { alc861_base_init_verbs }, 4627 .num_dacs = ARRAY_SIZE(alc861_dac_nids), 4628 .dac_nids = alc861_dac_nids, 4629 .dig_out_nid = ALC861_DIGOUT_NID, 4630 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes), 4631 .channel_mode = alc861_8ch_modes, 4632 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), 4633 .adc_nids = alc861_adc_nids, 4634 .input_mux = &alc861_capture_source, 4635 }, 4636}; 4637 4638 4639static int patch_alc861(struct hda_codec *codec) 4640{ 4641 struct alc_spec *spec; 4642 int board_config; 4643 int err; 4644 4645 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 4646 if (spec == NULL) 4647 return -ENOMEM; 4648 4649 codec->spec = spec; 4650 4651 board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl); 4652 if (board_config < 0 || board_config >= ALC861_MODEL_LAST) { 4653 printk(KERN_INFO "hda_codec: Unknown model for ALC861, trying auto-probe from BIOS...\n"); 4654 board_config = ALC861_AUTO; 4655 } 4656 4657 if (board_config == ALC861_AUTO) { 4658 /* automatic parse from the BIOS config */ 4659 err = alc861_parse_auto_config(codec); 4660 if (err < 0) { 4661 alc_free(codec); 4662 return err; 4663 } else if (! err) { 4664 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); 4665 board_config = ALC861_3ST_DIG; 4666 } 4667 } 4668 4669 if (board_config != ALC861_AUTO) 4670 setup_preset(spec, &alc861_presets[board_config]); 4671 4672 spec->stream_name_analog = "ALC861 Analog"; 4673 spec->stream_analog_playback = &alc861_pcm_analog_playback; 4674 spec->stream_analog_capture = &alc861_pcm_analog_capture; 4675 4676 spec->stream_name_digital = "ALC861 Digital"; 4677 spec->stream_digital_playback = &alc861_pcm_digital_playback; 4678 spec->stream_digital_capture = &alc861_pcm_digital_capture; 4679 4680 codec->patch_ops = alc_patch_ops; 4681 if (board_config == ALC861_AUTO) 4682 codec->patch_ops.init = alc861_auto_init; 4683 4684 return 0; 4685} 4686 4687/* 4688 * patch entries 4689 */ 4690struct hda_codec_preset snd_hda_preset_realtek[] = { 4691 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, 4692 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, 4693 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, 4694 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, 4695 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, 4696 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, 4697 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 }, 4698 {} /* terminator */ 4699}; 4700