diff options
author | Takashi Iwai <tiwai@suse.de> | 2006-03-21 05:24:42 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-03-22 04:40:14 -0500 |
commit | 82bc955f6379135e6ce35ff90c7ac411fd412c4c (patch) | |
tree | 314610afb5a469ac6a5a9f4d5e947436bb2c0538 /sound/pci/hda/patch_sigmatel.c | |
parent | 19739fef0203d2f3eecc9c4b1ef25b57d85f2b30 (diff) |
[ALSA] hda-codec - Fix BIOS auto-configuration
Modules: HDA Codec driver,HDA generic driver
- Fix autoconfig speaker/hp detection
Now it allows multiple speaker pins (e.g. Dell laptops have such config)
- Use speaker or hp pins if no line-outs are available
This fixes the silence output on recent Dell laptops with STAC9200
(ALSA bug#1843)
- Fix analog/realtek/sigmatel autoconfig parser
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_sigmatel.c')
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 84 |
1 files changed, 58 insertions, 26 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 240958df26ce..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; |
@@ -697,13 +698,7 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct aut | |||
697 | AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | 698 | AC_VERB_GET_CONNECT_LIST, 0) & 0xff; |
698 | } | 699 | } |
699 | 700 | ||
700 | if (cfg->line_outs) | 701 | spec->multiout.num_dacs = cfg->line_outs; |
701 | spec->multiout.num_dacs = cfg->line_outs; | ||
702 | else if (cfg->hp_pin) { | ||
703 | spec->multiout.dac_nids[0] = snd_hda_codec_read(codec, cfg->hp_pin, 0, | ||
704 | AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | ||
705 | spec->multiout.num_dacs = 1; | ||
706 | } | ||
707 | 702 | ||
708 | return 0; | 703 | return 0; |
709 | } | 704 | } |
@@ -772,11 +767,13 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin | |||
772 | return 0; | 767 | return 0; |
773 | 768 | ||
774 | wid_caps = get_wcaps(codec, pin); | 769 | wid_caps = get_wcaps(codec, pin); |
775 | if (wid_caps & AC_WCAP_UNSOL_CAP) | 770 | if (wid_caps & AC_WCAP_UNSOL_CAP) { |
776 | /* Enable unsolicited responses on the HP widget */ | 771 | /* Enable unsolicited responses on the HP widget */ |
777 | snd_hda_codec_write(codec, pin, 0, | 772 | snd_hda_codec_write(codec, pin, 0, |
778 | AC_VERB_SET_UNSOLICITED_ENABLE, | 773 | AC_VERB_SET_UNSOLICITED_ENABLE, |
779 | STAC_UNSOL_ENABLE); | 774 | STAC_UNSOL_ENABLE); |
775 | spec->hp_detect = 1; | ||
776 | } | ||
780 | 777 | ||
781 | 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; |
782 | for (i = 0; i < cfg->line_outs; i++) { | 779 | for (i = 0; i < cfg->line_outs; i++) { |
@@ -810,9 +807,6 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const | |||
810 | for (i = 0; i < AUTO_PIN_LAST; i++) { | 807 | for (i = 0; i < AUTO_PIN_LAST; i++) { |
811 | int index = -1; | 808 | int index = -1; |
812 | if (cfg->input_pins[i]) { | 809 | if (cfg->input_pins[i]) { |
813 | /* Enable active pin widget as an input */ | ||
814 | stac92xx_auto_set_pinctl(codec, cfg->input_pins[i], AC_PINCTL_IN_EN); | ||
815 | |||
816 | imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; | 810 | imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; |
817 | 811 | ||
818 | for (j=0; j<spec->num_muxes; j++) { | 812 | for (j=0; j<spec->num_muxes; j++) { |
@@ -861,10 +855,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
861 | 855 | ||
862 | 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) |
863 | return err; | 857 | return err; |
864 | if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin) | 858 | if (! spec->autocfg.line_outs) |
865 | return 0; /* can't find valid pin config */ | 859 | return 0; /* can't find valid pin config */ |
866 | stac92xx_auto_init_multi_out(codec); | ||
867 | stac92xx_auto_init_hp_out(codec); | ||
868 | if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) | 860 | if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) |
869 | return err; | 861 | return err; |
870 | if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) | 862 | if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) |
@@ -879,14 +871,10 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
879 | if (spec->multiout.max_channels > 2) | 871 | if (spec->multiout.max_channels > 2) |
880 | spec->surr_switch = 1; | 872 | spec->surr_switch = 1; |
881 | 873 | ||
882 | if (spec->autocfg.dig_out_pin) { | 874 | if (spec->autocfg.dig_out_pin) |
883 | spec->multiout.dig_out_nid = dig_out; | 875 | spec->multiout.dig_out_nid = dig_out; |
884 | stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN); | 876 | if (spec->autocfg.dig_in_pin) |
885 | } | ||
886 | if (spec->autocfg.dig_in_pin) { | ||
887 | spec->dig_in_nid = dig_in; | 877 | spec->dig_in_nid = dig_in; |
888 | stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN); | ||
889 | } | ||
890 | 878 | ||
891 | if (spec->kctl_alloc) | 879 | if (spec->kctl_alloc) |
892 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | 880 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; |
@@ -896,6 +884,29 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
896 | return 1; | 884 | return 1; |
897 | } | 885 | } |
898 | 886 | ||
887 | /* add playback controls for HP output */ | ||
888 | static 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 | |||
899 | static int stac9200_parse_auto_config(struct hda_codec *codec) | 910 | static int stac9200_parse_auto_config(struct hda_codec *codec) |
900 | { | 911 | { |
901 | struct sigmatel_spec *spec = codec->spec; | 912 | struct sigmatel_spec *spec = codec->spec; |
@@ -907,14 +918,13 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) | |||
907 | 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) |
908 | return err; | 919 | return err; |
909 | 920 | ||
910 | 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) | ||
911 | spec->multiout.dig_out_nid = 0x05; | 925 | spec->multiout.dig_out_nid = 0x05; |
912 | stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN); | 926 | if (spec->autocfg.dig_in_pin) |
913 | } | ||
914 | if (spec->autocfg.dig_in_pin) { | ||
915 | spec->dig_in_nid = 0x04; | 927 | spec->dig_in_nid = 0x04; |
916 | stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN); | ||
917 | } | ||
918 | 928 | ||
919 | if (spec->kctl_alloc) | 929 | if (spec->kctl_alloc) |
920 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | 930 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; |
@@ -927,9 +937,31 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) | |||
927 | static int stac92xx_init(struct hda_codec *codec) | 937 | static int stac92xx_init(struct hda_codec *codec) |
928 | { | 938 | { |
929 | struct sigmatel_spec *spec = codec->spec; | 939 | struct sigmatel_spec *spec = codec->spec; |
940 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
941 | int i; | ||
930 | 942 | ||
931 | snd_hda_sequence_write(codec, spec->init); | 943 | snd_hda_sequence_write(codec, spec->init); |
932 | 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 | |||
933 | return 0; | 965 | return 0; |
934 | } | 966 | } |
935 | 967 | ||