ALSA: hda - Fix AFG power management on IDT 92HD* codecs
The AFG pin power-mapping isn't properly set for the fixed I/O pins on IDT 92HD* codecs. This resulted in the low power mode after the boot until any jack detection is executed, thus no output from the speaker. This patch fixes the power mapping for the fixed pins, and also fixes the GPIO bits and digital I/O pin settings properly in stac92xx_ini(). Reference: Novell bnc#446025 https://bugzilla.novell.com/show_bug.cgi?id=446025 Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Родитель
9e97697666
Коммит
f73d35853e
|
@ -3697,10 +3697,14 @@ static void stac92xx_power_down(struct hda_codec *codec)
|
|||
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
|
||||
}
|
||||
|
||||
static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
|
||||
int enable);
|
||||
|
||||
static int stac92xx_init(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
unsigned int gpio;
|
||||
int i;
|
||||
|
||||
snd_hda_sequence_write(codec, spec->init);
|
||||
|
@ -3711,6 +3715,16 @@ static int stac92xx_init(struct hda_codec *codec)
|
|||
snd_hda_codec_write_cache(codec,
|
||||
spec->adc_nids[i], 0,
|
||||
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
|
||||
|
||||
/* set up GPIO */
|
||||
gpio = spec->gpio_data;
|
||||
/* turn on EAPD statically when spec->eapd_switch isn't set.
|
||||
* otherwise, unsol event will turn it on/off dynamically
|
||||
*/
|
||||
if (!spec->eapd_switch)
|
||||
gpio |= spec->eapd_mask;
|
||||
stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio);
|
||||
|
||||
/* set up pins */
|
||||
if (spec->hp_detect) {
|
||||
/* Enable unsolicited responses on the HP widget */
|
||||
|
@ -3750,39 +3764,43 @@ static int stac92xx_init(struct hda_codec *codec)
|
|||
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);
|
||||
int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
|
||||
0, AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
def_conf = get_defcfg_connect(def_conf);
|
||||
/* 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;
|
||||
/* skip any ports that don't have jacks since presence
|
||||
* detection is useless */
|
||||
if (def_conf && def_conf != AC_JACK_PORT_FIXED)
|
||||
continue;
|
||||
enable_pin_detect(codec, spec->pwr_nids[i], event | i);
|
||||
codec->patch_ops.unsol_event(codec, (event | i) << 26);
|
||||
}
|
||||
if (spec->dac_list)
|
||||
stac92xx_power_down(codec);
|
||||
if (cfg->dig_out_pin)
|
||||
stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
|
||||
AC_PINCTL_OUT_EN);
|
||||
if (cfg->dig_in_pin)
|
||||
stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
|
||||
AC_PINCTL_IN_EN);
|
||||
for (i = 0; i < spec->num_pwrs; i++) {
|
||||
hda_nid_t nid = spec->pwr_nids[i];
|
||||
int pinctl, def_conf;
|
||||
int event = STAC_PWR_EVENT;
|
||||
|
||||
stac_gpio_set(codec, spec->gpio_mask,
|
||||
spec->gpio_dir, spec->gpio_data);
|
||||
if (is_nid_hp_pin(cfg, nid) && spec->hp_detect)
|
||||
continue; /* already has an unsol event */
|
||||
|
||||
pinctl = snd_hda_codec_read(codec, nid, 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;
|
||||
def_conf = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
def_conf = get_defcfg_connect(def_conf);
|
||||
/* skip any ports that don't have jacks since presence
|
||||
* detection is useless */
|
||||
if (def_conf != AC_JACK_PORT_COMPLEX) {
|
||||
if (def_conf != AC_JACK_PORT_NONE)
|
||||
stac_toggle_power_map(codec, nid, 1);
|
||||
continue;
|
||||
}
|
||||
enable_pin_detect(codec, spec->pwr_nids[i], event | i);
|
||||
codec->patch_ops.unsol_event(codec, (event | i) << 26);
|
||||
}
|
||||
if (spec->dac_list)
|
||||
stac92xx_power_down(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3947,14 +3965,18 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
|
|||
}
|
||||
}
|
||||
|
||||
static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
|
||||
static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
|
||||
int enable)
|
||||
{
|
||||
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);
|
||||
unsigned int idx, val;
|
||||
|
||||
for (idx = 0; idx < spec->num_pwrs; idx++) {
|
||||
if (spec->pwr_nids[idx] == nid)
|
||||
break;
|
||||
}
|
||||
if (idx >= spec->num_pwrs)
|
||||
return;
|
||||
|
||||
/* several codecs have two power down bits */
|
||||
if (spec->pwr_mapping)
|
||||
|
@ -3962,14 +3984,20 @@ static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
|
|||
else
|
||||
idx = 1 << idx;
|
||||
|
||||
if (presence)
|
||||
val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
|
||||
if (enable)
|
||||
val &= ~idx;
|
||||
else
|
||||
val |= idx;
|
||||
|
||||
/* power down unused output ports */
|
||||
snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
|
||||
};
|
||||
}
|
||||
|
||||
static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid));
|
||||
}
|
||||
|
||||
static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче