diff options
author | Takashi Iwai <tiwai@suse.de> | 2006-09-20 11:10:27 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-09-23 04:47:38 -0400 |
commit | eb06ed8f4c2440558ebf465e8baeac6367d90201 (patch) | |
tree | 60501d5c4e918f96d26033b95373f4368ca929e2 /sound/pci/hda/patch_sigmatel.c | |
parent | 33ef765131bcf82bc5fca3f25d8313fa4df93ce0 (diff) |
[ALSA] hda-codec - Support multiple headphone pins
Some machines have multiple headpohne pins (usually on the lpatop
and on the docking station) while the current hda-codec driver
assumes a single headphone pin. Now it supports multiple hp pins
(at least for detection).
The sigmatel 92xx code supports this new multiple hp pins.
It detects all hp pins for auto-muting, too.
Also, the driver checks speaker pins in addition. In some cases,
all line-out, speaker and hp-pins coexist.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/hda/patch_sigmatel.c')
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 202 |
1 files changed, 136 insertions, 66 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index bcbbe111ab95..7cc064265204 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -1011,11 +1011,29 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, | |||
1011 | return 0; | 1011 | return 0; |
1012 | } | 1012 | } |
1013 | 1013 | ||
1014 | /* create volume control/switch for the given prefx type */ | ||
1015 | static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs) | ||
1016 | { | ||
1017 | char name[32]; | ||
1018 | int err; | ||
1019 | |||
1020 | sprintf(name, "%s Playback Volume", pfx); | ||
1021 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, | ||
1022 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); | ||
1023 | if (err < 0) | ||
1024 | return err; | ||
1025 | sprintf(name, "%s Playback Switch", pfx); | ||
1026 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name, | ||
1027 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); | ||
1028 | if (err < 0) | ||
1029 | return err; | ||
1030 | return 0; | ||
1031 | } | ||
1032 | |||
1014 | /* add playback controls from the parsed DAC table */ | 1033 | /* add playback controls from the parsed DAC table */ |
1015 | static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | 1034 | static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, |
1016 | const struct auto_pin_cfg *cfg) | 1035 | const struct auto_pin_cfg *cfg) |
1017 | { | 1036 | { |
1018 | char name[32]; | ||
1019 | static const char *chname[4] = { | 1037 | static const char *chname[4] = { |
1020 | "Front", "Surround", NULL /*CLFE*/, "Side" | 1038 | "Front", "Surround", NULL /*CLFE*/, "Side" |
1021 | }; | 1039 | }; |
@@ -1030,26 +1048,15 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | |||
1030 | 1048 | ||
1031 | if (i == 2) { | 1049 | if (i == 2) { |
1032 | /* Center/LFE */ | 1050 | /* Center/LFE */ |
1033 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Center Playback Volume", | 1051 | err = create_controls(spec, "Center", nid, 1); |
1034 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) | 1052 | if (err < 0) |
1035 | return err; | 1053 | return err; |
1036 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "LFE Playback Volume", | 1054 | err = create_controls(spec, "LFE", nid, 2); |
1037 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) | 1055 | if (err < 0) |
1038 | return err; | ||
1039 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Center Playback Switch", | ||
1040 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) | ||
1041 | return err; | ||
1042 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "LFE Playback Switch", | ||
1043 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) | ||
1044 | return err; | 1056 | return err; |
1045 | } else { | 1057 | } else { |
1046 | sprintf(name, "%s Playback Volume", chname[i]); | 1058 | err = create_controls(spec, chname[i], nid, 3); |
1047 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, | 1059 | if (err < 0) |
1048 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
1049 | return err; | ||
1050 | sprintf(name, "%s Playback Switch", chname[i]); | ||
1051 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name, | ||
1052 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
1053 | return err; | 1060 | return err; |
1054 | } | 1061 | } |
1055 | } | 1062 | } |
@@ -1065,39 +1072,85 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | |||
1065 | return 0; | 1072 | return 0; |
1066 | } | 1073 | } |
1067 | 1074 | ||
1068 | /* add playback controls for HP output */ | 1075 | static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) |
1069 | static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg) | ||
1070 | { | 1076 | { |
1071 | struct sigmatel_spec *spec = codec->spec; | 1077 | int i; |
1072 | hda_nid_t pin = cfg->hp_pin; | ||
1073 | hda_nid_t nid; | ||
1074 | int i, err; | ||
1075 | unsigned int wid_caps; | ||
1076 | 1078 | ||
1077 | if (! pin) | 1079 | for (i = 0; i < spec->multiout.num_dacs; i++) { |
1078 | return 0; | 1080 | if (spec->multiout.dac_nids[i] == nid) |
1081 | return 1; | ||
1082 | } | ||
1083 | if (spec->multiout.hp_nid == nid) | ||
1084 | return 1; | ||
1085 | return 0; | ||
1086 | } | ||
1079 | 1087 | ||
1080 | wid_caps = get_wcaps(codec, pin); | 1088 | static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) |
1081 | if (wid_caps & AC_WCAP_UNSOL_CAP) | 1089 | { |
1082 | spec->hp_detect = 1; | 1090 | if (!spec->multiout.hp_nid) |
1091 | spec->multiout.hp_nid = nid; | ||
1092 | else if (spec->multiout.num_dacs > 4) { | ||
1093 | printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); | ||
1094 | return 1; | ||
1095 | } else { | ||
1096 | spec->multiout.dac_nids[spec->multiout.num_dacs] = nid; | ||
1097 | spec->multiout.num_dacs++; | ||
1098 | } | ||
1099 | return 0; | ||
1100 | } | ||
1083 | 1101 | ||
1084 | nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | 1102 | /* add playback controls for Speaker and HP outputs */ |
1085 | for (i = 0; i < cfg->line_outs; i++) { | 1103 | static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, |
1086 | if (! spec->multiout.dac_nids[i]) | 1104 | struct auto_pin_cfg *cfg) |
1105 | { | ||
1106 | struct sigmatel_spec *spec = codec->spec; | ||
1107 | hda_nid_t nid; | ||
1108 | int i, old_num_dacs, err; | ||
1109 | |||
1110 | old_num_dacs = spec->multiout.num_dacs; | ||
1111 | for (i = 0; i < cfg->hp_outs; i++) { | ||
1112 | unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]); | ||
1113 | if (wid_caps & AC_WCAP_UNSOL_CAP) | ||
1114 | spec->hp_detect = 1; | ||
1115 | nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, | ||
1116 | AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | ||
1117 | if (check_in_dac_nids(spec, nid)) | ||
1118 | nid = 0; | ||
1119 | if (! nid) | ||
1087 | continue; | 1120 | continue; |
1088 | if (spec->multiout.dac_nids[i] == nid) | 1121 | add_spec_dacs(spec, nid); |
1089 | return 0; | 1122 | } |
1123 | for (i = 0; i < cfg->speaker_outs; i++) { | ||
1124 | nid = snd_hda_codec_read(codec, cfg->speaker_pins[0], 0, | ||
1125 | AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | ||
1126 | if (check_in_dac_nids(spec, nid)) | ||
1127 | nid = 0; | ||
1128 | if (check_in_dac_nids(spec, nid)) | ||
1129 | nid = 0; | ||
1130 | if (! nid) | ||
1131 | continue; | ||
1132 | add_spec_dacs(spec, nid); | ||
1090 | } | 1133 | } |
1091 | 1134 | ||
1092 | spec->multiout.hp_nid = nid; | 1135 | for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) { |
1093 | 1136 | static const char *pfxs[] = { | |
1094 | /* control HP volume/switch on the output mixer amp */ | 1137 | "Speaker", "External Speaker", "Speaker2", |
1095 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Headphone Playback Volume", | 1138 | }; |
1096 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | 1139 | err = create_controls(spec, pfxs[i - old_num_dacs], |
1097 | return err; | 1140 | spec->multiout.dac_nids[i], 3); |
1098 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Headphone Playback Switch", | 1141 | if (err < 0) |
1099 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | 1142 | return err; |
1100 | return err; | 1143 | } |
1144 | if (spec->multiout.hp_nid) { | ||
1145 | const char *pfx; | ||
1146 | if (old_num_dacs == spec->multiout.num_dacs) | ||
1147 | pfx = "Master"; | ||
1148 | else | ||
1149 | pfx = "Headphone"; | ||
1150 | err = create_controls(spec, pfx, spec->multiout.hp_nid, 3); | ||
1151 | if (err < 0) | ||
1152 | return err; | ||
1153 | } | ||
1101 | 1154 | ||
1102 | return 0; | 1155 | return 0; |
1103 | } | 1156 | } |
@@ -1160,11 +1213,20 @@ static void stac92xx_auto_init_multi_out(struct hda_codec *codec) | |||
1160 | static void stac92xx_auto_init_hp_out(struct hda_codec *codec) | 1213 | static void stac92xx_auto_init_hp_out(struct hda_codec *codec) |
1161 | { | 1214 | { |
1162 | struct sigmatel_spec *spec = codec->spec; | 1215 | struct sigmatel_spec *spec = codec->spec; |
1163 | hda_nid_t pin; | 1216 | int i; |
1164 | 1217 | ||
1165 | pin = spec->autocfg.hp_pin; | 1218 | for (i = 0; i < spec->autocfg.hp_outs; i++) { |
1166 | if (pin) /* connect to front */ | 1219 | hda_nid_t pin; |
1167 | stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | 1220 | pin = spec->autocfg.hp_pins[i]; |
1221 | if (pin) /* connect to front */ | ||
1222 | stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | ||
1223 | } | ||
1224 | for (i = 0; i < spec->autocfg.speaker_outs; i++) { | ||
1225 | hda_nid_t pin; | ||
1226 | pin = spec->autocfg.speaker_pins[i]; | ||
1227 | if (pin) /* connect to front */ | ||
1228 | stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN); | ||
1229 | } | ||
1168 | } | 1230 | } |
1169 | 1231 | ||
1170 | static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) | 1232 | static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) |
@@ -1210,7 +1272,7 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, | |||
1210 | struct auto_pin_cfg *cfg) | 1272 | struct auto_pin_cfg *cfg) |
1211 | { | 1273 | { |
1212 | struct sigmatel_spec *spec = codec->spec; | 1274 | struct sigmatel_spec *spec = codec->spec; |
1213 | hda_nid_t pin = cfg->hp_pin; | 1275 | hda_nid_t pin = cfg->hp_pins[0]; |
1214 | unsigned int wid_caps; | 1276 | unsigned int wid_caps; |
1215 | 1277 | ||
1216 | if (! pin) | 1278 | if (! pin) |
@@ -1266,16 +1328,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, | |||
1266 | } | 1328 | } |
1267 | 1329 | ||
1268 | if (lfe_pin) { | 1330 | if (lfe_pin) { |
1269 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, | 1331 | err = create_controls(spec, "LFE", lfe_pin, 1); |
1270 | "LFE Playback Volume", | ||
1271 | HDA_COMPOSE_AMP_VAL(lfe_pin, 1, 0, | ||
1272 | HDA_OUTPUT)); | ||
1273 | if (err < 0) | ||
1274 | return err; | ||
1275 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, | ||
1276 | "LFE Playback Switch", | ||
1277 | HDA_COMPOSE_AMP_VAL(lfe_pin, 1, 0, | ||
1278 | HDA_OUTPUT)); | ||
1279 | if (err < 0) | 1332 | if (err < 0) |
1280 | return err; | 1333 | return err; |
1281 | } | 1334 | } |
@@ -1363,9 +1416,11 @@ static int stac92xx_init(struct hda_codec *codec) | |||
1363 | /* set up pins */ | 1416 | /* set up pins */ |
1364 | if (spec->hp_detect) { | 1417 | if (spec->hp_detect) { |
1365 | /* Enable unsolicited responses on the HP widget */ | 1418 | /* Enable unsolicited responses on the HP widget */ |
1366 | snd_hda_codec_write(codec, cfg->hp_pin, 0, | 1419 | for (i = 0; i < cfg->hp_outs; i++) |
1367 | AC_VERB_SET_UNSOLICITED_ENABLE, | 1420 | if (get_wcaps(codec, cfg->hp_pins[i]) & AC_WCAP_UNSOL_CAP) |
1368 | STAC_UNSOL_ENABLE); | 1421 | snd_hda_codec_write(codec, cfg->hp_pins[i], 0, |
1422 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1423 | STAC_UNSOL_ENABLE); | ||
1369 | /* fake event to set up pins */ | 1424 | /* fake event to set up pins */ |
1370 | codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); | 1425 | codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); |
1371 | /* enable the headphones by default. If/when unsol_event detection works, this will be ignored */ | 1426 | /* enable the headphones by default. If/when unsol_event detection works, this will be ignored */ |
@@ -1447,21 +1502,36 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) | |||
1447 | if ((res >> 26) != STAC_HP_EVENT) | 1502 | if ((res >> 26) != STAC_HP_EVENT) |
1448 | return; | 1503 | return; |
1449 | 1504 | ||
1450 | presence = snd_hda_codec_read(codec, cfg->hp_pin, 0, | 1505 | presence = 0; |
1451 | AC_VERB_GET_PIN_SENSE, 0x00) >> 31; | 1506 | for (i = 0; i < cfg->hp_outs; i++) { |
1507 | int p = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, | ||
1508 | AC_VERB_GET_PIN_SENSE, 0x00); | ||
1509 | if (p & (1 << 31)) | ||
1510 | presence++; | ||
1511 | } | ||
1452 | 1512 | ||
1453 | if (presence) { | 1513 | if (presence) { |
1454 | /* disable lineouts, enable hp */ | 1514 | /* disable lineouts, enable hp */ |
1455 | for (i = 0; i < cfg->line_outs; i++) | 1515 | for (i = 0; i < cfg->line_outs; i++) |
1456 | stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], | 1516 | stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], |
1457 | AC_PINCTL_OUT_EN); | 1517 | AC_PINCTL_OUT_EN); |
1458 | stac92xx_set_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); | 1518 | for (i = 0; i < cfg->speaker_outs; i++) |
1519 | stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], | ||
1520 | AC_PINCTL_OUT_EN); | ||
1521 | for (i = 0; i < cfg->hp_outs; i++) | ||
1522 | stac92xx_set_pinctl(codec, cfg->hp_pins[i], | ||
1523 | AC_PINCTL_OUT_EN); | ||
1459 | } else { | 1524 | } else { |
1460 | /* enable lineouts, disable hp */ | 1525 | /* enable lineouts, disable hp */ |
1461 | for (i = 0; i < cfg->line_outs; i++) | 1526 | for (i = 0; i < cfg->line_outs; i++) |
1462 | stac92xx_set_pinctl(codec, cfg->line_out_pins[i], | 1527 | stac92xx_set_pinctl(codec, cfg->line_out_pins[i], |
1463 | AC_PINCTL_OUT_EN); | 1528 | AC_PINCTL_OUT_EN); |
1464 | stac92xx_reset_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); | 1529 | for (i = 0; i < cfg->speaker_outs; i++) |
1530 | stac92xx_set_pinctl(codec, cfg->speaker_pins[i], | ||
1531 | AC_PINCTL_OUT_EN); | ||
1532 | for (i = 0; i < cfg->hp_outs; i++) | ||
1533 | stac92xx_reset_pinctl(codec, cfg->hp_pins[i], | ||
1534 | AC_PINCTL_OUT_EN); | ||
1465 | } | 1535 | } |
1466 | } | 1536 | } |
1467 | 1537 | ||