aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_sigmatel.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2006-09-20 11:10:27 -0400
committerJaroslav Kysela <perex@suse.cz>2006-09-23 04:47:38 -0400
commiteb06ed8f4c2440558ebf465e8baeac6367d90201 (patch)
tree60501d5c4e918f96d26033b95373f4368ca929e2 /sound/pci/hda/patch_sigmatel.c
parent33ef765131bcf82bc5fca3f25d8313fa4df93ce0 (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.c202
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 */
1015static 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 */
1015static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, 1034static 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 */ 1075static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
1069static 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); 1088static 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++) { 1103static 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)
1160static void stac92xx_auto_init_hp_out(struct hda_codec *codec) 1213static 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
1170static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) 1232static 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