diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-11-24 10:06:23 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-01-03 06:29:47 -0500 |
commit | d32410b1095cf93e8e31f8919de46f496d7b3ce0 (patch) | |
tree | 8d4b825c568c6bde3fa751320fa1e03e26052773 /sound | |
parent | b2ec642362eef10f660e2b857dda12e2d61e0198 (diff) |
[ALSA] hda-codec - Fix/enhance AD1988 support
Modules: HDA Codec driver
Fix/enhance AD1988 support code.
- Fix for h/w bug of AD1988A rev 2
- The BIOS auto-configuration is added and used as fallback
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_analog.c | 572 |
1 files changed, 531 insertions, 41 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 3799d8a1afae..fabcbcf77a10 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * HD audio interface patch for AD1981HD, AD1983, AD1986A | 2 | * HD audio interface patch for AD1981HD, AD1983, AD1986A, AD1988 |
3 | * | 3 | * |
4 | * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de> | 4 | * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de> |
5 | * | 5 | * |
@@ -31,7 +31,7 @@ struct ad198x_spec { | |||
31 | struct snd_kcontrol_new *mixers[5]; | 31 | struct snd_kcontrol_new *mixers[5]; |
32 | int num_mixers; | 32 | int num_mixers; |
33 | 33 | ||
34 | const struct hda_verb *init_verbs[3]; /* initialization verbs | 34 | const struct hda_verb *init_verbs[5]; /* initialization verbs |
35 | * don't forget NULL termination! | 35 | * don't forget NULL termination! |
36 | */ | 36 | */ |
37 | unsigned int num_init_verbs; | 37 | unsigned int num_init_verbs; |
@@ -62,6 +62,13 @@ struct ad198x_spec { | |||
62 | 62 | ||
63 | struct semaphore amp_mutex; /* PCM volume/mute control mutex */ | 63 | struct semaphore amp_mutex; /* PCM volume/mute control mutex */ |
64 | unsigned int spdif_route; | 64 | unsigned int spdif_route; |
65 | |||
66 | /* dynamic controls, init_verbs and input_mux */ | ||
67 | struct auto_pin_cfg autocfg; | ||
68 | unsigned int num_kctl_alloc, num_kctl_used; | ||
69 | struct snd_kcontrol_new *kctl_alloc; | ||
70 | struct hda_input_mux private_imux; | ||
71 | hda_nid_t private_dac_nids[4]; | ||
65 | }; | 72 | }; |
66 | 73 | ||
67 | /* | 74 | /* |
@@ -284,6 +291,14 @@ static int ad198x_build_pcms(struct hda_codec *codec) | |||
284 | 291 | ||
285 | static void ad198x_free(struct hda_codec *codec) | 292 | static void ad198x_free(struct hda_codec *codec) |
286 | { | 293 | { |
294 | struct ad198x_spec *spec = codec->spec; | ||
295 | unsigned int i; | ||
296 | |||
297 | if (spec->kctl_alloc) { | ||
298 | for (i = 0; i < spec->num_kctl_used; i++) | ||
299 | kfree(spec->kctl_alloc[i].name); | ||
300 | kfree(spec->kctl_alloc); | ||
301 | } | ||
287 | kfree(codec->spec); | 302 | kfree(codec->spec); |
288 | } | 303 | } |
289 | 304 | ||
@@ -867,7 +882,7 @@ static int patch_ad1981(struct hda_codec *codec) | |||
867 | * | 882 | * |
868 | * Output pins and routes | 883 | * Output pins and routes |
869 | * | 884 | * |
870 | * Pin Mix Sel DAC | 885 | * Pin Mix Sel DAC (*) |
871 | * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06 | 886 | * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06 |
872 | * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06 | 887 | * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06 |
873 | * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a | 888 | * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a |
@@ -878,6 +893,8 @@ static int patch_ad1981(struct hda_codec *codec) | |||
878 | * port-H 0x25 (mute) <- 0x28 <- 0a | 893 | * port-H 0x25 (mute) <- 0x28 <- 0a |
879 | * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06 | 894 | * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06 |
880 | * | 895 | * |
896 | * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah | ||
897 | * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug. | ||
881 | * | 898 | * |
882 | * Input pins and routes | 899 | * Input pins and routes |
883 | * | 900 | * |
@@ -893,11 +910,8 @@ static int patch_ad1981(struct hda_codec *codec) | |||
893 | * | 910 | * |
894 | * | 911 | * |
895 | * DAC assignment | 912 | * DAC assignment |
896 | * front DAC - 04 | 913 | * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03 |
897 | * surr DAC - 06 | 914 | * 3stack - front/surr/CLFE/opt DACs - 04/0a/05/03 |
898 | * CLFE DAC - 05 | ||
899 | * side DAC - 0a | ||
900 | * opt DAC - 03 | ||
901 | * | 915 | * |
902 | * Inputs of Analog Mix (0x20) | 916 | * Inputs of Analog Mix (0x20) |
903 | * 0:Port-B (front mic) | 917 | * 0:Port-B (front mic) |
@@ -957,18 +971,35 @@ enum { | |||
957 | AD1988_3STACK_DIG, | 971 | AD1988_3STACK_DIG, |
958 | AD1988_LAPTOP, | 972 | AD1988_LAPTOP, |
959 | AD1988_LAPTOP_DIG, | 973 | AD1988_LAPTOP_DIG, |
974 | AD1988_AUTO, | ||
960 | AD1988_MODEL_LAST, | 975 | AD1988_MODEL_LAST, |
961 | }; | 976 | }; |
962 | 977 | ||
978 | /* reivision id to check workarounds */ | ||
979 | #define AD1988A_REV2 0x100200 | ||
980 | |||
963 | 981 | ||
964 | /* | 982 | /* |
965 | * mixers | 983 | * mixers |
966 | */ | 984 | */ |
967 | 985 | ||
968 | static hda_nid_t ad1988_dac_nids[4] = { | 986 | static hda_nid_t ad1988_6stack_dac_nids[4] = { |
969 | 0x04, 0x06, 0x05, 0x0a | 987 | 0x04, 0x06, 0x05, 0x0a |
970 | }; | 988 | }; |
971 | 989 | ||
990 | static hda_nid_t ad1988_3stack_dac_nids[3] = { | ||
991 | 0x04, 0x0a, 0x05 | ||
992 | }; | ||
993 | |||
994 | /* for AD1988A revision-2, DAC2-4 are swapped */ | ||
995 | static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { | ||
996 | 0x04, 0x05, 0x0a, 0x06 | ||
997 | }; | ||
998 | |||
999 | static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { | ||
1000 | 0x04, 0x06, 0x0a | ||
1001 | }; | ||
1002 | |||
972 | static hda_nid_t ad1988_adc_nids[3] = { | 1003 | static hda_nid_t ad1988_adc_nids[3] = { |
973 | 0x08, 0x09, 0x0f | 1004 | 0x08, 0x09, 0x0f |
974 | }; | 1005 | }; |
@@ -1068,13 +1099,23 @@ static int ad1988_eapd_put(struct snd_kcontrol *kcontrol, | |||
1068 | } | 1099 | } |
1069 | 1100 | ||
1070 | /* 6-stack mode */ | 1101 | /* 6-stack mode */ |
1071 | static struct snd_kcontrol_new ad1988_6stack_mixers[] = { | 1102 | static struct snd_kcontrol_new ad1988_6stack_mixers1[] = { |
1072 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | 1103 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), |
1073 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), | 1104 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), |
1074 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | 1105 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), |
1075 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | 1106 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), |
1076 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT), | 1107 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT), |
1108 | }; | ||
1109 | |||
1110 | static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { | ||
1111 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
1112 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
1113 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | ||
1114 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT), | ||
1115 | HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
1116 | }; | ||
1077 | 1117 | ||
1118 | static struct snd_kcontrol_new ad1988_6stack_mixers2[] = { | ||
1078 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), | 1119 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), |
1079 | HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), | 1120 | HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), |
1080 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), | 1121 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), |
@@ -1105,16 +1146,25 @@ static struct snd_kcontrol_new ad1988_6stack_mixers[] = { | |||
1105 | }; | 1146 | }; |
1106 | 1147 | ||
1107 | /* 3-stack mode */ | 1148 | /* 3-stack mode */ |
1108 | static struct snd_kcontrol_new ad1988_3stack_mixers[] = { | 1149 | static struct snd_kcontrol_new ad1988_3stack_mixers1[] = { |
1109 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | 1150 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), |
1110 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), | 1151 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), |
1111 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | 1152 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), |
1112 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | 1153 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), |
1154 | }; | ||
1155 | |||
1156 | static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { | ||
1157 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
1158 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
1159 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | ||
1160 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT), | ||
1161 | }; | ||
1113 | 1162 | ||
1163 | static struct snd_kcontrol_new ad1988_3stack_mixers2[] = { | ||
1114 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), | 1164 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), |
1115 | HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), | 1165 | HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT), |
1116 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), | 1166 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT), |
1117 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), | 1167 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT), |
1118 | HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), | 1168 | HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), |
1119 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | 1169 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), |
1120 | 1170 | ||
@@ -1391,11 +1441,11 @@ static struct hda_verb ad1988_3stack_ch2_init[] = { | |||
1391 | 1441 | ||
1392 | static struct hda_verb ad1988_3stack_ch6_init[] = { | 1442 | static struct hda_verb ad1988_3stack_ch6_init[] = { |
1393 | /* set port-C to surround out */ | 1443 | /* set port-C to surround out */ |
1394 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
1395 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | 1444 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
1445 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
1396 | /* set port-E to CLFE out */ | 1446 | /* set port-E to CLFE out */ |
1397 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
1398 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | 1447 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
1448 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
1399 | { } /* end */ | 1449 | { } /* end */ |
1400 | }; | 1450 | }; |
1401 | 1451 | ||
@@ -1431,15 +1481,17 @@ static struct hda_verb ad1988_3stack_init_verbs[] = { | |||
1431 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | 1481 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
1432 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1482 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
1433 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 1483 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
1434 | /* Port-C line-in/surround path */ | 1484 | /* Port-C line-in/surround path - 6ch mode as default */ |
1435 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | 1485 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1436 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 1486 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1437 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 1487 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
1488 | {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */ | ||
1438 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | 1489 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, |
1439 | /* Port-E mic-in/CLFE path */ | 1490 | /* Port-E mic-in/CLFE path - 6ch mode as default */ |
1440 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | 1491 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1441 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1492 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1442 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 1493 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
1494 | {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x06 */ | ||
1443 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | 1495 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, |
1444 | /* mute analog mix */ | 1496 | /* mute analog mix */ |
1445 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 1497 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
@@ -1546,6 +1598,420 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) | |||
1546 | 1598 | ||
1547 | 1599 | ||
1548 | /* | 1600 | /* |
1601 | * Automatic parse of I/O pins from the BIOS configuration | ||
1602 | */ | ||
1603 | |||
1604 | #define NUM_CONTROL_ALLOC 32 | ||
1605 | #define NUM_VERB_ALLOC 32 | ||
1606 | |||
1607 | enum { | ||
1608 | AD_CTL_WIDGET_VOL, | ||
1609 | AD_CTL_WIDGET_MUTE, | ||
1610 | AD_CTL_BIND_MUTE, | ||
1611 | }; | ||
1612 | static struct snd_kcontrol_new ad1988_control_templates[] = { | ||
1613 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | ||
1614 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | ||
1615 | HDA_BIND_MUTE(NULL, 0, 0, 0), | ||
1616 | }; | ||
1617 | |||
1618 | /* add dynamic controls */ | ||
1619 | static int add_control(struct ad198x_spec *spec, int type, const char *name, | ||
1620 | unsigned long val) | ||
1621 | { | ||
1622 | struct snd_kcontrol_new *knew; | ||
1623 | |||
1624 | if (spec->num_kctl_used >= spec->num_kctl_alloc) { | ||
1625 | int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; | ||
1626 | |||
1627 | knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ | ||
1628 | if (! knew) | ||
1629 | return -ENOMEM; | ||
1630 | if (spec->kctl_alloc) { | ||
1631 | memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); | ||
1632 | kfree(spec->kctl_alloc); | ||
1633 | } | ||
1634 | spec->kctl_alloc = knew; | ||
1635 | spec->num_kctl_alloc = num; | ||
1636 | } | ||
1637 | |||
1638 | knew = &spec->kctl_alloc[spec->num_kctl_used]; | ||
1639 | *knew = ad1988_control_templates[type]; | ||
1640 | knew->name = kstrdup(name, GFP_KERNEL); | ||
1641 | if (! knew->name) | ||
1642 | return -ENOMEM; | ||
1643 | knew->private_value = val; | ||
1644 | spec->num_kctl_used++; | ||
1645 | return 0; | ||
1646 | } | ||
1647 | |||
1648 | #define AD1988_PIN_CD_NID 0x18 | ||
1649 | #define AD1988_PIN_BEEP_NID 0x10 | ||
1650 | |||
1651 | static hda_nid_t ad1988_mixer_nids[8] = { | ||
1652 | /* A B C D E F G H */ | ||
1653 | 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28 | ||
1654 | }; | ||
1655 | |||
1656 | static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx) | ||
1657 | { | ||
1658 | static hda_nid_t idx_to_dac[8] = { | ||
1659 | /* A B C D E F G H */ | ||
1660 | 0x04, 0x06, 0x0a, 0x04, 0x05, 0x06, 0x05, 0x0a | ||
1661 | }; | ||
1662 | static hda_nid_t idx_to_dac_rev2[8] = { | ||
1663 | /* A B C D E F G H */ | ||
1664 | 0x04, 0x05, 0x06, 0x04, 0x0a, 0x05, 0x0a, 0x06 | ||
1665 | }; | ||
1666 | if (codec->revision_id == AD1988A_REV2) | ||
1667 | return idx_to_dac_rev2[idx]; | ||
1668 | else | ||
1669 | return idx_to_dac[idx]; | ||
1670 | } | ||
1671 | |||
1672 | static hda_nid_t ad1988_boost_nids[8] = { | ||
1673 | 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0 | ||
1674 | }; | ||
1675 | |||
1676 | static int ad1988_pin_idx(hda_nid_t nid) | ||
1677 | { | ||
1678 | static hda_nid_t ad1988_io_pins[8] = { | ||
1679 | 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25 | ||
1680 | }; | ||
1681 | int i; | ||
1682 | for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++) | ||
1683 | if (ad1988_io_pins[i] == nid) | ||
1684 | return i; | ||
1685 | return 0; /* should be -1 */ | ||
1686 | } | ||
1687 | |||
1688 | static int ad1988_pin_to_loopback_idx(hda_nid_t nid) | ||
1689 | { | ||
1690 | static int loopback_idx[8] = { | ||
1691 | 2, 0, 1, 3, 4, 5, 1, 4 | ||
1692 | }; | ||
1693 | switch (nid) { | ||
1694 | case AD1988_PIN_CD_NID: | ||
1695 | return 6; | ||
1696 | default: | ||
1697 | return loopback_idx[ad1988_pin_idx(nid)]; | ||
1698 | } | ||
1699 | } | ||
1700 | |||
1701 | static int ad1988_pin_to_adc_idx(hda_nid_t nid) | ||
1702 | { | ||
1703 | static int adc_idx[8] = { | ||
1704 | 0, 1, 2, 8, 4, 3, 6, 7 | ||
1705 | }; | ||
1706 | switch (nid) { | ||
1707 | case AD1988_PIN_CD_NID: | ||
1708 | return 5; | ||
1709 | default: | ||
1710 | return adc_idx[ad1988_pin_idx(nid)]; | ||
1711 | } | ||
1712 | } | ||
1713 | |||
1714 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
1715 | static int ad1988_auto_fill_dac_nids(struct hda_codec *codec, | ||
1716 | const struct auto_pin_cfg *cfg) | ||
1717 | { | ||
1718 | struct ad198x_spec *spec = codec->spec; | ||
1719 | int i, idx; | ||
1720 | |||
1721 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
1722 | |||
1723 | /* check the pins hardwired to audio widget */ | ||
1724 | for (i = 0; i < cfg->line_outs; i++) { | ||
1725 | idx = ad1988_pin_idx(cfg->line_out_pins[i]); | ||
1726 | spec->multiout.dac_nids[i] = ad1988_idx_to_dac(codec, idx); | ||
1727 | } | ||
1728 | spec->multiout.num_dacs = cfg->line_outs; | ||
1729 | return 0; | ||
1730 | } | ||
1731 | |||
1732 | /* add playback controls from the parsed DAC table */ | ||
1733 | static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec, | ||
1734 | const struct auto_pin_cfg *cfg) | ||
1735 | { | ||
1736 | char name[32]; | ||
1737 | static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; | ||
1738 | hda_nid_t nid; | ||
1739 | int i, err; | ||
1740 | |||
1741 | for (i = 0; i < cfg->line_outs; i++) { | ||
1742 | hda_nid_t dac = spec->multiout.dac_nids[i]; | ||
1743 | if (! dac) | ||
1744 | continue; | ||
1745 | nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])]; | ||
1746 | if (i == 2) { | ||
1747 | /* Center/LFE */ | ||
1748 | err = add_control(spec, AD_CTL_WIDGET_VOL, | ||
1749 | "Center Playback Volume", | ||
1750 | HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT)); | ||
1751 | if (err < 0) | ||
1752 | return err; | ||
1753 | err = add_control(spec, AD_CTL_WIDGET_VOL, | ||
1754 | "LFE Playback Volume", | ||
1755 | HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT)); | ||
1756 | if (err < 0) | ||
1757 | return err; | ||
1758 | err = add_control(spec, AD_CTL_BIND_MUTE, | ||
1759 | "Center Playback Switch", | ||
1760 | HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT)); | ||
1761 | if (err < 0) | ||
1762 | return err; | ||
1763 | err = add_control(spec, AD_CTL_BIND_MUTE, | ||
1764 | "LFE Playback Switch", | ||
1765 | HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT)); | ||
1766 | if (err < 0) | ||
1767 | return err; | ||
1768 | } else { | ||
1769 | sprintf(name, "%s Playback Volume", chname[i]); | ||
1770 | err = add_control(spec, AD_CTL_WIDGET_VOL, name, | ||
1771 | HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT)); | ||
1772 | if (err < 0) | ||
1773 | return err; | ||
1774 | sprintf(name, "%s Playback Switch", chname[i]); | ||
1775 | err = add_control(spec, AD_CTL_BIND_MUTE, name, | ||
1776 | HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); | ||
1777 | if (err < 0) | ||
1778 | return err; | ||
1779 | } | ||
1780 | } | ||
1781 | return 0; | ||
1782 | } | ||
1783 | |||
1784 | /* add playback controls for speaker and HP outputs */ | ||
1785 | static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, | ||
1786 | const char *pfx) | ||
1787 | { | ||
1788 | struct ad198x_spec *spec = codec->spec; | ||
1789 | hda_nid_t nid; | ||
1790 | int idx, err; | ||
1791 | char name[32]; | ||
1792 | |||
1793 | if (! pin) | ||
1794 | return 0; | ||
1795 | |||
1796 | idx = ad1988_pin_idx(pin); | ||
1797 | nid = ad1988_idx_to_dac(codec, idx); | ||
1798 | if (! spec->multiout.dac_nids[0]) { | ||
1799 | /* use this as the primary output */ | ||
1800 | spec->multiout.dac_nids[0] = nid; | ||
1801 | if (! spec->multiout.num_dacs) | ||
1802 | spec->multiout.num_dacs = 1; | ||
1803 | } else | ||
1804 | /* specify the DAC as the extra output */ | ||
1805 | spec->multiout.hp_nid = nid; | ||
1806 | /* control HP volume/switch on the output mixer amp */ | ||
1807 | sprintf(name, "%s Playback Volume", pfx); | ||
1808 | if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, | ||
1809 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
1810 | return err; | ||
1811 | nid = ad1988_mixer_nids[idx]; | ||
1812 | sprintf(name, "%s Playback Switch", pfx); | ||
1813 | if ((err = add_control(spec, AD_CTL_BIND_MUTE, name, | ||
1814 | HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) | ||
1815 | return err; | ||
1816 | return 0; | ||
1817 | } | ||
1818 | |||
1819 | /* create input playback/capture controls for the given pin */ | ||
1820 | static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin, | ||
1821 | const char *ctlname, int boost) | ||
1822 | { | ||
1823 | char name[32]; | ||
1824 | int err, idx; | ||
1825 | |||
1826 | sprintf(name, "%s Playback Volume", ctlname); | ||
1827 | idx = ad1988_pin_to_loopback_idx(pin); | ||
1828 | if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, | ||
1829 | HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0) | ||
1830 | return err; | ||
1831 | sprintf(name, "%s Playback Switch", ctlname); | ||
1832 | if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name, | ||
1833 | HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0) | ||
1834 | return err; | ||
1835 | if (boost) { | ||
1836 | hda_nid_t bnid; | ||
1837 | idx = ad1988_pin_idx(pin); | ||
1838 | bnid = ad1988_boost_nids[idx]; | ||
1839 | if (bnid) { | ||
1840 | sprintf(name, "%s Boost", ctlname); | ||
1841 | return add_control(spec, AD_CTL_WIDGET_VOL, name, | ||
1842 | HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT)); | ||
1843 | |||
1844 | } | ||
1845 | } | ||
1846 | return 0; | ||
1847 | } | ||
1848 | |||
1849 | /* create playback/capture controls for input pins */ | ||
1850 | static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec, | ||
1851 | const struct auto_pin_cfg *cfg) | ||
1852 | { | ||
1853 | static char *labels[AUTO_PIN_LAST] = { | ||
1854 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" | ||
1855 | }; | ||
1856 | struct hda_input_mux *imux = &spec->private_imux; | ||
1857 | int i, err; | ||
1858 | |||
1859 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
1860 | err = new_analog_input(spec, cfg->input_pins[i], labels[i], | ||
1861 | i <= AUTO_PIN_FRONT_MIC); | ||
1862 | if (err < 0) | ||
1863 | return err; | ||
1864 | imux->items[imux->num_items].label = labels[i]; | ||
1865 | imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]); | ||
1866 | imux->num_items++; | ||
1867 | } | ||
1868 | imux->items[imux->num_items].label = "Mix"; | ||
1869 | imux->items[imux->num_items].index = 9; | ||
1870 | imux->num_items++; | ||
1871 | |||
1872 | if ((err = add_control(spec, AD_CTL_WIDGET_VOL, | ||
1873 | "Analog Mix Playback Volume", | ||
1874 | HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0) | ||
1875 | return err; | ||
1876 | if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, | ||
1877 | "Analog Mix Playback Switch", | ||
1878 | HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0) | ||
1879 | return err; | ||
1880 | |||
1881 | return 0; | ||
1882 | } | ||
1883 | |||
1884 | static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec, | ||
1885 | hda_nid_t nid, int pin_type, | ||
1886 | int dac_idx) | ||
1887 | { | ||
1888 | /* set as output */ | ||
1889 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); | ||
1890 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); | ||
1891 | switch (nid) { | ||
1892 | case 0x11: /* port-A - DAC 04 */ | ||
1893 | snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01); | ||
1894 | break; | ||
1895 | case 0x14: /* port-B - DAC 06 */ | ||
1896 | snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02); | ||
1897 | break; | ||
1898 | case 0x15: /* port-C - DAC 05 */ | ||
1899 | snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00); | ||
1900 | break; | ||
1901 | case 0x17: /* port-E - DAC 06 */ | ||
1902 | snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01); | ||
1903 | break; | ||
1904 | case 0x13: /* mono - DAC 04 */ | ||
1905 | snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01); | ||
1906 | break; | ||
1907 | } | ||
1908 | } | ||
1909 | |||
1910 | static void ad1988_auto_init_multi_out(struct hda_codec *codec) | ||
1911 | { | ||
1912 | struct ad198x_spec *spec = codec->spec; | ||
1913 | int i; | ||
1914 | |||
1915 | for (i = 0; i < spec->autocfg.line_outs; i++) { | ||
1916 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | ||
1917 | ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); | ||
1918 | } | ||
1919 | } | ||
1920 | |||
1921 | static void ad1988_auto_init_extra_out(struct hda_codec *codec) | ||
1922 | { | ||
1923 | struct ad198x_spec *spec = codec->spec; | ||
1924 | hda_nid_t pin; | ||
1925 | |||
1926 | pin = spec->autocfg.speaker_pin; | ||
1927 | if (pin) /* connect to front */ | ||
1928 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); | ||
1929 | pin = spec->autocfg.hp_pin; | ||
1930 | if (pin) /* connect to front */ | ||
1931 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | ||
1932 | } | ||
1933 | |||
1934 | static void ad1988_auto_init_analog_input(struct hda_codec *codec) | ||
1935 | { | ||
1936 | struct ad198x_spec *spec = codec->spec; | ||
1937 | int i, idx; | ||
1938 | |||
1939 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
1940 | hda_nid_t nid = spec->autocfg.input_pins[i]; | ||
1941 | if (! nid) | ||
1942 | continue; | ||
1943 | switch (nid) { | ||
1944 | case 0x15: /* port-C */ | ||
1945 | snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0); | ||
1946 | break; | ||
1947 | case 0x17: /* port-E */ | ||
1948 | snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0); | ||
1949 | break; | ||
1950 | } | ||
1951 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1952 | i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); | ||
1953 | if (nid != AD1988_PIN_CD_NID) | ||
1954 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
1955 | AMP_OUT_MUTE); | ||
1956 | idx = ad1988_pin_idx(nid); | ||
1957 | if (ad1988_boost_nids[idx]) | ||
1958 | snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0, | ||
1959 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
1960 | AMP_OUT_ZERO); | ||
1961 | } | ||
1962 | } | ||
1963 | |||
1964 | /* parse the BIOS configuration and set up the alc_spec */ | ||
1965 | /* return 1 if successful, 0 if the proper config is not found, or a negative error code */ | ||
1966 | static int ad1988_parse_auto_config(struct hda_codec *codec) | ||
1967 | { | ||
1968 | struct ad198x_spec *spec = codec->spec; | ||
1969 | int err; | ||
1970 | |||
1971 | if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0) | ||
1972 | return err; | ||
1973 | if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) | ||
1974 | return err; | ||
1975 | if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && | ||
1976 | ! spec->autocfg.hp_pin) | ||
1977 | return 0; /* can't find valid BIOS pin config */ | ||
1978 | if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || | ||
1979 | (err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin, | ||
1980 | "Speaker")) < 0 || | ||
1981 | (err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin, | ||
1982 | "Headphone")) < 0 || | ||
1983 | (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | ||
1984 | return err; | ||
1985 | |||
1986 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
1987 | |||
1988 | if (spec->autocfg.dig_out_pin) | ||
1989 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
1990 | if (spec->autocfg.dig_in_pin) | ||
1991 | spec->dig_in_nid = AD1988_SPDIF_IN; | ||
1992 | |||
1993 | if (spec->kctl_alloc) | ||
1994 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
1995 | |||
1996 | spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs; | ||
1997 | |||
1998 | spec->input_mux = &spec->private_imux; | ||
1999 | |||
2000 | return 1; | ||
2001 | } | ||
2002 | |||
2003 | /* init callback for auto-configuration model -- overriding the default init */ | ||
2004 | static int ad1988_auto_init(struct hda_codec *codec) | ||
2005 | { | ||
2006 | ad198x_init(codec); | ||
2007 | ad1988_auto_init_multi_out(codec); | ||
2008 | ad1988_auto_init_extra_out(codec); | ||
2009 | ad1988_auto_init_analog_input(codec); | ||
2010 | return 0; | ||
2011 | } | ||
2012 | |||
2013 | |||
2014 | /* | ||
1549 | */ | 2015 | */ |
1550 | 2016 | ||
1551 | static struct hda_board_config ad1988_cfg_tbl[] = { | 2017 | static struct hda_board_config ad1988_cfg_tbl[] = { |
@@ -1555,6 +2021,7 @@ static struct hda_board_config ad1988_cfg_tbl[] = { | |||
1555 | { .modelname = "3stack-dig", .config = AD1988_3STACK_DIG }, | 2021 | { .modelname = "3stack-dig", .config = AD1988_3STACK_DIG }, |
1556 | { .modelname = "laptop", .config = AD1988_LAPTOP }, | 2022 | { .modelname = "laptop", .config = AD1988_LAPTOP }, |
1557 | { .modelname = "laptop-dig", .config = AD1988_LAPTOP_DIG }, | 2023 | { .modelname = "laptop-dig", .config = AD1988_LAPTOP_DIG }, |
2024 | { .modelname = "auto", .config = AD1988_AUTO }, | ||
1558 | {} | 2025 | {} |
1559 | }; | 2026 | }; |
1560 | 2027 | ||
@@ -1572,8 +2039,20 @@ static int patch_ad1988(struct hda_codec *codec) | |||
1572 | 2039 | ||
1573 | board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl); | 2040 | board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl); |
1574 | if (board_config < 0 || board_config >= AD1988_MODEL_LAST) { | 2041 | if (board_config < 0 || board_config >= AD1988_MODEL_LAST) { |
1575 | printk(KERN_INFO "hda_codec: Unknown model for AD1988, using 6stack model...\n"); | 2042 | printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n"); |
1576 | board_config = AD1988_6STACK; | 2043 | board_config = AD1988_AUTO; |
2044 | } | ||
2045 | |||
2046 | if (board_config == AD1988_AUTO) { | ||
2047 | /* automatic parse from the BIOS config */ | ||
2048 | int err = ad1988_parse_auto_config(codec); | ||
2049 | if (err < 0) { | ||
2050 | ad198x_free(codec); | ||
2051 | return err; | ||
2052 | } else if (! err) { | ||
2053 | printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n"); | ||
2054 | board_config = AD1988_6STACK; | ||
2055 | } | ||
1577 | } | 2056 | } |
1578 | 2057 | ||
1579 | switch (board_config) { | 2058 | switch (board_config) { |
@@ -1581,13 +2060,17 @@ static int patch_ad1988(struct hda_codec *codec) | |||
1581 | case AD1988_6STACK_DIG: | 2060 | case AD1988_6STACK_DIG: |
1582 | spec->multiout.max_channels = 8; | 2061 | spec->multiout.max_channels = 8; |
1583 | spec->multiout.num_dacs = 4; | 2062 | spec->multiout.num_dacs = 4; |
1584 | spec->multiout.dac_nids = ad1988_dac_nids; | 2063 | if (codec->revision_id == AD1988A_REV2) |
1585 | spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); | 2064 | spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2; |
1586 | spec->adc_nids = ad1988_adc_nids; | 2065 | else |
1587 | spec->capsrc_nids = ad1988_capsrc_nids; | 2066 | spec->multiout.dac_nids = ad1988_6stack_dac_nids; |
1588 | spec->input_mux = &ad1988_6stack_capture_source; | 2067 | spec->input_mux = &ad1988_6stack_capture_source; |
1589 | spec->num_mixers = 1; | 2068 | spec->num_mixers = 2; |
1590 | spec->mixers[0] = ad1988_6stack_mixers; | 2069 | if (codec->revision_id == AD1988A_REV2) |
2070 | spec->mixers[0] = ad1988_6stack_mixers1_rev2; | ||
2071 | else | ||
2072 | spec->mixers[0] = ad1988_6stack_mixers1; | ||
2073 | spec->mixers[1] = ad1988_6stack_mixers2; | ||
1591 | spec->num_init_verbs = 1; | 2074 | spec->num_init_verbs = 1; |
1592 | spec->init_verbs[0] = ad1988_6stack_init_verbs; | 2075 | spec->init_verbs[0] = ad1988_6stack_init_verbs; |
1593 | if (board_config == AD1988_6STACK_DIG) { | 2076 | if (board_config == AD1988_6STACK_DIG) { |
@@ -1599,15 +2082,19 @@ static int patch_ad1988(struct hda_codec *codec) | |||
1599 | case AD1988_3STACK_DIG: | 2082 | case AD1988_3STACK_DIG: |
1600 | spec->multiout.max_channels = 6; | 2083 | spec->multiout.max_channels = 6; |
1601 | spec->multiout.num_dacs = 3; | 2084 | spec->multiout.num_dacs = 3; |
1602 | spec->multiout.dac_nids = ad1988_dac_nids; | 2085 | if (codec->revision_id == AD1988A_REV2) |
1603 | spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); | 2086 | spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2; |
1604 | spec->adc_nids = ad1988_adc_nids; | 2087 | else |
1605 | spec->capsrc_nids = ad1988_capsrc_nids; | 2088 | spec->multiout.dac_nids = ad1988_3stack_dac_nids; |
1606 | spec->input_mux = &ad1988_6stack_capture_source; | 2089 | spec->input_mux = &ad1988_6stack_capture_source; |
1607 | spec->channel_mode = ad1988_3stack_modes; | 2090 | spec->channel_mode = ad1988_3stack_modes; |
1608 | spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes); | 2091 | spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes); |
1609 | spec->num_mixers = 1; | 2092 | spec->num_mixers = 2; |
1610 | spec->mixers[0] = ad1988_3stack_mixers; | 2093 | if (codec->revision_id == AD1988A_REV2) |
2094 | spec->mixers[0] = ad1988_3stack_mixers1_rev2; | ||
2095 | else | ||
2096 | spec->mixers[0] = ad1988_3stack_mixers1; | ||
2097 | spec->mixers[1] = ad1988_3stack_mixers2; | ||
1611 | spec->num_init_verbs = 1; | 2098 | spec->num_init_verbs = 1; |
1612 | spec->init_verbs[0] = ad1988_3stack_init_verbs; | 2099 | spec->init_verbs[0] = ad1988_3stack_init_verbs; |
1613 | if (board_config == AD1988_3STACK_DIG) | 2100 | if (board_config == AD1988_3STACK_DIG) |
@@ -1617,10 +2104,7 @@ static int patch_ad1988(struct hda_codec *codec) | |||
1617 | case AD1988_LAPTOP_DIG: | 2104 | case AD1988_LAPTOP_DIG: |
1618 | spec->multiout.max_channels = 2; | 2105 | spec->multiout.max_channels = 2; |
1619 | spec->multiout.num_dacs = 1; | 2106 | spec->multiout.num_dacs = 1; |
1620 | spec->multiout.dac_nids = ad1988_dac_nids; | 2107 | spec->multiout.dac_nids = ad1988_3stack_dac_nids; |
1621 | spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); | ||
1622 | spec->adc_nids = ad1988_adc_nids; | ||
1623 | spec->capsrc_nids = ad1988_capsrc_nids; | ||
1624 | spec->input_mux = &ad1988_laptop_capture_source; | 2108 | spec->input_mux = &ad1988_laptop_capture_source; |
1625 | spec->num_mixers = 1; | 2109 | spec->num_mixers = 1; |
1626 | spec->mixers[0] = ad1988_laptop_mixers; | 2110 | spec->mixers[0] = ad1988_laptop_mixers; |
@@ -1631,6 +2115,9 @@ static int patch_ad1988(struct hda_codec *codec) | |||
1631 | break; | 2115 | break; |
1632 | } | 2116 | } |
1633 | 2117 | ||
2118 | spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); | ||
2119 | spec->adc_nids = ad1988_adc_nids; | ||
2120 | spec->capsrc_nids = ad1988_capsrc_nids; | ||
1634 | spec->mixers[spec->num_mixers++] = ad1988_capture_mixers; | 2121 | spec->mixers[spec->num_mixers++] = ad1988_capture_mixers; |
1635 | spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs; | 2122 | spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs; |
1636 | if (spec->multiout.dig_out_nid) { | 2123 | if (spec->multiout.dig_out_nid) { |
@@ -1642,6 +2129,9 @@ static int patch_ad1988(struct hda_codec *codec) | |||
1642 | 2129 | ||
1643 | codec->patch_ops = ad198x_patch_ops; | 2130 | codec->patch_ops = ad198x_patch_ops; |
1644 | switch (board_config) { | 2131 | switch (board_config) { |
2132 | case AD1988_AUTO: | ||
2133 | codec->patch_ops.init = ad1988_auto_init; | ||
2134 | break; | ||
1645 | case AD1988_LAPTOP: | 2135 | case AD1988_LAPTOP: |
1646 | case AD1988_LAPTOP_DIG: | 2136 | case AD1988_LAPTOP_DIG: |
1647 | codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; | 2137 | codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; |