aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_sigmatel.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_sigmatel.c')
-rw-r--r--sound/pci/hda/patch_sigmatel.c251
1 files changed, 225 insertions, 26 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 35c2823a0a2b..b56ca4019392 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -51,6 +51,7 @@ struct sigmatel_spec {
51 unsigned int line_switch: 1; 51 unsigned int line_switch: 1;
52 unsigned int mic_switch: 1; 52 unsigned int mic_switch: 1;
53 unsigned int alt_switch: 1; 53 unsigned int alt_switch: 1;
54 unsigned int hp_detect: 1;
54 55
55 /* playback */ 56 /* playback */
56 struct hda_multi_out multiout; 57 struct hda_multi_out multiout;
@@ -303,6 +304,12 @@ static struct hda_board_config stac922x_cfg_tbl[] = {
303 .pci_subdevice = 0x0101, 304 .pci_subdevice = 0x0101,
304 .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ 305 .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */
305 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 306 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
307 .pci_subdevice = 0x0202,
308 .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack, 9221 A1 */
309 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
310 .pci_subdevice = 0x0b0b,
311 .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack, 9221 A1 */
312 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
306 .pci_subdevice = 0x0404, 313 .pci_subdevice = 0x0404,
307 .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */ 314 .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */
308 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 315 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
@@ -691,13 +698,7 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct aut
691 AC_VERB_GET_CONNECT_LIST, 0) & 0xff; 698 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
692 } 699 }
693 700
694 if (cfg->line_outs) 701 spec->multiout.num_dacs = cfg->line_outs;
695 spec->multiout.num_dacs = cfg->line_outs;
696 else if (cfg->hp_pin) {
697 spec->multiout.dac_nids[0] = snd_hda_codec_read(codec, cfg->hp_pin, 0,
698 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
699 spec->multiout.num_dacs = 1;
700 }
701 702
702 return 0; 703 return 0;
703} 704}
@@ -766,11 +767,13 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin
766 return 0; 767 return 0;
767 768
768 wid_caps = get_wcaps(codec, pin); 769 wid_caps = get_wcaps(codec, pin);
769 if (wid_caps & AC_WCAP_UNSOL_CAP) 770 if (wid_caps & AC_WCAP_UNSOL_CAP) {
770 /* Enable unsolicited responses on the HP widget */ 771 /* Enable unsolicited responses on the HP widget */
771 snd_hda_codec_write(codec, pin, 0, 772 snd_hda_codec_write(codec, pin, 0,
772 AC_VERB_SET_UNSOLICITED_ENABLE, 773 AC_VERB_SET_UNSOLICITED_ENABLE,
773 STAC_UNSOL_ENABLE); 774 STAC_UNSOL_ENABLE);
775 spec->hp_detect = 1;
776 }
774 777
775 nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; 778 nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
776 for (i = 0; i < cfg->line_outs; i++) { 779 for (i = 0; i < cfg->line_outs; i++) {
@@ -804,9 +807,6 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
804 for (i = 0; i < AUTO_PIN_LAST; i++) { 807 for (i = 0; i < AUTO_PIN_LAST; i++) {
805 int index = -1; 808 int index = -1;
806 if (cfg->input_pins[i]) { 809 if (cfg->input_pins[i]) {
807 /* Enable active pin widget as an input */
808 stac92xx_auto_set_pinctl(codec, cfg->input_pins[i], AC_PINCTL_IN_EN);
809
810 imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; 810 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
811 811
812 for (j=0; j<spec->num_muxes; j++) { 812 for (j=0; j<spec->num_muxes; j++) {
@@ -855,10 +855,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
855 855
856 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) 856 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
857 return err; 857 return err;
858 if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin) 858 if (! spec->autocfg.line_outs)
859 return 0; /* can't find valid pin config */ 859 return 0; /* can't find valid pin config */
860 stac92xx_auto_init_multi_out(codec);
861 stac92xx_auto_init_hp_out(codec);
862 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) 860 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
863 return err; 861 return err;
864 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) 862 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
@@ -873,14 +871,10 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
873 if (spec->multiout.max_channels > 2) 871 if (spec->multiout.max_channels > 2)
874 spec->surr_switch = 1; 872 spec->surr_switch = 1;
875 873
876 if (spec->autocfg.dig_out_pin) { 874 if (spec->autocfg.dig_out_pin)
877 spec->multiout.dig_out_nid = dig_out; 875 spec->multiout.dig_out_nid = dig_out;
878 stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN); 876 if (spec->autocfg.dig_in_pin)
879 }
880 if (spec->autocfg.dig_in_pin) {
881 spec->dig_in_nid = dig_in; 877 spec->dig_in_nid = dig_in;
882 stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN);
883 }
884 878
885 if (spec->kctl_alloc) 879 if (spec->kctl_alloc)
886 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 880 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
@@ -890,6 +884,29 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
890 return 1; 884 return 1;
891} 885}
892 886
887/* add playback controls for HP output */
888static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
889 struct auto_pin_cfg *cfg)
890{
891 struct sigmatel_spec *spec = codec->spec;
892 hda_nid_t pin = cfg->hp_pin;
893 unsigned int wid_caps;
894
895 if (! pin)
896 return 0;
897
898 wid_caps = get_wcaps(codec, pin);
899 if (wid_caps & AC_WCAP_UNSOL_CAP) {
900 /* Enable unsolicited responses on the HP widget */
901 snd_hda_codec_write(codec, pin, 0,
902 AC_VERB_SET_UNSOLICITED_ENABLE,
903 STAC_UNSOL_ENABLE);
904 spec->hp_detect = 1;
905 }
906
907 return 0;
908}
909
893static int stac9200_parse_auto_config(struct hda_codec *codec) 910static int stac9200_parse_auto_config(struct hda_codec *codec)
894{ 911{
895 struct sigmatel_spec *spec = codec->spec; 912 struct sigmatel_spec *spec = codec->spec;
@@ -901,14 +918,13 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
901 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) 918 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
902 return err; 919 return err;
903 920
904 if (spec->autocfg.dig_out_pin) { 921 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
922 return err;
923
924 if (spec->autocfg.dig_out_pin)
905 spec->multiout.dig_out_nid = 0x05; 925 spec->multiout.dig_out_nid = 0x05;
906 stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN); 926 if (spec->autocfg.dig_in_pin)
907 }
908 if (spec->autocfg.dig_in_pin) {
909 spec->dig_in_nid = 0x04; 927 spec->dig_in_nid = 0x04;
910 stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN);
911 }
912 928
913 if (spec->kctl_alloc) 929 if (spec->kctl_alloc)
914 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 930 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
@@ -921,9 +937,31 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
921static int stac92xx_init(struct hda_codec *codec) 937static int stac92xx_init(struct hda_codec *codec)
922{ 938{
923 struct sigmatel_spec *spec = codec->spec; 939 struct sigmatel_spec *spec = codec->spec;
940 struct auto_pin_cfg *cfg = &spec->autocfg;
941 int i;
924 942
925 snd_hda_sequence_write(codec, spec->init); 943 snd_hda_sequence_write(codec, spec->init);
926 944
945 /* set up pins */
946 if (spec->hp_detect) {
947 /* fake event to set up pins */
948 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
949 } else {
950 stac92xx_auto_init_multi_out(codec);
951 stac92xx_auto_init_hp_out(codec);
952 }
953 for (i = 0; i < AUTO_PIN_LAST; i++) {
954 if (cfg->input_pins[i])
955 stac92xx_auto_set_pinctl(codec, cfg->input_pins[i],
956 AC_PINCTL_IN_EN);
957 }
958 if (cfg->dig_out_pin)
959 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
960 AC_PINCTL_OUT_EN);
961 if (cfg->dig_in_pin)
962 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
963 AC_PINCTL_IN_EN);
964
927 return 0; 965 return 0;
928} 966}
929 967
@@ -1142,6 +1180,166 @@ static int patch_stac927x(struct hda_codec *codec)
1142} 1180}
1143 1181
1144/* 1182/*
1183 * STAC 7661(?) hack
1184 */
1185
1186/* static config for Sony VAIO FE550G */
1187static hda_nid_t vaio_dacs[] = { 0x2 };
1188#define VAIO_HP_DAC 0x5
1189static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
1190static hda_nid_t vaio_mux_nids[] = { 0x15 };
1191
1192static struct hda_input_mux vaio_mux = {
1193 .num_items = 2,
1194 .items = {
1195 /* { "HP", 0x0 },
1196 { "Unknown", 0x1 }, */
1197 { "Mic", 0x2 },
1198 { "PCM", 0x3 },
1199 }
1200};
1201
1202static struct hda_verb vaio_init[] = {
1203 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
1204 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
1205 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
1206 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
1207 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
1208 {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
1209 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
1210 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
1211 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
1212 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
1213 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
1214 {}
1215};
1216
1217/* bind volumes of both NID 0x02 and 0x05 */
1218static int vaio_master_vol_put(struct snd_kcontrol *kcontrol,
1219 struct snd_ctl_elem_value *ucontrol)
1220{
1221 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1222 long *valp = ucontrol->value.integer.value;
1223 int change;
1224
1225 change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0,
1226 0x7f, valp[0] & 0x7f);
1227 change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0,
1228 0x7f, valp[1] & 0x7f);
1229 snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
1230 0x7f, valp[0] & 0x7f);
1231 snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
1232 0x7f, valp[1] & 0x7f);
1233 return change;
1234}
1235
1236/* bind volumes of both NID 0x02 and 0x05 */
1237static int vaio_master_sw_put(struct snd_kcontrol *kcontrol,
1238 struct snd_ctl_elem_value *ucontrol)
1239{
1240 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1241 long *valp = ucontrol->value.integer.value;
1242 int change;
1243
1244 change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0,
1245 0x80, valp[0] & 0x80);
1246 change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0,
1247 0x80, valp[1] & 0x80);
1248 snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
1249 0x80, valp[0] & 0x80);
1250 snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
1251 0x80, valp[1] & 0x80);
1252 return change;
1253}
1254
1255static struct snd_kcontrol_new vaio_mixer[] = {
1256 {
1257 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1258 .name = "Master Playback Volume",
1259 .info = snd_hda_mixer_amp_volume_info,
1260 .get = snd_hda_mixer_amp_volume_get,
1261 .put = vaio_master_vol_put,
1262 .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
1263 },
1264 {
1265 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1266 .name = "Master Playback Switch",
1267 .info = snd_hda_mixer_amp_switch_info,
1268 .get = snd_hda_mixer_amp_switch_get,
1269 .put = vaio_master_sw_put,
1270 .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
1271 },
1272 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
1273 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
1274 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
1275 {
1276 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1277 .name = "Capture Source",
1278 .count = 1,
1279 .info = stac92xx_mux_enum_info,
1280 .get = stac92xx_mux_enum_get,
1281 .put = stac92xx_mux_enum_put,
1282 },
1283 {}
1284};
1285
1286static struct hda_codec_ops stac7661_patch_ops = {
1287 .build_controls = stac92xx_build_controls,
1288 .build_pcms = stac92xx_build_pcms,
1289 .init = stac92xx_init,
1290 .free = stac92xx_free,
1291#ifdef CONFIG_PM
1292 .resume = stac92xx_resume,
1293#endif
1294};
1295
1296enum { STAC7661_VAIO };
1297
1298static struct hda_board_config stac7661_cfg_tbl[] = {
1299 { .modelname = "vaio", .config = STAC7661_VAIO },
1300 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6,
1301 .config = STAC7661_VAIO },
1302 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef,
1303 .config = STAC7661_VAIO },
1304 {}
1305};
1306
1307static int patch_stac7661(struct hda_codec *codec)
1308{
1309 struct sigmatel_spec *spec;
1310 int board_config;
1311
1312 board_config = snd_hda_check_board_config(codec, stac7661_cfg_tbl);
1313 if (board_config < 0)
1314 /* unknown config, let generic-parser do its job... */
1315 return snd_hda_parse_generic_codec(codec);
1316
1317 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1318 if (spec == NULL)
1319 return -ENOMEM;
1320
1321 codec->spec = spec;
1322 switch (board_config) {
1323 case STAC7661_VAIO:
1324 spec->mixer = vaio_mixer;
1325 spec->init = vaio_init;
1326 spec->multiout.max_channels = 2;
1327 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
1328 spec->multiout.dac_nids = vaio_dacs;
1329 spec->multiout.hp_nid = VAIO_HP_DAC;
1330 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
1331 spec->adc_nids = vaio_adcs;
1332 spec->input_mux = &vaio_mux;
1333 spec->mux_nids = vaio_mux_nids;
1334 break;
1335 }
1336
1337 codec->patch_ops = stac7661_patch_ops;
1338 return 0;
1339}
1340
1341
1342/*
1145 * patch entries 1343 * patch entries
1146 */ 1344 */
1147struct hda_codec_preset snd_hda_preset_sigmatel[] = { 1345struct hda_codec_preset snd_hda_preset_sigmatel[] = {
@@ -1162,5 +1360,6 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
1162 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, 1360 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
1163 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, 1361 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
1164 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, 1362 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
1363 { .id = 0x83847661, .name = "STAC7661", .patch = patch_stac7661 },
1165 {} /* terminator */ 1364 {} /* terminator */
1166}; 1365};