diff options
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r-- | sound/pci/hda/patch_analog.c | 524 |
1 files changed, 307 insertions, 217 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 4d7f8d11ad75..54cfd4526d20 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -73,6 +73,12 @@ struct ad198x_spec { | |||
73 | struct snd_kcontrol_new *kctl_alloc; | 73 | struct snd_kcontrol_new *kctl_alloc; |
74 | struct hda_input_mux private_imux; | 74 | struct hda_input_mux private_imux; |
75 | hda_nid_t private_dac_nids[4]; | 75 | hda_nid_t private_dac_nids[4]; |
76 | |||
77 | unsigned int jack_present :1; | ||
78 | |||
79 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
80 | struct hda_loopback_check loopback; | ||
81 | #endif | ||
76 | }; | 82 | }; |
77 | 83 | ||
78 | /* | 84 | /* |
@@ -144,6 +150,14 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
144 | return 0; | 150 | return 0; |
145 | } | 151 | } |
146 | 152 | ||
153 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
154 | static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) | ||
155 | { | ||
156 | struct ad198x_spec *spec = codec->spec; | ||
157 | return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); | ||
158 | } | ||
159 | #endif | ||
160 | |||
147 | /* | 161 | /* |
148 | * Analog playback callbacks | 162 | * Analog playback callbacks |
149 | */ | 163 | */ |
@@ -318,30 +332,13 @@ static void ad198x_free(struct hda_codec *codec) | |||
318 | kfree(codec->spec); | 332 | kfree(codec->spec); |
319 | } | 333 | } |
320 | 334 | ||
321 | #ifdef CONFIG_PM | ||
322 | static int ad198x_resume(struct hda_codec *codec) | ||
323 | { | ||
324 | struct ad198x_spec *spec = codec->spec; | ||
325 | int i; | ||
326 | |||
327 | codec->patch_ops.init(codec); | ||
328 | for (i = 0; i < spec->num_mixers; i++) | ||
329 | snd_hda_resume_ctls(codec, spec->mixers[i]); | ||
330 | if (spec->multiout.dig_out_nid) | ||
331 | snd_hda_resume_spdif_out(codec); | ||
332 | if (spec->dig_in_nid) | ||
333 | snd_hda_resume_spdif_in(codec); | ||
334 | return 0; | ||
335 | } | ||
336 | #endif | ||
337 | |||
338 | static struct hda_codec_ops ad198x_patch_ops = { | 335 | static struct hda_codec_ops ad198x_patch_ops = { |
339 | .build_controls = ad198x_build_controls, | 336 | .build_controls = ad198x_build_controls, |
340 | .build_pcms = ad198x_build_pcms, | 337 | .build_pcms = ad198x_build_pcms, |
341 | .init = ad198x_init, | 338 | .init = ad198x_init, |
342 | .free = ad198x_free, | 339 | .free = ad198x_free, |
343 | #ifdef CONFIG_PM | 340 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
344 | .resume = ad198x_resume, | 341 | .check_power_status = ad198x_check_power_status, |
345 | #endif | 342 | #endif |
346 | }; | 343 | }; |
347 | 344 | ||
@@ -350,15 +347,7 @@ static struct hda_codec_ops ad198x_patch_ops = { | |||
350 | * EAPD control | 347 | * EAPD control |
351 | * the private value = nid | (invert << 8) | 348 | * the private value = nid | (invert << 8) |
352 | */ | 349 | */ |
353 | static int ad198x_eapd_info(struct snd_kcontrol *kcontrol, | 350 | #define ad198x_eapd_info snd_ctl_boolean_mono_info |
354 | struct snd_ctl_elem_info *uinfo) | ||
355 | { | ||
356 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
357 | uinfo->count = 1; | ||
358 | uinfo->value.integer.min = 0; | ||
359 | uinfo->value.integer.max = 1; | ||
360 | return 0; | ||
361 | } | ||
362 | 351 | ||
363 | static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, | 352 | static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, |
364 | struct snd_ctl_elem_value *ucontrol) | 353 | struct snd_ctl_elem_value *ucontrol) |
@@ -384,12 +373,12 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, | |||
384 | eapd = ucontrol->value.integer.value[0]; | 373 | eapd = ucontrol->value.integer.value[0]; |
385 | if (invert) | 374 | if (invert) |
386 | eapd = !eapd; | 375 | eapd = !eapd; |
387 | if (eapd == spec->cur_eapd && ! codec->in_resume) | 376 | if (eapd == spec->cur_eapd) |
388 | return 0; | 377 | return 0; |
389 | spec->cur_eapd = eapd; | 378 | spec->cur_eapd = eapd; |
390 | snd_hda_codec_write(codec, nid, | 379 | snd_hda_codec_write_cache(codec, nid, |
391 | 0, AC_VERB_SET_EAPD_BTLENABLE, | 380 | 0, AC_VERB_SET_EAPD_BTLENABLE, |
392 | eapd ? 0x02 : 0x00); | 381 | eapd ? 0x02 : 0x00); |
393 | return 1; | 382 | return 1; |
394 | } | 383 | } |
395 | 384 | ||
@@ -430,94 +419,36 @@ static struct hda_input_mux ad1986a_capture_source = { | |||
430 | }, | 419 | }, |
431 | }; | 420 | }; |
432 | 421 | ||
433 | /* | ||
434 | * PCM control | ||
435 | * | ||
436 | * bind volumes/mutes of 3 DACs as a single PCM control for simplicity | ||
437 | */ | ||
438 | |||
439 | #define ad1986a_pcm_amp_vol_info snd_hda_mixer_amp_volume_info | ||
440 | |||
441 | static int ad1986a_pcm_amp_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
442 | { | ||
443 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
444 | struct ad198x_spec *ad = codec->spec; | ||
445 | |||
446 | mutex_lock(&ad->amp_mutex); | ||
447 | snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); | ||
448 | mutex_unlock(&ad->amp_mutex); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
453 | { | ||
454 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
455 | struct ad198x_spec *ad = codec->spec; | ||
456 | int i, change = 0; | ||
457 | |||
458 | mutex_lock(&ad->amp_mutex); | ||
459 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { | ||
460 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); | ||
461 | change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); | ||
462 | } | ||
463 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); | ||
464 | mutex_unlock(&ad->amp_mutex); | ||
465 | return change; | ||
466 | } | ||
467 | |||
468 | #define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info | ||
469 | 422 | ||
470 | static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 423 | static struct hda_bind_ctls ad1986a_bind_pcm_vol = { |
471 | { | 424 | .ops = &snd_hda_bind_vol, |
472 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 425 | .values = { |
473 | struct ad198x_spec *ad = codec->spec; | 426 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), |
474 | 427 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), | |
475 | mutex_lock(&ad->amp_mutex); | 428 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), |
476 | snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); | 429 | 0 |
477 | mutex_unlock(&ad->amp_mutex); | 430 | }, |
478 | return 0; | 431 | }; |
479 | } | ||
480 | |||
481 | static int ad1986a_pcm_amp_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
482 | { | ||
483 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
484 | struct ad198x_spec *ad = codec->spec; | ||
485 | int i, change = 0; | ||
486 | 432 | ||
487 | mutex_lock(&ad->amp_mutex); | 433 | static struct hda_bind_ctls ad1986a_bind_pcm_sw = { |
488 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { | 434 | .ops = &snd_hda_bind_sw, |
489 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); | 435 | .values = { |
490 | change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | 436 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), |
491 | } | 437 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), |
492 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); | 438 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), |
493 | mutex_unlock(&ad->amp_mutex); | 439 | 0 |
494 | return change; | 440 | }, |
495 | } | 441 | }; |
496 | 442 | ||
497 | /* | 443 | /* |
498 | * mixers | 444 | * mixers |
499 | */ | 445 | */ |
500 | static struct snd_kcontrol_new ad1986a_mixers[] = { | 446 | static struct snd_kcontrol_new ad1986a_mixers[] = { |
501 | { | 447 | /* |
502 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 448 | * bind volumes/mutes of 3 DACs as a single PCM control for simplicity |
503 | .name = "PCM Playback Volume", | 449 | */ |
504 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 450 | HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol), |
505 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 451 | HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw), |
506 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, | ||
507 | .info = ad1986a_pcm_amp_vol_info, | ||
508 | .get = ad1986a_pcm_amp_vol_get, | ||
509 | .put = ad1986a_pcm_amp_vol_put, | ||
510 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
511 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) | ||
512 | }, | ||
513 | { | ||
514 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
515 | .name = "PCM Playback Switch", | ||
516 | .info = ad1986a_pcm_amp_sw_info, | ||
517 | .get = ad1986a_pcm_amp_sw_get, | ||
518 | .put = ad1986a_pcm_amp_sw_put, | ||
519 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) | ||
520 | }, | ||
521 | HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | 452 | HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), |
522 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 453 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
523 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | 454 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), |
@@ -569,13 +500,30 @@ static struct snd_kcontrol_new ad1986a_3st_mixers[] = { | |||
569 | /* laptop model - 2ch only */ | 500 | /* laptop model - 2ch only */ |
570 | static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; | 501 | static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; |
571 | 502 | ||
503 | /* master controls both pins 0x1a and 0x1b */ | ||
504 | static struct hda_bind_ctls ad1986a_laptop_master_vol = { | ||
505 | .ops = &snd_hda_bind_vol, | ||
506 | .values = { | ||
507 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
508 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), | ||
509 | 0, | ||
510 | }, | ||
511 | }; | ||
512 | |||
513 | static struct hda_bind_ctls ad1986a_laptop_master_sw = { | ||
514 | .ops = &snd_hda_bind_sw, | ||
515 | .values = { | ||
516 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
517 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), | ||
518 | 0, | ||
519 | }, | ||
520 | }; | ||
521 | |||
572 | static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { | 522 | static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { |
573 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | 523 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), |
574 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | 524 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), |
575 | HDA_CODEC_VOLUME("Master Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | 525 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), |
576 | HDA_CODEC_MUTE("Master Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 526 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), |
577 | /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), | ||
578 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), */ | ||
579 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), | 527 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), |
580 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 528 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
581 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), | 529 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), |
@@ -603,68 +551,114 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { | |||
603 | 551 | ||
604 | /* laptop-eapd model - 2ch only */ | 552 | /* laptop-eapd model - 2ch only */ |
605 | 553 | ||
606 | /* master controls both pins 0x1a and 0x1b */ | 554 | static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { |
607 | static int ad1986a_laptop_master_vol_put(struct snd_kcontrol *kcontrol, | 555 | .num_items = 3, |
608 | struct snd_ctl_elem_value *ucontrol) | 556 | .items = { |
557 | { "Mic", 0x0 }, | ||
558 | { "Internal Mic", 0x4 }, | ||
559 | { "Mix", 0x5 }, | ||
560 | }, | ||
561 | }; | ||
562 | |||
563 | static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | ||
564 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
565 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), | ||
566 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
567 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
568 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
569 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
570 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
571 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
572 | HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), | ||
573 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
574 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
575 | { | ||
576 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
577 | .name = "Capture Source", | ||
578 | .info = ad198x_mux_enum_info, | ||
579 | .get = ad198x_mux_enum_get, | ||
580 | .put = ad198x_mux_enum_put, | ||
581 | }, | ||
582 | { | ||
583 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
584 | .name = "External Amplifier", | ||
585 | .info = ad198x_eapd_info, | ||
586 | .get = ad198x_eapd_get, | ||
587 | .put = ad198x_eapd_put, | ||
588 | .private_value = 0x1b | (1 << 8), /* port-D, inversed */ | ||
589 | }, | ||
590 | { } /* end */ | ||
591 | }; | ||
592 | |||
593 | /* laptop-automute - 2ch only */ | ||
594 | |||
595 | static void ad1986a_update_hp(struct hda_codec *codec) | ||
609 | { | 596 | { |
610 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 597 | struct ad198x_spec *spec = codec->spec; |
611 | long *valp = ucontrol->value.integer.value; | 598 | unsigned int mute; |
612 | int change; | ||
613 | 599 | ||
614 | change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, | 600 | if (spec->jack_present) |
615 | 0x7f, valp[0] & 0x7f); | 601 | mute = HDA_AMP_MUTE; /* mute internal speaker */ |
616 | change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, | 602 | else |
617 | 0x7f, valp[1] & 0x7f); | 603 | /* unmute internal speaker if necessary */ |
618 | snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | 604 | mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); |
619 | 0x7f, valp[0] & 0x7f); | 605 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, |
620 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | 606 | HDA_AMP_MUTE, mute); |
621 | 0x7f, valp[1] & 0x7f); | ||
622 | return change; | ||
623 | } | 607 | } |
624 | 608 | ||
625 | static int ad1986a_laptop_master_sw_put(struct snd_kcontrol *kcontrol, | 609 | static void ad1986a_hp_automute(struct hda_codec *codec) |
626 | struct snd_ctl_elem_value *ucontrol) | 610 | { |
611 | struct ad198x_spec *spec = codec->spec; | ||
612 | unsigned int present; | ||
613 | |||
614 | present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0); | ||
615 | spec->jack_present = (present & 0x80000000) != 0; | ||
616 | ad1986a_update_hp(codec); | ||
617 | } | ||
618 | |||
619 | #define AD1986A_HP_EVENT 0x37 | ||
620 | |||
621 | static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
622 | { | ||
623 | if ((res >> 26) != AD1986A_HP_EVENT) | ||
624 | return; | ||
625 | ad1986a_hp_automute(codec); | ||
626 | } | ||
627 | |||
628 | static int ad1986a_hp_init(struct hda_codec *codec) | ||
629 | { | ||
630 | ad198x_init(codec); | ||
631 | ad1986a_hp_automute(codec); | ||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | /* bind hp and internal speaker mute (with plug check) */ | ||
636 | static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
637 | struct snd_ctl_elem_value *ucontrol) | ||
627 | { | 638 | { |
628 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 639 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
629 | long *valp = ucontrol->value.integer.value; | 640 | long *valp = ucontrol->value.integer.value; |
630 | int change; | 641 | int change; |
631 | 642 | ||
632 | change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, | 643 | change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, |
633 | 0x80, valp[0] ? 0 : 0x80); | 644 | HDA_AMP_MUTE, |
645 | valp[0] ? 0 : HDA_AMP_MUTE); | ||
634 | change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, | 646 | change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, |
635 | 0x80, valp[1] ? 0 : 0x80); | 647 | HDA_AMP_MUTE, |
636 | snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | 648 | valp[1] ? 0 : HDA_AMP_MUTE); |
637 | 0x80, valp[0] ? 0 : 0x80); | 649 | if (change) |
638 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | 650 | ad1986a_update_hp(codec); |
639 | 0x80, valp[1] ? 0 : 0x80); | ||
640 | return change; | 651 | return change; |
641 | } | 652 | } |
642 | 653 | ||
643 | static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { | 654 | static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = { |
644 | .num_items = 3, | 655 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), |
645 | .items = { | ||
646 | { "Mic", 0x0 }, | ||
647 | { "Internal Mic", 0x4 }, | ||
648 | { "Mix", 0x5 }, | ||
649 | }, | ||
650 | }; | ||
651 | |||
652 | static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | ||
653 | { | ||
654 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
655 | .name = "Master Playback Volume", | ||
656 | .info = snd_hda_mixer_amp_volume_info, | ||
657 | .get = snd_hda_mixer_amp_volume_get, | ||
658 | .put = ad1986a_laptop_master_vol_put, | ||
659 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
660 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
661 | }, | ||
662 | { | 656 | { |
663 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 657 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
664 | .name = "Master Playback Switch", | 658 | .name = "Master Playback Switch", |
665 | .info = snd_hda_mixer_amp_switch_info, | 659 | .info = snd_hda_mixer_amp_switch_info, |
666 | .get = snd_hda_mixer_amp_switch_get, | 660 | .get = snd_hda_mixer_amp_switch_get, |
667 | .put = ad1986a_laptop_master_sw_put, | 661 | .put = ad1986a_hp_master_sw_put, |
668 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | 662 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), |
669 | }, | 663 | }, |
670 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | 664 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), |
@@ -674,6 +668,8 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | |||
674 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | 668 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), |
675 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | 669 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), |
676 | HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), | 670 | HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), |
671 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x18, 0x0, HDA_OUTPUT), | ||
672 | HDA_CODEC_MUTE("Beep Playback Switch", 0x18, 0x0, HDA_OUTPUT), | ||
677 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | 673 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), |
678 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | 674 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), |
679 | { | 675 | { |
@@ -807,12 +803,20 @@ static struct hda_verb ad1986a_ultra_init[] = { | |||
807 | { } /* end */ | 803 | { } /* end */ |
808 | }; | 804 | }; |
809 | 805 | ||
806 | /* pin sensing on HP jack */ | ||
807 | static struct hda_verb ad1986a_hp_init_verbs[] = { | ||
808 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, | ||
809 | {} | ||
810 | }; | ||
811 | |||
812 | |||
810 | /* models */ | 813 | /* models */ |
811 | enum { | 814 | enum { |
812 | AD1986A_6STACK, | 815 | AD1986A_6STACK, |
813 | AD1986A_3STACK, | 816 | AD1986A_3STACK, |
814 | AD1986A_LAPTOP, | 817 | AD1986A_LAPTOP, |
815 | AD1986A_LAPTOP_EAPD, | 818 | AD1986A_LAPTOP_EAPD, |
819 | AD1986A_LAPTOP_AUTOMUTE, | ||
816 | AD1986A_ULTRA, | 820 | AD1986A_ULTRA, |
817 | AD1986A_MODELS | 821 | AD1986A_MODELS |
818 | }; | 822 | }; |
@@ -822,6 +826,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = { | |||
822 | [AD1986A_3STACK] = "3stack", | 826 | [AD1986A_3STACK] = "3stack", |
823 | [AD1986A_LAPTOP] = "laptop", | 827 | [AD1986A_LAPTOP] = "laptop", |
824 | [AD1986A_LAPTOP_EAPD] = "laptop-eapd", | 828 | [AD1986A_LAPTOP_EAPD] = "laptop-eapd", |
829 | [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", | ||
825 | [AD1986A_ULTRA] = "ultra", | 830 | [AD1986A_ULTRA] = "ultra", |
826 | }; | 831 | }; |
827 | 832 | ||
@@ -850,11 +855,22 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { | |||
850 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), | 855 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), |
851 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), | 856 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), |
852 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), | 857 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), |
853 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD), | 858 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), |
854 | SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), | 859 | SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), |
855 | {} | 860 | {} |
856 | }; | 861 | }; |
857 | 862 | ||
863 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
864 | static struct hda_amp_list ad1986a_loopbacks[] = { | ||
865 | { 0x13, HDA_OUTPUT, 0 }, /* Mic */ | ||
866 | { 0x14, HDA_OUTPUT, 0 }, /* Phone */ | ||
867 | { 0x15, HDA_OUTPUT, 0 }, /* CD */ | ||
868 | { 0x16, HDA_OUTPUT, 0 }, /* Aux */ | ||
869 | { 0x17, HDA_OUTPUT, 0 }, /* Line */ | ||
870 | { } /* end */ | ||
871 | }; | ||
872 | #endif | ||
873 | |||
858 | static int patch_ad1986a(struct hda_codec *codec) | 874 | static int patch_ad1986a(struct hda_codec *codec) |
859 | { | 875 | { |
860 | struct ad198x_spec *spec; | 876 | struct ad198x_spec *spec; |
@@ -864,7 +880,6 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
864 | if (spec == NULL) | 880 | if (spec == NULL) |
865 | return -ENOMEM; | 881 | return -ENOMEM; |
866 | 882 | ||
867 | mutex_init(&spec->amp_mutex); | ||
868 | codec->spec = spec; | 883 | codec->spec = spec; |
869 | 884 | ||
870 | spec->multiout.max_channels = 6; | 885 | spec->multiout.max_channels = 6; |
@@ -879,6 +894,9 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
879 | spec->mixers[0] = ad1986a_mixers; | 894 | spec->mixers[0] = ad1986a_mixers; |
880 | spec->num_init_verbs = 1; | 895 | spec->num_init_verbs = 1; |
881 | spec->init_verbs[0] = ad1986a_init_verbs; | 896 | spec->init_verbs[0] = ad1986a_init_verbs; |
897 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
898 | spec->loopback.amplist = ad1986a_loopbacks; | ||
899 | #endif | ||
882 | 900 | ||
883 | codec->patch_ops = ad198x_patch_ops; | 901 | codec->patch_ops = ad198x_patch_ops; |
884 | 902 | ||
@@ -914,6 +932,19 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
914 | spec->multiout.dig_out_nid = 0; | 932 | spec->multiout.dig_out_nid = 0; |
915 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | 933 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; |
916 | break; | 934 | break; |
935 | case AD1986A_LAPTOP_AUTOMUTE: | ||
936 | spec->mixers[0] = ad1986a_laptop_automute_mixers; | ||
937 | spec->num_init_verbs = 3; | ||
938 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
939 | spec->init_verbs[2] = ad1986a_hp_init_verbs; | ||
940 | spec->multiout.max_channels = 2; | ||
941 | spec->multiout.num_dacs = 1; | ||
942 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
943 | spec->multiout.dig_out_nid = 0; | ||
944 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | ||
945 | codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; | ||
946 | codec->patch_ops.init = ad1986a_hp_init; | ||
947 | break; | ||
917 | case AD1986A_ULTRA: | 948 | case AD1986A_ULTRA: |
918 | spec->mixers[0] = ad1986a_laptop_eapd_mixers; | 949 | spec->mixers[0] = ad1986a_laptop_eapd_mixers; |
919 | spec->num_init_verbs = 2; | 950 | spec->num_init_verbs = 2; |
@@ -982,8 +1013,9 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
982 | 1013 | ||
983 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { | 1014 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { |
984 | spec->spdif_route = ucontrol->value.enumerated.item[0]; | 1015 | spec->spdif_route = ucontrol->value.enumerated.item[0]; |
985 | snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0, | 1016 | snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, |
986 | AC_VERB_SET_CONNECT_SEL, spec->spdif_route); | 1017 | AC_VERB_SET_CONNECT_SEL, |
1018 | spec->spdif_route); | ||
987 | return 1; | 1019 | return 1; |
988 | } | 1020 | } |
989 | return 0; | 1021 | return 0; |
@@ -1063,6 +1095,13 @@ static struct hda_verb ad1983_init_verbs[] = { | |||
1063 | { } /* end */ | 1095 | { } /* end */ |
1064 | }; | 1096 | }; |
1065 | 1097 | ||
1098 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1099 | static struct hda_amp_list ad1983_loopbacks[] = { | ||
1100 | { 0x12, HDA_OUTPUT, 0 }, /* Mic */ | ||
1101 | { 0x13, HDA_OUTPUT, 0 }, /* Line */ | ||
1102 | { } /* end */ | ||
1103 | }; | ||
1104 | #endif | ||
1066 | 1105 | ||
1067 | static int patch_ad1983(struct hda_codec *codec) | 1106 | static int patch_ad1983(struct hda_codec *codec) |
1068 | { | 1107 | { |
@@ -1072,7 +1111,6 @@ static int patch_ad1983(struct hda_codec *codec) | |||
1072 | if (spec == NULL) | 1111 | if (spec == NULL) |
1073 | return -ENOMEM; | 1112 | return -ENOMEM; |
1074 | 1113 | ||
1075 | mutex_init(&spec->amp_mutex); | ||
1076 | codec->spec = spec; | 1114 | codec->spec = spec; |
1077 | 1115 | ||
1078 | spec->multiout.max_channels = 2; | 1116 | spec->multiout.max_channels = 2; |
@@ -1088,6 +1126,9 @@ static int patch_ad1983(struct hda_codec *codec) | |||
1088 | spec->num_init_verbs = 1; | 1126 | spec->num_init_verbs = 1; |
1089 | spec->init_verbs[0] = ad1983_init_verbs; | 1127 | spec->init_verbs[0] = ad1983_init_verbs; |
1090 | spec->spdif_route = 0; | 1128 | spec->spdif_route = 0; |
1129 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1130 | spec->loopback.amplist = ad1983_loopbacks; | ||
1131 | #endif | ||
1091 | 1132 | ||
1092 | codec->patch_ops = ad198x_patch_ops; | 1133 | codec->patch_ops = ad198x_patch_ops; |
1093 | 1134 | ||
@@ -1211,6 +1252,17 @@ static struct hda_verb ad1981_init_verbs[] = { | |||
1211 | { } /* end */ | 1252 | { } /* end */ |
1212 | }; | 1253 | }; |
1213 | 1254 | ||
1255 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1256 | static struct hda_amp_list ad1981_loopbacks[] = { | ||
1257 | { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ | ||
1258 | { 0x13, HDA_OUTPUT, 0 }, /* Line */ | ||
1259 | { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ | ||
1260 | { 0x1c, HDA_OUTPUT, 0 }, /* Mic */ | ||
1261 | { 0x1d, HDA_OUTPUT, 0 }, /* CD */ | ||
1262 | { } /* end */ | ||
1263 | }; | ||
1264 | #endif | ||
1265 | |||
1214 | /* | 1266 | /* |
1215 | * Patch for HP nx6320 | 1267 | * Patch for HP nx6320 |
1216 | * | 1268 | * |
@@ -1240,31 +1292,21 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
1240 | return 0; | 1292 | return 0; |
1241 | 1293 | ||
1242 | /* toggle HP mute appropriately */ | 1294 | /* toggle HP mute appropriately */ |
1243 | snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, | 1295 | snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, |
1244 | 0x80, spec->cur_eapd ? 0 : 0x80); | 1296 | HDA_AMP_MUTE, |
1245 | snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, | 1297 | spec->cur_eapd ? 0 : HDA_AMP_MUTE); |
1246 | 0x80, spec->cur_eapd ? 0 : 0x80); | ||
1247 | return 1; | 1298 | return 1; |
1248 | } | 1299 | } |
1249 | 1300 | ||
1250 | /* bind volumes of both NID 0x05 and 0x06 */ | 1301 | /* bind volumes of both NID 0x05 and 0x06 */ |
1251 | static int ad1981_hp_master_vol_put(struct snd_kcontrol *kcontrol, | 1302 | static struct hda_bind_ctls ad1981_hp_bind_master_vol = { |
1252 | struct snd_ctl_elem_value *ucontrol) | 1303 | .ops = &snd_hda_bind_vol, |
1253 | { | 1304 | .values = { |
1254 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1305 | HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), |
1255 | long *valp = ucontrol->value.integer.value; | 1306 | HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT), |
1256 | int change; | 1307 | 0 |
1257 | 1308 | }, | |
1258 | change = snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, | 1309 | }; |
1259 | 0x7f, valp[0] & 0x7f); | ||
1260 | change |= snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, | ||
1261 | 0x7f, valp[1] & 0x7f); | ||
1262 | snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, | ||
1263 | 0x7f, valp[0] & 0x7f); | ||
1264 | snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, | ||
1265 | 0x7f, valp[1] & 0x7f); | ||
1266 | return change; | ||
1267 | } | ||
1268 | 1310 | ||
1269 | /* mute internal speaker if HP is plugged */ | 1311 | /* mute internal speaker if HP is plugged */ |
1270 | static void ad1981_hp_automute(struct hda_codec *codec) | 1312 | static void ad1981_hp_automute(struct hda_codec *codec) |
@@ -1273,10 +1315,8 @@ static void ad1981_hp_automute(struct hda_codec *codec) | |||
1273 | 1315 | ||
1274 | present = snd_hda_codec_read(codec, 0x06, 0, | 1316 | present = snd_hda_codec_read(codec, 0x06, 0, |
1275 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 1317 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
1276 | snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, | 1318 | snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, |
1277 | 0x80, present ? 0x80 : 0); | 1319 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
1278 | snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, | ||
1279 | 0x80, present ? 0x80 : 0); | ||
1280 | } | 1320 | } |
1281 | 1321 | ||
1282 | /* toggle input of built-in and mic jack appropriately */ | 1322 | /* toggle input of built-in and mic jack appropriately */ |
@@ -1327,14 +1367,7 @@ static struct hda_input_mux ad1981_hp_capture_source = { | |||
1327 | }; | 1367 | }; |
1328 | 1368 | ||
1329 | static struct snd_kcontrol_new ad1981_hp_mixers[] = { | 1369 | static struct snd_kcontrol_new ad1981_hp_mixers[] = { |
1330 | { | 1370 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), |
1331 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1332 | .name = "Master Playback Volume", | ||
1333 | .info = snd_hda_mixer_amp_volume_info, | ||
1334 | .get = snd_hda_mixer_amp_volume_get, | ||
1335 | .put = ad1981_hp_master_vol_put, | ||
1336 | .private_value = HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), | ||
1337 | }, | ||
1338 | { | 1371 | { |
1339 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1372 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1340 | .name = "Master Playback Switch", | 1373 | .name = "Master Playback Switch", |
@@ -1474,7 +1507,6 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1474 | if (spec == NULL) | 1507 | if (spec == NULL) |
1475 | return -ENOMEM; | 1508 | return -ENOMEM; |
1476 | 1509 | ||
1477 | mutex_init(&spec->amp_mutex); | ||
1478 | codec->spec = spec; | 1510 | codec->spec = spec; |
1479 | 1511 | ||
1480 | spec->multiout.max_channels = 2; | 1512 | spec->multiout.max_channels = 2; |
@@ -1490,6 +1522,9 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1490 | spec->num_init_verbs = 1; | 1522 | spec->num_init_verbs = 1; |
1491 | spec->init_verbs[0] = ad1981_init_verbs; | 1523 | spec->init_verbs[0] = ad1981_init_verbs; |
1492 | spec->spdif_route = 0; | 1524 | spec->spdif_route = 0; |
1525 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1526 | spec->loopback.amplist = ad1981_loopbacks; | ||
1527 | #endif | ||
1493 | 1528 | ||
1494 | codec->patch_ops = ad198x_patch_ops; | 1529 | codec->patch_ops = ad198x_patch_ops; |
1495 | 1530 | ||
@@ -1897,16 +1932,19 @@ static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol, | |||
1897 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1932 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1898 | unsigned int sel; | 1933 | unsigned int sel; |
1899 | 1934 | ||
1900 | sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); | 1935 | sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, |
1901 | if (sel > 0) { | 1936 | AC_AMP_GET_INPUT); |
1937 | if (!(sel & 0x80)) | ||
1938 | ucontrol->value.enumerated.item[0] = 0; | ||
1939 | else { | ||
1902 | sel = snd_hda_codec_read(codec, 0x0b, 0, | 1940 | sel = snd_hda_codec_read(codec, 0x0b, 0, |
1903 | AC_VERB_GET_CONNECT_SEL, 0); | 1941 | AC_VERB_GET_CONNECT_SEL, 0); |
1904 | if (sel < 3) | 1942 | if (sel < 3) |
1905 | sel++; | 1943 | sel++; |
1906 | else | 1944 | else |
1907 | sel = 0; | 1945 | sel = 0; |
1946 | ucontrol->value.enumerated.item[0] = sel; | ||
1908 | } | 1947 | } |
1909 | ucontrol->value.enumerated.item[0] = sel; | ||
1910 | return 0; | 1948 | return 0; |
1911 | } | 1949 | } |
1912 | 1950 | ||
@@ -1918,23 +1956,39 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, | |||
1918 | int change; | 1956 | int change; |
1919 | 1957 | ||
1920 | val = ucontrol->value.enumerated.item[0]; | 1958 | val = ucontrol->value.enumerated.item[0]; |
1921 | sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); | ||
1922 | if (!val) { | 1959 | if (!val) { |
1923 | change = sel != 0; | 1960 | sel = snd_hda_codec_read(codec, 0x1d, 0, |
1924 | if (change || codec->in_resume) | 1961 | AC_VERB_GET_AMP_GAIN_MUTE, |
1925 | snd_hda_codec_write(codec, 0x02, 0, | 1962 | AC_AMP_GET_INPUT); |
1926 | AC_VERB_SET_CONNECT_SEL, 0); | 1963 | change = sel & 0x80; |
1964 | if (change) { | ||
1965 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
1966 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
1967 | AMP_IN_UNMUTE(0)); | ||
1968 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
1969 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
1970 | AMP_IN_MUTE(1)); | ||
1971 | } | ||
1927 | } else { | 1972 | } else { |
1928 | change = sel == 0; | 1973 | sel = snd_hda_codec_read(codec, 0x1d, 0, |
1929 | if (change || codec->in_resume) | 1974 | AC_VERB_GET_AMP_GAIN_MUTE, |
1930 | snd_hda_codec_write(codec, 0x02, 0, | 1975 | AC_AMP_GET_INPUT | 0x01); |
1931 | AC_VERB_SET_CONNECT_SEL, 1); | 1976 | change = sel & 0x80; |
1977 | if (change) { | ||
1978 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
1979 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
1980 | AMP_IN_MUTE(0)); | ||
1981 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
1982 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
1983 | AMP_IN_UNMUTE(1)); | ||
1984 | } | ||
1932 | sel = snd_hda_codec_read(codec, 0x0b, 0, | 1985 | sel = snd_hda_codec_read(codec, 0x0b, 0, |
1933 | AC_VERB_GET_CONNECT_SEL, 0) + 1; | 1986 | AC_VERB_GET_CONNECT_SEL, 0) + 1; |
1934 | change |= sel != val; | 1987 | change |= sel != val; |
1935 | if (change || codec->in_resume) | 1988 | if (change) |
1936 | snd_hda_codec_write(codec, 0x0b, 0, | 1989 | snd_hda_codec_write_cache(codec, 0x0b, 0, |
1937 | AC_VERB_SET_CONNECT_SEL, val - 1); | 1990 | AC_VERB_SET_CONNECT_SEL, |
1991 | val - 1); | ||
1938 | } | 1992 | } |
1939 | return change; | 1993 | return change; |
1940 | } | 1994 | } |
@@ -2047,10 +2101,9 @@ static struct hda_verb ad1988_spdif_init_verbs[] = { | |||
2047 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | 2101 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ |
2048 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ | 2102 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ |
2049 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 2103 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
2050 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 2104 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
2051 | /* SPDIF out pin */ | 2105 | /* SPDIF out pin */ |
2052 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | 2106 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ |
2053 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x17}, /* 0dB */ | ||
2054 | 2107 | ||
2055 | { } | 2108 | { } |
2056 | }; | 2109 | }; |
@@ -2225,6 +2278,15 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) | |||
2225 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); | 2278 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); |
2226 | } | 2279 | } |
2227 | 2280 | ||
2281 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
2282 | static struct hda_amp_list ad1988_loopbacks[] = { | ||
2283 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
2284 | { 0x20, HDA_INPUT, 1 }, /* Line */ | ||
2285 | { 0x20, HDA_INPUT, 4 }, /* Mic */ | ||
2286 | { 0x20, HDA_INPUT, 6 }, /* CD */ | ||
2287 | { } /* end */ | ||
2288 | }; | ||
2289 | #endif | ||
2228 | 2290 | ||
2229 | /* | 2291 | /* |
2230 | * Automatic parse of I/O pins from the BIOS configuration | 2292 | * Automatic parse of I/O pins from the BIOS configuration |
@@ -2663,7 +2725,6 @@ static int patch_ad1988(struct hda_codec *codec) | |||
2663 | if (spec == NULL) | 2725 | if (spec == NULL) |
2664 | return -ENOMEM; | 2726 | return -ENOMEM; |
2665 | 2727 | ||
2666 | mutex_init(&spec->amp_mutex); | ||
2667 | codec->spec = spec; | 2728 | codec->spec = spec; |
2668 | 2729 | ||
2669 | if (is_rev2(codec)) | 2730 | if (is_rev2(codec)) |
@@ -2770,6 +2831,9 @@ static int patch_ad1988(struct hda_codec *codec) | |||
2770 | codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; | 2831 | codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; |
2771 | break; | 2832 | break; |
2772 | } | 2833 | } |
2834 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
2835 | spec->loopback.amplist = ad1988_loopbacks; | ||
2836 | #endif | ||
2773 | 2837 | ||
2774 | return 0; | 2838 | return 0; |
2775 | } | 2839 | } |
@@ -2926,6 +2990,16 @@ static struct hda_verb ad1884_init_verbs[] = { | |||
2926 | { } /* end */ | 2990 | { } /* end */ |
2927 | }; | 2991 | }; |
2928 | 2992 | ||
2993 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
2994 | static struct hda_amp_list ad1884_loopbacks[] = { | ||
2995 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
2996 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
2997 | { 0x20, HDA_INPUT, 2 }, /* CD */ | ||
2998 | { 0x20, HDA_INPUT, 4 }, /* Docking */ | ||
2999 | { } /* end */ | ||
3000 | }; | ||
3001 | #endif | ||
3002 | |||
2929 | static int patch_ad1884(struct hda_codec *codec) | 3003 | static int patch_ad1884(struct hda_codec *codec) |
2930 | { | 3004 | { |
2931 | struct ad198x_spec *spec; | 3005 | struct ad198x_spec *spec; |
@@ -2950,6 +3024,9 @@ static int patch_ad1884(struct hda_codec *codec) | |||
2950 | spec->num_init_verbs = 1; | 3024 | spec->num_init_verbs = 1; |
2951 | spec->init_verbs[0] = ad1884_init_verbs; | 3025 | spec->init_verbs[0] = ad1884_init_verbs; |
2952 | spec->spdif_route = 0; | 3026 | spec->spdif_route = 0; |
3027 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3028 | spec->loopback.amplist = ad1884_loopbacks; | ||
3029 | #endif | ||
2953 | 3030 | ||
2954 | codec->patch_ops = ad198x_patch_ops; | 3031 | codec->patch_ops = ad198x_patch_ops; |
2955 | 3032 | ||
@@ -3331,6 +3408,16 @@ static struct hda_verb ad1882_init_verbs[] = { | |||
3331 | { } /* end */ | 3408 | { } /* end */ |
3332 | }; | 3409 | }; |
3333 | 3410 | ||
3411 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3412 | static struct hda_amp_list ad1882_loopbacks[] = { | ||
3413 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
3414 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
3415 | { 0x20, HDA_INPUT, 4 }, /* Line */ | ||
3416 | { 0x20, HDA_INPUT, 6 }, /* CD */ | ||
3417 | { } /* end */ | ||
3418 | }; | ||
3419 | #endif | ||
3420 | |||
3334 | /* models */ | 3421 | /* models */ |
3335 | enum { | 3422 | enum { |
3336 | AD1882_3STACK, | 3423 | AD1882_3STACK, |
@@ -3369,6 +3456,9 @@ static int patch_ad1882(struct hda_codec *codec) | |||
3369 | spec->num_init_verbs = 1; | 3456 | spec->num_init_verbs = 1; |
3370 | spec->init_verbs[0] = ad1882_init_verbs; | 3457 | spec->init_verbs[0] = ad1882_init_verbs; |
3371 | spec->spdif_route = 0; | 3458 | spec->spdif_route = 0; |
3459 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3460 | spec->loopback.amplist = ad1882_loopbacks; | ||
3461 | #endif | ||
3372 | 3462 | ||
3373 | codec->patch_ops = ad198x_patch_ops; | 3463 | codec->patch_ops = ad198x_patch_ops; |
3374 | 3464 | ||