Commit a64135a2d880183a2aff149f42dab7779a37a67f

Authored by Matthew Ranostay
Committed by Jaroslav Kysela
1 parent 2134ea4f37

[ALSA] hda: 92HD7XXX power management support

Added support for advanced power management support for output ports on
92HD7xxx family of codecs. Inactive output ports are powered down when
the pin sense  doesn't detect a connection, and powered back up when a
connection is sensed.

Signed-off-by: Matthew Ranostay <mranostay@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>

Showing 1 changed file with 83 additions and 8 deletions Side-by-side Diff

sound/pci/hda/patch_sigmatel.c
... ... @@ -34,7 +34,8 @@
34 34 #include "hda_local.h"
35 35  
36 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 40 enum {
40 41 STAC_REF,
... ... @@ -126,6 +127,10 @@
126 127 unsigned char aloopback_mask;
127 128 unsigned char aloopback_shift;
128 129  
  130 + /* power management */
  131 + unsigned int num_pwrs;
  132 + hda_nid_t *pwr_nids;
  133 +
129 134 /* playback */
130 135 struct hda_multi_out multiout;
131 136 hda_nid_t dac_nids[5];
... ... @@ -187,6 +192,11 @@
187 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 200 static hda_nid_t stac92hd73xx_adc_nids[2] = {
191 201 0x1a, 0x1b
192 202 };
... ... @@ -209,6 +219,10 @@
209 219 0x20, 0x21,
210 220 };
211 221  
  222 +static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
  223 + 0x0a, 0x0d, 0x0f
  224 +};
  225 +
212 226 static hda_nid_t stac92hd71bxx_adc_nids[2] = {
213 227 0x12, 0x13,
214 228 };
... ... @@ -546,7 +560,7 @@
546 560 /* connect ports 0d and 0f to audio mixer */
547 561 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
548 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 564 /* unmute dac0 input in audio mixer */
551 565 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
552 566 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
... ... @@ -2704,6 +2718,16 @@
2704 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 2731 static int stac92xx_init(struct hda_codec *codec)
2708 2732 {
2709 2733 struct sigmatel_spec *spec = codec->spec;
... ... @@ -2739,10 +2763,23 @@
2739 2763 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2740 2764 }
2741 2765 }
2742   - if (spec->num_dmics > 0)
2743   - for (i = 0; i < spec->num_dmics; i++)
2744   - stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
2745   - AC_PINCTL_IN_EN);
  2766 + for (i = 0; i < spec->num_dmics; i++)
  2767 + stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
  2768 + 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 2784 if (cfg->dig_out_pin)
2748 2785 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
2749 2786  
2750 2787  
... ... @@ -2869,12 +2906,37 @@
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 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 2934 case STAC_HP_EVENT:
2876 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 @@
2945 3007 spec->num_muxes = 1;
2946 3008 spec->num_dmics = 0;
2947 3009 spec->num_adcs = 1;
  3010 + spec->num_pwrs = 0;
2948 3011  
2949 3012 if (spec->board_config == STAC_9200_GATEWAY)
2950 3013 spec->init = stac9200_eapd_init;
... ... @@ -3000,6 +3063,7 @@
3000 3063 spec->mux_nids = stac925x_mux_nids;
3001 3064 spec->num_muxes = 1;
3002 3065 spec->num_adcs = 1;
  3066 + spec->num_pwrs = 0;
3003 3067 switch (codec->vendor_id) {
3004 3068 case 0x83847632: /* STAC9202 */
3005 3069 case 0x83847633: /* STAC9202D */
... ... @@ -3123,6 +3187,9 @@
3123 3187 spec->gpio_mask = spec->gpio_data = 0x000001;
3124 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 3193 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3127 3194  
3128 3195 if (!err) {
... ... @@ -3205,6 +3272,9 @@
3205 3272 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
3206 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 3278 spec->multiout.num_dacs = 2;
3209 3279 spec->multiout.hp_nid = 0x11;
3210 3280 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
... ... @@ -3299,6 +3369,7 @@
3299 3369 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
3300 3370 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
3301 3371 spec->num_dmics = 0;
  3372 + spec->num_pwrs = 0;
3302 3373  
3303 3374 spec->init = stac922x_core_init;
3304 3375 spec->mixer = stac922x_mixer;
... ... @@ -3405,6 +3476,7 @@
3405 3476 spec->mixer = stac927x_mixer;
3406 3477 }
3407 3478  
  3479 + spec->num_pwrs = 0;
3408 3480 spec->aloopback_mask = 0x40;
3409 3481 spec->aloopback_shift = 0;
3410 3482  
... ... @@ -3466,6 +3538,7 @@
3466 3538 spec->num_dmics = STAC9205_NUM_DMICS;
3467 3539 spec->dmux_nids = stac9205_dmux_nids;
3468 3540 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
  3541 + spec->num_pwrs = 0;
3469 3542  
3470 3543 spec->init = stac9205_core_init;
3471 3544 spec->mixer = stac9205_mixer;
... ... @@ -3728,6 +3801,7 @@
3728 3801 spec->multiout.hp_nid = VAIO_HP_DAC;
3729 3802 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
3730 3803 spec->adc_nids = vaio_adcs;
  3804 + spec->num_pwrs = 0;
3731 3805 spec->input_mux = &vaio_mux;
3732 3806 spec->mux_nids = vaio_mux_nids;
3733 3807 codec->patch_ops = stac9872_vaio_patch_ops;
... ... @@ -3741,6 +3815,7 @@
3741 3815 spec->multiout.dac_nids = vaio_dacs;
3742 3816 spec->multiout.hp_nid = VAIO_HP_DAC;
3743 3817 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
  3818 + spec->num_pwrs = 0;
3744 3819 spec->adc_nids = vaio_adcs;
3745 3820 spec->input_mux = &vaio_mux;
3746 3821 spec->mux_nids = vaio_mux_nids;