Skip to content

Commit

Permalink
[ALSA] hda-codec - Fix mic input with STAC92xx codecs
Browse files Browse the repository at this point in the history
Fixed mic input with STAC92xx codecs.  The mic pin was sometimes set to
OUTPUT by the headphone jack detection.
Also, try to assign a secondary mic as front-mic (or vice versa)
in the auto-detection if possible.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
  • Loading branch information
Takashi Iwai authored and Jaroslav Kysela committed Sep 23, 2006
1 parent 7ffffec commit 314634b
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 35 deletions.
19 changes: 14 additions & 5 deletions sound/pci/hda/hda_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -2079,12 +2079,21 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
cfg->hp_pins[cfg->hp_outs] = nid;
cfg->hp_outs++;
break;
case AC_JACK_MIC_IN:
if (loc == AC_JACK_LOC_FRONT)
cfg->input_pins[AUTO_PIN_FRONT_MIC] = nid;
else
cfg->input_pins[AUTO_PIN_MIC] = nid;
case AC_JACK_MIC_IN: {
int preferred, alt;
if (loc == AC_JACK_LOC_FRONT) {
preferred = AUTO_PIN_FRONT_MIC;
alt = AUTO_PIN_MIC;
} else {
preferred = AUTO_PIN_MIC;
alt = AUTO_PIN_FRONT_MIC;
}
if (!cfg->input_pins[preferred])
cfg->input_pins[preferred] = nid;
else if (!cfg->input_pins[alt])
cfg->input_pins[alt] = nid;
break;
}
case AC_JACK_LINE_IN:
if (loc == AC_JACK_LOC_FRONT)
cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
Expand Down
90 changes: 60 additions & 30 deletions sound/pci/hda/patch_sigmatel.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@

#define NUM_CONTROL_ALLOC 32
#define STAC_HP_EVENT 0x37
#define STAC_UNSOL_ENABLE (AC_USRSP_EN | STAC_HP_EVENT)

#define STAC_REF 0
#define STAC_D945GTP3 1
Expand Down Expand Up @@ -1164,23 +1163,28 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
int i, j, k;

for (i = 0; i < AUTO_PIN_LAST; i++) {
int index = -1;
if (cfg->input_pins[i]) {
imux->items[imux->num_items].label = auto_pin_cfg_labels[i];

for (j=0; j<spec->num_muxes; j++) {
int num_cons = snd_hda_get_connections(codec, spec->mux_nids[j], con_lst, HDA_MAX_NUM_INPUTS);
for (k=0; k<num_cons; k++)
if (con_lst[k] == cfg->input_pins[i]) {
index = k;
break;
}
if (index >= 0)
break;
}
imux->items[imux->num_items].index = index;
imux->num_items++;
int index;

if (!cfg->input_pins[i])
continue;
index = -1;
for (j = 0; j < spec->num_muxes; j++) {
int num_cons;
num_cons = snd_hda_get_connections(codec,
spec->mux_nids[j],
con_lst,
HDA_MAX_NUM_INPUTS);
for (k = 0; k < num_cons; k++)
if (con_lst[k] == cfg->input_pins[i]) {
index = k;
goto found;
}
}
continue;
found:
imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
imux->items[imux->num_items].index = index;
imux->num_items++;
}

if (imux->num_items == 1) {
Expand Down Expand Up @@ -1405,6 +1409,15 @@ static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted)
AC_VERB_SET_GPIO_DATA, gpiostate);
}

static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
unsigned int event)
{
if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
(AC_USRSP_EN | event));
}

static int stac92xx_init(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
Expand All @@ -1417,13 +1430,13 @@ static int stac92xx_init(struct hda_codec *codec)
if (spec->hp_detect) {
/* Enable unsolicited responses on the HP widget */
for (i = 0; i < cfg->hp_outs; i++)
if (get_wcaps(codec, cfg->hp_pins[i]) & AC_WCAP_UNSOL_CAP)
snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
STAC_UNSOL_ENABLE);
enable_pin_detect(codec, cfg->hp_pins[i],
STAC_HP_EVENT);
/* fake event to set up pins */
codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
/* enable the headphones by default. If/when unsol_event detection works, this will be ignored */
/* enable the headphones by default.
* If/when unsol_event detection works, this will be ignored
*/
stac92xx_auto_init_hp_out(codec);
} else {
stac92xx_auto_init_multi_out(codec);
Expand Down Expand Up @@ -1478,6 +1491,8 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
{
unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
if (flag == AC_PINCTL_OUT_EN && (pin_ctl & AC_PINCTL_IN_EN))
return;
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
pin_ctl | flag);
Expand All @@ -1493,21 +1508,27 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
pin_ctl & ~flag);
}

static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
{
if (!nid)
return 0;
if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
& (1 << 31))
return 1;
return 0;
}

static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
{
struct sigmatel_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
int i, presence;

if ((res >> 26) != STAC_HP_EVENT)
return;

presence = 0;
for (i = 0; i < cfg->hp_outs; i++) {
int p = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
AC_VERB_GET_PIN_SENSE, 0x00);
if (p & (1 << 31))
presence++;
presence = get_pin_presence(codec, cfg->hp_pins[i]);
if (presence)
break;
}

if (presence) {
Expand Down Expand Up @@ -1535,6 +1556,15 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
}
}

static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
{
switch (res >> 26) {
case STAC_HP_EVENT:
stac92xx_hp_detect(codec, res);
break;
}
}

#ifdef CONFIG_PM
static int stac92xx_resume(struct hda_codec *codec)
{
Expand Down

0 comments on commit 314634b

Please sign in to comment.