patch_realtek.c revision 1c1fa8b69e6d538bcc1e58791938b31a2354ee65
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 PeiSen Hou <pshou@realtek.com.tw> 7 * Takashi Iwai <tiwai@suse.de> 8 * 9 * This driver is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This driver is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24#include <sound/driver.h> 25#include <linux/init.h> 26#include <linux/delay.h> 27#include <linux/slab.h> 28#include <linux/pci.h> 29#include <sound/core.h> 30#include "hda_codec.h" 31#include "hda_local.h" 32 33 34/* ALC880 board config type */ 35enum { 36 ALC880_3ST, 37 ALC880_3ST_DIG, 38 ALC880_5ST, 39 ALC880_5ST_DIG, 40 ALC880_W810, 41 ALC880_Z71V, 42 ALC880_AUTO, 43 ALC880_6ST, 44 ALC880_6ST_DIG, 45 ALC880_F1734, 46 ALC880_ASUS, 47 ALC880_ASUS_DIG, 48 ALC880_ASUS_W1V, 49 ALC880_UNIWILL_DIG, 50#ifdef CONFIG_SND_DEBUG 51 ALC880_TEST, 52#endif 53 ALC880_MODEL_LAST /* last tag */ 54}; 55 56/* ALC260 models */ 57enum { 58 ALC260_BASIC, 59 ALC260_HP, 60 ALC260_MODEL_LAST /* last tag */ 61}; 62 63/* amp values */ 64#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) 65#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) 66#define AMP_OUT_MUTE 0xb080 67#define AMP_OUT_UNMUTE 0xb000 68#define AMP_OUT_ZERO 0xb000 69/* pinctl values */ 70#define PIN_IN 0x20 71#define PIN_VREF80 0x24 72#define PIN_VREF50 0x21 73#define PIN_OUT 0x40 74#define PIN_HP 0xc0 75 76struct alc_spec { 77 /* codec parameterization */ 78 snd_kcontrol_new_t *mixers[3]; /* mixer arrays */ 79 unsigned int num_mixers; 80 81 const struct hda_verb *init_verbs[3]; /* initialization verbs 82 * don't forget NULL termination! 83 */ 84 unsigned int num_init_verbs; 85 86 char *stream_name_analog; /* analog PCM stream */ 87 struct hda_pcm_stream *stream_analog_playback; 88 struct hda_pcm_stream *stream_analog_capture; 89 90 char *stream_name_digital; /* digital PCM stream */ 91 struct hda_pcm_stream *stream_digital_playback; 92 struct hda_pcm_stream *stream_digital_capture; 93 94 /* playback */ 95 struct hda_multi_out multiout; /* playback set-up 96 * max_channels, dacs must be set 97 * dig_out_nid and hp_nid are optional 98 */ 99 100 /* capture */ 101 unsigned int num_adc_nids; 102 hda_nid_t *adc_nids; 103 hda_nid_t dig_in_nid; /* digital-in NID; optional */ 104 105 /* capture source */ 106 const struct hda_input_mux *input_mux; 107 unsigned int cur_mux[3]; 108 109 /* channel model */ 110 const struct alc_channel_mode *channel_mode; 111 int num_channel_mode; 112 113 /* PCM information */ 114 struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ 115 116 struct semaphore bind_mutex; /* for bound controls */ 117 118 /* dynamic controls, init_verbs and input_mux */ 119 struct auto_pin_cfg autocfg; 120 unsigned int num_kctl_alloc, num_kctl_used; 121 snd_kcontrol_new_t *kctl_alloc; 122 struct hda_input_mux private_imux; 123 hda_nid_t private_dac_nids[4]; 124}; 125 126 127/* 128 * input MUX handling 129 */ 130static int alc_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 131{ 132 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 133 struct alc_spec *spec = codec->spec; 134 return snd_hda_input_mux_info(spec->input_mux, uinfo); 135} 136 137static int alc_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 138{ 139 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 140 struct alc_spec *spec = codec->spec; 141 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 142 143 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 144 return 0; 145} 146 147static int alc_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 148{ 149 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 150 struct alc_spec *spec = codec->spec; 151 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 152 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 153 spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); 154} 155 156 157/* 158 * channel mode setting 159 */ 160struct alc_channel_mode { 161 int channels; 162 const struct hda_verb *sequence; 163}; 164 165static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 166{ 167 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 168 struct alc_spec *spec = codec->spec; 169 int items = kcontrol->private_value ? (int)kcontrol->private_value : 2; 170 171 snd_assert(spec->channel_mode, return -ENXIO); 172 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 173 uinfo->count = 1; 174 uinfo->value.enumerated.items = items; 175 if (uinfo->value.enumerated.item >= items) 176 uinfo->value.enumerated.item = items - 1; 177 sprintf(uinfo->value.enumerated.name, "%dch", 178 spec->channel_mode[uinfo->value.enumerated.item].channels); 179 return 0; 180} 181 182static int alc880_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 183{ 184 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 185 struct alc_spec *spec = codec->spec; 186 int items = kcontrol->private_value ? (int)kcontrol->private_value : 2; 187 int i; 188 189 snd_assert(spec->channel_mode, return -ENXIO); 190 for (i = 0; i < items; i++) { 191 if (spec->multiout.max_channels == spec->channel_mode[i].channels) { 192 ucontrol->value.enumerated.item[0] = i; 193 break; 194 } 195 } 196 return 0; 197} 198 199static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 200{ 201 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 202 struct alc_spec *spec = codec->spec; 203 int mode; 204 205 snd_assert(spec->channel_mode, return -ENXIO); 206 mode = ucontrol->value.enumerated.item[0] ? 1 : 0; 207 if (spec->multiout.max_channels == spec->channel_mode[mode].channels && 208 ! codec->in_resume) 209 return 0; 210 211 /* change the current channel setting */ 212 spec->multiout.max_channels = spec->channel_mode[mode].channels; 213 if (spec->channel_mode[mode].sequence) 214 snd_hda_sequence_write(codec, spec->channel_mode[mode].sequence); 215 216 return 1; 217} 218 219 220/* 221 * bound volume controls 222 * 223 * bind multiple volumes (# indices, from 0) 224 */ 225 226#define AMP_VAL_IDX_SHIFT 19 227#define AMP_VAL_IDX_MASK (0x0f<<19) 228 229static int alc_bind_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 230{ 231 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 232 struct alc_spec *spec = codec->spec; 233 unsigned long pval; 234 235 down(&spec->bind_mutex); 236 pval = kcontrol->private_value; 237 kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ 238 snd_hda_mixer_amp_switch_info(kcontrol, uinfo); 239 kcontrol->private_value = pval; 240 up(&spec->bind_mutex); 241 return 0; 242} 243 244static int alc_bind_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 245{ 246 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 247 struct alc_spec *spec = codec->spec; 248 unsigned long pval; 249 250 down(&spec->bind_mutex); 251 pval = kcontrol->private_value; 252 kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ 253 snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); 254 kcontrol->private_value = pval; 255 up(&spec->bind_mutex); 256 return 0; 257} 258 259static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 260{ 261 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 262 struct alc_spec *spec = codec->spec; 263 unsigned long pval; 264 int i, indices, change = 0; 265 266 down(&spec->bind_mutex); 267 pval = kcontrol->private_value; 268 indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; 269 for (i = 0; i < indices; i++) { 270 kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT); 271 change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); 272 } 273 kcontrol->private_value = pval; 274 up(&spec->bind_mutex); 275 return change; 276} 277 278#define ALC_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ 279 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ 280 .info = alc_bind_switch_info, \ 281 .get = alc_bind_switch_get, \ 282 .put = alc_bind_switch_put, \ 283 .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } 284 285#define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir) 286 287 288/* 289 * ALC880 3-stack model 290 * 291 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) 292 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, F-Mic = 0x1b 293 * HP = 0x19 294 */ 295 296static hda_nid_t alc880_dac_nids[4] = { 297 /* front, rear, clfe, rear_surr */ 298 0x02, 0x05, 0x04, 0x03 299}; 300 301static hda_nid_t alc880_adc_nids[3] = { 302 /* ADC0-2 */ 303 0x07, 0x08, 0x09, 304}; 305 306/* The datasheet says the node 0x07 is connected from inputs, 307 * but it shows zero connection in the real implementation on some devices. 308 */ 309static hda_nid_t alc880_adc_nids_alt[2] = { 310 /* ADC1-2 */ 311 0x08, 0x09, 312}; 313 314#define ALC880_DIGOUT_NID 0x06 315#define ALC880_DIGIN_NID 0x0a 316 317static struct hda_input_mux alc880_capture_source = { 318 .num_items = 4, 319 .items = { 320 { "Mic", 0x0 }, 321 { "Front Mic", 0x3 }, 322 { "Line", 0x2 }, 323 { "CD", 0x4 }, 324 }, 325}; 326 327/* channel source setting (2/6 channel selection for 3-stack) */ 328/* 2ch mode */ 329static struct hda_verb alc880_threestack_ch2_init[] = { 330 /* set line-in to input, mute it */ 331 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, 332 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, 333 /* set mic-in to input vref 80%, mute it */ 334 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, 335 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, 336 { } /* end */ 337}; 338 339/* 6ch mode */ 340static struct hda_verb alc880_threestack_ch6_init[] = { 341 /* set line-in to output, unmute it */ 342 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 343 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, 344 /* set mic-in to output, unmute it */ 345 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 346 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, 347 { } /* end */ 348}; 349 350static struct alc_channel_mode alc880_threestack_modes[2] = { 351 { 2, alc880_threestack_ch2_init }, 352 { 6, alc880_threestack_ch6_init }, 353}; 354 355static snd_kcontrol_new_t alc880_three_stack_mixer[] = { 356 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 357 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 358 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), 359 ALC_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), 360 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 361 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 362 ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 363 ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), 364 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 365 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 366 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 367 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 368 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 369 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 370 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), 371 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), 372 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 373 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 374 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), 375 { 376 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 377 .name = "Channel Mode", 378 .info = alc880_ch_mode_info, 379 .get = alc880_ch_mode_get, 380 .put = alc880_ch_mode_put, 381 }, 382 { } /* end */ 383}; 384 385/* capture mixer elements */ 386static snd_kcontrol_new_t alc880_capture_mixer[] = { 387 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), 388 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), 389 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), 390 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), 391 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), 392 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), 393 { 394 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 395 /* The multiple "Capture Source" controls confuse alsamixer 396 * So call somewhat different.. 397 * FIXME: the controls appear in the "playback" view! 398 */ 399 /* .name = "Capture Source", */ 400 .name = "Input Source", 401 .count = 3, 402 .info = alc_mux_enum_info, 403 .get = alc_mux_enum_get, 404 .put = alc_mux_enum_put, 405 }, 406 { } /* end */ 407}; 408 409/* capture mixer elements (in case NID 0x07 not available) */ 410static snd_kcontrol_new_t alc880_capture_alt_mixer[] = { 411 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 412 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 413 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), 414 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), 415 { 416 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 417 /* The multiple "Capture Source" controls confuse alsamixer 418 * So call somewhat different.. 419 * FIXME: the controls appear in the "playback" view! 420 */ 421 /* .name = "Capture Source", */ 422 .name = "Input Source", 423 .count = 2, 424 .info = alc_mux_enum_info, 425 .get = alc_mux_enum_get, 426 .put = alc_mux_enum_put, 427 }, 428 { } /* end */ 429}; 430 431 432 433/* 434 * ALC880 5-stack model 435 * 436 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), Side = 0x02 (0xd) 437 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 438 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 439 */ 440 441/* additional mixers to alc880_three_stack_mixer */ 442static snd_kcontrol_new_t alc880_five_stack_mixer[] = { 443 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 444 ALC_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), 445 { } /* end */ 446}; 447 448/* channel source setting (6/8 channel selection for 5-stack) */ 449/* 6ch mode */ 450static struct hda_verb alc880_fivestack_ch6_init[] = { 451 /* set line-in to input, mute it */ 452 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, 453 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, 454 { } /* end */ 455}; 456 457/* 8ch mode */ 458static struct hda_verb alc880_fivestack_ch8_init[] = { 459 /* set line-in to output, unmute it */ 460 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 461 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, 462 { } /* end */ 463}; 464 465static struct alc_channel_mode alc880_fivestack_modes[2] = { 466 { 6, alc880_fivestack_ch6_init }, 467 { 8, alc880_fivestack_ch8_init }, 468}; 469 470 471/* 472 * ALC880 6-stack model 473 * 474 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), Side = 0x05 (0x0f) 475 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, 476 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b 477 */ 478 479static hda_nid_t alc880_6st_dac_nids[4] = { 480 /* front, rear, clfe, rear_surr */ 481 0x02, 0x03, 0x04, 0x05 482}; 483 484static struct hda_input_mux alc880_6stack_capture_source = { 485 .num_items = 4, 486 .items = { 487 { "Mic", 0x0 }, 488 { "Front Mic", 0x1 }, 489 { "Line", 0x2 }, 490 { "CD", 0x4 }, 491 }, 492}; 493 494/* fixed 8-channels */ 495static struct alc_channel_mode alc880_sixstack_modes[1] = { 496 { 8, NULL }, 497}; 498 499static snd_kcontrol_new_t alc880_six_stack_mixer[] = { 500 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 501 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 502 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 503 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 504 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 505 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 506 ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 507 ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), 508 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), 509 ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), 510 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 511 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 512 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 513 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 514 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 515 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 516 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), 517 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), 518 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 519 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 520 { 521 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 522 .name = "Channel Mode", 523 .info = alc880_ch_mode_info, 524 .get = alc880_ch_mode_get, 525 .put = alc880_ch_mode_put, 526 }, 527 { } /* end */ 528}; 529 530 531/* 532 * ALC880 W810 model 533 * 534 * W810 has rear IO for: 535 * Front (DAC 02) 536 * Surround (DAC 03) 537 * Center/LFE (DAC 04) 538 * Digital out (06) 539 * 540 * The system also has a pair of internal speakers, and a headphone jack. 541 * These are both connected to Line2 on the codec, hence to DAC 02. 542 * 543 * There is a variable resistor to control the speaker or headphone 544 * volume. This is a hardware-only device without a software API. 545 * 546 * Plugging headphones in will disable the internal speakers. This is 547 * implemented in hardware, not via the driver using jack sense. In 548 * a similar fashion, plugging into the rear socket marked "front" will 549 * disable both the speakers and headphones. 550 * 551 * For input, there's a microphone jack, and an "audio in" jack. 552 * These may not do anything useful with this driver yet, because I 553 * haven't setup any initialization verbs for these yet... 554 */ 555 556static hda_nid_t alc880_w810_dac_nids[3] = { 557 /* front, rear/surround, clfe */ 558 0x02, 0x03, 0x04 559}; 560 561/* fixed 6 channels */ 562static struct alc_channel_mode alc880_w810_modes[1] = { 563 { 6, NULL } 564}; 565 566/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ 567static snd_kcontrol_new_t alc880_w810_base_mixer[] = { 568 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 569 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 570 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 571 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 572 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 573 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 574 ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 575 ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), 576 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), 577 { } /* end */ 578}; 579 580 581/* 582 * Z710V model 583 * 584 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) 585 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), Line = 0x1a 586 */ 587 588static hda_nid_t alc880_z71v_dac_nids[1] = { 589 0x02 590}; 591#define ALC880_Z71V_HP_DAC 0x03 592 593/* fixed 2 channels */ 594static struct alc_channel_mode alc880_2_jack_modes[1] = { 595 { 2, NULL } 596}; 597 598static snd_kcontrol_new_t alc880_z71v_mixer[] = { 599 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 600 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 601 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 602 ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), 603 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 604 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 605 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 606 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 607 { } /* end */ 608}; 609 610 611/* FIXME! */ 612/* 613 * ALC880 F1734 model 614 * 615 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) 616 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 617 */ 618 619static hda_nid_t alc880_f1734_dac_nids[1] = { 620 0x03 621}; 622#define ALC880_F1734_HP_DAC 0x02 623 624static snd_kcontrol_new_t alc880_f1734_mixer[] = { 625 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 626 ALC_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), 627 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 628 ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), 629 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 630 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 631 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 632 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 633 { } /* end */ 634}; 635 636 637/* FIXME! */ 638/* 639 * ALC880 ASUS model 640 * 641 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) 642 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, 643 * Mic = 0x18, Line = 0x1a 644 */ 645 646#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ 647#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ 648 649static snd_kcontrol_new_t alc880_asus_mixer[] = { 650 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 651 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 652 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 653 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 654 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 655 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 656 ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 657 ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), 658 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 659 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 660 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 661 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 662 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 663 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 664 { 665 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 666 .name = "Channel Mode", 667 .info = alc880_ch_mode_info, 668 .get = alc880_ch_mode_get, 669 .put = alc880_ch_mode_put, 670 }, 671 { } /* end */ 672}; 673 674/* FIXME! */ 675/* 676 * ALC880 ASUS W1V model 677 * 678 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) 679 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, 680 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b 681 */ 682 683/* additional mixers to alc880_asus_mixer */ 684static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { 685 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), 686 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), 687 { } /* end */ 688}; 689 690/* additional mixers to alc880_asus_mixer */ 691static snd_kcontrol_new_t alc880_pcbeep_mixer[] = { 692 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 693 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 694 { } /* end */ 695}; 696 697/* 698 * build control elements 699 */ 700static int alc_build_controls(struct hda_codec *codec) 701{ 702 struct alc_spec *spec = codec->spec; 703 int err; 704 int i; 705 706 for (i = 0; i < spec->num_mixers; i++) { 707 err = snd_hda_add_new_ctls(codec, spec->mixers[i]); 708 if (err < 0) 709 return err; 710 } 711 712 if (spec->multiout.dig_out_nid) { 713 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); 714 if (err < 0) 715 return err; 716 } 717 if (spec->dig_in_nid) { 718 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 719 if (err < 0) 720 return err; 721 } 722 return 0; 723} 724 725 726/* 727 * initialize the codec volumes, etc 728 */ 729 730/* 731 * generic initialization of ADC, input mixers and output mixers 732 */ 733static struct hda_verb alc880_volume_init_verbs[] = { 734 /* 735 * Unmute ADC0-2 and set the default input to mic-in 736 */ 737 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 738 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 739 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 740 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 741 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 742 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 743 744 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 745 * mixer widget 746 * Note: PASD motherboards uses the Line In 2 as the input for front panel 747 * mic (mic 2) 748 */ 749 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ 750 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 751 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 752 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 753 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 754 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 755 756 /* 757 * Set up output mixers (0x0c - 0x0f) 758 */ 759 /* set vol=0 to output mixers */ 760 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 761 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 762 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 763 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 764 /* set up input amps for analog loopback */ 765 /* Amp Indices: DAC = 0, mixer = 1 */ 766 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 767 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 768 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 769 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 770 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 771 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 772 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 773 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 774 775 { } 776}; 777 778/* 779 * 3-stack pin configuration: 780 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b 781 */ 782static struct hda_verb alc880_pin_3stack_init_verbs[] = { 783 /* 784 * preset connection lists of input pins 785 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround 786 */ 787 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ 788 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ 789 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ 790 791 /* 792 * Set pin mode and muting 793 */ 794 /* set front pin widgets 0x14 for output */ 795 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 796 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 797 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 798 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 799 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 800 /* Mic2 (as headphone out) for HP output */ 801 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 802 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 803 /* Line In pin widget for input */ 804 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 805 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 806 /* Line2 (as front mic) pin widget for input and vref at 80% */ 807 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 808 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 809 /* CD pin widget for input */ 810 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 811 812 { } 813}; 814 815/* 816 * 5-stack pin configuration: 817 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, 818 * line-in/side = 0x1a, f-mic = 0x1b 819 */ 820static struct hda_verb alc880_pin_5stack_init_verbs[] = { 821 /* 822 * preset connection lists of input pins 823 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround 824 */ 825 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ 826 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ 827 828 /* 829 * Set pin mode and muting 830 */ 831 /* set pin widgets 0x14-0x17 for output */ 832 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 833 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 834 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 835 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 836 /* unmute pins for output (no gain on this amp) */ 837 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 838 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 839 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 840 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 841 842 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 843 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 844 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 845 /* Mic2 (as headphone out) for HP output */ 846 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 847 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 848 /* Line In pin widget for input */ 849 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 850 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 851 /* Line2 (as front mic) pin widget for input and vref at 80% */ 852 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 853 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 854 /* CD pin widget for input */ 855 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 856 857 { } 858}; 859 860/* 861 * W810 pin configuration: 862 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b 863 */ 864static struct hda_verb alc880_pin_w810_init_verbs[] = { 865 /* hphone/speaker input selector: front DAC */ 866 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, 867 868 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 869 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 870 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 871 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 872 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 873 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 874 875 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 876 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 877 878 { } 879}; 880 881/* 882 * Z71V pin configuration: 883 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) 884 */ 885static struct hda_verb alc880_pin_z71v_init_verbs[] = { 886 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 887 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 888 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 889 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 890 891 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 892 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 893 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 894 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 895 896 { } 897}; 898 899/* 900 * 6-stack pin configuration: 901 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, f-mic = 0x19, 902 * line = 0x1a, HP = 0x1b 903 */ 904static struct hda_verb alc880_pin_6stack_init_verbs[] = { 905 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ 906 907 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 908 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 909 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 910 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 911 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 912 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 913 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 914 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 915 916 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 917 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 918 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 919 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 920 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 921 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 922 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 923 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 924 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 925 926 { } 927}; 928 929/* FIXME! */ 930/* 931 * F1734 pin configuration: 932 * HP = 0x14, speaker-out = 0x15, mic = 0x18 933 */ 934static struct hda_verb alc880_pin_f1734_init_verbs[] = { 935 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, 936 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, 937 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, 938 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, 939 940 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 941 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 942 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 943 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 944 945 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 946 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 947 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 948 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 949 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 950 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 951 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 952 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 953 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 954 955 { } 956}; 957 958/* FIXME! */ 959/* 960 * ASUS pin configuration: 961 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a 962 */ 963static struct hda_verb alc880_pin_asus_init_verbs[] = { 964 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, 965 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, 966 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, 967 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, 968 969 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 970 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 971 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 972 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 973 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 974 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 975 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 976 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 977 978 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 979 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 980 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 981 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 982 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 983 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 984 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 985 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 986 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 987 988 { } 989}; 990 991/* Enable GPIO mask and set output */ 992static struct hda_verb alc880_gpio1_init_verbs[] = { 993 {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, 994 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, 995 {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, 996}; 997 998/* Enable GPIO mask and set output */ 999static struct hda_verb alc880_gpio2_init_verbs[] = { 1000 {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, 1001 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, 1002 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, 1003}; 1004 1005 1006/* 1007 */ 1008 1009static int alc_init(struct hda_codec *codec) 1010{ 1011 struct alc_spec *spec = codec->spec; 1012 unsigned int i; 1013 1014 for (i = 0; i < spec->num_init_verbs; i++) 1015 snd_hda_sequence_write(codec, spec->init_verbs[i]); 1016 return 0; 1017} 1018 1019#ifdef CONFIG_PM 1020/* 1021 * resume 1022 */ 1023static int alc_resume(struct hda_codec *codec) 1024{ 1025 struct alc_spec *spec = codec->spec; 1026 int i; 1027 1028 alc_init(codec); 1029 for (i = 0; i < spec->num_mixers; i++) 1030 snd_hda_resume_ctls(codec, spec->mixers[i]); 1031 if (spec->multiout.dig_out_nid) 1032 snd_hda_resume_spdif_out(codec); 1033 if (spec->dig_in_nid) 1034 snd_hda_resume_spdif_in(codec); 1035 1036 return 0; 1037} 1038#endif 1039 1040/* 1041 * Analog playback callbacks 1042 */ 1043static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo, 1044 struct hda_codec *codec, 1045 snd_pcm_substream_t *substream) 1046{ 1047 struct alc_spec *spec = codec->spec; 1048 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); 1049} 1050 1051static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 1052 struct hda_codec *codec, 1053 unsigned int stream_tag, 1054 unsigned int format, 1055 snd_pcm_substream_t *substream) 1056{ 1057 struct alc_spec *spec = codec->spec; 1058 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, 1059 format, substream); 1060} 1061 1062static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 1063 struct hda_codec *codec, 1064 snd_pcm_substream_t *substream) 1065{ 1066 struct alc_spec *spec = codec->spec; 1067 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 1068} 1069 1070/* 1071 * Digital out 1072 */ 1073static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 1074 struct hda_codec *codec, 1075 snd_pcm_substream_t *substream) 1076{ 1077 struct alc_spec *spec = codec->spec; 1078 return snd_hda_multi_out_dig_open(codec, &spec->multiout); 1079} 1080 1081static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 1082 struct hda_codec *codec, 1083 snd_pcm_substream_t *substream) 1084{ 1085 struct alc_spec *spec = codec->spec; 1086 return snd_hda_multi_out_dig_close(codec, &spec->multiout); 1087} 1088 1089/* 1090 * Analog capture 1091 */ 1092static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 1093 struct hda_codec *codec, 1094 unsigned int stream_tag, 1095 unsigned int format, 1096 snd_pcm_substream_t *substream) 1097{ 1098 struct alc_spec *spec = codec->spec; 1099 1100 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 1101 stream_tag, 0, format); 1102 return 0; 1103} 1104 1105static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 1106 struct hda_codec *codec, 1107 snd_pcm_substream_t *substream) 1108{ 1109 struct alc_spec *spec = codec->spec; 1110 1111 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); 1112 return 0; 1113} 1114 1115 1116/* 1117 */ 1118static struct hda_pcm_stream alc880_pcm_analog_playback = { 1119 .substreams = 1, 1120 .channels_min = 2, 1121 .channels_max = 8, 1122 /* NID is set in alc_build_pcms */ 1123 .ops = { 1124 .open = alc880_playback_pcm_open, 1125 .prepare = alc880_playback_pcm_prepare, 1126 .cleanup = alc880_playback_pcm_cleanup 1127 }, 1128}; 1129 1130static struct hda_pcm_stream alc880_pcm_analog_capture = { 1131 .substreams = 2, 1132 .channels_min = 2, 1133 .channels_max = 2, 1134 /* NID is set in alc_build_pcms */ 1135 .ops = { 1136 .prepare = alc880_capture_pcm_prepare, 1137 .cleanup = alc880_capture_pcm_cleanup 1138 }, 1139}; 1140 1141static struct hda_pcm_stream alc880_pcm_digital_playback = { 1142 .substreams = 1, 1143 .channels_min = 2, 1144 .channels_max = 2, 1145 /* NID is set in alc_build_pcms */ 1146 .ops = { 1147 .open = alc880_dig_playback_pcm_open, 1148 .close = alc880_dig_playback_pcm_close 1149 }, 1150}; 1151 1152static struct hda_pcm_stream alc880_pcm_digital_capture = { 1153 .substreams = 1, 1154 .channels_min = 2, 1155 .channels_max = 2, 1156 /* NID is set in alc_build_pcms */ 1157}; 1158 1159static int alc_build_pcms(struct hda_codec *codec) 1160{ 1161 struct alc_spec *spec = codec->spec; 1162 struct hda_pcm *info = spec->pcm_rec; 1163 int i; 1164 1165 codec->num_pcms = 1; 1166 codec->pcm_info = info; 1167 1168 info->name = spec->stream_name_analog; 1169 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); 1170 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; 1171 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); 1172 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 1173 1174 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; 1175 for (i = 0; i < spec->num_channel_mode; i++) { 1176 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) { 1177 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels; 1178 } 1179 } 1180 1181 if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 1182 codec->num_pcms++; 1183 info++; 1184 info->name = spec->stream_name_digital; 1185 if (spec->multiout.dig_out_nid) { 1186 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback); 1187 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; 1188 } 1189 if (spec->dig_in_nid) { 1190 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture); 1191 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; 1192 } 1193 } 1194 1195 return 0; 1196} 1197 1198static void alc_free(struct hda_codec *codec) 1199{ 1200 struct alc_spec *spec = codec->spec; 1201 unsigned int i; 1202 1203 if (! spec) 1204 return; 1205 1206 if (spec->kctl_alloc) { 1207 for (i = 0; i < spec->num_kctl_used; i++) 1208 kfree(spec->kctl_alloc[i].name); 1209 kfree(spec->kctl_alloc); 1210 } 1211 kfree(spec); 1212} 1213 1214/* 1215 */ 1216static struct hda_codec_ops alc_patch_ops = { 1217 .build_controls = alc_build_controls, 1218 .build_pcms = alc_build_pcms, 1219 .init = alc_init, 1220 .free = alc_free, 1221#ifdef CONFIG_PM 1222 .resume = alc_resume, 1223#endif 1224}; 1225 1226 1227/* 1228 * Test configuration for debugging 1229 * 1230 * Almost all inputs/outputs are enabled. I/O pins can be configured via 1231 * enum controls. 1232 */ 1233#ifdef CONFIG_SND_DEBUG 1234static hda_nid_t alc880_test_dac_nids[4] = { 1235 0x02, 0x03, 0x04, 0x05 1236}; 1237 1238static struct hda_input_mux alc880_test_capture_source = { 1239 .num_items = 5, 1240 .items = { 1241 { "In-1", 0x0 }, 1242 { "In-2", 0x1 }, 1243 { "In-3", 0x2 }, 1244 { "In-4", 0x3 }, 1245 { "CD", 0x4 }, 1246 }, 1247}; 1248 1249static struct alc_channel_mode alc880_test_modes[4] = { 1250 { 2, NULL }, 1251 { 4, NULL }, 1252 { 6, NULL }, 1253 { 8, NULL }, 1254}; 1255 1256static int alc_test_pin_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 1257{ 1258 static char *texts[] = { 1259 "N/A", "Line Out", "HP Out", 1260 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" 1261 }; 1262 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1263 uinfo->count = 1; 1264 uinfo->value.enumerated.items = 8; 1265 if (uinfo->value.enumerated.item >= 8) 1266 uinfo->value.enumerated.item = 7; 1267 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 1268 return 0; 1269} 1270 1271static int alc_test_pin_ctl_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 1272{ 1273 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1274 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1275 unsigned int pin_ctl, item = 0; 1276 1277 pin_ctl = snd_hda_codec_read(codec, nid, 0, 1278 AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 1279 if (pin_ctl & AC_PINCTL_OUT_EN) { 1280 if (pin_ctl & AC_PINCTL_HP_EN) 1281 item = 2; 1282 else 1283 item = 1; 1284 } else if (pin_ctl & AC_PINCTL_IN_EN) { 1285 switch (pin_ctl & AC_PINCTL_VREFEN) { 1286 case AC_PINCTL_VREF_HIZ: item = 3; break; 1287 case AC_PINCTL_VREF_50: item = 4; break; 1288 case AC_PINCTL_VREF_GRD: item = 5; break; 1289 case AC_PINCTL_VREF_80: item = 6; break; 1290 case AC_PINCTL_VREF_100: item = 7; break; 1291 } 1292 } 1293 ucontrol->value.enumerated.item[0] = item; 1294 return 0; 1295} 1296 1297static int alc_test_pin_ctl_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 1298{ 1299 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1300 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1301 static unsigned int ctls[] = { 1302 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, 1303 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, 1304 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, 1305 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, 1306 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, 1307 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, 1308 }; 1309 unsigned int old_ctl, new_ctl; 1310 1311 old_ctl = snd_hda_codec_read(codec, nid, 0, 1312 AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 1313 new_ctl = ctls[ucontrol->value.enumerated.item[0]]; 1314 if (old_ctl != new_ctl) { 1315 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); 1316 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 1317 ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000); 1318 return 1; 1319 } 1320 return 0; 1321} 1322 1323static int alc_test_pin_src_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 1324{ 1325 static char *texts[] = { 1326 "Front", "Surround", "CLFE", "Side" 1327 }; 1328 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1329 uinfo->count = 1; 1330 uinfo->value.enumerated.items = 4; 1331 if (uinfo->value.enumerated.item >= 4) 1332 uinfo->value.enumerated.item = 3; 1333 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 1334 return 0; 1335} 1336 1337static int alc_test_pin_src_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 1338{ 1339 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1340 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1341 unsigned int sel; 1342 1343 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); 1344 ucontrol->value.enumerated.item[0] = sel & 3; 1345 return 0; 1346} 1347 1348static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 1349{ 1350 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1351 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1352 unsigned int sel; 1353 1354 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; 1355 if (ucontrol->value.enumerated.item[0] != sel) { 1356 sel = ucontrol->value.enumerated.item[0] & 3; 1357 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); 1358 return 1; 1359 } 1360 return 0; 1361} 1362 1363#define PIN_CTL_TEST(xname,nid) { \ 1364 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 1365 .name = xname, \ 1366 .info = alc_test_pin_ctl_info, \ 1367 .get = alc_test_pin_ctl_get, \ 1368 .put = alc_test_pin_ctl_put, \ 1369 .private_value = nid \ 1370 } 1371 1372#define PIN_SRC_TEST(xname,nid) { \ 1373 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 1374 .name = xname, \ 1375 .info = alc_test_pin_src_info, \ 1376 .get = alc_test_pin_src_get, \ 1377 .put = alc_test_pin_src_put, \ 1378 .private_value = nid \ 1379 } 1380 1381static snd_kcontrol_new_t alc880_test_mixer[] = { 1382 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 1383 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 1384 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), 1385 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), 1386 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 1387 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 1388 ALC_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT), 1389 ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), 1390 PIN_CTL_TEST("Front Pin Mode", 0x14), 1391 PIN_CTL_TEST("Surround Pin Mode", 0x15), 1392 PIN_CTL_TEST("CLFE Pin Mode", 0x16), 1393 PIN_CTL_TEST("Side Pin Mode", 0x17), 1394 PIN_CTL_TEST("In-1 Pin Mode", 0x18), 1395 PIN_CTL_TEST("In-2 Pin Mode", 0x19), 1396 PIN_CTL_TEST("In-3 Pin Mode", 0x1a), 1397 PIN_CTL_TEST("In-4 Pin Mode", 0x1b), 1398 PIN_SRC_TEST("In-1 Pin Source", 0x18), 1399 PIN_SRC_TEST("In-2 Pin Source", 0x19), 1400 PIN_SRC_TEST("In-3 Pin Source", 0x1a), 1401 PIN_SRC_TEST("In-4 Pin Source", 0x1b), 1402 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), 1403 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), 1404 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), 1405 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), 1406 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), 1407 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), 1408 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), 1409 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), 1410 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), 1411 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), 1412 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 1413 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 1414 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), 1415 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), 1416 { 1417 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1418 .name = "Input Source", 1419 .count = 2, 1420 .info = alc_mux_enum_info, 1421 .get = alc_mux_enum_get, 1422 .put = alc_mux_enum_put, 1423 }, 1424 { 1425 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1426 .name = "Channel Mode", 1427 .info = alc880_ch_mode_info, 1428 .get = alc880_ch_mode_get, 1429 .put = alc880_ch_mode_put, 1430 }, 1431 { } /* end */ 1432}; 1433 1434static struct hda_verb alc880_test_init_verbs[] = { 1435 /* Unmute inputs of 0x0c - 0x0f */ 1436 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1437 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1438 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1439 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1440 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1441 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1442 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1443 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1444 /* Vol output for 0x0c-0x0f */ 1445 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1446 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1447 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1448 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1449 /* Set output pins 0x14-0x17 */ 1450 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1451 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1452 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1453 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1454 /* Unmute output pins 0x14-0x17 */ 1455 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1456 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1457 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1458 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1459 /* Set input pins 0x18-0x1c */ 1460 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1461 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1462 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1463 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1464 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1465 /* Mute input pins 0x18-0x1b */ 1466 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1467 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1468 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1469 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1470 /* ADC set up */ 1471 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1472 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 1473 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1474 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 1475 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1476 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 1477 /* Analog input/passthru */ 1478 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1479 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 1480 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 1481 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 1482 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 1483 { } 1484}; 1485#endif 1486 1487/* 1488 */ 1489 1490static struct hda_board_config alc880_cfg_tbl[] = { 1491 /* Back 3 jack, front 2 jack */ 1492 { .modelname = "3stack", .config = ALC880_3ST }, 1493 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST }, 1494 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST }, 1495 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST }, 1496 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST }, 1497 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST }, 1498 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST }, 1499 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST }, 1500 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST }, 1501 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST }, 1502 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST }, 1503 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST }, 1504 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST }, 1505 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST }, 1506 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST }, 1507 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST }, 1508 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, 1509 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, 1510 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, 1511 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, 1512 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, 1513 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, 1514 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, 1515 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST }, 1516 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST }, 1517 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST }, 1518 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST }, 1519 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST }, 1520 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST }, 1521 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST }, 1522 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST }, 1523 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, 1524 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, 1525 1526 /* Back 3 jack, front 2 jack (Internal add Aux-In) */ 1527 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, 1528 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST }, 1529 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST }, 1530 1531 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ 1532 { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, 1533 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, 1534 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG }, 1535 1536 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ 1537 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, 1538 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG }, 1539 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG }, 1540 1541 /* Back 5 jack, front 2 jack */ 1542 { .modelname = "5stack", .config = ALC880_5ST }, 1543 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST }, 1544 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST }, 1545 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST }, 1546 { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST }, 1547 { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST }, 1548 1549 /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ 1550 { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, 1551 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG }, 1552 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG }, 1553 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG }, 1554 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG }, 1555 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG }, 1556 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG }, 1557 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG }, 1558 { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG }, 1559 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG }, 1560 /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */ 1561 { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG }, 1562 /* note subvendor = 0 below */ 1563 /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */ 1564 1565 { .modelname = "w810", .config = ALC880_W810 }, 1566 { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 }, 1567 1568 { .modelname = "z71v", .config = ALC880_Z71V }, 1569 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, 1570 1571 { .modelname = "6stack", .config = ALC880_6ST }, 1572 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */ 1573 1574 { .modelname = "6stack-digout", .config = ALC880_6ST_DIG }, 1575 { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG }, 1576 { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG }, 1577 { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, 1578 { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, 1579 1580 { .modelname = "asus", .config = ALC880_ASUS }, 1581 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, 1582 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG }, 1583 { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG }, 1584 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, 1585 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG }, 1586 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, 1587 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, 1588 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, 1589 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, 1590 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, 1591 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, 1592 1593 { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, 1594 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, 1595 1596 { .modelname = "F1734", .config = ALC880_F1734 }, 1597 { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, 1598 1599#ifdef CONFIG_SND_DEBUG 1600 { .modelname = "test", .config = ALC880_TEST }, 1601#endif 1602 1603 {} 1604}; 1605 1606/* 1607 * configuration template - to be copied to the spec instance 1608 */ 1609struct alc_config_preset { 1610 snd_kcontrol_new_t *mixers[4]; 1611 const struct hda_verb *init_verbs[4]; 1612 unsigned int num_dacs; 1613 hda_nid_t *dac_nids; 1614 hda_nid_t dig_out_nid; /* optional */ 1615 hda_nid_t hp_nid; /* optional */ 1616 unsigned int num_adc_nids; 1617 hda_nid_t *adc_nids; 1618 unsigned int num_channel_mode; 1619 const struct alc_channel_mode *channel_mode; 1620 const struct hda_input_mux *input_mux; 1621}; 1622 1623static struct alc_config_preset alc880_presets[] = { 1624 [ALC880_3ST] = { 1625 .mixers = { alc880_three_stack_mixer }, 1626 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, 1627 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1628 .dac_nids = alc880_dac_nids, 1629 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), 1630 .channel_mode = alc880_threestack_modes, 1631 .input_mux = &alc880_capture_source, 1632 }, 1633 [ALC880_3ST_DIG] = { 1634 .mixers = { alc880_three_stack_mixer }, 1635 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, 1636 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1637 .dac_nids = alc880_dac_nids, 1638 .dig_out_nid = ALC880_DIGOUT_NID, 1639 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), 1640 .channel_mode = alc880_threestack_modes, 1641 .input_mux = &alc880_capture_source, 1642 }, 1643 [ALC880_5ST] = { 1644 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer}, 1645 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, 1646 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1647 .dac_nids = alc880_dac_nids, 1648 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), 1649 .channel_mode = alc880_fivestack_modes, 1650 .input_mux = &alc880_capture_source, 1651 }, 1652 [ALC880_5ST_DIG] = { 1653 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer }, 1654 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, 1655 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1656 .dac_nids = alc880_dac_nids, 1657 .dig_out_nid = ALC880_DIGOUT_NID, 1658 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), 1659 .channel_mode = alc880_fivestack_modes, 1660 .input_mux = &alc880_capture_source, 1661 }, 1662 [ALC880_6ST] = { 1663 .mixers = { alc880_six_stack_mixer }, 1664 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs }, 1665 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), 1666 .dac_nids = alc880_6st_dac_nids, 1667 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), 1668 .channel_mode = alc880_sixstack_modes, 1669 .input_mux = &alc880_6stack_capture_source, 1670 }, 1671 [ALC880_6ST_DIG] = { 1672 .mixers = { alc880_six_stack_mixer }, 1673 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs }, 1674 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), 1675 .dac_nids = alc880_6st_dac_nids, 1676 .dig_out_nid = ALC880_DIGOUT_NID, 1677 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), 1678 .channel_mode = alc880_sixstack_modes, 1679 .input_mux = &alc880_6stack_capture_source, 1680 }, 1681 [ALC880_W810] = { 1682 .mixers = { alc880_w810_base_mixer }, 1683 .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs, 1684 alc880_gpio2_init_verbs }, 1685 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), 1686 .dac_nids = alc880_w810_dac_nids, 1687 .dig_out_nid = ALC880_DIGOUT_NID, 1688 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), 1689 .channel_mode = alc880_w810_modes, 1690 .input_mux = &alc880_capture_source, 1691 }, 1692 [ALC880_Z71V] = { 1693 .mixers = { alc880_z71v_mixer }, 1694 .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs }, 1695 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), 1696 .dac_nids = alc880_z71v_dac_nids, 1697 .dig_out_nid = ALC880_DIGOUT_NID, 1698 .hp_nid = 0x03, 1699 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), 1700 .channel_mode = alc880_2_jack_modes, 1701 .input_mux = &alc880_capture_source, 1702 }, 1703 [ALC880_F1734] = { 1704 .mixers = { alc880_f1734_mixer }, 1705 .init_verbs = { alc880_volume_init_verbs, alc880_pin_f1734_init_verbs }, 1706 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), 1707 .dac_nids = alc880_f1734_dac_nids, 1708 .hp_nid = 0x02, 1709 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), 1710 .channel_mode = alc880_2_jack_modes, 1711 .input_mux = &alc880_capture_source, 1712 }, 1713 [ALC880_ASUS] = { 1714 .mixers = { alc880_asus_mixer }, 1715 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, 1716 alc880_gpio1_init_verbs }, 1717 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 1718 .dac_nids = alc880_asus_dac_nids, 1719 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1720 .channel_mode = alc880_asus_modes, 1721 .input_mux = &alc880_capture_source, 1722 }, 1723 [ALC880_ASUS_DIG] = { 1724 .mixers = { alc880_asus_mixer }, 1725 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, 1726 alc880_gpio1_init_verbs }, 1727 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 1728 .dac_nids = alc880_asus_dac_nids, 1729 .dig_out_nid = ALC880_DIGOUT_NID, 1730 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1731 .channel_mode = alc880_asus_modes, 1732 .input_mux = &alc880_capture_source, 1733 }, 1734 [ALC880_ASUS_W1V] = { 1735 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, 1736 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, 1737 alc880_gpio1_init_verbs }, 1738 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 1739 .dac_nids = alc880_asus_dac_nids, 1740 .dig_out_nid = ALC880_DIGOUT_NID, 1741 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1742 .channel_mode = alc880_asus_modes, 1743 .input_mux = &alc880_capture_source, 1744 }, 1745 [ALC880_UNIWILL_DIG] = { 1746 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer }, 1747 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs }, 1748 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 1749 .dac_nids = alc880_asus_dac_nids, 1750 .dig_out_nid = ALC880_DIGOUT_NID, 1751 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1752 .channel_mode = alc880_asus_modes, 1753 .input_mux = &alc880_capture_source, 1754 }, 1755#ifdef CONFIG_SND_DEBUG 1756 [ALC880_TEST] = { 1757 .mixers = { alc880_test_mixer }, 1758 .init_verbs = { alc880_test_init_verbs }, 1759 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), 1760 .dac_nids = alc880_test_dac_nids, 1761 .dig_out_nid = ALC880_DIGOUT_NID, 1762 .num_channel_mode = ARRAY_SIZE(alc880_test_modes), 1763 .channel_mode = alc880_test_modes, 1764 .input_mux = &alc880_test_capture_source, 1765 }, 1766#endif 1767}; 1768 1769/* 1770 * Automatic parse of I/O pins from the BIOS configuration 1771 */ 1772 1773#define NUM_CONTROL_ALLOC 32 1774#define NUM_VERB_ALLOC 32 1775 1776enum { 1777 ALC_CTL_WIDGET_VOL, 1778 ALC_CTL_WIDGET_MUTE, 1779 ALC_CTL_BIND_MUTE, 1780}; 1781static snd_kcontrol_new_t alc880_control_templates[] = { 1782 HDA_CODEC_VOLUME(NULL, 0, 0, 0), 1783 HDA_CODEC_MUTE(NULL, 0, 0, 0), 1784 ALC_BIND_MUTE(NULL, 0, 0, 0), 1785}; 1786 1787/* add dynamic controls */ 1788static int add_control(struct alc_spec *spec, int type, const char *name, unsigned long val) 1789{ 1790 snd_kcontrol_new_t *knew; 1791 1792 if (spec->num_kctl_used >= spec->num_kctl_alloc) { 1793 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; 1794 1795 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ 1796 if (! knew) 1797 return -ENOMEM; 1798 if (spec->kctl_alloc) { 1799 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); 1800 kfree(spec->kctl_alloc); 1801 } 1802 spec->kctl_alloc = knew; 1803 spec->num_kctl_alloc = num; 1804 } 1805 1806 knew = &spec->kctl_alloc[spec->num_kctl_used]; 1807 *knew = alc880_control_templates[type]; 1808 knew->name = kstrdup(name, GFP_KERNEL); 1809 if (! knew->name) 1810 return -ENOMEM; 1811 knew->private_value = val; 1812 spec->num_kctl_used++; 1813 return 0; 1814} 1815 1816#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) 1817#define alc880_fixed_pin_idx(nid) ((nid) - 0x14) 1818#define alc880_is_multi_pin(nid) ((nid) >= 0x18) 1819#define alc880_multi_pin_idx(nid) ((nid) - 0x18) 1820#define alc880_is_input_pin(nid) ((nid) >= 0x18) 1821#define alc880_input_pin_idx(nid) ((nid) - 0x18) 1822#define alc880_idx_to_dac(nid) ((nid) + 0x02) 1823#define alc880_dac_to_idx(nid) ((nid) - 0x02) 1824#define alc880_idx_to_mixer(nid) ((nid) + 0x0c) 1825#define alc880_idx_to_selector(nid) ((nid) + 0x10) 1826#define ALC880_PIN_CD_NID 0x1c 1827 1828/* fill in the dac_nids table from the parsed pin configuration */ 1829static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 1830{ 1831 hda_nid_t nid; 1832 int assigned[4]; 1833 int i, j; 1834 1835 memset(assigned, 0, sizeof(assigned)); 1836 spec->multiout.dac_nids = spec->private_dac_nids; 1837 1838 /* check the pins hardwired to audio widget */ 1839 for (i = 0; i < cfg->line_outs; i++) { 1840 nid = cfg->line_out_pins[i]; 1841 if (alc880_is_fixed_pin(nid)) { 1842 int idx = alc880_fixed_pin_idx(nid); 1843 spec->multiout.dac_nids[i] = alc880_dac_to_idx(idx); 1844 assigned[idx] = 1; 1845 } 1846 } 1847 /* left pins can be connect to any audio widget */ 1848 for (i = 0; i < cfg->line_outs; i++) { 1849 nid = cfg->line_out_pins[i]; 1850 if (alc880_is_fixed_pin(nid)) 1851 continue; 1852 /* search for an empty channel */ 1853 for (j = 0; j < cfg->line_outs; j++) { 1854 if (! assigned[j]) { 1855 spec->multiout.dac_nids[i] = alc880_idx_to_dac(j); 1856 assigned[j] = 1; 1857 break; 1858 } 1859 } 1860 } 1861 spec->multiout.num_dacs = cfg->line_outs; 1862 return 0; 1863} 1864 1865/* add playback controls from the parsed DAC table */ 1866static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 1867{ 1868 char name[32]; 1869 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; 1870 hda_nid_t nid; 1871 int i, err; 1872 1873 for (i = 0; i < cfg->line_outs; i++) { 1874 if (! spec->multiout.dac_nids[i]) 1875 continue; 1876 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); 1877 if (i == 2) { 1878 /* Center/LFE */ 1879 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Center Playback Volume", 1880 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) 1881 return err; 1882 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "LFE Playback Volume", 1883 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) 1884 return err; 1885 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch", 1886 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT))) < 0) 1887 return err; 1888 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch", 1889 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT))) < 0) 1890 return err; 1891 } else { 1892 sprintf(name, "%s Playback Volume", chname[i]); 1893 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, 1894 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 1895 return err; 1896 sprintf(name, "%s Playback Switch", chname[i]); 1897 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, 1898 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) 1899 return err; 1900 } 1901 } 1902 1903 return 0; 1904} 1905 1906/* add playback controls for HP output */ 1907static int alc880_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) 1908{ 1909 hda_nid_t nid; 1910 int err; 1911 1912 if (! pin) 1913 return 0; 1914 1915 if (alc880_is_fixed_pin(pin)) { 1916 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); 1917 if (! spec->multiout.dac_nids[0]) { 1918 /* use this as the primary output */ 1919 spec->multiout.dac_nids[0] = nid; 1920 if (! spec->multiout.num_dacs) 1921 spec->multiout.num_dacs = 1; 1922 } else 1923 /* specify the DAC as the extra HP output */ 1924 spec->multiout.hp_nid = nid; 1925 /* control HP volume/switch on the output mixer amp */ 1926 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); 1927 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", 1928 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 1929 return err; 1930 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Headphone Playback Switch", 1931 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) 1932 return err; 1933 } else if (alc880_is_multi_pin(pin)) { 1934 /* set manual connection */ 1935 if (! spec->multiout.dac_nids[0]) { 1936 /* use this as the primary output */ 1937 spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin)); 1938 if (! spec->multiout.num_dacs) 1939 spec->multiout.num_dacs = 1; 1940 } 1941 /* we have only a switch on HP-out PIN */ 1942 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", 1943 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT))) < 0) 1944 return err; 1945 } 1946 return 0; 1947} 1948 1949/* create input playback/capture controls for the given pin */ 1950static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname) 1951{ 1952 char name[32]; 1953 int err, idx; 1954 1955 sprintf(name, "%s Playback Volume", ctlname); 1956 idx = alc880_input_pin_idx(pin); 1957 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, 1958 HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) 1959 return err; 1960 sprintf(name, "%s Playback Switch", ctlname); 1961 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, 1962 HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) 1963 return err; 1964 return 0; 1965} 1966 1967/* create playback/capture controls for input pins */ 1968static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 1969{ 1970 static char *labels[AUTO_PIN_LAST] = { 1971 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" 1972 }; 1973 struct hda_input_mux *imux = &spec->private_imux; 1974 int i, err; 1975 1976 for (i = 0; i < AUTO_PIN_LAST; i++) { 1977 if (alc880_is_input_pin(cfg->input_pins[i])) { 1978 err = new_analog_input(spec, cfg->input_pins[i], labels[i]); 1979 if (err < 0) 1980 return err; 1981 imux->items[imux->num_items].label = labels[i]; 1982 imux->items[imux->num_items].index = alc880_input_pin_idx(cfg->input_pins[i]); 1983 imux->num_items++; 1984 } 1985 } 1986 return 0; 1987} 1988 1989static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, 1990 int dac_idx) 1991{ 1992 /* set as output */ 1993 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); 1994 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 1995 /* need the manual connection? */ 1996 if (alc880_is_multi_pin(nid)) { 1997 struct alc_spec *spec = codec->spec; 1998 int idx = alc880_multi_pin_idx(nid); 1999 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, 2000 AC_VERB_SET_CONNECT_SEL, 2001 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); 2002 } 2003} 2004 2005static void alc880_auto_init_multi_out(struct hda_codec *codec) 2006{ 2007 struct alc_spec *spec = codec->spec; 2008 int i; 2009 2010 for (i = 0; i < spec->autocfg.line_outs; i++) { 2011 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 2012 alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); 2013 } 2014} 2015 2016static void alc880_auto_init_hp_out(struct hda_codec *codec) 2017{ 2018 struct alc_spec *spec = codec->spec; 2019 hda_nid_t pin; 2020 2021 pin = spec->autocfg.hp_pin; 2022 if (pin) /* connect to front */ 2023 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); 2024} 2025 2026static void alc880_auto_init_analog_input(struct hda_codec *codec) 2027{ 2028 struct alc_spec *spec = codec->spec; 2029 int i; 2030 2031 for (i = 0; i < AUTO_PIN_LAST; i++) { 2032 hda_nid_t nid = spec->autocfg.input_pins[i]; 2033 if (alc880_is_input_pin(nid)) { 2034 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 2035 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); 2036 if (nid != ALC880_PIN_CD_NID) 2037 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 2038 AMP_OUT_MUTE); 2039 } 2040 } 2041} 2042 2043/* parse the BIOS configuration and set up the alc_spec */ 2044/* return 1 if successful, 0 if the proper config is not found, or a negative error code */ 2045static int alc880_parse_auto_config(struct hda_codec *codec) 2046{ 2047 struct alc_spec *spec = codec->spec; 2048 int err; 2049 2050 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0) 2051 return err; 2052 if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0) 2053 return err; 2054 if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin) 2055 return 0; /* can't find valid BIOS pin config */ 2056 if ((err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || 2057 (err = alc880_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || 2058 (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) 2059 return err; 2060 2061 spec->multiout.max_channels = spec->multiout.num_dacs * 2; 2062 2063 if (spec->autocfg.dig_out_pin) 2064 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; 2065 if (spec->autocfg.dig_in_pin) 2066 spec->dig_in_nid = ALC880_DIGIN_NID; 2067 2068 if (spec->kctl_alloc) 2069 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 2070 2071 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; 2072 2073 spec->input_mux = &spec->private_imux; 2074 2075 return 1; 2076} 2077 2078/* init callback for auto-configuration model -- overriding the default init */ 2079static int alc880_auto_init(struct hda_codec *codec) 2080{ 2081 alc_init(codec); 2082 alc880_auto_init_multi_out(codec); 2083 alc880_auto_init_hp_out(codec); 2084 alc880_auto_init_analog_input(codec); 2085 return 0; 2086} 2087 2088/* 2089 * OK, here we have finally the patch for ALC880 2090 */ 2091 2092static int patch_alc880(struct hda_codec *codec) 2093{ 2094 struct alc_spec *spec; 2095 int board_config; 2096 int i, err; 2097 2098 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 2099 if (spec == NULL) 2100 return -ENOMEM; 2101 2102 init_MUTEX(&spec->bind_mutex); 2103 codec->spec = spec; 2104 2105 board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); 2106 if (board_config < 0 || board_config >= ALC880_MODEL_LAST) { 2107 printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n"); 2108 board_config = ALC880_AUTO; 2109 } 2110 2111 if (board_config == ALC880_AUTO) { 2112 /* automatic parse from the BIOS config */ 2113 err = alc880_parse_auto_config(codec); 2114 if (err < 0) { 2115 alc_free(codec); 2116 return err; 2117 } else if (! err) { 2118 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 3-stack mode...\n"); 2119 board_config = ALC880_3ST; 2120 } 2121 } 2122 2123 if (board_config != ALC880_AUTO) { 2124 /* set up from the preset table */ 2125 const struct alc_config_preset *preset; 2126 2127 preset = &alc880_presets[board_config]; 2128 2129 for (i = 0; preset->mixers[i]; i++) { 2130 snd_assert(spec->num_mixers < ARRAY_SIZE(spec->mixers), break); 2131 spec->mixers[spec->num_mixers++] = preset->mixers[i]; 2132 } 2133 for (i = 0; preset->init_verbs[i]; i++) { 2134 snd_assert(spec->num_init_verbs < ARRAY_SIZE(spec->init_verbs), break); 2135 spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i]; 2136 } 2137 2138 spec->channel_mode = preset->channel_mode; 2139 spec->num_channel_mode = preset->num_channel_mode; 2140 2141 spec->multiout.max_channels = spec->channel_mode[0].channels; 2142 2143 spec->multiout.num_dacs = preset->num_dacs; 2144 spec->multiout.dac_nids = preset->dac_nids; 2145 spec->multiout.dig_out_nid = preset->dig_out_nid; 2146 spec->multiout.hp_nid = preset->hp_nid; 2147 2148 spec->input_mux = preset->input_mux; 2149 2150 spec->num_adc_nids = preset->num_adc_nids; 2151 spec->adc_nids = preset->adc_nids; 2152 } 2153 2154 spec->stream_name_analog = "ALC880 Analog"; 2155 spec->stream_analog_playback = &alc880_pcm_analog_playback; 2156 spec->stream_analog_capture = &alc880_pcm_analog_capture; 2157 2158 spec->stream_name_digital = "ALC880 Digital"; 2159 spec->stream_digital_playback = &alc880_pcm_digital_playback; 2160 spec->stream_digital_capture = &alc880_pcm_digital_capture; 2161 2162 if (! spec->adc_nids && spec->input_mux) { 2163 /* check whether NID 0x07 is valid */ 2164 unsigned int wcap = snd_hda_param_read(codec, alc880_adc_nids[0], 2165 AC_PAR_AUDIO_WIDGET_CAP); 2166 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ 2167 if (wcap != AC_WID_AUD_IN) { 2168 spec->adc_nids = alc880_adc_nids_alt; 2169 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); 2170 spec->mixers[spec->num_mixers] = alc880_capture_alt_mixer; 2171 spec->num_mixers++; 2172 } else { 2173 spec->adc_nids = alc880_adc_nids; 2174 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); 2175 spec->mixers[spec->num_mixers] = alc880_capture_mixer; 2176 spec->num_mixers++; 2177 } 2178 } 2179 2180 codec->patch_ops = alc_patch_ops; 2181 if (board_config == ALC880_AUTO) 2182 codec->patch_ops.init = alc880_auto_init; 2183 2184 return 0; 2185} 2186 2187 2188/* 2189 * ALC260 support 2190 */ 2191 2192static hda_nid_t alc260_dac_nids[1] = { 2193 /* front */ 2194 0x02, 2195}; 2196 2197static hda_nid_t alc260_adc_nids[1] = { 2198 /* ADC0 */ 2199 0x04, 2200}; 2201 2202static hda_nid_t alc260_hp_adc_nids[1] = { 2203 /* ADC1 */ 2204 0x05, 2205}; 2206 2207#define ALC260_DIGOUT_NID 0x03 2208#define ALC260_DIGIN_NID 0x06 2209 2210static struct hda_input_mux alc260_capture_source = { 2211 .num_items = 4, 2212 .items = { 2213 { "Mic", 0x0 }, 2214 { "Front Mic", 0x1 }, 2215 { "Line", 0x2 }, 2216 { "CD", 0x4 }, 2217 }, 2218}; 2219 2220/* 2221 * This is just place-holder, so there's something for alc_build_pcms to look 2222 * at when it calculates the maximum number of channels. ALC260 has no mixer 2223 * element which allows changing the channel mode, so the verb list is 2224 * never used. 2225 */ 2226static struct alc_channel_mode alc260_modes[1] = { 2227 { 2, NULL }, 2228}; 2229 2230static snd_kcontrol_new_t alc260_base_mixer[] = { 2231 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), 2232 ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), 2233 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), 2234 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), 2235 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), 2236 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), 2237 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), 2238 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), 2239 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), 2240 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), 2241 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), 2242 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), 2243 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), 2244 ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), 2245 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), 2246 ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), 2247 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), 2248 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), 2249 { 2250 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2251 .name = "Capture Source", 2252 .info = alc_mux_enum_info, 2253 .get = alc_mux_enum_get, 2254 .put = alc_mux_enum_put, 2255 }, 2256 { } /* end */ 2257}; 2258 2259static snd_kcontrol_new_t alc260_hp_mixer[] = { 2260 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), 2261 ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), 2262 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), 2263 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), 2264 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), 2265 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), 2266 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), 2267 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), 2268 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), 2269 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), 2270 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), 2271 ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), 2272 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), 2273 ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), 2274 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), 2275 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), 2276 { 2277 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2278 .name = "Capture Source", 2279 .info = alc_mux_enum_info, 2280 .get = alc_mux_enum_get, 2281 .put = alc_mux_enum_put, 2282 }, 2283 { } /* end */ 2284}; 2285 2286static struct hda_verb alc260_init_verbs[] = { 2287 /* Line In pin widget for input */ 2288 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2289 /* CD pin widget for input */ 2290 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2291 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 2292 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2293 /* Mic2 (front panel) pin widget for input and vref at 80% */ 2294 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2295 /* LINE-2 is used for line-out in rear */ 2296 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2297 /* select line-out */ 2298 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, 2299 /* LINE-OUT pin */ 2300 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2301 /* enable HP */ 2302 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 2303 /* enable Mono */ 2304 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2305 /* mute capture amp left and right */ 2306 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2307 /* set connection select to line in (default select for this ADC) */ 2308 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, 2309 /* mute capture amp left and right */ 2310 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2311 /* set connection select to line in (default select for this ADC) */ 2312 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, 2313 /* set vol=0 Line-Out mixer amp left and right */ 2314 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2315 /* unmute pin widget amp left and right (no gain on this amp) */ 2316 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2317 /* set vol=0 HP mixer amp left and right */ 2318 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2319 /* unmute pin widget amp left and right (no gain on this amp) */ 2320 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2321 /* set vol=0 Mono mixer amp left and right */ 2322 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2323 /* unmute pin widget amp left and right (no gain on this amp) */ 2324 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2325 /* unmute LINE-2 out pin */ 2326 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2327 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ 2328 /* mute CD */ 2329 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 2330 /* mute Line In */ 2331 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 2332 /* mute Mic */ 2333 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2334 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ 2335 /* mute Front out path */ 2336 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2337 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2338 /* mute Headphone out path */ 2339 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2340 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2341 /* mute Mono out path */ 2342 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2343 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2344 { } 2345}; 2346 2347static struct hda_pcm_stream alc260_pcm_analog_playback = { 2348 .substreams = 1, 2349 .channels_min = 2, 2350 .channels_max = 2, 2351}; 2352 2353static struct hda_pcm_stream alc260_pcm_analog_capture = { 2354 .substreams = 1, 2355 .channels_min = 2, 2356 .channels_max = 2, 2357}; 2358 2359static struct hda_board_config alc260_cfg_tbl[] = { 2360 { .modelname = "hp", .config = ALC260_HP }, 2361 { .pci_subvendor = 0x103c, .config = ALC260_HP }, 2362 {} 2363}; 2364 2365static int patch_alc260(struct hda_codec *codec) 2366{ 2367 struct alc_spec *spec; 2368 int board_config; 2369 2370 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 2371 if (spec == NULL) 2372 return -ENOMEM; 2373 2374 init_MUTEX(&spec->bind_mutex); 2375 codec->spec = spec; 2376 2377 board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); 2378 if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { 2379 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n"); 2380 board_config = ALC260_BASIC; 2381 } 2382 2383 switch (board_config) { 2384 case ALC260_HP: 2385 spec->mixers[spec->num_mixers] = alc260_hp_mixer; 2386 spec->num_mixers++; 2387 break; 2388 default: 2389 spec->mixers[spec->num_mixers] = alc260_base_mixer; 2390 spec->num_mixers++; 2391 break; 2392 } 2393 2394 spec->init_verbs[0] = alc260_init_verbs; 2395 spec->num_init_verbs = 1; 2396 2397 spec->channel_mode = alc260_modes; 2398 spec->num_channel_mode = ARRAY_SIZE(alc260_modes); 2399 2400 spec->stream_name_analog = "ALC260 Analog"; 2401 spec->stream_analog_playback = &alc260_pcm_analog_playback; 2402 spec->stream_analog_capture = &alc260_pcm_analog_capture; 2403 2404 spec->multiout.max_channels = spec->channel_mode[0].channels; 2405 spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids); 2406 spec->multiout.dac_nids = alc260_dac_nids; 2407 2408 spec->input_mux = &alc260_capture_source; 2409 switch (board_config) { 2410 case ALC260_HP: 2411 spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); 2412 spec->adc_nids = alc260_hp_adc_nids; 2413 break; 2414 default: 2415 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); 2416 spec->adc_nids = alc260_adc_nids; 2417 break; 2418 } 2419 2420 codec->patch_ops = alc_patch_ops; 2421 2422 return 0; 2423} 2424 2425 2426/* 2427 * ALC882 support 2428 * 2429 * ALC882 is almost identical with ALC880 but has cleaner and more flexible 2430 * configuration. Each pin widget can choose any input DACs and a mixer. 2431 * Each ADC is connected from a mixer of all inputs. This makes possible 2432 * 6-channel independent captures. 2433 * 2434 * In addition, an independent DAC for the multi-playback (not used in this 2435 * driver yet). 2436 */ 2437 2438static struct alc_channel_mode alc882_ch_modes[1] = { 2439 { 8, NULL } 2440}; 2441 2442static hda_nid_t alc882_dac_nids[4] = { 2443 /* front, rear, clfe, rear_surr */ 2444 0x02, 0x03, 0x04, 0x05 2445}; 2446 2447static hda_nid_t alc882_adc_nids[3] = { 2448 /* ADC0-2 */ 2449 0x07, 0x08, 0x09, 2450}; 2451 2452/* input MUX */ 2453/* FIXME: should be a matrix-type input source selection */ 2454 2455static struct hda_input_mux alc882_capture_source = { 2456 .num_items = 4, 2457 .items = { 2458 { "Mic", 0x0 }, 2459 { "Front Mic", 0x1 }, 2460 { "Line", 0x2 }, 2461 { "CD", 0x4 }, 2462 }, 2463}; 2464 2465#define alc882_mux_enum_info alc_mux_enum_info 2466#define alc882_mux_enum_get alc_mux_enum_get 2467 2468static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 2469{ 2470 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2471 struct alc_spec *spec = codec->spec; 2472 const struct hda_input_mux *imux = spec->input_mux; 2473 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2474 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; 2475 hda_nid_t nid = capture_mixers[adc_idx]; 2476 unsigned int *cur_val = &spec->cur_mux[adc_idx]; 2477 unsigned int i, idx; 2478 2479 idx = ucontrol->value.enumerated.item[0]; 2480 if (idx >= imux->num_items) 2481 idx = imux->num_items - 1; 2482 if (*cur_val == idx && ! codec->in_resume) 2483 return 0; 2484 for (i = 0; i < imux->num_items; i++) { 2485 unsigned int v = (i == idx) ? 0x7000 : 0x7080; 2486 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 2487 v | (imux->items[i].index << 8)); 2488 } 2489 *cur_val = idx; 2490 return 1; 2491} 2492 2493/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 2494 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b 2495 */ 2496static snd_kcontrol_new_t alc882_base_mixer[] = { 2497 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 2498 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 2499 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 2500 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 2501 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 2502 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 2503 ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 2504 ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_OUTPUT), 2505 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), 2506 ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), 2507 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), 2508 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 2509 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 2510 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 2511 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 2512 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 2513 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 2514 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), 2515 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), 2516 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 2517 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 2518 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), 2519 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), 2520 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), 2521 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), 2522 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), 2523 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), 2524 { 2525 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2526 /* .name = "Capture Source", */ 2527 .name = "Input Source", 2528 .count = 3, 2529 .info = alc882_mux_enum_info, 2530 .get = alc882_mux_enum_get, 2531 .put = alc882_mux_enum_put, 2532 }, 2533 { } /* end */ 2534}; 2535 2536static struct hda_verb alc882_init_verbs[] = { 2537 /* Front mixer: unmute input/output amp left and right (volume = 0) */ 2538 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2539 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2540 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2541 /* Rear mixer */ 2542 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2543 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2544 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2545 /* CLFE mixer */ 2546 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2547 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2548 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2549 /* Side mixer */ 2550 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2551 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2552 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2553 2554 /* Front Pin: output 0 (0x0c) */ 2555 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2556 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2557 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, 2558 /* Rear Pin: output 1 (0x0d) */ 2559 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2560 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2561 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, 2562 /* CLFE Pin: output 2 (0x0e) */ 2563 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2564 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2565 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, 2566 /* Side Pin: output 3 (0x0f) */ 2567 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2568 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2569 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, 2570 /* Mic (rear) pin: input vref at 80% */ 2571 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2572 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 2573 /* Front Mic pin: input vref at 80% */ 2574 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2575 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 2576 /* Line In pin: input */ 2577 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2578 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 2579 /* Line-2 In: Headphone output (output 0 - 0x0c) */ 2580 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 2581 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2582 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, 2583 /* CD pin widget for input */ 2584 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2585 2586 /* FIXME: use matrix-type input source selection */ 2587 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ 2588 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ 2589 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2590 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2591 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2592 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 2593 /* Input mixer2 */ 2594 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2595 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2596 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2597 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 2598 /* Input mixer3 */ 2599 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2600 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2601 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2602 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 2603 /* ADC1: mute amp left and right */ 2604 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2605 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 2606 /* ADC2: mute amp left and right */ 2607 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2608 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 2609 /* ADC3: mute amp left and right */ 2610 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2611 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 2612 2613 { } 2614}; 2615 2616static int patch_alc882(struct hda_codec *codec) 2617{ 2618 struct alc_spec *spec; 2619 2620 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 2621 if (spec == NULL) 2622 return -ENOMEM; 2623 2624 init_MUTEX(&spec->bind_mutex); 2625 codec->spec = spec; 2626 2627 spec->mixers[spec->num_mixers] = alc882_base_mixer; 2628 spec->num_mixers++; 2629 2630 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; 2631 spec->dig_in_nid = ALC880_DIGIN_NID; 2632 spec->init_verbs[0] = alc882_init_verbs; 2633 spec->num_init_verbs = 1; 2634 2635 spec->channel_mode = alc882_ch_modes; 2636 spec->num_channel_mode = ARRAY_SIZE(alc882_ch_modes); 2637 2638 spec->stream_name_analog = "ALC882 Analog"; 2639 spec->stream_analog_playback = &alc880_pcm_analog_playback; 2640 spec->stream_analog_capture = &alc880_pcm_analog_capture; 2641 2642 spec->stream_name_digital = "ALC882 Digital"; 2643 spec->stream_digital_playback = &alc880_pcm_digital_playback; 2644 spec->stream_digital_capture = &alc880_pcm_digital_capture; 2645 2646 spec->multiout.max_channels = spec->channel_mode[0].channels; 2647 spec->multiout.num_dacs = ARRAY_SIZE(alc882_dac_nids); 2648 spec->multiout.dac_nids = alc882_dac_nids; 2649 2650 spec->input_mux = &alc882_capture_source; 2651 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); 2652 spec->adc_nids = alc882_adc_nids; 2653 2654 codec->patch_ops = alc_patch_ops; 2655 2656 return 0; 2657} 2658 2659/* 2660 * patch entries 2661 */ 2662struct hda_codec_preset snd_hda_preset_realtek[] = { 2663 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, 2664 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, 2665 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, 2666 {} /* terminator */ 2667}; 2668