aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/patch_sigmatel.c91
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
39enum { 40enum {
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
195static hda_nid_t stac92hd73xx_pwr_nids[8] = {
196 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
197 0x0f, 0x10, 0x11
198};
199
190static hda_nid_t stac92hd73xx_adc_nids[2] = { 200static 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
222static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
223 0x0a, 0x0d, 0x0f
224};
225
212static hda_nid_t stac92hd71bxx_adc_nids[2] = { 226static 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
2721static 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
2707static int stac92xx_init(struct hda_codec *codec) 2731static 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
2909static 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
2872static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) 2928static 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;