aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-12-10 17:29:26 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-20 07:45:06 -0800
commit2a9f683edd34578a3d1e789781f4499af4990d63 (patch)
treeff827ca459d063201bc6507b38d4b3571d706ec6
parent44b8b7a7f2e76dd1aea131bcf79417252a1f3f11 (diff)
ALSA: hda - Add static DAC/pin mapping for AD1986A codec
commit 3690739b013504d33fe9348dd45f6b126aa370fb upstream. 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 Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--sound/pci/hda/hda_generic.c23
-rw-r--r--sound/pci/hda/hda_generic.h3
-rw-r--r--sound/pci/hda/patch_analog.c10
3 files changed, 35 insertions, 1 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 7975031312c..b4e4dd6fd91 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -468,6 +468,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)
@@ -1134,7 +1148,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 76200314ee9..a18a1005002 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -241,6 +241,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 e17b55a95bc..a7b07f72c9d 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -1227,6 +1227,14 @@ static int ad1986a_parse_auto_config(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)
@@ -1247,6 +1255,8 @@ static int ad1986a_parse_auto_config(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;
snd_hda_pick_fixup(codec, NULL, ad1986a_fixup_tbl, ad1986a_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);