From 1cd9b2f78bf29d5282e02b32f9b3ecebc5842a7c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 Dec 2013 13:19:45 +0100 Subject: ALSA: hda - Fix bad EAPD setup for HP machines with AD1984A It seems that EAPD on NID 0x16 is the only control over all outputs on HP machines with AD1984A while turning EAPD on NID 0x12 breaks the output. Thus we need to avoid fiddling EAPD on NID. As a quick workaround, just set own_eapd_ctrl flag for the wrong EAPD, then implement finer EAPD controls. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=66321 Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda/patch_analog.c') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1a83559f4cb..34d86ec5d3d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -962,6 +962,7 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec, switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook; + spec->gen.own_eapd_ctl = 1; snd_hda_sequence_write_cache(codec, gpio_init_verbs); break; case HDA_FIXUP_ACT_PROBE: -- cgit v1.2.3-70-g09d2 From ce8e0fd239e411e08a0cd83868898cd3f573d7cf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 Dec 2013 15:01:35 +0100 Subject: ALSA: hda/analog - Handle inverted EAPD properly in vmaster hook ad_vmaster_eapd_hook() needs to handle the inverted EAPD case properly, too. Otherwise the output gets broken on Lenovo N100 with AD1986A codec. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=64971 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci/hda/patch_analog.c') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 34d86ec5d3d..f6351b8e0f5 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -147,6 +147,8 @@ static void ad_vmaster_eapd_hook(void *private_data, int enabled) if (!spec->eapd_nid) return; + if (codec->inv_eapd) + enabled = !enabled; snd_hda_codec_update_cache(codec, spec->eapd_nid, 0, AC_VERB_SET_EAPD_BTLENABLE, enabled ? 0x02 : 0x00); -- cgit v1.2.3-70-g09d2 From b3bd4fc3822a6b5883eaa556822487d87752d443 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 Dec 2013 15:04:03 +0100 Subject: ALSA: hda - Use always amps for auto-mute on AD1986A codec It seems that AD1986A cannot manage the dynamic pin on/off for auto-muting, but rather gets confused. Since each output has own amp, let's use it instead. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=64971 Cc: [v3.11+] Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/pci/hda/patch_analog.c') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index f6351b8e0f5..cac015be332 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -361,6 +361,9 @@ static int patch_ad1986a(struct hda_codec *codec) */ spec->gen.multiout.no_share_stream = 1; + /* AD1986A can't manage the dynamic pin on/off smoothly */ + spec->gen.auto_mute_via_amp = 1; + snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl, ad1986a_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); -- cgit v1.2.3-70-g09d2 From 3690739b013504d33fe9348dd45f6b126aa370fb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 10 Dec 2013 17:29:26 +0100 Subject: ALSA: hda - Add static DAC/pin mapping for AD1986A codec AD1986A codec is a pretty old codec and has really many hidden restrictions. One of such is that each DAC is dedicated to certain pin although there are possible connections. Currently, the generic parser tries to assign individual DACs as much as possible, and this lead to two bad situations: connections where the sound actually doesn't work, and connections conflicting other channels. We may fix this by trying to find the best connections more harder, but as of now, it's easier to give some hints for paired DAC/pin connections and honor them if available, since such a hint is needed only for specific codecs (right now only AD1986A, and there will be unlikely any others in future). Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=64971 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=66621 Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 23 ++++++++++++++++++++++- sound/pci/hda/hda_generic.h | 3 +++ sound/pci/hda/patch_analog.c | 10 ++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda/patch_analog.c') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 249cd461590..c7f6d1cab60 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -474,6 +474,20 @@ static void invalidate_nid_path(struct hda_codec *codec, int idx) memset(path, 0, sizeof(*path)); } +/* return a DAC if paired to the given pin by codec driver */ +static hda_nid_t get_preferred_dac(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + const hda_nid_t *list = spec->preferred_dacs; + + if (!list) + return 0; + for (; *list; list += 2) + if (*list == pin) + return list[1]; + return 0; +} + /* look for an empty DAC slot */ static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin, bool is_digital) @@ -1192,7 +1206,14 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs, continue; } - dacs[i] = look_for_dac(codec, pin, false); + dacs[i] = get_preferred_dac(codec, pin); + if (dacs[i]) { + if (is_dac_already_used(codec, dacs[i])) + badness += bad->shared_primary; + } + + if (!dacs[i]) + dacs[i] = look_for_dac(codec, pin, false); if (!dacs[i] && !i) { /* try to steal the DAC of surrounds for the front */ for (j = 1; j < num_outs; j++) { diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 7e45cb44d15..0929a06df81 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -249,6 +249,9 @@ struct hda_gen_spec { const struct badness_table *main_out_badness; const struct badness_table *extra_out_badness; + /* preferred pin/DAC pairs; an array of paired NIDs */ + const hda_nid_t *preferred_dacs; + /* loopback mixing mode */ bool aamix_mode; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index cac015be332..699262a3e07 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -340,6 +340,14 @@ static int patch_ad1986a(struct hda_codec *codec) { int err; struct ad198x_spec *spec; + static hda_nid_t preferred_pairs[] = { + 0x1a, 0x03, + 0x1b, 0x03, + 0x1c, 0x04, + 0x1d, 0x05, + 0x1e, 0x03, + 0 + }; err = alloc_ad_spec(codec); if (err < 0) @@ -360,6 +368,8 @@ static int patch_ad1986a(struct hda_codec *codec) * So, let's disable the shared stream. */ spec->gen.multiout.no_share_stream = 1; + /* give fixed DAC/pin pairs */ + spec->gen.preferred_dacs = preferred_pairs; /* AD1986A can't manage the dynamic pin on/off smoothly */ spec->gen.auto_mute_via_amp = 1; -- cgit v1.2.3-70-g09d2