diff options
author | David Henningsson <david.henningsson@canonical.com> | 2014-10-07 04:18:42 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-10-07 06:01:48 -0400 |
commit | 9d36a7dc4df6ef77cfc02ba78a10bc8577c2663f (patch) | |
tree | f30d38a2bc9a12372222ebe711e27fabb399516b /sound | |
parent | a33cc48d28b4ff58e2627e2613f15c63754dc376 (diff) |
ALSA: hda - Make the inv dmic handling for Realtek use generic parser
From what I can see, the generic parser is now good enough to handle
Realtek's inverted dmic handling, so let's remove the special handling
and use the generic parser instead.
Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 158 |
1 files changed, 8 insertions, 150 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 82ea50ec978f..69d1236365e0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -90,11 +90,6 @@ struct alc_spec { | |||
90 | struct alc_customize_define cdefine; | 90 | struct alc_customize_define cdefine; |
91 | unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ | 91 | unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ |
92 | 92 | ||
93 | /* inverted dmic fix */ | ||
94 | unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */ | ||
95 | unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */ | ||
96 | hda_nid_t inv_dmic_pin; | ||
97 | |||
98 | /* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */ | 93 | /* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */ |
99 | int mute_led_polarity; | 94 | int mute_led_polarity; |
100 | hda_nid_t mute_led_nid; | 95 | hda_nid_t mute_led_nid; |
@@ -625,147 +620,12 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) | |||
625 | /* | 620 | /* |
626 | */ | 621 | */ |
627 | 622 | ||
628 | static hda_nid_t get_adc_nid(struct hda_codec *codec, int adc_idx, int imux_idx) | 623 | static void alc_fixup_inv_dmic(struct hda_codec *codec, |
629 | { | 624 | const struct hda_fixup *fix, int action) |
630 | struct hda_gen_spec *spec = codec->spec; | ||
631 | if (spec->dyn_adc_switch) | ||
632 | adc_idx = spec->dyn_adc_idx[imux_idx]; | ||
633 | return spec->adc_nids[adc_idx]; | ||
634 | } | ||
635 | |||
636 | static void alc_inv_dmic_sync_adc(struct hda_codec *codec, int adc_idx) | ||
637 | { | ||
638 | struct alc_spec *spec = codec->spec; | ||
639 | struct hda_input_mux *imux = &spec->gen.input_mux; | ||
640 | struct nid_path *path; | ||
641 | hda_nid_t nid; | ||
642 | int i, dir, parm; | ||
643 | unsigned int val; | ||
644 | |||
645 | for (i = 0; i < imux->num_items; i++) { | ||
646 | if (spec->gen.imux_pins[i] == spec->inv_dmic_pin) | ||
647 | break; | ||
648 | } | ||
649 | if (i >= imux->num_items) | ||
650 | return; | ||
651 | |||
652 | path = snd_hda_get_nid_path(codec, spec->inv_dmic_pin, | ||
653 | get_adc_nid(codec, adc_idx, i)); | ||
654 | val = path->ctls[NID_PATH_MUTE_CTL]; | ||
655 | if (!val) | ||
656 | return; | ||
657 | nid = get_amp_nid_(val); | ||
658 | dir = get_amp_direction_(val); | ||
659 | parm = AC_AMP_SET_RIGHT | | ||
660 | (dir == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT); | ||
661 | |||
662 | /* flush all cached amps at first */ | ||
663 | snd_hda_codec_flush_cache(codec); | ||
664 | |||
665 | /* we care only right channel */ | ||
666 | val = snd_hda_codec_amp_read(codec, nid, 1, dir, 0); | ||
667 | if (val & 0x80) /* if already muted, we don't need to touch */ | ||
668 | return; | ||
669 | val |= 0x80; | ||
670 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
671 | parm | val); | ||
672 | } | ||
673 | |||
674 | /* | ||
675 | * Inverted digital-mic handling | ||
676 | * | ||
677 | * First off, it's a bit tricky. The "Inverted Internal Mic Capture Switch" | ||
678 | * gives the additional mute only to the right channel of the digital mic | ||
679 | * capture stream. This is a workaround for avoiding the almost silence | ||
680 | * by summing the stereo stream from some (known to be ForteMedia) | ||
681 | * digital mic unit. | ||
682 | * | ||
683 | * The logic is to call alc_inv_dmic_sync() after each action (possibly) | ||
684 | * modifying ADC amp. When the mute flag is set, it mutes the R-channel | ||
685 | * without caching so that the cache can still keep the original value. | ||
686 | * The cached value is then restored when the flag is set off or any other | ||
687 | * than d-mic is used as the current input source. | ||
688 | */ | ||
689 | static void alc_inv_dmic_sync(struct hda_codec *codec, bool force) | ||
690 | { | ||
691 | struct alc_spec *spec = codec->spec; | ||
692 | int src, nums; | ||
693 | |||
694 | if (!spec->inv_dmic_fixup) | ||
695 | return; | ||
696 | if (!spec->inv_dmic_muted && !force) | ||
697 | return; | ||
698 | nums = spec->gen.dyn_adc_switch ? 1 : spec->gen.num_adc_nids; | ||
699 | for (src = 0; src < nums; src++) { | ||
700 | bool dmic_fixup = false; | ||
701 | |||
702 | if (spec->inv_dmic_muted && | ||
703 | spec->gen.imux_pins[spec->gen.cur_mux[src]] == spec->inv_dmic_pin) | ||
704 | dmic_fixup = true; | ||
705 | if (!dmic_fixup && !force) | ||
706 | continue; | ||
707 | alc_inv_dmic_sync_adc(codec, src); | ||
708 | } | ||
709 | } | ||
710 | |||
711 | static void alc_inv_dmic_hook(struct hda_codec *codec, | ||
712 | struct snd_kcontrol *kcontrol, | ||
713 | struct snd_ctl_elem_value *ucontrol) | ||
714 | { | ||
715 | alc_inv_dmic_sync(codec, false); | ||
716 | } | ||
717 | |||
718 | static int alc_inv_dmic_sw_get(struct snd_kcontrol *kcontrol, | ||
719 | struct snd_ctl_elem_value *ucontrol) | ||
720 | { | ||
721 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
722 | struct alc_spec *spec = codec->spec; | ||
723 | |||
724 | ucontrol->value.integer.value[0] = !spec->inv_dmic_muted; | ||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | static int alc_inv_dmic_sw_put(struct snd_kcontrol *kcontrol, | ||
729 | struct snd_ctl_elem_value *ucontrol) | ||
730 | { | ||
731 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
732 | struct alc_spec *spec = codec->spec; | ||
733 | unsigned int val = !ucontrol->value.integer.value[0]; | ||
734 | |||
735 | if (val == spec->inv_dmic_muted) | ||
736 | return 0; | ||
737 | spec->inv_dmic_muted = val; | ||
738 | alc_inv_dmic_sync(codec, true); | ||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | static const struct snd_kcontrol_new alc_inv_dmic_sw = { | ||
743 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
744 | .name = "Inverted Internal Mic Capture Switch", | ||
745 | .info = snd_ctl_boolean_mono_info, | ||
746 | .get = alc_inv_dmic_sw_get, | ||
747 | .put = alc_inv_dmic_sw_put, | ||
748 | }; | ||
749 | |||
750 | static int alc_add_inv_dmic_mixer(struct hda_codec *codec, hda_nid_t nid) | ||
751 | { | 625 | { |
752 | struct alc_spec *spec = codec->spec; | 626 | struct alc_spec *spec = codec->spec; |
753 | 627 | ||
754 | if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &alc_inv_dmic_sw)) | 628 | spec->gen.inv_dmic_split = 1; |
755 | return -ENOMEM; | ||
756 | spec->inv_dmic_fixup = 1; | ||
757 | spec->inv_dmic_muted = 0; | ||
758 | spec->inv_dmic_pin = nid; | ||
759 | spec->gen.cap_sync_hook = alc_inv_dmic_hook; | ||
760 | return 0; | ||
761 | } | ||
762 | |||
763 | /* typically the digital mic is put at node 0x12 */ | ||
764 | static void alc_fixup_inv_dmic_0x12(struct hda_codec *codec, | ||
765 | const struct hda_fixup *fix, int action) | ||
766 | { | ||
767 | if (action == HDA_FIXUP_ACT_PROBE) | ||
768 | alc_add_inv_dmic_mixer(codec, 0x12); | ||
769 | } | 629 | } |
770 | 630 | ||
771 | 631 | ||
@@ -874,7 +734,6 @@ static int alc_resume(struct hda_codec *codec) | |||
874 | codec->patch_ops.init(codec); | 734 | codec->patch_ops.init(codec); |
875 | snd_hda_codec_resume_amp(codec); | 735 | snd_hda_codec_resume_amp(codec); |
876 | snd_hda_codec_resume_cache(codec); | 736 | snd_hda_codec_resume_cache(codec); |
877 | alc_inv_dmic_sync(codec, true); | ||
878 | hda_call_check_power_status(codec, 0x01); | 737 | hda_call_check_power_status(codec, 0x01); |
879 | return 0; | 738 | return 0; |
880 | } | 739 | } |
@@ -2217,7 +2076,7 @@ static const struct hda_fixup alc882_fixups[] = { | |||
2217 | }, | 2076 | }, |
2218 | [ALC882_FIXUP_INV_DMIC] = { | 2077 | [ALC882_FIXUP_INV_DMIC] = { |
2219 | .type = HDA_FIXUP_FUNC, | 2078 | .type = HDA_FIXUP_FUNC, |
2220 | .v.func = alc_fixup_inv_dmic_0x12, | 2079 | .v.func = alc_fixup_inv_dmic, |
2221 | }, | 2080 | }, |
2222 | [ALC882_FIXUP_NO_PRIMARY_HP] = { | 2081 | [ALC882_FIXUP_NO_PRIMARY_HP] = { |
2223 | .type = HDA_FIXUP_FUNC, | 2082 | .type = HDA_FIXUP_FUNC, |
@@ -2468,7 +2327,7 @@ static const struct hda_fixup alc262_fixups[] = { | |||
2468 | }, | 2327 | }, |
2469 | [ALC262_FIXUP_INV_DMIC] = { | 2328 | [ALC262_FIXUP_INV_DMIC] = { |
2470 | .type = HDA_FIXUP_FUNC, | 2329 | .type = HDA_FIXUP_FUNC, |
2471 | .v.func = alc_fixup_inv_dmic_0x12, | 2330 | .v.func = alc_fixup_inv_dmic, |
2472 | }, | 2331 | }, |
2473 | [ALC262_FIXUP_INTEL_BAYLEYBAY] = { | 2332 | [ALC262_FIXUP_INTEL_BAYLEYBAY] = { |
2474 | .type = HDA_FIXUP_FUNC, | 2333 | .type = HDA_FIXUP_FUNC, |
@@ -2581,7 +2440,7 @@ enum { | |||
2581 | static const struct hda_fixup alc268_fixups[] = { | 2440 | static const struct hda_fixup alc268_fixups[] = { |
2582 | [ALC268_FIXUP_INV_DMIC] = { | 2441 | [ALC268_FIXUP_INV_DMIC] = { |
2583 | .type = HDA_FIXUP_FUNC, | 2442 | .type = HDA_FIXUP_FUNC, |
2584 | .v.func = alc_fixup_inv_dmic_0x12, | 2443 | .v.func = alc_fixup_inv_dmic, |
2585 | }, | 2444 | }, |
2586 | [ALC268_FIXUP_HP_EAPD] = { | 2445 | [ALC268_FIXUP_HP_EAPD] = { |
2587 | .type = HDA_FIXUP_VERBS, | 2446 | .type = HDA_FIXUP_VERBS, |
@@ -3167,7 +3026,6 @@ static int alc269_resume(struct hda_codec *codec) | |||
3167 | 3026 | ||
3168 | snd_hda_codec_resume_amp(codec); | 3027 | snd_hda_codec_resume_amp(codec); |
3169 | snd_hda_codec_resume_cache(codec); | 3028 | snd_hda_codec_resume_cache(codec); |
3170 | alc_inv_dmic_sync(codec, true); | ||
3171 | hda_call_check_power_status(codec, 0x01); | 3029 | hda_call_check_power_status(codec, 0x01); |
3172 | 3030 | ||
3173 | /* on some machine, the BIOS will clear the codec gpio data when enter | 3031 | /* on some machine, the BIOS will clear the codec gpio data when enter |
@@ -4520,7 +4378,7 @@ static const struct hda_fixup alc269_fixups[] = { | |||
4520 | }, | 4378 | }, |
4521 | [ALC269_FIXUP_INV_DMIC] = { | 4379 | [ALC269_FIXUP_INV_DMIC] = { |
4522 | .type = HDA_FIXUP_FUNC, | 4380 | .type = HDA_FIXUP_FUNC, |
4523 | .v.func = alc_fixup_inv_dmic_0x12, | 4381 | .v.func = alc_fixup_inv_dmic, |
4524 | }, | 4382 | }, |
4525 | [ALC269_FIXUP_NO_SHUTUP] = { | 4383 | [ALC269_FIXUP_NO_SHUTUP] = { |
4526 | .type = HDA_FIXUP_FUNC, | 4384 | .type = HDA_FIXUP_FUNC, |
@@ -5980,7 +5838,7 @@ static const struct hda_fixup alc662_fixups[] = { | |||
5980 | }, | 5838 | }, |
5981 | [ALC662_FIXUP_INV_DMIC] = { | 5839 | [ALC662_FIXUP_INV_DMIC] = { |
5982 | .type = HDA_FIXUP_FUNC, | 5840 | .type = HDA_FIXUP_FUNC, |
5983 | .v.func = alc_fixup_inv_dmic_0x12, | 5841 | .v.func = alc_fixup_inv_dmic, |
5984 | }, | 5842 | }, |
5985 | [ALC668_FIXUP_DELL_XPS13] = { | 5843 | [ALC668_FIXUP_DELL_XPS13] = { |
5986 | .type = HDA_FIXUP_FUNC, | 5844 | .type = HDA_FIXUP_FUNC, |