1 From: Takashi Iwai <tiwai@suse.de>
2 Subject: ALSA: hda - Fix AFG power management on IDT 92HD* codecs
6 The AFG pin power-mapping isn't properly set for the fixed I/O pins
7 on IDT 92HD* codecs. This resulted in the low power mode after the
8 boot until any jack detection is executed, thus no output from the
11 This patch fixes the power mapping for the fixed pins, and also fixes
12 the GPIO bits and digital I/O pin settings properly in stac92xx_ini().
14 Reference: Novell bnc#446025
15 https://bugzilla.novell.com/show_bug.cgi?id=446025
17 Signed-off-by: Takashi Iwai <tiwai@suse.de>
20 sound/pci/hda/patch_sigmatel.c | 80 +++++++++++++++++++++++++++--------------
21 1 file changed, 54 insertions(+), 26 deletions(-)
23 --- a/sound/pci/hda/patch_sigmatel.c
24 +++ b/sound/pci/hda/patch_sigmatel.c
25 @@ -3700,10 +3700,14 @@ static void stac92xx_power_down(struct h
26 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
29 +static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
32 static int stac92xx_init(struct hda_codec *codec)
34 struct sigmatel_spec *spec = codec->spec;
35 struct auto_pin_cfg *cfg = &spec->autocfg;
39 snd_hda_sequence_write(codec, spec->init);
40 @@ -3714,6 +3718,16 @@ static int stac92xx_init(struct hda_code
41 snd_hda_codec_write_cache(codec,
43 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
46 + gpio = spec->gpio_data;
47 + /* turn on EAPD statically when spec->eapd_switch isn't set.
48 + * otherwise, unsol event will turn it on/off dynamically
50 + if (!spec->eapd_switch)
51 + gpio |= spec->eapd_mask;
52 + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio);
55 if (spec->hp_detect) {
56 /* Enable unsolicited responses on the HP widget */
57 @@ -3753,39 +3767,43 @@ static int stac92xx_init(struct hda_code
58 for (i = 0; i < spec->num_dmics; i++)
59 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
61 + if (cfg->dig_out_pin)
62 + stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
64 + if (cfg->dig_in_pin)
65 + stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
67 for (i = 0; i < spec->num_pwrs; i++) {
68 - int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
69 - ? STAC_HP_EVENT : STAC_PWR_EVENT;
70 - int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
71 - 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
72 - int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
73 - 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
74 - def_conf = get_defcfg_connect(def_conf);
75 + hda_nid_t nid = spec->pwr_nids[i];
76 + int pinctl, def_conf;
77 + int event = STAC_PWR_EVENT;
79 + if (is_nid_hp_pin(cfg, nid) && spec->hp_detect)
80 + continue; /* already has an unsol event */
82 + pinctl = snd_hda_codec_read(codec, nid, 0,
83 + AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
84 /* outputs are only ports capable of power management
85 * any attempts on powering down a input port cause the
86 * referenced VREF to act quirky.
88 if (pinctl & AC_PINCTL_IN_EN)
90 + def_conf = snd_hda_codec_read(codec, nid, 0,
91 + AC_VERB_GET_CONFIG_DEFAULT, 0);
92 + def_conf = get_defcfg_connect(def_conf);
93 /* skip any ports that don't have jacks since presence
94 * detection is useless */
95 - if (def_conf && def_conf != AC_JACK_PORT_FIXED)
96 + if (def_conf != AC_JACK_PORT_COMPLEX) {
97 + if (def_conf != AC_JACK_PORT_NONE)
98 + stac_toggle_power_map(codec, nid, 1);
101 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
102 codec->patch_ops.unsol_event(codec, (event | i) << 26);
105 stac92xx_power_down(codec);
106 - if (cfg->dig_out_pin)
107 - stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
109 - if (cfg->dig_in_pin)
110 - stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
113 - stac_gpio_set(codec, spec->gpio_mask,
114 - spec->gpio_dir, spec->gpio_data);
119 @@ -3950,14 +3968,18 @@ static void stac92xx_hp_detect(struct hd
123 -static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
124 +static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
127 struct sigmatel_spec *spec = codec->spec;
128 - hda_nid_t nid = spec->pwr_nids[idx];
130 - val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
132 - presence = get_hp_pin_presence(codec, nid);
133 + unsigned int idx, val;
135 + for (idx = 0; idx < spec->num_pwrs; idx++) {
136 + if (spec->pwr_nids[idx] == nid)
139 + if (idx >= spec->num_pwrs)
142 /* several codecs have two power down bits */
143 if (spec->pwr_mapping)
144 @@ -3965,14 +3987,20 @@ static void stac92xx_pin_sense(struct hd
149 + val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
155 /* power down unused output ports */
156 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
160 +static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
162 + stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid));
165 static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)