Skip to content

Commit

Permalink
[ALSA] hda: 92HD7XXX power management support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Matthew Ranostay authored and Jaroslav Kysela committed Jan 31, 2008
1 parent 2134ea4 commit a64135a
Showing 1 changed file with 83 additions and 8 deletions.
91 changes: 83 additions & 8 deletions sound/pci/hda/patch_sigmatel.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
#include "hda_local.h"

#define NUM_CONTROL_ALLOC 32
#define STAC_HP_EVENT 0x37
#define STAC_PWR_EVENT 0x20
#define STAC_HP_EVENT 0x30

enum {
STAC_REF,
Expand Down Expand Up @@ -126,6 +127,10 @@ struct sigmatel_spec {
unsigned char aloopback_mask;
unsigned char aloopback_shift;

/* power management */
unsigned int num_pwrs;
hda_nid_t *pwr_nids;

/* playback */
struct hda_multi_out multiout;
hda_nid_t dac_nids[5];
Expand Down Expand Up @@ -187,6 +192,11 @@ static hda_nid_t stac9200_dac_nids[1] = {
0x02,
};

static hda_nid_t stac92hd73xx_pwr_nids[8] = {
0x0a, 0x0b, 0x0c, 0xd, 0x0e,
0x0f, 0x10, 0x11
};

static hda_nid_t stac92hd73xx_adc_nids[2] = {
0x1a, 0x1b
};
Expand All @@ -209,6 +219,10 @@ static hda_nid_t stac92hd73xx_dmux_nids[2] = {
0x20, 0x21,
};

static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
0x0a, 0x0d, 0x0f
};

static hda_nid_t stac92hd71bxx_adc_nids[2] = {
0x12, 0x13,
};
Expand Down Expand Up @@ -546,7 +560,7 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = {
/* connect ports 0d and 0f to audio mixer */
{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
/* unmute dac0 input in audio mixer */
{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
/* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
Expand Down Expand Up @@ -2704,6 +2718,16 @@ static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
(AC_USRSP_EN | event));
}

static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
{
int i;
for (i = 0; i < cfg->hp_outs; i++)
if (cfg->hp_pins[i] == nid)
return 1; /* nid is a HP-Out */

return 0; /* nid is not a HP-Out */
};

static int stac92xx_init(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
Expand Down Expand Up @@ -2739,10 +2763,23 @@ static int stac92xx_init(struct hda_codec *codec)
stac92xx_auto_set_pinctl(codec, nid, pinctl);
}
}
if (spec->num_dmics > 0)
for (i = 0; i < spec->num_dmics; i++)
stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
AC_PINCTL_IN_EN);
for (i = 0; i < spec->num_dmics; i++)
stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
AC_PINCTL_IN_EN);
for (i = 0; i < spec->num_pwrs; i++) {
int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
? STAC_HP_EVENT : STAC_PWR_EVENT;
int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
/* outputs are only ports capable of power management
* any attempts on powering down a input port cause the
* referenced VREF to act quirky.
*/
if (pinctl & AC_PINCTL_IN_EN)
continue;
enable_pin_detect(codec, spec->pwr_nids[i], event | i);
codec->patch_ops.unsol_event(codec, (event | i) << 26);
}

if (cfg->dig_out_pin)
stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
Expand Down Expand Up @@ -2869,12 +2906,37 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
}
}

static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
{
struct sigmatel_spec *spec = codec->spec;
hda_nid_t nid = spec->pwr_nids[idx];
int presence, val;
val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
& 0x000000ff;
presence = get_hp_pin_presence(codec, nid);
idx = 1 << idx;

if (presence)
val &= ~idx;
else
val |= idx;

/* power down unused output ports */
snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
};

static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
{
switch (res >> 26) {
struct sigmatel_spec *spec = codec->spec;
int idx = res >> 26 & 0x0f;

switch ((res >> 26) & 0x30) {
case STAC_HP_EVENT:
stac92xx_hp_detect(codec, res);
break;
/* fallthru */
case STAC_PWR_EVENT:
if (spec->num_pwrs > 0)
stac92xx_pin_sense(codec, idx);
}
}

Expand Down Expand Up @@ -2945,6 +3007,7 @@ static int patch_stac9200(struct hda_codec *codec)
spec->num_muxes = 1;
spec->num_dmics = 0;
spec->num_adcs = 1;
spec->num_pwrs = 0;

if (spec->board_config == STAC_9200_GATEWAY)
spec->init = stac9200_eapd_init;
Expand Down Expand Up @@ -3000,6 +3063,7 @@ static int patch_stac925x(struct hda_codec *codec)
spec->mux_nids = stac925x_mux_nids;
spec->num_muxes = 1;
spec->num_adcs = 1;
spec->num_pwrs = 0;
switch (codec->vendor_id) {
case 0x83847632: /* STAC9202 */
case 0x83847633: /* STAC9202D */
Expand Down Expand Up @@ -3123,6 +3187,9 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
spec->gpio_mask = spec->gpio_data = 0x000001;
stac92xx_enable_gpio_mask(codec);

spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
spec->pwr_nids = stac92hd73xx_pwr_nids;

err = stac92xx_parse_auto_config(codec, 0x22, 0x24);

if (!err) {
Expand Down Expand Up @@ -3205,6 +3272,9 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);

spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
spec->pwr_nids = stac92hd71bxx_pwr_nids;

spec->multiout.num_dacs = 2;
spec->multiout.hp_nid = 0x11;
spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
Expand Down Expand Up @@ -3299,6 +3369,7 @@ static int patch_stac922x(struct hda_codec *codec)
spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
spec->num_dmics = 0;
spec->num_pwrs = 0;

spec->init = stac922x_core_init;
spec->mixer = stac922x_mixer;
Expand Down Expand Up @@ -3405,6 +3476,7 @@ static int patch_stac927x(struct hda_codec *codec)
spec->mixer = stac927x_mixer;
}

spec->num_pwrs = 0;
spec->aloopback_mask = 0x40;
spec->aloopback_shift = 0;

Expand Down Expand Up @@ -3466,6 +3538,7 @@ static int patch_stac9205(struct hda_codec *codec)
spec->num_dmics = STAC9205_NUM_DMICS;
spec->dmux_nids = stac9205_dmux_nids;
spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
spec->num_pwrs = 0;

spec->init = stac9205_core_init;
spec->mixer = stac9205_mixer;
Expand Down Expand Up @@ -3728,6 +3801,7 @@ static int patch_stac9872(struct hda_codec *codec)
spec->multiout.hp_nid = VAIO_HP_DAC;
spec->num_adcs = ARRAY_SIZE(vaio_adcs);
spec->adc_nids = vaio_adcs;
spec->num_pwrs = 0;
spec->input_mux = &vaio_mux;
spec->mux_nids = vaio_mux_nids;
codec->patch_ops = stac9872_vaio_patch_ops;
Expand All @@ -3741,6 +3815,7 @@ static int patch_stac9872(struct hda_codec *codec)
spec->multiout.dac_nids = vaio_dacs;
spec->multiout.hp_nid = VAIO_HP_DAC;
spec->num_adcs = ARRAY_SIZE(vaio_adcs);
spec->num_pwrs = 0;
spec->adc_nids = vaio_adcs;
spec->input_mux = &vaio_mux;
spec->mux_nids = vaio_mux_nids;
Expand Down

0 comments on commit a64135a

Please sign in to comment.