patch_realtek.c revision b6482d48e536729829025262d6529df09ae20396
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 691/* 692 * build control elements 693 */ 694static int alc_build_controls(struct hda_codec *codec) 695{ 696 struct alc_spec *spec = codec->spec; 697 int err; 698 int i; 699 700 for (i = 0; i < spec->num_mixers; i++) { 701 err = snd_hda_add_new_ctls(codec, spec->mixers[i]); 702 if (err < 0) 703 return err; 704 } 705 706 if (spec->multiout.dig_out_nid) { 707 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); 708 if (err < 0) 709 return err; 710 } 711 if (spec->dig_in_nid) { 712 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 713 if (err < 0) 714 return err; 715 } 716 return 0; 717} 718 719 720/* 721 * initialize the codec volumes, etc 722 */ 723 724/* 725 * generic initialization of ADC, input mixers and output mixers 726 */ 727static struct hda_verb alc880_volume_init_verbs[] = { 728 /* 729 * Unmute ADC0-2 and set the default input to mic-in 730 */ 731 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 732 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 733 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 734 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 735 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 736 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 737 738 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 739 * mixer widget 740 * Note: PASD motherboards uses the Line In 2 as the input for front panel 741 * mic (mic 2) 742 */ 743 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ 744 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 745 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 746 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 747 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 748 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 749 750 /* 751 * Set up output mixers (0x0c - 0x0f) 752 */ 753 /* set vol=0 to output mixers */ 754 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 755 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 756 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 757 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 758 /* set up input amps for analog loopback */ 759 /* Amp Indices: DAC = 0, mixer = 1 */ 760 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 761 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 762 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 763 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 764 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 765 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 766 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 767 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 768 769 { } 770}; 771 772/* 773 * 3-stack pin configuration: 774 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b 775 */ 776static struct hda_verb alc880_pin_3stack_init_verbs[] = { 777 /* 778 * preset connection lists of input pins 779 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround 780 */ 781 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ 782 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ 783 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ 784 785 /* 786 * Set pin mode and muting 787 */ 788 /* set front pin widgets 0x14 for output */ 789 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 790 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 791 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 792 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 793 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 794 /* Mic2 (as headphone out) for HP output */ 795 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 796 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 797 /* Line In pin widget for input */ 798 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 799 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 800 /* Line2 (as front mic) pin widget for input and vref at 80% */ 801 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 802 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 803 /* CD pin widget for input */ 804 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 805 806 { } 807}; 808 809/* 810 * 5-stack pin configuration: 811 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, 812 * line-in/side = 0x1a, f-mic = 0x1b 813 */ 814static struct hda_verb alc880_pin_5stack_init_verbs[] = { 815 /* 816 * preset connection lists of input pins 817 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround 818 */ 819 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ 820 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ 821 822 /* 823 * Set pin mode and muting 824 */ 825 /* set pin widgets 0x14-0x17 for output */ 826 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 827 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 828 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 829 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 830 /* unmute pins for output (no gain on this amp) */ 831 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 832 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 833 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 834 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 835 836 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 837 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 838 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 839 /* Mic2 (as headphone out) for HP output */ 840 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 841 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 842 /* Line In pin widget for input */ 843 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 844 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 845 /* Line2 (as front mic) pin widget for input and vref at 80% */ 846 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 847 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 848 /* CD pin widget for input */ 849 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 850 851 { } 852}; 853 854/* 855 * W810 pin configuration: 856 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b 857 */ 858static struct hda_verb alc880_pin_w810_init_verbs[] = { 859 /* hphone/speaker input selector: front DAC */ 860 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, 861 862 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 863 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 864 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 865 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 866 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 867 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 868 869 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 870 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 871 872 { } 873}; 874 875/* 876 * Z71V pin configuration: 877 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) 878 */ 879static struct hda_verb alc880_pin_z71v_init_verbs[] = { 880 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 881 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 882 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 883 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 884 885 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 886 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 887 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 888 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 889 890 { } 891}; 892 893/* 894 * 6-stack pin configuration: 895 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, f-mic = 0x19, 896 * line = 0x1a, HP = 0x1b 897 */ 898static struct hda_verb alc880_pin_6stack_init_verbs[] = { 899 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ 900 901 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 902 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 903 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 904 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 905 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 906 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 907 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 908 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 909 910 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 911 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 912 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 913 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 914 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 915 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 916 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 917 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 918 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 919 920 { } 921}; 922 923/* FIXME! */ 924/* 925 * F1734 pin configuration: 926 * HP = 0x14, speaker-out = 0x15, mic = 0x18 927 */ 928static struct hda_verb alc880_pin_f1734_init_verbs[] = { 929 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, 930 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, 931 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, 932 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, 933 934 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 935 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 936 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 937 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 938 939 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 940 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 941 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 942 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 943 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 944 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 945 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 946 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 947 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 948 949 { } 950}; 951 952/* FIXME! */ 953/* 954 * ASUS pin configuration: 955 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a 956 */ 957static struct hda_verb alc880_pin_asus_init_verbs[] = { 958 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, 959 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, 960 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, 961 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, 962 963 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 964 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 965 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 966 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 967 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 968 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 969 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 970 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 971 972 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 973 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 974 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 975 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 976 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 977 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 978 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 979 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 980 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 981 982 { } 983}; 984 985/* Enable GPIO mask and set output */ 986static struct hda_verb alc880_gpio1_init_verbs[] = { 987 {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, 988 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, 989 {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, 990}; 991 992/* Enable GPIO mask and set output */ 993static struct hda_verb alc880_gpio2_init_verbs[] = { 994 {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, 995 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, 996 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, 997}; 998 999 1000/* 1001 */ 1002 1003static int alc_init(struct hda_codec *codec) 1004{ 1005 struct alc_spec *spec = codec->spec; 1006 unsigned int i; 1007 1008 for (i = 0; i < spec->num_init_verbs; i++) 1009 snd_hda_sequence_write(codec, spec->init_verbs[i]); 1010 return 0; 1011} 1012 1013#ifdef CONFIG_PM 1014/* 1015 * resume 1016 */ 1017static int alc_resume(struct hda_codec *codec) 1018{ 1019 struct alc_spec *spec = codec->spec; 1020 int i; 1021 1022 alc_init(codec); 1023 for (i = 0; i < spec->num_mixers; i++) 1024 snd_hda_resume_ctls(codec, spec->mixers[i]); 1025 if (spec->multiout.dig_out_nid) 1026 snd_hda_resume_spdif_out(codec); 1027 if (spec->dig_in_nid) 1028 snd_hda_resume_spdif_in(codec); 1029 1030 return 0; 1031} 1032#endif 1033 1034/* 1035 * Analog playback callbacks 1036 */ 1037static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo, 1038 struct hda_codec *codec, 1039 snd_pcm_substream_t *substream) 1040{ 1041 struct alc_spec *spec = codec->spec; 1042 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); 1043} 1044 1045static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 1046 struct hda_codec *codec, 1047 unsigned int stream_tag, 1048 unsigned int format, 1049 snd_pcm_substream_t *substream) 1050{ 1051 struct alc_spec *spec = codec->spec; 1052 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, 1053 format, substream); 1054} 1055 1056static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 1057 struct hda_codec *codec, 1058 snd_pcm_substream_t *substream) 1059{ 1060 struct alc_spec *spec = codec->spec; 1061 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 1062} 1063 1064/* 1065 * Digital out 1066 */ 1067static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 1068 struct hda_codec *codec, 1069 snd_pcm_substream_t *substream) 1070{ 1071 struct alc_spec *spec = codec->spec; 1072 return snd_hda_multi_out_dig_open(codec, &spec->multiout); 1073} 1074 1075static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 1076 struct hda_codec *codec, 1077 snd_pcm_substream_t *substream) 1078{ 1079 struct alc_spec *spec = codec->spec; 1080 return snd_hda_multi_out_dig_close(codec, &spec->multiout); 1081} 1082 1083/* 1084 * Analog capture 1085 */ 1086static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 1087 struct hda_codec *codec, 1088 unsigned int stream_tag, 1089 unsigned int format, 1090 snd_pcm_substream_t *substream) 1091{ 1092 struct alc_spec *spec = codec->spec; 1093 1094 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 1095 stream_tag, 0, format); 1096 return 0; 1097} 1098 1099static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 1100 struct hda_codec *codec, 1101 snd_pcm_substream_t *substream) 1102{ 1103 struct alc_spec *spec = codec->spec; 1104 1105 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); 1106 return 0; 1107} 1108 1109 1110/* 1111 */ 1112static struct hda_pcm_stream alc880_pcm_analog_playback = { 1113 .substreams = 1, 1114 .channels_min = 2, 1115 .channels_max = 8, 1116 /* NID is set in alc_build_pcms */ 1117 .ops = { 1118 .open = alc880_playback_pcm_open, 1119 .prepare = alc880_playback_pcm_prepare, 1120 .cleanup = alc880_playback_pcm_cleanup 1121 }, 1122}; 1123 1124static struct hda_pcm_stream alc880_pcm_analog_capture = { 1125 .substreams = 2, 1126 .channels_min = 2, 1127 .channels_max = 2, 1128 /* NID is set in alc_build_pcms */ 1129 .ops = { 1130 .prepare = alc880_capture_pcm_prepare, 1131 .cleanup = alc880_capture_pcm_cleanup 1132 }, 1133}; 1134 1135static struct hda_pcm_stream alc880_pcm_digital_playback = { 1136 .substreams = 1, 1137 .channels_min = 2, 1138 .channels_max = 2, 1139 /* NID is set in alc_build_pcms */ 1140 .ops = { 1141 .open = alc880_dig_playback_pcm_open, 1142 .close = alc880_dig_playback_pcm_close 1143 }, 1144}; 1145 1146static struct hda_pcm_stream alc880_pcm_digital_capture = { 1147 .substreams = 1, 1148 .channels_min = 2, 1149 .channels_max = 2, 1150 /* NID is set in alc_build_pcms */ 1151}; 1152 1153static int alc_build_pcms(struct hda_codec *codec) 1154{ 1155 struct alc_spec *spec = codec->spec; 1156 struct hda_pcm *info = spec->pcm_rec; 1157 int i; 1158 1159 codec->num_pcms = 1; 1160 codec->pcm_info = info; 1161 1162 info->name = spec->stream_name_analog; 1163 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); 1164 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; 1165 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); 1166 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 1167 1168 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; 1169 for (i = 0; i < spec->num_channel_mode; i++) { 1170 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) { 1171 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels; 1172 } 1173 } 1174 1175 if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 1176 codec->num_pcms++; 1177 info++; 1178 info->name = spec->stream_name_digital; 1179 if (spec->multiout.dig_out_nid) { 1180 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback); 1181 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; 1182 } 1183 if (spec->dig_in_nid) { 1184 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture); 1185 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; 1186 } 1187 } 1188 1189 return 0; 1190} 1191 1192static void alc_free(struct hda_codec *codec) 1193{ 1194 struct alc_spec *spec = codec->spec; 1195 unsigned int i; 1196 1197 if (! spec) 1198 return; 1199 1200 if (spec->kctl_alloc) { 1201 for (i = 0; i < spec->num_kctl_used; i++) 1202 kfree(spec->kctl_alloc[i].name); 1203 kfree(spec->kctl_alloc); 1204 } 1205 kfree(spec); 1206} 1207 1208/* 1209 */ 1210static struct hda_codec_ops alc_patch_ops = { 1211 .build_controls = alc_build_controls, 1212 .build_pcms = alc_build_pcms, 1213 .init = alc_init, 1214 .free = alc_free, 1215#ifdef CONFIG_PM 1216 .resume = alc_resume, 1217#endif 1218}; 1219 1220 1221/* 1222 * Test configuration for debugging 1223 * 1224 * Almost all inputs/outputs are enabled. I/O pins can be configured via 1225 * enum controls. 1226 */ 1227#ifdef CONFIG_SND_DEBUG 1228static hda_nid_t alc880_test_dac_nids[4] = { 1229 0x02, 0x03, 0x04, 0x05 1230}; 1231 1232static struct hda_input_mux alc880_test_capture_source = { 1233 .num_items = 5, 1234 .items = { 1235 { "In-1", 0x0 }, 1236 { "In-2", 0x1 }, 1237 { "In-3", 0x2 }, 1238 { "In-4", 0x3 }, 1239 { "CD", 0x4 }, 1240 }, 1241}; 1242 1243static struct alc_channel_mode alc880_test_modes[4] = { 1244 { 2, NULL }, 1245 { 4, NULL }, 1246 { 6, NULL }, 1247 { 8, NULL }, 1248}; 1249 1250static int alc_test_pin_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 1251{ 1252 static char *texts[] = { 1253 "N/A", "Line Out", "HP Out", 1254 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" 1255 }; 1256 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1257 uinfo->count = 1; 1258 uinfo->value.enumerated.items = 8; 1259 if (uinfo->value.enumerated.item >= 8) 1260 uinfo->value.enumerated.item = 7; 1261 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 1262 return 0; 1263} 1264 1265static int alc_test_pin_ctl_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 1266{ 1267 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1268 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1269 unsigned int pin_ctl, item = 0; 1270 1271 pin_ctl = snd_hda_codec_read(codec, nid, 0, 1272 AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 1273 if (pin_ctl & AC_PINCTL_OUT_EN) { 1274 if (pin_ctl & AC_PINCTL_HP_EN) 1275 item = 2; 1276 else 1277 item = 1; 1278 } else if (pin_ctl & AC_PINCTL_IN_EN) { 1279 switch (pin_ctl & AC_PINCTL_VREFEN) { 1280 case AC_PINCTL_VREF_HIZ: item = 3; break; 1281 case AC_PINCTL_VREF_50: item = 4; break; 1282 case AC_PINCTL_VREF_GRD: item = 5; break; 1283 case AC_PINCTL_VREF_80: item = 6; break; 1284 case AC_PINCTL_VREF_100: item = 7; break; 1285 } 1286 } 1287 ucontrol->value.enumerated.item[0] = item; 1288 return 0; 1289} 1290 1291static int alc_test_pin_ctl_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 1292{ 1293 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1294 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1295 static unsigned int ctls[] = { 1296 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, 1297 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, 1298 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, 1299 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, 1300 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, 1301 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, 1302 }; 1303 unsigned int old_ctl, new_ctl; 1304 1305 old_ctl = snd_hda_codec_read(codec, nid, 0, 1306 AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 1307 new_ctl = ctls[ucontrol->value.enumerated.item[0]]; 1308 if (old_ctl != new_ctl) { 1309 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); 1310 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 1311 ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000); 1312 return 1; 1313 } 1314 return 0; 1315} 1316 1317static int alc_test_pin_src_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 1318{ 1319 static char *texts[] = { 1320 "Front", "Surround", "CLFE", "Side" 1321 }; 1322 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1323 uinfo->count = 1; 1324 uinfo->value.enumerated.items = 4; 1325 if (uinfo->value.enumerated.item >= 4) 1326 uinfo->value.enumerated.item = 3; 1327 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 1328 return 0; 1329} 1330 1331static int alc_test_pin_src_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 1332{ 1333 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1334 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1335 unsigned int sel; 1336 1337 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); 1338 ucontrol->value.enumerated.item[0] = sel & 3; 1339 return 0; 1340} 1341 1342static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 1343{ 1344 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1345 hda_nid_t nid = (hda_nid_t)kcontrol->private_value; 1346 unsigned int sel; 1347 1348 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; 1349 if (ucontrol->value.enumerated.item[0] != sel) { 1350 sel = ucontrol->value.enumerated.item[0] & 3; 1351 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); 1352 return 1; 1353 } 1354 return 0; 1355} 1356 1357#define PIN_CTL_TEST(xname,nid) { \ 1358 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 1359 .name = xname, \ 1360 .info = alc_test_pin_ctl_info, \ 1361 .get = alc_test_pin_ctl_get, \ 1362 .put = alc_test_pin_ctl_put, \ 1363 .private_value = nid \ 1364 } 1365 1366#define PIN_SRC_TEST(xname,nid) { \ 1367 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 1368 .name = xname, \ 1369 .info = alc_test_pin_src_info, \ 1370 .get = alc_test_pin_src_get, \ 1371 .put = alc_test_pin_src_put, \ 1372 .private_value = nid \ 1373 } 1374 1375static snd_kcontrol_new_t alc880_test_mixer[] = { 1376 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 1377 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 1378 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), 1379 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), 1380 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 1381 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 1382 ALC_BIND_MUTE("CLFE Playback Volume", 0x0e, 2, HDA_INPUT), 1383 ALC_BIND_MUTE("Side Playback Volume", 0x0f, 2, HDA_INPUT), 1384 PIN_CTL_TEST("Front Pin Mode", 0x14), 1385 PIN_CTL_TEST("Surround Pin Mode", 0x15), 1386 PIN_CTL_TEST("CLFE Pin Mode", 0x16), 1387 PIN_CTL_TEST("Side Pin Mode", 0x17), 1388 PIN_CTL_TEST("In-1 Pin Mode", 0x18), 1389 PIN_CTL_TEST("In-2 Pin Mode", 0x19), 1390 PIN_CTL_TEST("In-3 Pin Mode", 0x1a), 1391 PIN_CTL_TEST("In-4 Pin Mode", 0x1b), 1392 PIN_SRC_TEST("In-1 Pin Source", 0x18), 1393 PIN_SRC_TEST("In-2 Pin Source", 0x19), 1394 PIN_SRC_TEST("In-3 Pin Source", 0x1a), 1395 PIN_SRC_TEST("In-4 Pin Source", 0x1b), 1396 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), 1397 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), 1398 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), 1399 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), 1400 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), 1401 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), 1402 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), 1403 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), 1404 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), 1405 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), 1406 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), 1407 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), 1408 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), 1409 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), 1410 { 1411 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1412 .name = "Input Source", 1413 .count = 2, 1414 .info = alc_mux_enum_info, 1415 .get = alc_mux_enum_get, 1416 .put = alc_mux_enum_put, 1417 }, 1418 { 1419 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1420 .name = "Channel Mode", 1421 .info = alc880_ch_mode_info, 1422 .get = alc880_ch_mode_get, 1423 .put = alc880_ch_mode_put, 1424 }, 1425 { } /* end */ 1426}; 1427 1428static struct hda_verb alc880_test_init_verbs[] = { 1429 /* Unmute inputs of 0x0c - 0x0f */ 1430 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1431 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1432 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1433 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1434 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1435 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1436 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1437 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1438 /* Vol output for 0x0c-0x0f */ 1439 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1440 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1441 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1442 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1443 /* Set output pins 0x14-0x17 */ 1444 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1445 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1446 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1447 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1448 /* Unmute output pins 0x14-0x17 */ 1449 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1450 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1451 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1452 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1453 /* Set input pins 0x18-0x1c */ 1454 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1455 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1456 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1457 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1458 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1459 /* Mute input pins 0x18-0x1b */ 1460 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1461 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1462 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1463 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1464 /* ADC set up */ 1465 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1466 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 1467 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1468 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 1469 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1470 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 1471 /* Analog input/passthru */ 1472 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1473 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 1474 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 1475 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 1476 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 1477 { } 1478}; 1479#endif 1480 1481/* 1482 */ 1483 1484static struct hda_board_config alc880_cfg_tbl[] = { 1485 /* Back 3 jack, front 2 jack */ 1486 { .modelname = "3stack", .config = ALC880_3ST }, 1487 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST }, 1488 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST }, 1489 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST }, 1490 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST }, 1491 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST }, 1492 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST }, 1493 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST }, 1494 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST }, 1495 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST }, 1496 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST }, 1497 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST }, 1498 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST }, 1499 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST }, 1500 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST }, 1501 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST }, 1502 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, 1503 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, 1504 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, 1505 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, 1506 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, 1507 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, 1508 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, 1509 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST }, 1510 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST }, 1511 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST }, 1512 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST }, 1513 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST }, 1514 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST }, 1515 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST }, 1516 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST }, 1517 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, 1518 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, 1519 1520 /* Back 3 jack, front 2 jack (Internal add Aux-In) */ 1521 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, 1522 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST }, 1523 1524 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ 1525 { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, 1526 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, 1527 1528 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ 1529 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, 1530 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG }, 1531 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG }, 1532 1533 /* Back 5 jack, front 2 jack */ 1534 { .modelname = "5stack", .config = ALC880_5ST }, 1535 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST }, 1536 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST }, 1537 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST }, 1538 { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST }, 1539 { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST }, 1540 1541 /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ 1542 { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, 1543 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG }, 1544 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG }, 1545 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG }, 1546 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG }, 1547 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG }, 1548 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG }, 1549 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG }, 1550 { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG }, 1551 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG }, 1552 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, 1553 { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG }, 1554 /* note subvendor = 0 below */ 1555 /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */ 1556 1557 { .modelname = "w810", .config = ALC880_W810 }, 1558 { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 }, 1559 1560 { .modelname = "z71v", .config = ALC880_Z71V }, 1561 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, 1562 1563 { .modelname = "6stack", .config = ALC880_6ST }, 1564 1565 { .modelname = "6stack-digout", .config = ALC880_6ST_DIG }, 1566 { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG }, 1567 { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG }, 1568 { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, 1569 { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, 1570 1571 { .modelname = "asus", .config = ALC880_ASUS }, 1572 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, 1573 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG }, 1574 { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG }, 1575 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, 1576 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, 1577 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, 1578 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, 1579 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, 1580 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, 1581 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, 1582 1583 { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, 1584 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, 1585 1586 { .modelname = "F1734", .config = ALC880_F1734 }, 1587 { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, 1588 1589#ifdef CONFIG_SND_DEBUG 1590 { .modelname = "test", .config = ALC880_TEST }, 1591#endif 1592 1593 {} 1594}; 1595 1596/* 1597 * configuration template - to be copied to the spec instance 1598 */ 1599struct alc_config_preset { 1600 snd_kcontrol_new_t *mixers[4]; 1601 const struct hda_verb *init_verbs[4]; 1602 unsigned int num_dacs; 1603 hda_nid_t *dac_nids; 1604 hda_nid_t dig_out_nid; /* optional */ 1605 hda_nid_t hp_nid; /* optional */ 1606 unsigned int num_adc_nids; 1607 hda_nid_t *adc_nids; 1608 unsigned int num_channel_mode; 1609 const struct alc_channel_mode *channel_mode; 1610 const struct hda_input_mux *input_mux; 1611}; 1612 1613static struct alc_config_preset alc880_presets[] = { 1614 [ALC880_3ST] = { 1615 .mixers = { alc880_three_stack_mixer }, 1616 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, 1617 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1618 .dac_nids = alc880_dac_nids, 1619 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), 1620 .channel_mode = alc880_threestack_modes, 1621 .input_mux = &alc880_capture_source, 1622 }, 1623 [ALC880_3ST_DIG] = { 1624 .mixers = { alc880_three_stack_mixer }, 1625 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, 1626 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1627 .dac_nids = alc880_dac_nids, 1628 .dig_out_nid = ALC880_DIGOUT_NID, 1629 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), 1630 .channel_mode = alc880_threestack_modes, 1631 .input_mux = &alc880_capture_source, 1632 }, 1633 [ALC880_5ST] = { 1634 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer}, 1635 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, 1636 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1637 .dac_nids = alc880_dac_nids, 1638 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), 1639 .channel_mode = alc880_fivestack_modes, 1640 .input_mux = &alc880_capture_source, 1641 }, 1642 [ALC880_5ST_DIG] = { 1643 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer }, 1644 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, 1645 .num_dacs = ARRAY_SIZE(alc880_dac_nids), 1646 .dac_nids = alc880_dac_nids, 1647 .dig_out_nid = ALC880_DIGOUT_NID, 1648 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), 1649 .channel_mode = alc880_fivestack_modes, 1650 .input_mux = &alc880_capture_source, 1651 }, 1652 [ALC880_6ST] = { 1653 .mixers = { alc880_six_stack_mixer }, 1654 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs }, 1655 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), 1656 .dac_nids = alc880_6st_dac_nids, 1657 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), 1658 .channel_mode = alc880_sixstack_modes, 1659 .input_mux = &alc880_6stack_capture_source, 1660 }, 1661 [ALC880_6ST_DIG] = { 1662 .mixers = { alc880_six_stack_mixer }, 1663 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs }, 1664 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), 1665 .dac_nids = alc880_6st_dac_nids, 1666 .dig_out_nid = ALC880_DIGOUT_NID, 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_W810] = { 1672 .mixers = { alc880_w810_base_mixer }, 1673 .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs, 1674 alc880_gpio2_init_verbs }, 1675 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), 1676 .dac_nids = alc880_w810_dac_nids, 1677 .dig_out_nid = ALC880_DIGOUT_NID, 1678 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), 1679 .channel_mode = alc880_w810_modes, 1680 .input_mux = &alc880_capture_source, 1681 }, 1682 [ALC880_Z71V] = { 1683 .mixers = { alc880_z71v_mixer }, 1684 .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs }, 1685 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), 1686 .dac_nids = alc880_z71v_dac_nids, 1687 .dig_out_nid = ALC880_DIGOUT_NID, 1688 .hp_nid = 0x03, 1689 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), 1690 .channel_mode = alc880_2_jack_modes, 1691 .input_mux = &alc880_capture_source, 1692 }, 1693 [ALC880_F1734] = { 1694 .mixers = { alc880_f1734_mixer }, 1695 .init_verbs = { alc880_volume_init_verbs, alc880_pin_f1734_init_verbs }, 1696 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), 1697 .dac_nids = alc880_f1734_dac_nids, 1698 .hp_nid = 0x02, 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_ASUS] = { 1704 .mixers = { alc880_asus_mixer }, 1705 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, 1706 alc880_gpio1_init_verbs }, 1707 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 1708 .dac_nids = alc880_asus_dac_nids, 1709 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1710 .channel_mode = alc880_asus_modes, 1711 .input_mux = &alc880_capture_source, 1712 }, 1713 [ALC880_ASUS_DIG] = { 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 .dig_out_nid = ALC880_DIGOUT_NID, 1720 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1721 .channel_mode = alc880_asus_modes, 1722 .input_mux = &alc880_capture_source, 1723 }, 1724 [ALC880_ASUS_W1V] = { 1725 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, 1726 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, 1727 alc880_gpio1_init_verbs }, 1728 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 1729 .dac_nids = alc880_asus_dac_nids, 1730 .dig_out_nid = ALC880_DIGOUT_NID, 1731 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), 1732 .channel_mode = alc880_asus_modes, 1733 .input_mux = &alc880_capture_source, 1734 }, 1735 [ALC880_UNIWILL_DIG] = { 1736 .mixers = { alc880_asus_mixer }, 1737 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_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#ifdef CONFIG_SND_DEBUG 1746 [ALC880_TEST] = { 1747 .mixers = { alc880_test_mixer }, 1748 .init_verbs = { alc880_test_init_verbs }, 1749 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), 1750 .dac_nids = alc880_test_dac_nids, 1751 .dig_out_nid = ALC880_DIGOUT_NID, 1752 .num_channel_mode = ARRAY_SIZE(alc880_test_modes), 1753 .channel_mode = alc880_test_modes, 1754 .input_mux = &alc880_test_capture_source, 1755 }, 1756#endif 1757}; 1758 1759/* 1760 * Automatic parse of I/O pins from the BIOS configuration 1761 */ 1762 1763#define NUM_CONTROL_ALLOC 32 1764#define NUM_VERB_ALLOC 32 1765 1766enum { 1767 ALC_CTL_WIDGET_VOL, 1768 ALC_CTL_WIDGET_MUTE, 1769 ALC_CTL_BIND_MUTE, 1770}; 1771static snd_kcontrol_new_t alc880_control_templates[] = { 1772 HDA_CODEC_VOLUME(NULL, 0, 0, 0), 1773 HDA_CODEC_MUTE(NULL, 0, 0, 0), 1774 ALC_BIND_MUTE(NULL, 0, 0, 0), 1775}; 1776 1777/* add dynamic controls */ 1778static int add_control(struct alc_spec *spec, int type, const char *name, unsigned long val) 1779{ 1780 snd_kcontrol_new_t *knew; 1781 1782 if (spec->num_kctl_used >= spec->num_kctl_alloc) { 1783 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; 1784 1785 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ 1786 if (! knew) 1787 return -ENOMEM; 1788 if (spec->kctl_alloc) { 1789 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); 1790 kfree(spec->kctl_alloc); 1791 } 1792 spec->kctl_alloc = knew; 1793 spec->num_kctl_alloc = num; 1794 } 1795 1796 knew = &spec->kctl_alloc[spec->num_kctl_used]; 1797 *knew = alc880_control_templates[type]; 1798 knew->name = kstrdup(name, GFP_KERNEL); 1799 if (! knew->name) 1800 return -ENOMEM; 1801 knew->private_value = val; 1802 spec->num_kctl_used++; 1803 return 0; 1804} 1805 1806#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) 1807#define alc880_fixed_pin_idx(nid) ((nid) - 0x14) 1808#define alc880_is_multi_pin(nid) ((nid) >= 0x18) 1809#define alc880_multi_pin_idx(nid) ((nid) - 0x18) 1810#define alc880_is_input_pin(nid) ((nid) >= 0x18) 1811#define alc880_input_pin_idx(nid) ((nid) - 0x18) 1812#define alc880_idx_to_dac(nid) ((nid) + 0x02) 1813#define alc880_dac_to_idx(nid) ((nid) - 0x02) 1814#define alc880_idx_to_mixer(nid) ((nid) + 0x0c) 1815#define alc880_idx_to_selector(nid) ((nid) + 0x10) 1816#define ALC880_PIN_CD_NID 0x1c 1817 1818/* fill in the dac_nids table from the parsed pin configuration */ 1819static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 1820{ 1821 hda_nid_t nid; 1822 int assigned[4]; 1823 int i, j; 1824 1825 memset(assigned, 0, sizeof(assigned)); 1826 spec->multiout.dac_nids = spec->private_dac_nids; 1827 1828 /* check the pins hardwired to audio widget */ 1829 for (i = 0; i < cfg->line_outs; i++) { 1830 nid = cfg->line_out_pins[i]; 1831 if (alc880_is_fixed_pin(nid)) { 1832 int idx = alc880_fixed_pin_idx(nid); 1833 spec->multiout.dac_nids[i] = alc880_dac_to_idx(idx); 1834 assigned[idx] = 1; 1835 } 1836 } 1837 /* left pins can be connect to any audio widget */ 1838 for (i = 0; i < cfg->line_outs; i++) { 1839 nid = cfg->line_out_pins[i]; 1840 if (alc880_is_fixed_pin(nid)) 1841 continue; 1842 /* search for an empty channel */ 1843 for (j = 0; j < cfg->line_outs; j++) { 1844 if (! assigned[j]) { 1845 spec->multiout.dac_nids[i] = alc880_idx_to_dac(j); 1846 assigned[j] = 1; 1847 break; 1848 } 1849 } 1850 } 1851 spec->multiout.num_dacs = cfg->line_outs; 1852 return 0; 1853} 1854 1855/* add playback controls from the parsed DAC table */ 1856static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 1857{ 1858 char name[32]; 1859 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; 1860 hda_nid_t nid; 1861 int i, err; 1862 1863 for (i = 0; i < cfg->line_outs; i++) { 1864 if (! spec->multiout.dac_nids[i]) 1865 continue; 1866 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); 1867 if (i == 2) { 1868 /* Center/LFE */ 1869 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Center Playback Volume", 1870 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) 1871 return err; 1872 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "LFE Playback Volume", 1873 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) 1874 return err; 1875 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch", 1876 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT))) < 0) 1877 return err; 1878 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch", 1879 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT))) < 0) 1880 return err; 1881 } else { 1882 sprintf(name, "%s Playback Volume", chname[i]); 1883 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, 1884 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 1885 return err; 1886 sprintf(name, "%s Playback Switch", chname[i]); 1887 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, 1888 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) 1889 return err; 1890 } 1891 } 1892 1893 return 0; 1894} 1895 1896/* add playback controls for HP output */ 1897static int alc880_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) 1898{ 1899 hda_nid_t nid; 1900 int err; 1901 1902 if (! pin) 1903 return 0; 1904 1905 if (alc880_is_fixed_pin(pin)) { 1906 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); 1907 if (! spec->multiout.dac_nids[0]) { 1908 /* use this as the primary output */ 1909 spec->multiout.dac_nids[0] = nid; 1910 if (! spec->multiout.num_dacs) 1911 spec->multiout.num_dacs = 1; 1912 } else 1913 /* specify the DAC as the extra HP output */ 1914 spec->multiout.hp_nid = nid; 1915 /* control HP volume/switch on the output mixer amp */ 1916 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); 1917 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", 1918 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) 1919 return err; 1920 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Headphone Playback Switch", 1921 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) 1922 return err; 1923 } else if (alc880_is_multi_pin(pin)) { 1924 /* set manual connection */ 1925 if (! spec->multiout.dac_nids[0]) { 1926 /* use this as the primary output */ 1927 spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin)); 1928 if (! spec->multiout.num_dacs) 1929 spec->multiout.num_dacs = 1; 1930 } 1931 /* we have only a switch on HP-out PIN */ 1932 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", 1933 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT))) < 0) 1934 return err; 1935 } 1936 return 0; 1937} 1938 1939/* create input playback/capture controls for the given pin */ 1940static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname) 1941{ 1942 char name[32]; 1943 int err, idx; 1944 1945 sprintf(name, "%s Playback Volume", ctlname); 1946 idx = alc880_input_pin_idx(pin); 1947 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, 1948 HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) 1949 return err; 1950 sprintf(name, "%s Playback Switch", ctlname); 1951 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, 1952 HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) 1953 return err; 1954 return 0; 1955} 1956 1957/* create playback/capture controls for input pins */ 1958static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) 1959{ 1960 static char *labels[AUTO_PIN_LAST] = { 1961 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" 1962 }; 1963 struct hda_input_mux *imux = &spec->private_imux; 1964 int i, err; 1965 1966 for (i = 0; i < AUTO_PIN_LAST; i++) { 1967 if (alc880_is_input_pin(cfg->input_pins[i])) { 1968 err = new_analog_input(spec, cfg->input_pins[i], labels[i]); 1969 if (err < 0) 1970 return err; 1971 imux->items[imux->num_items].label = labels[i]; 1972 imux->items[imux->num_items].index = alc880_input_pin_idx(cfg->input_pins[i]); 1973 imux->num_items++; 1974 } 1975 } 1976 return 0; 1977} 1978 1979static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, 1980 int dac_idx) 1981{ 1982 /* set as output */ 1983 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); 1984 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 1985 /* need the manual connection? */ 1986 if (alc880_is_multi_pin(nid)) { 1987 struct alc_spec *spec = codec->spec; 1988 int idx = alc880_multi_pin_idx(nid); 1989 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, 1990 AC_VERB_SET_CONNECT_SEL, 1991 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); 1992 } 1993} 1994 1995static void alc880_auto_init_multi_out(struct hda_codec *codec) 1996{ 1997 struct alc_spec *spec = codec->spec; 1998 int i; 1999 2000 for (i = 0; i < spec->autocfg.line_outs; i++) { 2001 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 2002 alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); 2003 } 2004} 2005 2006static void alc880_auto_init_hp_out(struct hda_codec *codec) 2007{ 2008 struct alc_spec *spec = codec->spec; 2009 hda_nid_t pin; 2010 2011 pin = spec->autocfg.hp_pin; 2012 if (pin) /* connect to front */ 2013 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); 2014} 2015 2016static void alc880_auto_init_analog_input(struct hda_codec *codec) 2017{ 2018 struct alc_spec *spec = codec->spec; 2019 int i; 2020 2021 for (i = 0; i < AUTO_PIN_LAST; i++) { 2022 hda_nid_t nid = spec->autocfg.input_pins[i]; 2023 if (alc880_is_input_pin(nid)) { 2024 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 2025 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); 2026 if (nid != ALC880_PIN_CD_NID) 2027 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 2028 AMP_OUT_MUTE); 2029 } 2030 } 2031} 2032 2033/* parse the BIOS configuration and set up the alc_spec */ 2034/* return 1 if successful, 0 if the proper config is not found, or a negative error code */ 2035static int alc880_parse_auto_config(struct hda_codec *codec) 2036{ 2037 struct alc_spec *spec = codec->spec; 2038 int err; 2039 2040 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0) 2041 return err; 2042 if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0) 2043 return err; 2044 if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin) 2045 return 0; /* can't find valid BIOS pin config */ 2046 if ((err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || 2047 (err = alc880_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || 2048 (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) 2049 return err; 2050 2051 spec->multiout.max_channels = spec->multiout.num_dacs * 2; 2052 2053 if (spec->autocfg.dig_out_pin) 2054 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; 2055 if (spec->autocfg.dig_in_pin) 2056 spec->dig_in_nid = ALC880_DIGIN_NID; 2057 2058 if (spec->kctl_alloc) 2059 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 2060 2061 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; 2062 2063 spec->input_mux = &spec->private_imux; 2064 2065 return 1; 2066} 2067 2068/* init callback for auto-configuration model -- overriding the default init */ 2069static int alc880_auto_init(struct hda_codec *codec) 2070{ 2071 alc_init(codec); 2072 alc880_auto_init_multi_out(codec); 2073 alc880_auto_init_hp_out(codec); 2074 alc880_auto_init_analog_input(codec); 2075 return 0; 2076} 2077 2078/* 2079 * OK, here we have finally the patch for ALC880 2080 */ 2081 2082static int patch_alc880(struct hda_codec *codec) 2083{ 2084 struct alc_spec *spec; 2085 int board_config; 2086 int i, err; 2087 2088 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 2089 if (spec == NULL) 2090 return -ENOMEM; 2091 2092 init_MUTEX(&spec->bind_mutex); 2093 codec->spec = spec; 2094 2095 board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); 2096 if (board_config < 0 || board_config >= ALC880_MODEL_LAST) { 2097 printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n"); 2098 board_config = ALC880_AUTO; 2099 } 2100 2101 if (board_config == ALC880_AUTO) { 2102 /* automatic parse from the BIOS config */ 2103 err = alc880_parse_auto_config(codec); 2104 if (err < 0) { 2105 alc_free(codec); 2106 return err; 2107 } else if (! err) { 2108 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 3-stack mode...\n"); 2109 board_config = ALC880_3ST; 2110 } 2111 } 2112 2113 if (board_config != ALC880_AUTO) { 2114 /* set up from the preset table */ 2115 const struct alc_config_preset *preset; 2116 2117 preset = &alc880_presets[board_config]; 2118 2119 for (i = 0; preset->mixers[i]; i++) { 2120 snd_assert(spec->num_mixers < ARRAY_SIZE(spec->mixers), break); 2121 spec->mixers[spec->num_mixers++] = preset->mixers[i]; 2122 } 2123 for (i = 0; preset->init_verbs[i]; i++) { 2124 snd_assert(spec->num_init_verbs < ARRAY_SIZE(spec->init_verbs), break); 2125 spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i]; 2126 } 2127 2128 spec->channel_mode = preset->channel_mode; 2129 spec->num_channel_mode = preset->num_channel_mode; 2130 2131 spec->multiout.max_channels = spec->channel_mode[0].channels; 2132 2133 spec->multiout.num_dacs = preset->num_dacs; 2134 spec->multiout.dac_nids = preset->dac_nids; 2135 spec->multiout.dig_out_nid = preset->dig_out_nid; 2136 spec->multiout.hp_nid = preset->hp_nid; 2137 2138 spec->input_mux = preset->input_mux; 2139 2140 spec->num_adc_nids = preset->num_adc_nids; 2141 spec->adc_nids = preset->adc_nids; 2142 } 2143 2144 spec->stream_name_analog = "ALC880 Analog"; 2145 spec->stream_analog_playback = &alc880_pcm_analog_playback; 2146 spec->stream_analog_capture = &alc880_pcm_analog_capture; 2147 2148 spec->stream_name_digital = "ALC880 Digital"; 2149 spec->stream_digital_playback = &alc880_pcm_digital_playback; 2150 spec->stream_digital_capture = &alc880_pcm_digital_capture; 2151 2152 if (! spec->adc_nids && spec->input_mux) { 2153 /* check whether NID 0x07 is valid */ 2154 unsigned int wcap = snd_hda_param_read(codec, alc880_adc_nids[0], 2155 AC_PAR_AUDIO_WIDGET_CAP); 2156 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ 2157 if (wcap != AC_WID_AUD_IN) { 2158 spec->adc_nids = alc880_adc_nids_alt; 2159 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); 2160 spec->mixers[spec->num_mixers] = alc880_capture_alt_mixer; 2161 spec->num_mixers++; 2162 } else { 2163 spec->adc_nids = alc880_adc_nids; 2164 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); 2165 spec->mixers[spec->num_mixers] = alc880_capture_mixer; 2166 spec->num_mixers++; 2167 } 2168 } 2169 2170 codec->patch_ops = alc_patch_ops; 2171 if (board_config == ALC880_AUTO) 2172 codec->patch_ops.init = alc880_auto_init; 2173 2174 return 0; 2175} 2176 2177 2178/* 2179 * ALC260 support 2180 */ 2181 2182static hda_nid_t alc260_dac_nids[1] = { 2183 /* front */ 2184 0x02, 2185}; 2186 2187static hda_nid_t alc260_adc_nids[1] = { 2188 /* ADC0 */ 2189 0x04, 2190}; 2191 2192static hda_nid_t alc260_hp_adc_nids[1] = { 2193 /* ADC1 */ 2194 0x05, 2195}; 2196 2197#define ALC260_DIGOUT_NID 0x03 2198#define ALC260_DIGIN_NID 0x06 2199 2200static struct hda_input_mux alc260_capture_source = { 2201 .num_items = 4, 2202 .items = { 2203 { "Mic", 0x0 }, 2204 { "Front Mic", 0x1 }, 2205 { "Line", 0x2 }, 2206 { "CD", 0x4 }, 2207 }, 2208}; 2209 2210/* 2211 * This is just place-holder, so there's something for alc_build_pcms to look 2212 * at when it calculates the maximum number of channels. ALC260 has no mixer 2213 * element which allows changing the channel mode, so the verb list is 2214 * never used. 2215 */ 2216static struct alc_channel_mode alc260_modes[1] = { 2217 { 2, NULL }, 2218}; 2219 2220static snd_kcontrol_new_t alc260_base_mixer[] = { 2221 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), 2222 ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), 2223 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), 2224 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), 2225 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), 2226 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), 2227 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), 2228 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), 2229 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), 2230 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), 2231 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), 2232 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), 2233 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), 2234 ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), 2235 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), 2236 ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_OUTPUT), 2237 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), 2238 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), 2239 { 2240 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2241 .name = "Capture Source", 2242 .info = alc_mux_enum_info, 2243 .get = alc_mux_enum_get, 2244 .put = alc_mux_enum_put, 2245 }, 2246 { } /* end */ 2247}; 2248 2249static snd_kcontrol_new_t alc260_hp_mixer[] = { 2250 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), 2251 ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), 2252 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), 2253 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), 2254 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), 2255 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), 2256 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), 2257 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), 2258 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), 2259 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), 2260 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), 2261 ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), 2262 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), 2263 ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_OUTPUT), 2264 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), 2265 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), 2266 { 2267 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2268 .name = "Capture Source", 2269 .info = alc_mux_enum_info, 2270 .get = alc_mux_enum_get, 2271 .put = alc_mux_enum_put, 2272 }, 2273 { } /* end */ 2274}; 2275 2276static struct hda_verb alc260_init_verbs[] = { 2277 /* Line In pin widget for input */ 2278 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2279 /* CD pin widget for input */ 2280 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2281 /* Mic1 (rear panel) pin widget for input and vref at 80% */ 2282 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2283 /* Mic2 (front panel) pin widget for input and vref at 80% */ 2284 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2285 /* LINE-2 is used for line-out in rear */ 2286 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2287 /* select line-out */ 2288 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, 2289 /* LINE-OUT pin */ 2290 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2291 /* enable HP */ 2292 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 2293 /* enable Mono */ 2294 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2295 /* mute capture amp left and right */ 2296 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2297 /* set connection select to line in (default select for this ADC) */ 2298 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, 2299 /* mute capture amp left and right */ 2300 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2301 /* set connection select to line in (default select for this ADC) */ 2302 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, 2303 /* set vol=0 Line-Out mixer amp left and right */ 2304 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2305 /* unmute pin widget amp left and right (no gain on this amp) */ 2306 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2307 /* set vol=0 HP mixer amp left and right */ 2308 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2309 /* unmute pin widget amp left and right (no gain on this amp) */ 2310 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2311 /* set vol=0 Mono mixer amp left and right */ 2312 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2313 /* unmute pin widget amp left and right (no gain on this amp) */ 2314 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2315 /* unmute LINE-2 out pin */ 2316 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2317 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ 2318 /* mute CD */ 2319 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 2320 /* mute Line In */ 2321 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 2322 /* mute Mic */ 2323 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2324 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ 2325 /* mute Front out path */ 2326 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2327 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2328 /* mute Headphone out path */ 2329 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2330 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2331 /* mute Mono out path */ 2332 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2333 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2334 { } 2335}; 2336 2337static struct hda_pcm_stream alc260_pcm_analog_playback = { 2338 .substreams = 1, 2339 .channels_min = 2, 2340 .channels_max = 2, 2341}; 2342 2343static struct hda_pcm_stream alc260_pcm_analog_capture = { 2344 .substreams = 1, 2345 .channels_min = 2, 2346 .channels_max = 2, 2347}; 2348 2349static struct hda_board_config alc260_cfg_tbl[] = { 2350 { .modelname = "hp", .config = ALC260_HP }, 2351 { .pci_subvendor = 0x103c, .config = ALC260_HP }, 2352 {} 2353}; 2354 2355static int patch_alc260(struct hda_codec *codec) 2356{ 2357 struct alc_spec *spec; 2358 int board_config; 2359 2360 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 2361 if (spec == NULL) 2362 return -ENOMEM; 2363 2364 init_MUTEX(&spec->bind_mutex); 2365 codec->spec = spec; 2366 2367 board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); 2368 if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { 2369 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n"); 2370 board_config = ALC260_BASIC; 2371 } 2372 2373 switch (board_config) { 2374 case ALC260_HP: 2375 spec->mixers[spec->num_mixers] = alc260_hp_mixer; 2376 spec->num_mixers++; 2377 break; 2378 default: 2379 spec->mixers[spec->num_mixers] = alc260_base_mixer; 2380 spec->num_mixers++; 2381 break; 2382 } 2383 2384 spec->init_verbs[0] = alc260_init_verbs; 2385 spec->num_init_verbs = 1; 2386 2387 spec->channel_mode = alc260_modes; 2388 spec->num_channel_mode = ARRAY_SIZE(alc260_modes); 2389 2390 spec->stream_name_analog = "ALC260 Analog"; 2391 spec->stream_analog_playback = &alc260_pcm_analog_playback; 2392 spec->stream_analog_capture = &alc260_pcm_analog_capture; 2393 2394 spec->multiout.max_channels = spec->channel_mode[0].channels; 2395 spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids); 2396 spec->multiout.dac_nids = alc260_dac_nids; 2397 2398 spec->input_mux = &alc260_capture_source; 2399 switch (board_config) { 2400 case ALC260_HP: 2401 spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); 2402 spec->adc_nids = alc260_hp_adc_nids; 2403 break; 2404 default: 2405 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); 2406 spec->adc_nids = alc260_adc_nids; 2407 break; 2408 } 2409 2410 codec->patch_ops = alc_patch_ops; 2411 2412 return 0; 2413} 2414 2415 2416/* 2417 * ALC882 support 2418 * 2419 * ALC882 is almost identical with ALC880 but has cleaner and more flexible 2420 * configuration. Each pin widget can choose any input DACs and a mixer. 2421 * Each ADC is connected from a mixer of all inputs. This makes possible 2422 * 6-channel independent captures. 2423 * 2424 * In addition, an independent DAC for the multi-playback (not used in this 2425 * driver yet). 2426 */ 2427 2428static struct alc_channel_mode alc882_ch_modes[1] = { 2429 { 8, NULL } 2430}; 2431 2432static hda_nid_t alc882_dac_nids[4] = { 2433 /* front, rear, clfe, rear_surr */ 2434 0x02, 0x03, 0x04, 0x05 2435}; 2436 2437static hda_nid_t alc882_adc_nids[3] = { 2438 /* ADC0-2 */ 2439 0x07, 0x08, 0x09, 2440}; 2441 2442/* input MUX */ 2443/* FIXME: should be a matrix-type input source selection */ 2444 2445static struct hda_input_mux alc882_capture_source = { 2446 .num_items = 4, 2447 .items = { 2448 { "Mic", 0x0 }, 2449 { "Front Mic", 0x1 }, 2450 { "Line", 0x2 }, 2451 { "CD", 0x4 }, 2452 }, 2453}; 2454 2455#define alc882_mux_enum_info alc_mux_enum_info 2456#define alc882_mux_enum_get alc_mux_enum_get 2457 2458static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 2459{ 2460 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2461 struct alc_spec *spec = codec->spec; 2462 const struct hda_input_mux *imux = spec->input_mux; 2463 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2464 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; 2465 hda_nid_t nid = capture_mixers[adc_idx]; 2466 unsigned int *cur_val = &spec->cur_mux[adc_idx]; 2467 unsigned int i, idx; 2468 2469 idx = ucontrol->value.enumerated.item[0]; 2470 if (idx >= imux->num_items) 2471 idx = imux->num_items - 1; 2472 if (*cur_val == idx && ! codec->in_resume) 2473 return 0; 2474 for (i = 0; i < imux->num_items; i++) { 2475 unsigned int v = (i == idx) ? 0x7000 : 0x7080; 2476 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 2477 v | (imux->items[i].index << 8)); 2478 } 2479 *cur_val = idx; 2480 return 1; 2481} 2482 2483/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 2484 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b 2485 */ 2486static snd_kcontrol_new_t alc882_base_mixer[] = { 2487 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 2488 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 2489 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), 2490 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), 2491 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), 2492 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), 2493 ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), 2494 ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_OUTPUT), 2495 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), 2496 ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), 2497 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), 2498 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 2499 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 2500 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 2501 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 2502 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 2503 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 2504 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), 2505 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), 2506 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 2507 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 2508 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), 2509 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), 2510 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), 2511 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), 2512 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), 2513 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), 2514 { 2515 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2516 /* .name = "Capture Source", */ 2517 .name = "Input Source", 2518 .count = 3, 2519 .info = alc882_mux_enum_info, 2520 .get = alc882_mux_enum_get, 2521 .put = alc882_mux_enum_put, 2522 }, 2523 { } /* end */ 2524}; 2525 2526static struct hda_verb alc882_init_verbs[] = { 2527 /* Front mixer: unmute input/output amp left and right (volume = 0) */ 2528 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2529 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2530 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2531 /* Rear mixer */ 2532 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2533 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2534 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2535 /* CLFE mixer */ 2536 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2537 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2538 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2539 /* Side mixer */ 2540 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 2541 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2542 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2543 2544 /* Front Pin: output 0 (0x0c) */ 2545 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2546 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2547 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, 2548 /* Rear Pin: output 1 (0x0d) */ 2549 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2550 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2551 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, 2552 /* CLFE Pin: output 2 (0x0e) */ 2553 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2554 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2555 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, 2556 /* Side Pin: output 3 (0x0f) */ 2557 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2558 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2559 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, 2560 /* Mic (rear) pin: input vref at 80% */ 2561 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2562 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 2563 /* Front Mic pin: input vref at 80% */ 2564 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2565 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 2566 /* Line In pin: input */ 2567 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2568 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 2569 /* Line-2 In: Headphone output (output 0 - 0x0c) */ 2570 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 2571 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2572 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, 2573 /* CD pin widget for input */ 2574 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2575 2576 /* FIXME: use matrix-type input source selection */ 2577 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ 2578 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ 2579 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2580 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2581 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2582 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 2583 /* Input mixer2 */ 2584 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2585 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2586 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2587 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 2588 /* Input mixer3 */ 2589 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 2590 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2591 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2592 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 2593 /* ADC1: mute amp left and right */ 2594 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2595 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, 2596 /* ADC2: mute amp left and right */ 2597 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2598 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, 2599 /* ADC3: mute amp left and right */ 2600 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2601 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, 2602 2603 { } 2604}; 2605 2606static int patch_alc882(struct hda_codec *codec) 2607{ 2608 struct alc_spec *spec; 2609 2610 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 2611 if (spec == NULL) 2612 return -ENOMEM; 2613 2614 init_MUTEX(&spec->bind_mutex); 2615 codec->spec = spec; 2616 2617 spec->mixers[spec->num_mixers] = alc882_base_mixer; 2618 spec->num_mixers++; 2619 2620 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; 2621 spec->dig_in_nid = ALC880_DIGIN_NID; 2622 spec->init_verbs[0] = alc882_init_verbs; 2623 spec->num_init_verbs = 1; 2624 2625 spec->channel_mode = alc882_ch_modes; 2626 spec->num_channel_mode = ARRAY_SIZE(alc882_ch_modes); 2627 2628 spec->stream_name_analog = "ALC882 Analog"; 2629 spec->stream_analog_playback = &alc880_pcm_analog_playback; 2630 spec->stream_analog_capture = &alc880_pcm_analog_capture; 2631 2632 spec->stream_name_digital = "ALC882 Digital"; 2633 spec->stream_digital_playback = &alc880_pcm_digital_playback; 2634 spec->stream_digital_capture = &alc880_pcm_digital_capture; 2635 2636 spec->multiout.max_channels = spec->channel_mode[0].channels; 2637 spec->multiout.num_dacs = ARRAY_SIZE(alc882_dac_nids); 2638 spec->multiout.dac_nids = alc882_dac_nids; 2639 2640 spec->input_mux = &alc882_capture_source; 2641 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); 2642 spec->adc_nids = alc882_adc_nids; 2643 2644 codec->patch_ops = alc_patch_ops; 2645 2646 return 0; 2647} 2648 2649/* 2650 * patch entries 2651 */ 2652struct hda_codec_preset snd_hda_preset_realtek[] = { 2653 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, 2654 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, 2655 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, 2656 {} /* terminator */ 2657}; 2658