patch_realtek.c revision c5f2ea08fbd8911e2c975094780d2b16e65f27e0
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/* 2682 * for BIOS auto-configuration 2683 */ 2684 2685static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid, 2686 const char *pfx) 2687{ 2688 hda_nid_t nid_vol; 2689 unsigned long vol_val, sw_val; 2690 char name[32]; 2691 int err; 2692 2693 if (nid >= 0x0f && nid < 0x11) { 2694 nid_vol = nid - 0x7; 2695 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); 2696 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2697 } else if (nid == 0x11) { 2698 nid_vol = nid - 0x7; 2699 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT); 2700 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); 2701 } else if (nid >= 0x12 && nid <= 0x15) { 2702 nid_vol = 0x08; 2703 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); 2704 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2705 } else 2706 return 0; /* N/A */ 2707 2708 snprintf(name, sizeof(name), "%s Playback Volume", pfx); 2709 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val)) < 0) 2710 return err; 2711 snprintf(name, sizeof(name), "%s Playback Switch", pfx); 2712 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val)) < 0) 2713 return err; 2714 return 1; 2715} 2716 2717/* add playback controls from the parsed DAC table */ 2718static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, 2719 const struct auto_pin_cfg *cfg) 2720{ 2721 hda_nid_t nid; 2722 int err; 2723 2724 spec->multiout.num_dacs = 1; 2725 spec->multiout.dac_nids = spec->private_dac_nids; 2726 spec->multiout.dac_nids[0] = 0x02; 2727 2728 nid = cfg->line_out_pins[0]; 2729 if (nid) { 2730 err = alc260_add_playback_controls(spec, nid, "Front"); 2731 if (err < 0) 2732 return err; 2733 } 2734 2735 nid = cfg->speaker_pin; 2736 if (nid) { 2737 err = alc260_add_playback_controls(spec, nid, "Speaker"); 2738 if (err < 0) 2739 return err; 2740 } 2741 2742 nid = cfg->hp_pin; 2743 if (nid) { 2744 err = alc260_add_playback_controls(spec, nid, "Headphone"); 2745 if (err < 0) 2746 return err; 2747 } 2748 return 0; 2749} 2750 2751/* create playback/capture controls for input pins */ 2752static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec, 2753 const struct auto_pin_cfg *cfg) 2754{ 2755 static char *labels[AUTO_PIN_LAST] = { 2756 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" 2757 }; 2758 struct hda_input_mux *imux = &spec->private_imux; 2759 int i, err, idx; 2760 2761 for (i = 0; i < AUTO_PIN_LAST; i++) { 2762 if (cfg->input_pins[i] >= 0x12) { 2763 idx = cfg->input_pins[i] - 0x12; 2764 err = new_analog_input(spec, cfg->input_pins[i], labels[i], idx, 0x07); 2765 if (err < 0) 2766 return err; 2767 imux->items[imux->num_items].label = labels[i]; 2768 imux->items[imux->num_items].index = idx; 2769 imux->num_items++; 2770 } 2771 if ((cfg->input_pins[i] >= 0x0f) && (cfg->input_pins[i] <= 0x10)){ 2772 idx = cfg->input_pins[i] - 0x09; 2773 err = new_analog_input(spec, cfg->input_pins[i], labels[i], idx, 0x07); 2774 if (err < 0) 2775 return err; 2776 imux->items[imux->num_items].label = labels[i]; 2777 imux->items[imux->num_items].index = idx; 2778 imux->num_items++; 2779 } 2780 } 2781 return 0; 2782} 2783 2784static void alc260_auto_set_output_and_unmute(struct hda_codec *codec, 2785 hda_nid_t nid, int pin_type, 2786 int sel_idx) 2787{ 2788 /* set as output */ 2789 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); 2790 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 2791 /* need the manual connection? */ 2792 if (nid >= 0x12) { 2793 int idx = nid - 0x12; 2794 snd_hda_codec_write(codec, idx + 0x0b, 0, 2795 AC_VERB_SET_CONNECT_SEL, sel_idx); 2796 2797 } 2798} 2799 2800static void alc260_auto_init_multi_out(struct hda_codec *codec) 2801{ 2802 struct alc_spec *spec = codec->spec; 2803 hda_nid_t nid; 2804 2805 nid = spec->autocfg.line_out_pins[0]; 2806 if (nid) 2807 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); 2808 2809 nid = spec->autocfg.speaker_pin; 2810 if (nid) 2811 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); 2812 2813 nid = spec->autocfg.hp_pin; 2814 if (nid) 2815 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); 2816} 2817 2818#define ALC260_PIN_CD_NID 0x16 2819static void alc260_auto_init_analog_input(struct hda_codec *codec) 2820{ 2821 struct alc_spec *spec = codec->spec; 2822 int i; 2823 2824 for (i = 0; i < AUTO_PIN_LAST; i++) { 2825 hda_nid_t nid = spec->autocfg.input_pins[i]; 2826 if (nid >= 0x12) { 2827 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 2828 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); 2829 if (nid != ALC260_PIN_CD_NID) 2830 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 2831 AMP_OUT_MUTE); 2832 } 2833 } 2834} 2835 2836/* 2837 * generic initialization of ADC, input mixers and output mixers 2838 */ 2839static struct hda_verb alc260_volume_init_verbs[] = { 2840 /* 2841 * Unmute ADC0-1 and set the default input to mic-in 2842 */ 2843 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, 2844 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2845 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, 2846 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2847 2848 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 2849 * mixer widget 2850 * Note: PASD motherboards uses the Line In 2 as the input for front panel 2851 * mic (mic 2) 2852 */ 2853 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ 2854 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2855 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 2856 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 2857 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 2858 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 2859 2860 /* 2861 * Set up output mixers (0x08 - 0x0a) 2862 */ 2863 /* set vol=0 to output mixers */ 2864 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2865 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2866 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2867 /* set up input amps for analog loopback */ 2868 /* Amp Indices: DAC = 0, mixer = 1 */ 2869 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2870 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 2871 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2872 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 2873 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2874 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 2875 2876 { } 2877}; 2878 2879static int alc260_parse_auto_config(struct hda_codec *codec) 2880{ 2881 struct alc_spec *spec = codec->spec; 2882 unsigned int wcap; 2883 int err; 2884 static hda_nid_t alc260_ignore[] = { 0x17, 0 }; 2885 2886 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, 2887 alc260_ignore)) < 0) 2888 return err; 2889 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && 2890 ! spec->autocfg.hp_pin) 2891 return 0; /* can't find valid BIOS pin config */ 2892 if ((err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || 2893 (err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) 2894 return err; 2895 2896 spec->multiout.max_channels = 2; 2897 2898 if (spec->autocfg.dig_out_pin) 2899 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; 2900 if (spec->kctl_alloc) 2901 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 2902 2903 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs; 2904 2905 spec->input_mux = &spec->private_imux; 2906 2907 /* check whether NID 0x04 is valid */ 2908 wcap = snd_hda_param_read(codec, alc260_adc_nids[0], AC_PAR_AUDIO_WIDGET_CAP); 2909 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ 2910 if (wcap != AC_WID_AUD_IN) { 2911 spec->adc_nids = alc260_adc_nids_alt; 2912 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); 2913 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer; 2914 spec->num_mixers++; 2915 } else { 2916 spec->adc_nids = alc260_adc_nids; 2917 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); 2918 spec->mixers[spec->num_mixers] = alc260_capture_mixer; 2919 spec->num_mixers++; 2920 } 2921 2922 return 1; 2923} 2924 2925/* init callback for auto-configuration model -- overriding the default init */ 2926static int alc260_auto_init(struct hda_codec *codec) 2927{ 2928 alc_init(codec); 2929 alc260_auto_init_multi_out(codec); 2930 alc260_auto_init_analog_input(codec); 2931 return 0; 2932} 2933 2934/* 2935 * ALC260 configurations 2936 */ 2937static struct hda_board_config alc260_cfg_tbl[] = { 2938 { .modelname = "basic", .config = ALC260_BASIC }, 2939 { .modelname = "hp", .config = ALC260_HP }, 2940 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP }, 2941 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, 2942 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP }, 2943 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 }, 2944 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP }, 2945 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP }, 2946 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP }, 2947 { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X }, 2948 { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X }, 2949 { .modelname = "auto", .config = ALC260_AUTO }, 2950 {} 2951}; 2952 2953static struct alc_config_preset alc260_presets[] = { 2954 [ALC260_BASIC] = { 2955 .mixers = { alc260_base_output_mixer, 2956 alc260_input_mixer, 2957 alc260_pc_beep_mixer, 2958 alc260_capture_mixer }, 2959 .init_verbs = { alc260_init_verbs }, 2960 .num_dacs = ARRAY_SIZE(alc260_dac_nids), 2961 .dac_nids = alc260_dac_nids, 2962 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), 2963 .adc_nids = alc260_adc_nids, 2964 .num_channel_mode = ARRAY_SIZE(alc260_modes), 2965 .channel_mode = alc260_modes, 2966 .input_mux = &alc260_capture_source, 2967 }, 2968 [ALC260_HP] = { 2969 .mixers = { alc260_base_output_mixer, 2970 alc260_input_mixer, 2971 alc260_capture_alt_mixer }, 2972 .init_verbs = { alc260_hp_init_verbs }, 2973 .num_dacs = ARRAY_SIZE(alc260_dac_nids), 2974 .dac_nids = alc260_dac_nids, 2975 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), 2976 .adc_nids = alc260_hp_adc_nids, 2977 .num_channel_mode = ARRAY_SIZE(alc260_modes), 2978 .channel_mode = alc260_modes, 2979 .input_mux = &alc260_capture_source, 2980 }, 2981 [ALC260_HP_3013] = { 2982 .mixers = { alc260_hp_3013_mixer, 2983 alc260_input_mixer, 2984 alc260_capture_alt_mixer }, 2985 .init_verbs = { alc260_hp_3013_init_verbs }, 2986 .num_dacs = ARRAY_SIZE(alc260_dac_nids), 2987 .dac_nids = alc260_dac_nids, 2988 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), 2989 .adc_nids = alc260_hp_adc_nids, 2990 .num_channel_mode = ARRAY_SIZE(alc260_modes), 2991 .channel_mode = alc260_modes, 2992 .input_mux = &alc260_capture_source, 2993 }, 2994 [ALC260_FUJITSU_S702X] = { 2995 .mixers = { alc260_fujitsu_mixer, 2996 alc260_capture_mixer }, 2997 .init_verbs = { alc260_fujitsu_init_verbs }, 2998 .num_dacs = ARRAY_SIZE(alc260_dac_nids), 2999 .dac_nids = alc260_dac_nids, 3000 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), 3001 .adc_nids = alc260_adc_nids, 3002 .num_channel_mode = ARRAY_SIZE(alc260_modes), 3003 .channel_mode = alc260_modes, 3004 .input_mux = &alc260_fujitsu_capture_source, 3005 }, 3006}; 3007 3008static int patch_alc260(struct hda_codec *codec) 3009{ 3010 struct alc_spec *spec; 3011 int err, board_config; 3012 3013 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 3014 if (spec == NULL) 3015 return -ENOMEM; 3016 3017 codec->spec = spec; 3018 3019 board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); 3020 if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { 3021 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n"); 3022 board_config = ALC260_AUTO; 3023 } 3024 3025 if (board_config == ALC260_AUTO) { 3026 /* automatic parse from the BIOS config */ 3027 err = alc260_parse_auto_config(codec); 3028 if (err < 0) { 3029 alc_free(codec); 3030 return err; 3031 } else if (! err) { 3032 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); 3033 board_config = ALC260_BASIC; 3034 } 3035 } 3036 3037 if (board_config != ALC260_AUTO) 3038 setup_preset(spec, &alc260_presets[board_config]); 3039 3040 spec->stream_name_analog = "ALC260 Analog"; 3041 spec->stream_analog_playback = &alc260_pcm_analog_playback; 3042 spec->stream_analog_capture = &alc260_pcm_analog_capture; 3043 3044 codec->patch_ops = alc_patch_ops; 3045 if (board_config == ALC260_AUTO) 3046 codec->patch_ops.init = alc260_auto_init; 3047 3048 return 0; 3049} 3050 3051 3052/* 3053 * ALC882 support 3054 * 3055 * ALC882 is almost identical with ALC880 but has cleaner and more flexible 3056 * configuration. Each pin widget can choose any input DACs and a mixer. 3057 * Each ADC is connected from a mixer of all inputs. This makes possible 3058 * 6-channel independent captures. 3059 * 3060 * In addition, an independent DAC for the multi-playback (not used in this 3061 * driver yet). 3062 */ 3063#define ALC882_DIGOUT_NID 0x06 3064#define ALC882_DIGIN_NID 0x0a 3065 3066static struct hda_channel_mode alc882_ch_modes[1] = { 3067 { 8, NULL } 3068}; 3069 3070static hda_nid_t alc882_dac_nids[4] = { 3071 /* front, rear, clfe, rear_surr */ 3072 0x02, 0x03, 0x04, 0x05 3073}; 3074 3075/* identical with ALC880 */ 3076#define alc882_adc_nids alc880_adc_nids 3077#define alc882_adc_nids_alt alc880_adc_nids_alt 3078 3079/* input MUX */ 3080/* FIXME: should be a matrix-type input source selection */ 3081 3082static struct hda_input_mux alc882_capture_source = { 3083 .num_items = 4, 3084 .items = { 3085 { "Mic", 0x0 }, 3086 { "Front Mic", 0x1 }, 3087 { "Line", 0x2 }, 3088 { "CD", 0x4 }, 3089 }, 3090}; 3091 3092#define alc882_mux_enum_info alc_mux_enum_info 3093#define alc882_mux_enum_get alc_mux_enum_get 3094 3095static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 3096{ 3097 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3098 struct alc_spec *spec = codec->spec; 3099 const struct hda_input_mux *imux = spec->input_mux; 3100 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3101 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; 3102 hda_nid_t nid = capture_mixers[adc_idx]; 3103 unsigned int *cur_val = &spec->cur_mux[adc_idx]; 3104 unsigned int i, idx; 3105 3106 idx = ucontrol->value.enumerated.item[0]; 3107 if (idx >= imux->num_items) 3108 idx = imux->num_items - 1; 3109 if (*cur_val == idx && ! codec->in_resume) 3110 return 0; 3111 for (i = 0; i < imux->num_items; i++) { 3112 unsigned int v = (i == idx) ? 0x7000 : 0x7080; 3113 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 3114 v | (imux->items[i].index << 8)); 3115 } 3116 *cur_val = idx; 3117 return 1; 3118} 3119 3120/* 3121 * 6ch mode 3122 */ 3123static struct hda_verb alc882_sixstack_ch6_init[] = { 3124 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, 3125 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3126 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3127 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3128 { } /* end */ 3129}; 3130 3131/* 3132 * 8ch mode 3133 */ 3134static struct hda_verb alc882_sixstack_ch8_init[] = { 3135 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3136 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3137 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3138 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 3139 { } /* end */ 3140}; 3141 3142static struct hda_channel_mode alc882_sixstack_modes[2] = { 3143 { 6, alc882_sixstack_ch6_init }, 3144 { 8, alc882_sixstack_ch8_init }, 3145}; 3146 3147/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 3148 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b 3149 */ 3150static struct snd_kcontrol_new alc882_base_mixer[] = { 3151 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 3152 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 3153 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 3154 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 3155 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 3156 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 3157 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 3158 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), 3159 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), 3160 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), 3161 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), 3162 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 3163 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 3164 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 3165 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 3166 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 3167 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 3168 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), 3169 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), 3170 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 3171 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 3172 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), 3173 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), 3174 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), 3175 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), 3176 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), 3177 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), 3178 { 3179 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3180 /* .name = "Capture Source", */ 3181 .name = "Input Source", 3182 .count = 3, 3183 .info = alc882_mux_enum_info, 3184 .get = alc882_mux_enum_get, 3185 .put = alc882_mux_enum_put, 3186 }, 3187 { } /* end */ 3188}; 3189 3190static struct snd_kcontrol_new alc882_chmode_mixer[] = { 3191 { 3192 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3193 .name = "Channel Mode", 3194 .info = alc_ch_mode_info, 3195 .get = alc_ch_mode_get, 3196 .put = alc_ch_mode_put, 3197 }, 3198 { } /* end */ 3199}; 3200 3201static struct hda_verb alc882_init_verbs[] = { 3202 /* Front mixer: unmute input/output amp left and right (volume = 0) */ 3203 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3204 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3205 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 3206 /* Rear mixer */ 3207 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3208 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3209 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 3210 /* CLFE mixer */ 3211 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3212 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3213 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 3214 /* Side mixer */ 3215 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3216 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3217 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 3218 3219 /* Front Pin: output 0 (0x0c) */ 3220 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 3221 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 3222 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, 3223 /* Rear Pin: output 1 (0x0d) */ 3224 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 3225 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 3226 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, 3227 /* CLFE Pin: output 2 (0x0e) */ 3228 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 3229 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 3230 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, 3231 /* Side Pin: output 3 (0x0f) */ 3232 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 3233 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 3234 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, 3235 /* Mic (rear) pin: input vref at 80% */ 3236 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 3237 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 3238 /* Front Mic pin: input vref at 80% */ 3239 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 3240 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 3241 /* Line In pin: input */ 3242 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 3243 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 3244 /* Line-2 In: Headphone output (output 0 - 0x0c) */ 3245 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 3246 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 3247 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, 3248 /* CD pin widget for input */ 3249 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 3250 3251 /* FIXME: use matrix-type input source selection */ 3252 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ 3253 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ 3254 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3255 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 3256 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 3257 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 3258 /* Input mixer2 */ 3259 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3260 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 3261 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 3262 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 3263 /* Input mixer3 */ 3264 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3265 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 3266 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 3267 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 3268 /* ADC1: mute amp left and right */ 3269 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3270 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 3271 /* ADC2: mute amp left and right */ 3272 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3273 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 3274 /* ADC3: mute amp left and right */ 3275 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3276 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 3277 3278 { } 3279}; 3280 3281/* 3282 * generic initialization of ADC, input mixers and output mixers 3283 */ 3284static struct hda_verb alc882_auto_init_verbs[] = { 3285 /* 3286 * Unmute ADC0-2 and set the default input to mic-in 3287 */ 3288 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 3289 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3290 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 3291 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3292 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 3293 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3294 3295 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 3296 * mixer widget 3297 * Note: PASD motherboards uses the Line In 2 as the input for front panel 3298 * mic (mic 2) 3299 */ 3300 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ 3301 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3302 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3303 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 3304 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 3305 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 3306 3307 /* 3308 * Set up output mixers (0x0c - 0x0f) 3309 */ 3310 /* set vol=0 to output mixers */ 3311 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3312 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3313 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3314 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3315 /* set up input amps for analog loopback */ 3316 /* Amp Indices: DAC = 0, mixer = 1 */ 3317 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3318 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3319 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3320 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3321 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3322 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3323 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3324 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3325 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3326 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3327 3328 /* FIXME: use matrix-type input source selection */ 3329 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ 3330 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ 3331 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3332 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3333 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3334 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3335 /* Input mixer2 */ 3336 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3337 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3338 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3339 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3340 /* Input mixer3 */ 3341 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3342 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3343 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3344 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3345 3346 { } 3347}; 3348 3349/* capture mixer elements */ 3350static struct snd_kcontrol_new alc882_capture_alt_mixer[] = { 3351 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 3352 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 3353 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), 3354 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), 3355 { 3356 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3357 /* The multiple "Capture Source" controls confuse alsamixer 3358 * So call somewhat different.. 3359 * FIXME: the controls appear in the "playback" view! 3360 */ 3361 /* .name = "Capture Source", */ 3362 .name = "Input Source", 3363 .count = 2, 3364 .info = alc882_mux_enum_info, 3365 .get = alc882_mux_enum_get, 3366 .put = alc882_mux_enum_put, 3367 }, 3368 { } /* end */ 3369}; 3370 3371static struct snd_kcontrol_new alc882_capture_mixer[] = { 3372 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), 3373 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), 3374 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), 3375 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), 3376 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), 3377 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), 3378 { 3379 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3380 /* The multiple "Capture Source" controls confuse alsamixer 3381 * So call somewhat different.. 3382 * FIXME: the controls appear in the "playback" view! 3383 */ 3384 /* .name = "Capture Source", */ 3385 .name = "Input Source", 3386 .count = 3, 3387 .info = alc882_mux_enum_info, 3388 .get = alc882_mux_enum_get, 3389 .put = alc882_mux_enum_put, 3390 }, 3391 { } /* end */ 3392}; 3393 3394/* pcm configuration: identiacal with ALC880 */ 3395#define alc882_pcm_analog_playback alc880_pcm_analog_playback 3396#define alc882_pcm_analog_capture alc880_pcm_analog_capture 3397#define alc882_pcm_digital_playback alc880_pcm_digital_playback 3398#define alc882_pcm_digital_capture alc880_pcm_digital_capture 3399 3400/* 3401 * configuration and preset 3402 */ 3403static struct hda_board_config alc882_cfg_tbl[] = { 3404 { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, 3405 { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, 3406 { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* MSI */ 3407 { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* Foxconn */ 3408 { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* ECS */ 3409 { .modelname = "auto", .config = ALC861_AUTO }, 3410 {} 3411}; 3412 3413static struct alc_config_preset alc882_presets[] = { 3414 [ALC882_3ST_DIG] = { 3415 .mixers = { alc882_base_mixer }, 3416 .init_verbs = { alc882_init_verbs }, 3417 .num_dacs = ARRAY_SIZE(alc882_dac_nids), 3418 .dac_nids = alc882_dac_nids, 3419 .dig_out_nid = ALC882_DIGOUT_NID, 3420 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), 3421 .adc_nids = alc882_adc_nids, 3422 .dig_in_nid = ALC882_DIGIN_NID, 3423 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), 3424 .channel_mode = alc882_ch_modes, 3425 .input_mux = &alc882_capture_source, 3426 }, 3427 [ALC882_6ST_DIG] = { 3428 .mixers = { alc882_base_mixer, alc882_chmode_mixer }, 3429 .init_verbs = { alc882_init_verbs }, 3430 .num_dacs = ARRAY_SIZE(alc882_dac_nids), 3431 .dac_nids = alc882_dac_nids, 3432 .dig_out_nid = ALC882_DIGOUT_NID, 3433 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), 3434 .adc_nids = alc882_adc_nids, 3435 .dig_in_nid = ALC882_DIGIN_NID, 3436 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), 3437 .channel_mode = alc882_sixstack_modes, 3438 .input_mux = &alc882_capture_source, 3439 }, 3440}; 3441 3442 3443/* 3444 * BIOS auto configuration 3445 */ 3446static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, 3447 hda_nid_t nid, int pin_type, 3448 int dac_idx) 3449{ 3450 /* set as output */ 3451 struct alc_spec *spec = codec->spec; 3452 int idx; 3453 3454 if (spec->multiout.dac_nids[dac_idx] == 0x25) 3455 idx = 4; 3456 else 3457 idx = spec->multiout.dac_nids[dac_idx] - 2; 3458 3459 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); 3460 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 3461 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); 3462 3463} 3464 3465static void alc882_auto_init_multi_out(struct hda_codec *codec) 3466{ 3467 struct alc_spec *spec = codec->spec; 3468 int i; 3469 3470 for (i = 0; i <= HDA_SIDE; i++) { 3471 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 3472 if (nid) 3473 alc882_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); 3474 } 3475} 3476 3477static void alc882_auto_init_hp_out(struct hda_codec *codec) 3478{ 3479 struct alc_spec *spec = codec->spec; 3480 hda_nid_t pin; 3481 3482 pin = spec->autocfg.hp_pin; 3483 if (pin) /* connect to front */ 3484 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */ 3485} 3486 3487#define alc882_is_input_pin(nid) alc880_is_input_pin(nid) 3488#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID 3489 3490static void alc882_auto_init_analog_input(struct hda_codec *codec) 3491{ 3492 struct alc_spec *spec = codec->spec; 3493 int i; 3494 3495 for (i = 0; i < AUTO_PIN_LAST; i++) { 3496 hda_nid_t nid = spec->autocfg.input_pins[i]; 3497 if (alc882_is_input_pin(nid)) { 3498 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 3499 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); 3500 if (nid != ALC882_PIN_CD_NID) 3501 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 3502 AMP_OUT_MUTE); 3503 } 3504 } 3505} 3506 3507/* almost identical with ALC880 parser... */ 3508static int alc882_parse_auto_config(struct hda_codec *codec) 3509{ 3510 struct alc_spec *spec = codec->spec; 3511 int err = alc880_parse_auto_config(codec); 3512 3513 if (err < 0) 3514 return err; 3515 else if (err > 0) 3516 /* hack - override the init verbs */ 3517 spec->init_verbs[0] = alc882_auto_init_verbs; 3518 return err; 3519} 3520 3521/* init callback for auto-configuration model -- overriding the default init */ 3522static int alc882_auto_init(struct hda_codec *codec) 3523{ 3524 alc_init(codec); 3525 alc882_auto_init_multi_out(codec); 3526 alc882_auto_init_hp_out(codec); 3527 alc882_auto_init_analog_input(codec); 3528 return 0; 3529} 3530 3531/* 3532 * ALC882 Headphone poll in 3.5.1a or 3.5.2 3533 */ 3534 3535static int patch_alc882(struct hda_codec *codec) 3536{ 3537 struct alc_spec *spec; 3538 int err, board_config; 3539 3540 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 3541 if (spec == NULL) 3542 return -ENOMEM; 3543 3544 codec->spec = spec; 3545 3546 board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl); 3547 3548 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { 3549 printk(KERN_INFO "hda_codec: Unknown model for ALC882, trying auto-probe from BIOS...\n"); 3550 board_config = ALC882_AUTO; 3551 } 3552 3553 if (board_config == ALC882_AUTO) { 3554 /* automatic parse from the BIOS config */ 3555 err = alc882_parse_auto_config(codec); 3556 if (err < 0) { 3557 alc_free(codec); 3558 return err; 3559 } else if (! err) { 3560 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); 3561 board_config = ALC882_3ST_DIG; 3562 } 3563 } 3564 3565 if (board_config != ALC882_AUTO) 3566 setup_preset(spec, &alc882_presets[board_config]); 3567 3568 spec->stream_name_analog = "ALC882 Analog"; 3569 spec->stream_analog_playback = &alc882_pcm_analog_playback; 3570 spec->stream_analog_capture = &alc882_pcm_analog_capture; 3571 3572 spec->stream_name_digital = "ALC882 Digital"; 3573 spec->stream_digital_playback = &alc882_pcm_digital_playback; 3574 spec->stream_digital_capture = &alc882_pcm_digital_capture; 3575 3576 if (! spec->adc_nids && spec->input_mux) { 3577 /* check whether NID 0x07 is valid */ 3578 unsigned int wcap = snd_hda_param_read(codec, 0x07, 3579 AC_PAR_AUDIO_WIDGET_CAP); 3580 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ 3581 if (wcap != AC_WID_AUD_IN) { 3582 spec->adc_nids = alc882_adc_nids_alt; 3583 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt); 3584 spec->mixers[spec->num_mixers] = alc882_capture_alt_mixer; 3585 spec->num_mixers++; 3586 } else { 3587 spec->adc_nids = alc882_adc_nids; 3588 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); 3589 spec->mixers[spec->num_mixers] = alc882_capture_mixer; 3590 spec->num_mixers++; 3591 } 3592 } 3593 3594 codec->patch_ops = alc_patch_ops; 3595 if (board_config == ALC882_AUTO) 3596 codec->patch_ops.init = alc882_auto_init; 3597 3598 return 0; 3599} 3600 3601/* 3602 * ALC262 support 3603 */ 3604 3605#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID 3606#define ALC262_DIGIN_NID ALC880_DIGIN_NID 3607 3608#define alc262_dac_nids alc260_dac_nids 3609#define alc262_adc_nids alc882_adc_nids 3610#define alc262_adc_nids_alt alc882_adc_nids_alt 3611 3612#define alc262_modes alc260_modes 3613#define alc262_capture_source alc882_capture_source 3614 3615static struct snd_kcontrol_new alc262_base_mixer[] = { 3616 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 3617 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), 3618 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 3619 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 3620 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 3621 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 3622 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 3623 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 3624 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), 3625 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), 3626 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), 3627 HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */ 3628 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT), 3629 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), 3630 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 3631 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), 3632 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 3633 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 3634 { 3635 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3636 .name = "Capture Source", 3637 .count = 1, 3638 .info = alc882_mux_enum_info, 3639 .get = alc882_mux_enum_get, 3640 .put = alc882_mux_enum_put, 3641 }, 3642 { } /* end */ 3643}; 3644 3645#define alc262_capture_mixer alc882_capture_mixer 3646#define alc262_capture_alt_mixer alc882_capture_alt_mixer 3647 3648/* 3649 * generic initialization of ADC, input mixers and output mixers 3650 */ 3651static struct hda_verb alc262_init_verbs[] = { 3652 /* 3653 * Unmute ADC0-2 and set the default input to mic-in 3654 */ 3655 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 3656 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3657 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 3658 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3659 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 3660 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3661 3662 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 3663 * mixer widget 3664 * Note: PASD motherboards uses the Line In 2 as the input for front panel 3665 * mic (mic 2) 3666 */ 3667 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ 3668 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3669 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3670 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 3671 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 3672 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 3673 3674 /* 3675 * Set up output mixers (0x0c - 0x0e) 3676 */ 3677 /* set vol=0 to output mixers */ 3678 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3679 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3680 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3681 /* set up input amps for analog loopback */ 3682 /* Amp Indices: DAC = 0, mixer = 1 */ 3683 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3684 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3685 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3686 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3687 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3688 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3689 3690 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, 3691 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, 3692 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, 3693 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, 3694 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, 3695 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, 3696 3697 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 3698 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 3699 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 3700 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 3701 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, 3702 3703 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, 3704 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, 3705 3706 /* FIXME: use matrix-type input source selection */ 3707 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ 3708 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ 3709 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3710 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3711 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3712 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3713 /* Input mixer2 */ 3714 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3715 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3716 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3717 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3718 /* Input mixer3 */ 3719 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3720 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3721 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3722 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3723 3724 { } 3725}; 3726 3727/* add playback controls from the parsed DAC table */ 3728static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 3729{ 3730 hda_nid_t nid; 3731 int err; 3732 3733 spec->multiout.num_dacs = 1; /* only use one dac */ 3734 spec->multiout.dac_nids = spec->private_dac_nids; 3735 spec->multiout.dac_nids[0] = 2; 3736 3737 nid = cfg->line_out_pins[0]; 3738 if (nid) { 3739 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Front Playback Volume", 3740 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0) 3741 return err; 3742 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Front Playback Switch", 3743 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 3744 return err; 3745 } 3746 3747 nid = cfg->speaker_pin; 3748 if (nid) { 3749 if (nid == 0x16) { 3750 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume", 3751 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT))) < 0) 3752 return err; 3753 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch", 3754 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) 3755 return err; 3756 } else { 3757 if (! cfg->line_out_pins[0]) 3758 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume", 3759 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0) 3760 return err; 3761 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch", 3762 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 3763 return err; 3764 } 3765 } 3766 nid = cfg->hp_pin; 3767 if (nid) { 3768 /* spec->multiout.hp_nid = 2; */ 3769 if (nid == 0x16) { 3770 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", 3771 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT))) < 0) 3772 return err; 3773 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", 3774 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) 3775 return err; 3776 } else { 3777 if (! cfg->line_out_pins[0]) 3778 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", 3779 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0) 3780 return err; 3781 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", 3782 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 3783 return err; 3784 } 3785 } 3786 return 0; 3787} 3788 3789/* identical with ALC880 */ 3790#define alc262_auto_create_analog_input_ctls alc880_auto_create_analog_input_ctls 3791 3792/* 3793 * generic initialization of ADC, input mixers and output mixers 3794 */ 3795static struct hda_verb alc262_volume_init_verbs[] = { 3796 /* 3797 * Unmute ADC0-2 and set the default input to mic-in 3798 */ 3799 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 3800 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3801 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 3802 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3803 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 3804 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3805 3806 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 3807 * mixer widget 3808 * Note: PASD motherboards uses the Line In 2 as the input for front panel 3809 * mic (mic 2) 3810 */ 3811 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ 3812 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3813 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3814 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 3815 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 3816 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 3817 3818 /* 3819 * Set up output mixers (0x0c - 0x0f) 3820 */ 3821 /* set vol=0 to output mixers */ 3822 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3823 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3824 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 3825 3826 /* set up input amps for analog loopback */ 3827 /* Amp Indices: DAC = 0, mixer = 1 */ 3828 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3829 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3830 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3831 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3832 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 3833 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 3834 3835 /* FIXME: use matrix-type input source selection */ 3836 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ 3837 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ 3838 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3839 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3840 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3841 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3842 /* Input mixer2 */ 3843 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3844 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3845 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3846 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3847 /* Input mixer3 */ 3848 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, 3849 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, 3850 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, 3851 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, 3852 3853 { } 3854}; 3855 3856/* pcm configuration: identiacal with ALC880 */ 3857#define alc262_pcm_analog_playback alc880_pcm_analog_playback 3858#define alc262_pcm_analog_capture alc880_pcm_analog_capture 3859#define alc262_pcm_digital_playback alc880_pcm_digital_playback 3860#define alc262_pcm_digital_capture alc880_pcm_digital_capture 3861 3862/* 3863 * BIOS auto configuration 3864 */ 3865static int alc262_parse_auto_config(struct hda_codec *codec) 3866{ 3867 struct alc_spec *spec = codec->spec; 3868 int err; 3869 static hda_nid_t alc262_ignore[] = { 0x1d, 0 }; 3870 3871 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, 3872 alc262_ignore)) < 0) 3873 return err; 3874 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && 3875 ! spec->autocfg.hp_pin) 3876 return 0; /* can't find valid BIOS pin config */ 3877 if ((err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || 3878 (err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) 3879 return err; 3880 3881 spec->multiout.max_channels = spec->multiout.num_dacs * 2; 3882 3883 if (spec->autocfg.dig_out_pin) 3884 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID; 3885 if (spec->autocfg.dig_in_pin) 3886 spec->dig_in_nid = ALC262_DIGIN_NID; 3887 3888 if (spec->kctl_alloc) 3889 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 3890 3891 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs; 3892 spec->input_mux = &spec->private_imux; 3893 3894 return 1; 3895} 3896 3897#define alc262_auto_init_multi_out alc882_auto_init_multi_out 3898#define alc262_auto_init_hp_out alc882_auto_init_hp_out 3899#define alc262_auto_init_analog_input alc882_auto_init_analog_input 3900 3901 3902/* init callback for auto-configuration model -- overriding the default init */ 3903static int alc262_auto_init(struct hda_codec *codec) 3904{ 3905 alc_init(codec); 3906 alc262_auto_init_multi_out(codec); 3907 alc262_auto_init_hp_out(codec); 3908 alc262_auto_init_analog_input(codec); 3909 return 0; 3910} 3911 3912/* 3913 * configuration and preset 3914 */ 3915static struct hda_board_config alc262_cfg_tbl[] = { 3916 { .modelname = "basic", .config = ALC262_BASIC }, 3917 { .modelname = "auto", .config = ALC262_AUTO }, 3918 {} 3919}; 3920 3921static struct alc_config_preset alc262_presets[] = { 3922 [ALC262_BASIC] = { 3923 .mixers = { alc262_base_mixer }, 3924 .init_verbs = { alc262_init_verbs }, 3925 .num_dacs = ARRAY_SIZE(alc262_dac_nids), 3926 .dac_nids = alc262_dac_nids, 3927 .hp_nid = 0x03, 3928 .num_channel_mode = ARRAY_SIZE(alc262_modes), 3929 .channel_mode = alc262_modes, 3930 .input_mux = alc262_capture_source, 3931 }, 3932}; 3933 3934static int patch_alc262(struct hda_codec *codec) 3935{ 3936 struct alc_spec *spec; 3937 int board_config; 3938 int err; 3939 3940 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 3941 if (spec == NULL) 3942 return -ENOMEM; 3943 3944 codec->spec = spec; 3945#if 0 3946 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is under-run */ 3947 { 3948 int tmp; 3949 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); 3950 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); 3951 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); 3952 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); 3953 } 3954#endif 3955 3956 board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl); 3957 if (board_config < 0 || board_config >= ALC262_MODEL_LAST) { 3958 printk(KERN_INFO "hda_codec: Unknown model for ALC262, trying auto-probe from BIOS...\n"); 3959 board_config = ALC262_AUTO; 3960 } 3961 3962 if (board_config == ALC262_AUTO) { 3963 /* automatic parse from the BIOS config */ 3964 err = alc262_parse_auto_config(codec); 3965 if (err < 0) { 3966 alc_free(codec); 3967 return err; 3968 } else if (! err) { 3969 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); 3970 board_config = ALC262_BASIC; 3971 } 3972 } 3973 3974 if (board_config != ALC262_AUTO) 3975 setup_preset(spec, &alc262_presets[board_config]); 3976 3977 spec->stream_name_analog = "ALC262 Analog"; 3978 spec->stream_analog_playback = &alc262_pcm_analog_playback; 3979 spec->stream_analog_capture = &alc262_pcm_analog_capture; 3980 3981 spec->stream_name_digital = "ALC262 Digital"; 3982 spec->stream_digital_playback = &alc262_pcm_digital_playback; 3983 spec->stream_digital_capture = &alc262_pcm_digital_capture; 3984 3985 if (! spec->adc_nids && spec->input_mux) { 3986 /* check whether NID 0x07 is valid */ 3987 unsigned int wcap = snd_hda_param_read(codec, 0x07, 3988 AC_PAR_AUDIO_WIDGET_CAP); 3989 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ 3990 if (wcap != AC_WID_AUD_IN) { 3991 spec->adc_nids = alc262_adc_nids_alt; 3992 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt); 3993 spec->mixers[spec->num_mixers] = alc262_capture_alt_mixer; 3994 spec->num_mixers++; 3995 } else { 3996 spec->adc_nids = alc262_adc_nids; 3997 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids); 3998 spec->mixers[spec->num_mixers] = alc262_capture_mixer; 3999 spec->num_mixers++; 4000 } 4001 } 4002 4003 codec->patch_ops = alc_patch_ops; 4004 if (board_config == ALC262_AUTO) 4005 codec->patch_ops.init = alc262_auto_init; 4006 4007 return 0; 4008} 4009 4010 4011/* 4012 * ALC861 channel source setting (2/6 channel selection for 3-stack) 4013 */ 4014 4015/* 4016 * set the path ways for 2 channel output 4017 * need to set the codec line out and mic 1 pin widgets to inputs 4018 */ 4019static struct hda_verb alc861_threestack_ch2_init[] = { 4020 /* set pin widget 1Ah (line in) for input */ 4021 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, 4022 /* set pin widget 18h (mic1/2) for input, for mic also enable the vref */ 4023 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 4024 4025 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, 4026 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, //mic 4027 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, //line in 4028 { } /* end */ 4029}; 4030/* 4031 * 6ch mode 4032 * need to set the codec line out and mic 1 pin widgets to outputs 4033 */ 4034static struct hda_verb alc861_threestack_ch6_init[] = { 4035 /* set pin widget 1Ah (line in) for output (Back Surround)*/ 4036 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4037 /* set pin widget 18h (mic1) for output (CLFE)*/ 4038 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4039 4040 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4041 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4042 4043 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, 4044 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, //mic 4045 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, //line in 4046 { } /* end */ 4047}; 4048 4049static struct hda_channel_mode alc861_threestack_modes[2] = { 4050 { 2, alc861_threestack_ch2_init }, 4051 { 6, alc861_threestack_ch6_init }, 4052}; 4053 4054/* patch-ALC861 */ 4055 4056static struct snd_kcontrol_new alc861_base_mixer[] = { 4057 /* output mixer control */ 4058 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), 4059 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), 4060 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), 4061 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), 4062 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), 4063 4064 /*Input mixer control */ 4065 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), 4066 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ 4067 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), 4068 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), 4069 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), 4070 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), 4071 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), 4072 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), 4073 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), 4074 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), 4075 4076 /* Capture mixer control */ 4077 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 4078 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 4079 { 4080 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4081 .name = "Capture Source", 4082 .count = 1, 4083 .info = alc_mux_enum_info, 4084 .get = alc_mux_enum_get, 4085 .put = alc_mux_enum_put, 4086 }, 4087 { } /* end */ 4088}; 4089 4090static struct snd_kcontrol_new alc861_3ST_mixer[] = { 4091 /* output mixer control */ 4092 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), 4093 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), 4094 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), 4095 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), 4096 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ 4097 4098 /* Input mixer control */ 4099 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), 4100 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ 4101 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), 4102 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), 4103 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), 4104 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), 4105 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), 4106 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), 4107 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), 4108 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), 4109 4110 /* Capture mixer control */ 4111 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 4112 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 4113 { 4114 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4115 .name = "Capture Source", 4116 .count = 1, 4117 .info = alc_mux_enum_info, 4118 .get = alc_mux_enum_get, 4119 .put = alc_mux_enum_put, 4120 }, 4121 { 4122 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4123 .name = "Channel Mode", 4124 .info = alc_ch_mode_info, 4125 .get = alc_ch_mode_get, 4126 .put = alc_ch_mode_put, 4127 .private_value = ARRAY_SIZE(alc861_threestack_modes), 4128 }, 4129 { } /* end */ 4130}; 4131 4132/* 4133 * generic initialization of ADC, input mixers and output mixers 4134 */ 4135static struct hda_verb alc861_base_init_verbs[] = { 4136 /* 4137 * Unmute ADC0 and set the default input to mic-in 4138 */ 4139 /* port-A for surround (rear panel) */ 4140 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4141 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4142 /* port-B for mic-in (rear panel) with vref */ 4143 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 4144 /* port-C for line-in (rear panel) */ 4145 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, 4146 /* port-D for Front */ 4147 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4148 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4149 /* port-E for HP out (front panel) */ 4150 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, 4151 /* route front PCM to HP */ 4152 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, 4153 /* port-F for mic-in (front panel) with vref */ 4154 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 4155 /* port-G for CLFE (rear panel) */ 4156 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4157 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4158 /* port-H for side (rear panel) */ 4159 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4160 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4161 /* CD-in */ 4162 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, 4163 /* route front mic to ADC1*/ 4164 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 4165 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4166 4167 /* Unmute DAC0~3 & spdif out*/ 4168 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4169 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4170 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4171 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4172 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4173 4174 /* Unmute Mixer 14 (mic) 1c (Line in)*/ 4175 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4176 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4177 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4178 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4179 4180 /* Unmute Stereo Mixer 15 */ 4181 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4182 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4183 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4184 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step 4185 4186 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4187 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4188 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4189 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4190 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4191 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4192 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4193 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4194 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front) 4195 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4196 4197 { } 4198}; 4199 4200static struct hda_verb alc861_threestack_init_verbs[] = { 4201 /* 4202 * Unmute ADC0 and set the default input to mic-in 4203 */ 4204 /* port-A for surround (rear panel) */ 4205 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, 4206 /* port-B for mic-in (rear panel) with vref */ 4207 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 4208 /* port-C for line-in (rear panel) */ 4209 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, 4210 /* port-D for Front */ 4211 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, 4212 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, 4213 /* port-E for HP out (front panel) */ 4214 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, 4215 /* route front PCM to HP */ 4216 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, 4217 /* port-F for mic-in (front panel) with vref */ 4218 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 4219 /* port-G for CLFE (rear panel) */ 4220 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, 4221 /* port-H for side (rear panel) */ 4222 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, 4223 /* CD-in */ 4224 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, 4225 /* route front mic to ADC1*/ 4226 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 4227 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4228 /* Unmute DAC0~3 & spdif out*/ 4229 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4230 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4231 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4232 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4233 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4234 4235 /* Unmute Mixer 14 (mic) 1c (Line in)*/ 4236 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4237 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4238 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4239 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4240 4241 /* Unmute Stereo Mixer 15 */ 4242 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4243 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4244 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4245 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step 4246 4247 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4248 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4249 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4250 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4251 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4252 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4253 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4254 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4255 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front) 4256 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4257 { } 4258}; 4259/* 4260 * generic initialization of ADC, input mixers and output mixers 4261 */ 4262static struct hda_verb alc861_auto_init_verbs[] = { 4263 /* 4264 * Unmute ADC0 and set the default input to mic-in 4265 */ 4266// {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 4267 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4268 4269 /* Unmute DAC0~3 & spdif out*/ 4270 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 4271 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 4272 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 4273 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 4274 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 4275 4276 /* Unmute Mixer 14 (mic) 1c (Line in)*/ 4277 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4278 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4279 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4280 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4281 4282 /* Unmute Stereo Mixer 15 */ 4283 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4284 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4285 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4286 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, 4287 4288 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4289 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4290 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4291 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4292 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4293 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4294 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 4295 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 4296 4297 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 4298 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 4299 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4300 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 4301 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 4302 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 4303 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 4304 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 4305 4306 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, // set Mic 1 4307 4308 { } 4309}; 4310 4311/* pcm configuration: identiacal with ALC880 */ 4312#define alc861_pcm_analog_playback alc880_pcm_analog_playback 4313#define alc861_pcm_analog_capture alc880_pcm_analog_capture 4314#define alc861_pcm_digital_playback alc880_pcm_digital_playback 4315#define alc861_pcm_digital_capture alc880_pcm_digital_capture 4316 4317 4318#define ALC861_DIGOUT_NID 0x07 4319 4320static struct hda_channel_mode alc861_8ch_modes[1] = { 4321 { 8, NULL } 4322}; 4323 4324static hda_nid_t alc861_dac_nids[4] = { 4325 /* front, surround, clfe, side */ 4326 0x03, 0x06, 0x05, 0x04 4327}; 4328 4329static hda_nid_t alc861_adc_nids[1] = { 4330 /* ADC0-2 */ 4331 0x08, 4332}; 4333 4334static struct hda_input_mux alc861_capture_source = { 4335 .num_items = 5, 4336 .items = { 4337 { "Mic", 0x0 }, 4338 { "Front Mic", 0x3 }, 4339 { "Line", 0x1 }, 4340 { "CD", 0x4 }, 4341 { "Mixer", 0x5 }, 4342 }, 4343}; 4344 4345/* fill in the dac_nids table from the parsed pin configuration */ 4346static int alc861_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 4347{ 4348 int i; 4349 hda_nid_t nid; 4350 4351 spec->multiout.dac_nids = spec->private_dac_nids; 4352 for (i = 0; i < cfg->line_outs; i++) { 4353 nid = cfg->line_out_pins[i]; 4354 if (nid) { 4355 if (i >= ARRAY_SIZE(alc861_dac_nids)) 4356 continue; 4357 spec->multiout.dac_nids[i] = alc861_dac_nids[i]; 4358 } 4359 } 4360 spec->multiout.num_dacs = cfg->line_outs; 4361 return 0; 4362} 4363 4364/* add playback controls from the parsed DAC table */ 4365static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec, 4366 const struct auto_pin_cfg *cfg) 4367{ 4368 char name[32]; 4369 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; 4370 hda_nid_t nid; 4371 int i, idx, err; 4372 4373 for (i = 0; i < cfg->line_outs; i++) { 4374 nid = spec->multiout.dac_nids[i]; 4375 if (! nid) 4376 continue; 4377 if (nid == 0x05) { 4378 /* Center/LFE */ 4379 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch", 4380 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) 4381 return err; 4382 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch", 4383 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) 4384 return err; 4385 } else { 4386 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1; idx++) 4387 if (nid == alc861_dac_nids[idx]) 4388 break; 4389 sprintf(name, "%s Playback Switch", chname[idx]); 4390 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, 4391 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 4392 return err; 4393 } 4394 } 4395 return 0; 4396} 4397 4398static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) 4399{ 4400 int err; 4401 hda_nid_t nid; 4402 4403 if (! pin) 4404 return 0; 4405 4406 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) { 4407 nid = 0x03; 4408 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", 4409 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 4410 return err; 4411 spec->multiout.hp_nid = nid; 4412 } 4413 return 0; 4414} 4415 4416/* create playback/capture controls for input pins */ 4417static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 4418{ 4419 static char *labels[AUTO_PIN_LAST] = { 4420 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" 4421 }; 4422 struct hda_input_mux *imux = &spec->private_imux; 4423 int i, err, idx, idx1; 4424 4425 for (i = 0; i < AUTO_PIN_LAST; i++) { 4426 switch(cfg->input_pins[i]) { 4427 case 0x0c: 4428 idx1 = 1; 4429 idx = 2; // Line In 4430 break; 4431 case 0x0f: 4432 idx1 = 2; 4433 idx = 2; // Line In 4434 break; 4435 case 0x0d: 4436 idx1 = 0; 4437 idx = 1; // Mic In 4438 break; 4439 case 0x10: 4440 idx1 = 3; 4441 idx = 1; // Mic In 4442 break; 4443 case 0x11: 4444 idx1 = 4; 4445 idx = 0; // CD 4446 break; 4447 default: 4448 continue; 4449 } 4450 4451 err = new_analog_input(spec, cfg->input_pins[i], labels[i], idx, 0x15); 4452 if (err < 0) 4453 return err; 4454 4455 imux->items[imux->num_items].label = labels[i]; 4456 imux->items[imux->num_items].index = idx1; 4457 imux->num_items++; 4458 } 4459 return 0; 4460} 4461 4462static struct snd_kcontrol_new alc861_capture_mixer[] = { 4463 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 4464 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 4465 4466 { 4467 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4468 /* The multiple "Capture Source" controls confuse alsamixer 4469 * So call somewhat different.. 4470 *FIXME: the controls appear in the "playback" view! 4471 */ 4472 /* .name = "Capture Source", */ 4473 .name = "Input Source", 4474 .count = 1, 4475 .info = alc_mux_enum_info, 4476 .get = alc_mux_enum_get, 4477 .put = alc_mux_enum_put, 4478 }, 4479 { } /* end */ 4480}; 4481 4482static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, 4483 int pin_type, int dac_idx) 4484{ 4485 /* set as output */ 4486 4487 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); 4488 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 4489 4490} 4491 4492static void alc861_auto_init_multi_out(struct hda_codec *codec) 4493{ 4494 struct alc_spec *spec = codec->spec; 4495 int i; 4496 4497 for (i = 0; i < spec->autocfg.line_outs; i++) { 4498 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 4499 if (nid) 4500 alc861_auto_set_output_and_unmute(codec, nid, PIN_OUT, spec->multiout.dac_nids[i]); 4501 } 4502} 4503 4504static void alc861_auto_init_hp_out(struct hda_codec *codec) 4505{ 4506 struct alc_spec *spec = codec->spec; 4507 hda_nid_t pin; 4508 4509 pin = spec->autocfg.hp_pin; 4510 if (pin) /* connect to front */ 4511 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]); 4512} 4513 4514static void alc861_auto_init_analog_input(struct hda_codec *codec) 4515{ 4516 struct alc_spec *spec = codec->spec; 4517 int i; 4518 4519 for (i = 0; i < AUTO_PIN_LAST; i++) { 4520 hda_nid_t nid = spec->autocfg.input_pins[i]; 4521 if ((nid>=0x0c) && (nid <=0x11)) { 4522 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 4523 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); 4524 } 4525 } 4526} 4527 4528/* parse the BIOS configuration and set up the alc_spec */ 4529/* return 1 if successful, 0 if the proper config is not found, or a negative error code */ 4530static int alc861_parse_auto_config(struct hda_codec *codec) 4531{ 4532 struct alc_spec *spec = codec->spec; 4533 int err; 4534 static hda_nid_t alc861_ignore[] = { 0x1d, 0 }; 4535 4536 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, 4537 alc861_ignore)) < 0) 4538 return err; 4539 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && 4540 ! spec->autocfg.hp_pin) 4541 return 0; /* can't find valid BIOS pin config */ 4542 4543 if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || 4544 (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || 4545 (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || 4546 (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) 4547 return err; 4548 4549 spec->multiout.max_channels = spec->multiout.num_dacs * 2; 4550 4551 if (spec->autocfg.dig_out_pin) 4552 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; 4553 4554 if (spec->kctl_alloc) 4555 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 4556 4557 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs; 4558 4559 spec->input_mux = &spec->private_imux; 4560 4561 spec->adc_nids = alc861_adc_nids; 4562 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); 4563 spec->mixers[spec->num_mixers] = alc861_capture_mixer; 4564 spec->num_mixers++; 4565 4566 return 1; 4567} 4568 4569/* init callback for auto-configuration model -- overriding the default init */ 4570static int alc861_auto_init(struct hda_codec *codec) 4571{ 4572 alc_init(codec); 4573 alc861_auto_init_multi_out(codec); 4574 alc861_auto_init_hp_out(codec); 4575 alc861_auto_init_analog_input(codec); 4576 4577 return 0; 4578} 4579 4580 4581/* 4582 * configuration and preset 4583 */ 4584static struct hda_board_config alc861_cfg_tbl[] = { 4585 { .modelname = "3stack", .config = ALC861_3ST }, 4586 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, .config = ALC861_3ST }, 4587 { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, 4588 { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, 4589 { .modelname = "auto", .config = ALC861_AUTO }, 4590 {} 4591}; 4592 4593static struct alc_config_preset alc861_presets[] = { 4594 [ALC861_3ST] = { 4595 .mixers = { alc861_3ST_mixer }, 4596 .init_verbs = { alc861_threestack_init_verbs }, 4597 .num_dacs = ARRAY_SIZE(alc861_dac_nids), 4598 .dac_nids = alc861_dac_nids, 4599 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), 4600 .channel_mode = alc861_threestack_modes, 4601 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), 4602 .adc_nids = alc861_adc_nids, 4603 .input_mux = &alc861_capture_source, 4604 }, 4605 [ALC861_3ST_DIG] = { 4606 .mixers = { alc861_base_mixer }, 4607 .init_verbs = { alc861_threestack_init_verbs }, 4608 .num_dacs = ARRAY_SIZE(alc861_dac_nids), 4609 .dac_nids = alc861_dac_nids, 4610 .dig_out_nid = ALC861_DIGOUT_NID, 4611 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), 4612 .channel_mode = alc861_threestack_modes, 4613 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), 4614 .adc_nids = alc861_adc_nids, 4615 .input_mux = &alc861_capture_source, 4616 }, 4617 [ALC861_6ST_DIG] = { 4618 .mixers = { alc861_base_mixer }, 4619 .init_verbs = { alc861_base_init_verbs }, 4620 .num_dacs = ARRAY_SIZE(alc861_dac_nids), 4621 .dac_nids = alc861_dac_nids, 4622 .dig_out_nid = ALC861_DIGOUT_NID, 4623 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes), 4624 .channel_mode = alc861_8ch_modes, 4625 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), 4626 .adc_nids = alc861_adc_nids, 4627 .input_mux = &alc861_capture_source, 4628 }, 4629}; 4630 4631 4632static int patch_alc861(struct hda_codec *codec) 4633{ 4634 struct alc_spec *spec; 4635 int board_config; 4636 int err; 4637 4638 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 4639 if (spec == NULL) 4640 return -ENOMEM; 4641 4642 codec->spec = spec; 4643 4644 board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl); 4645 if (board_config < 0 || board_config >= ALC861_MODEL_LAST) { 4646 printk(KERN_INFO "hda_codec: Unknown model for ALC861, trying auto-probe from BIOS...\n"); 4647 board_config = ALC861_AUTO; 4648 } 4649 4650 if (board_config == ALC861_AUTO) { 4651 /* automatic parse from the BIOS config */ 4652 err = alc861_parse_auto_config(codec); 4653 if (err < 0) { 4654 alc_free(codec); 4655 return err; 4656 } else if (! err) { 4657 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); 4658 board_config = ALC861_3ST_DIG; 4659 } 4660 } 4661 4662 if (board_config != ALC861_AUTO) 4663 setup_preset(spec, &alc861_presets[board_config]); 4664 4665 spec->stream_name_analog = "ALC861 Analog"; 4666 spec->stream_analog_playback = &alc861_pcm_analog_playback; 4667 spec->stream_analog_capture = &alc861_pcm_analog_capture; 4668 4669 spec->stream_name_digital = "ALC861 Digital"; 4670 spec->stream_digital_playback = &alc861_pcm_digital_playback; 4671 spec->stream_digital_capture = &alc861_pcm_digital_capture; 4672 4673 codec->patch_ops = alc_patch_ops; 4674 if (board_config == ALC861_AUTO) 4675 codec->patch_ops.init = alc861_auto_init; 4676 4677 return 0; 4678} 4679 4680/* 4681 * patch entries 4682 */ 4683struct hda_codec_preset snd_hda_preset_realtek[] = { 4684 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, 4685 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, 4686 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, 4687 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, 4688 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, 4689 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, 4690 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 }, 4691 {} /* terminator */ 4692}; 4693