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