aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_sigmatel.c
diff options
context:
space:
mode:
authorMatthew Ranostay <mranostay@embeddedalley.com>2008-01-10 10:55:06 -0500
committerJaroslav Kysela <perex@perex.cz>2008-01-31 11:29:54 -0500
commita64135a2d880183a2aff149f42dab7779a37a67f (patch)
tree33e637198ef86282b82eefed94074ff5fc665b85 /sound/pci/hda/patch_sigmatel.c
parent2134ea4f37d36addbe86d4901f6c67a22a5db006 (diff)
[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>
Diffstat (limited to 'sound/pci/hda/patch_sigmatel.c')
-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;