diff options
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 91 |
1 files changed, 83 insertions, 8 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 190e112f2f8e..0e85e4759eb4 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -34,7 +34,8 @@ | |||
34 | #include "hda_local.h" | 34 | #include "hda_local.h" |
35 | 35 | ||
36 | #define NUM_CONTROL_ALLOC 32 | 36 | #define NUM_CONTROL_ALLOC 32 |
37 | #define STAC_HP_EVENT 0x37 | 37 | #define STAC_PWR_EVENT 0x20 |
38 | #define STAC_HP_EVENT 0x30 | ||
38 | 39 | ||
39 | enum { | 40 | enum { |
40 | STAC_REF, | 41 | STAC_REF, |
@@ -126,6 +127,10 @@ struct sigmatel_spec { | |||
126 | unsigned char aloopback_mask; | 127 | unsigned char aloopback_mask; |
127 | unsigned char aloopback_shift; | 128 | unsigned char aloopback_shift; |
128 | 129 | ||
130 | /* power management */ | ||
131 | unsigned int num_pwrs; | ||
132 | hda_nid_t *pwr_nids; | ||
133 | |||
129 | /* playback */ | 134 | /* playback */ |
130 | struct hda_multi_out multiout; | 135 | struct hda_multi_out multiout; |
131 | hda_nid_t dac_nids[5]; | 136 | hda_nid_t dac_nids[5]; |
@@ -187,6 +192,11 @@ static hda_nid_t stac9200_dac_nids[1] = { | |||
187 | 0x02, | 192 | 0x02, |
188 | }; | 193 | }; |
189 | 194 | ||
195 | static hda_nid_t stac92hd73xx_pwr_nids[8] = { | ||
196 | 0x0a, 0x0b, 0x0c, 0xd, 0x0e, | ||
197 | 0x0f, 0x10, 0x11 | ||
198 | }; | ||
199 | |||
190 | static hda_nid_t stac92hd73xx_adc_nids[2] = { | 200 | static hda_nid_t stac92hd73xx_adc_nids[2] = { |
191 | 0x1a, 0x1b | 201 | 0x1a, 0x1b |
192 | }; | 202 | }; |
@@ -209,6 +219,10 @@ static hda_nid_t stac92hd73xx_dmux_nids[2] = { | |||
209 | 0x20, 0x21, | 219 | 0x20, 0x21, |
210 | }; | 220 | }; |
211 | 221 | ||
222 | static hda_nid_t stac92hd71bxx_pwr_nids[3] = { | ||
223 | 0x0a, 0x0d, 0x0f | ||
224 | }; | ||
225 | |||
212 | static hda_nid_t stac92hd71bxx_adc_nids[2] = { | 226 | static hda_nid_t stac92hd71bxx_adc_nids[2] = { |
213 | 0x12, 0x13, | 227 | 0x12, 0x13, |
214 | }; | 228 | }; |
@@ -546,7 +560,7 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = { | |||
546 | /* connect ports 0d and 0f to audio mixer */ | 560 | /* connect ports 0d and 0f to audio mixer */ |
547 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2}, | 561 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2}, |
548 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, | 562 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, |
549 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 563 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ |
550 | /* unmute dac0 input in audio mixer */ | 564 | /* unmute dac0 input in audio mixer */ |
551 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, | 565 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, |
552 | /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ | 566 | /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ |
@@ -2704,6 +2718,16 @@ static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, | |||
2704 | (AC_USRSP_EN | event)); | 2718 | (AC_USRSP_EN | event)); |
2705 | } | 2719 | } |
2706 | 2720 | ||
2721 | static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) | ||
2722 | { | ||
2723 | int i; | ||
2724 | for (i = 0; i < cfg->hp_outs; i++) | ||
2725 | if (cfg->hp_pins[i] == nid) | ||
2726 | return 1; /* nid is a HP-Out */ | ||
2727 | |||
2728 | return 0; /* nid is not a HP-Out */ | ||
2729 | }; | ||
2730 | |||
2707 | static int stac92xx_init(struct hda_codec *codec) | 2731 | static int stac92xx_init(struct hda_codec *codec) |
2708 | { | 2732 | { |
2709 | struct sigmatel_spec *spec = codec->spec; | 2733 | struct sigmatel_spec *spec = codec->spec; |
@@ -2739,10 +2763,23 @@ static int stac92xx_init(struct hda_codec *codec) | |||
2739 | stac92xx_auto_set_pinctl(codec, nid, pinctl); | 2763 | stac92xx_auto_set_pinctl(codec, nid, pinctl); |
2740 | } | 2764 | } |
2741 | } | 2765 | } |
2742 | if (spec->num_dmics > 0) | 2766 | for (i = 0; i < spec->num_dmics; i++) |
2743 | for (i = 0; i < spec->num_dmics; i++) | 2767 | stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], |
2744 | stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], | 2768 | AC_PINCTL_IN_EN); |
2745 | AC_PINCTL_IN_EN); | 2769 | for (i = 0; i < spec->num_pwrs; i++) { |
2770 | int event = is_nid_hp_pin(cfg, spec->pwr_nids[i]) | ||
2771 | ? STAC_HP_EVENT : STAC_PWR_EVENT; | ||
2772 | int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i], | ||
2773 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
2774 | /* outputs are only ports capable of power management | ||
2775 | * any attempts on powering down a input port cause the | ||
2776 | * referenced VREF to act quirky. | ||
2777 | */ | ||
2778 | if (pinctl & AC_PINCTL_IN_EN) | ||
2779 | continue; | ||
2780 | enable_pin_detect(codec, spec->pwr_nids[i], event | i); | ||
2781 | codec->patch_ops.unsol_event(codec, (event | i) << 26); | ||
2782 | } | ||
2746 | 2783 | ||
2747 | if (cfg->dig_out_pin) | 2784 | if (cfg->dig_out_pin) |
2748 | stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, | 2785 | stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, |
@@ -2869,12 +2906,37 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |||
2869 | } | 2906 | } |
2870 | } | 2907 | } |
2871 | 2908 | ||
2909 | static void stac92xx_pin_sense(struct hda_codec *codec, int idx) | ||
2910 | { | ||
2911 | struct sigmatel_spec *spec = codec->spec; | ||
2912 | hda_nid_t nid = spec->pwr_nids[idx]; | ||
2913 | int presence, val; | ||
2914 | val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) | ||
2915 | & 0x000000ff; | ||
2916 | presence = get_hp_pin_presence(codec, nid); | ||
2917 | idx = 1 << idx; | ||
2918 | |||
2919 | if (presence) | ||
2920 | val &= ~idx; | ||
2921 | else | ||
2922 | val |= idx; | ||
2923 | |||
2924 | /* power down unused output ports */ | ||
2925 | snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val); | ||
2926 | }; | ||
2927 | |||
2872 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) | 2928 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) |
2873 | { | 2929 | { |
2874 | switch (res >> 26) { | 2930 | struct sigmatel_spec *spec = codec->spec; |
2931 | int idx = res >> 26 & 0x0f; | ||
2932 | |||
2933 | switch ((res >> 26) & 0x30) { | ||
2875 | case STAC_HP_EVENT: | 2934 | case STAC_HP_EVENT: |
2876 | stac92xx_hp_detect(codec, res); | 2935 | stac92xx_hp_detect(codec, res); |
2877 | break; | 2936 | /* fallthru */ |
2937 | case STAC_PWR_EVENT: | ||
2938 | if (spec->num_pwrs > 0) | ||
2939 | stac92xx_pin_sense(codec, idx); | ||
2878 | } | 2940 | } |
2879 | } | 2941 | } |
2880 | 2942 | ||
@@ -2945,6 +3007,7 @@ static int patch_stac9200(struct hda_codec *codec) | |||
2945 | spec->num_muxes = 1; | 3007 | spec->num_muxes = 1; |
2946 | spec->num_dmics = 0; | 3008 | spec->num_dmics = 0; |
2947 | spec->num_adcs = 1; | 3009 | spec->num_adcs = 1; |
3010 | spec->num_pwrs = 0; | ||
2948 | 3011 | ||
2949 | if (spec->board_config == STAC_9200_GATEWAY) | 3012 | if (spec->board_config == STAC_9200_GATEWAY) |
2950 | spec->init = stac9200_eapd_init; | 3013 | spec->init = stac9200_eapd_init; |
@@ -3000,6 +3063,7 @@ static int patch_stac925x(struct hda_codec *codec) | |||
3000 | spec->mux_nids = stac925x_mux_nids; | 3063 | spec->mux_nids = stac925x_mux_nids; |
3001 | spec->num_muxes = 1; | 3064 | spec->num_muxes = 1; |
3002 | spec->num_adcs = 1; | 3065 | spec->num_adcs = 1; |
3066 | spec->num_pwrs = 0; | ||
3003 | switch (codec->vendor_id) { | 3067 | switch (codec->vendor_id) { |
3004 | case 0x83847632: /* STAC9202 */ | 3068 | case 0x83847632: /* STAC9202 */ |
3005 | case 0x83847633: /* STAC9202D */ | 3069 | case 0x83847633: /* STAC9202D */ |
@@ -3123,6 +3187,9 @@ again: | |||
3123 | spec->gpio_mask = spec->gpio_data = 0x000001; | 3187 | spec->gpio_mask = spec->gpio_data = 0x000001; |
3124 | stac92xx_enable_gpio_mask(codec); | 3188 | stac92xx_enable_gpio_mask(codec); |
3125 | 3189 | ||
3190 | spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); | ||
3191 | spec->pwr_nids = stac92hd73xx_pwr_nids; | ||
3192 | |||
3126 | err = stac92xx_parse_auto_config(codec, 0x22, 0x24); | 3193 | err = stac92xx_parse_auto_config(codec, 0x22, 0x24); |
3127 | 3194 | ||
3128 | if (!err) { | 3195 | if (!err) { |
@@ -3205,6 +3272,9 @@ again: | |||
3205 | spec->num_dmics = STAC92HD71BXX_NUM_DMICS; | 3272 | spec->num_dmics = STAC92HD71BXX_NUM_DMICS; |
3206 | spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); | 3273 | spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); |
3207 | 3274 | ||
3275 | spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); | ||
3276 | spec->pwr_nids = stac92hd71bxx_pwr_nids; | ||
3277 | |||
3208 | spec->multiout.num_dacs = 2; | 3278 | spec->multiout.num_dacs = 2; |
3209 | spec->multiout.hp_nid = 0x11; | 3279 | spec->multiout.hp_nid = 0x11; |
3210 | spec->multiout.dac_nids = stac92hd71bxx_dac_nids; | 3280 | spec->multiout.dac_nids = stac92hd71bxx_dac_nids; |
@@ -3299,6 +3369,7 @@ static int patch_stac922x(struct hda_codec *codec) | |||
3299 | spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); | 3369 | spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); |
3300 | spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); | 3370 | spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); |
3301 | spec->num_dmics = 0; | 3371 | spec->num_dmics = 0; |
3372 | spec->num_pwrs = 0; | ||
3302 | 3373 | ||
3303 | spec->init = stac922x_core_init; | 3374 | spec->init = stac922x_core_init; |
3304 | spec->mixer = stac922x_mixer; | 3375 | spec->mixer = stac922x_mixer; |
@@ -3405,6 +3476,7 @@ static int patch_stac927x(struct hda_codec *codec) | |||
3405 | spec->mixer = stac927x_mixer; | 3476 | spec->mixer = stac927x_mixer; |
3406 | } | 3477 | } |
3407 | 3478 | ||
3479 | spec->num_pwrs = 0; | ||
3408 | spec->aloopback_mask = 0x40; | 3480 | spec->aloopback_mask = 0x40; |
3409 | spec->aloopback_shift = 0; | 3481 | spec->aloopback_shift = 0; |
3410 | 3482 | ||
@@ -3466,6 +3538,7 @@ static int patch_stac9205(struct hda_codec *codec) | |||
3466 | spec->num_dmics = STAC9205_NUM_DMICS; | 3538 | spec->num_dmics = STAC9205_NUM_DMICS; |
3467 | spec->dmux_nids = stac9205_dmux_nids; | 3539 | spec->dmux_nids = stac9205_dmux_nids; |
3468 | spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids); | 3540 | spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids); |
3541 | spec->num_pwrs = 0; | ||
3469 | 3542 | ||
3470 | spec->init = stac9205_core_init; | 3543 | spec->init = stac9205_core_init; |
3471 | spec->mixer = stac9205_mixer; | 3544 | spec->mixer = stac9205_mixer; |
@@ -3728,6 +3801,7 @@ static int patch_stac9872(struct hda_codec *codec) | |||
3728 | spec->multiout.hp_nid = VAIO_HP_DAC; | 3801 | spec->multiout.hp_nid = VAIO_HP_DAC; |
3729 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); | 3802 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); |
3730 | spec->adc_nids = vaio_adcs; | 3803 | spec->adc_nids = vaio_adcs; |
3804 | spec->num_pwrs = 0; | ||
3731 | spec->input_mux = &vaio_mux; | 3805 | spec->input_mux = &vaio_mux; |
3732 | spec->mux_nids = vaio_mux_nids; | 3806 | spec->mux_nids = vaio_mux_nids; |
3733 | codec->patch_ops = stac9872_vaio_patch_ops; | 3807 | codec->patch_ops = stac9872_vaio_patch_ops; |
@@ -3741,6 +3815,7 @@ static int patch_stac9872(struct hda_codec *codec) | |||
3741 | spec->multiout.dac_nids = vaio_dacs; | 3815 | spec->multiout.dac_nids = vaio_dacs; |
3742 | spec->multiout.hp_nid = VAIO_HP_DAC; | 3816 | spec->multiout.hp_nid = VAIO_HP_DAC; |
3743 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); | 3817 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); |
3818 | spec->num_pwrs = 0; | ||
3744 | spec->adc_nids = vaio_adcs; | 3819 | spec->adc_nids = vaio_adcs; |
3745 | spec->input_mux = &vaio_mux; | 3820 | spec->input_mux = &vaio_mux; |
3746 | spec->mux_nids = vaio_mux_nids; | 3821 | spec->mux_nids = vaio_mux_nids; |