Commit eb06ed8f authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela

[ALSA] hda-codec - Support multiple headphone pins

Some machines have multiple headpohne pins (usually on the lpatop
and on the docking station) while the current hda-codec driver
assumes a single headphone pin.  Now it supports multiple hp pins
(at least for detection).
The sigmatel 92xx code supports this new multiple hp pins.
It detects all hp pins for auto-muting, too.
Also, the driver checks speaker pins in addition.  In some cases,
all line-out, speaker and hp-pins coexist.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@suse.cz>
parent 33ef7651
...@@ -2012,7 +2012,7 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) ...@@ -2012,7 +2012,7 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)
* in the order of front, rear, CLFE, side, ... * in the order of front, rear, CLFE, side, ...
* *
* If more extra outputs (speaker and headphone) are found, the pins are * If more extra outputs (speaker and headphone) are found, the pins are
* assisnged to hp_pin and speaker_pins[], respectively. If no line-out jack * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack
* is detected, one of speaker of HP pins is assigned as the primary * is detected, one of speaker of HP pins is assigned as the primary
* output, i.e. to line_out_pins[0]. So, line_outs is always positive * output, i.e. to line_out_pins[0]. So, line_outs is always positive
* if any analog output exists. * if any analog output exists.
...@@ -2074,7 +2074,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c ...@@ -2074,7 +2074,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
cfg->speaker_outs++; cfg->speaker_outs++;
break; break;
case AC_JACK_HP_OUT: case AC_JACK_HP_OUT:
cfg->hp_pin = nid; if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
continue;
cfg->hp_pins[cfg->hp_outs] = nid;
cfg->hp_outs++;
break; break;
case AC_JACK_MIC_IN: case AC_JACK_MIC_IN:
if (loc == AC_JACK_LOC_FRONT) if (loc == AC_JACK_LOC_FRONT)
...@@ -2147,8 +2150,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c ...@@ -2147,8 +2150,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
cfg->speaker_outs, cfg->speaker_pins[0], cfg->speaker_outs, cfg->speaker_pins[0],
cfg->speaker_pins[1], cfg->speaker_pins[2], cfg->speaker_pins[1], cfg->speaker_pins[2],
cfg->speaker_pins[3], cfg->speaker_pins[4]); cfg->speaker_pins[3], cfg->speaker_pins[4]);
snd_printd(" hp=0x%x, dig_out=0x%x, din_in=0x%x\n", snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
cfg->hp_pin, cfg->dig_out_pin, cfg->dig_in_pin); cfg->hp_outs, cfg->hp_pins[0],
cfg->hp_pins[1], cfg->hp_pins[2],
cfg->hp_pins[3], cfg->hp_pins[4]);
snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
" cd=0x%x, aux=0x%x\n", " cd=0x%x, aux=0x%x\n",
cfg->input_pins[AUTO_PIN_MIC], cfg->input_pins[AUTO_PIN_MIC],
...@@ -2169,10 +2174,12 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c ...@@ -2169,10 +2174,12 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
sizeof(cfg->speaker_pins)); sizeof(cfg->speaker_pins));
cfg->speaker_outs = 0; cfg->speaker_outs = 0;
memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
} else if (cfg->hp_pin) { } else if (cfg->hp_outs) {
cfg->line_outs = 1; cfg->line_outs = cfg->hp_outs;
cfg->line_out_pins[0] = cfg->hp_pin; memcpy(cfg->line_out_pins, cfg->hp_pins,
cfg->hp_pin = 0; sizeof(cfg->hp_pins));
cfg->hp_outs = 0;
memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
} }
} }
......
...@@ -229,7 +229,8 @@ struct auto_pin_cfg { ...@@ -229,7 +229,8 @@ struct auto_pin_cfg {
hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */
int speaker_outs; int speaker_outs;
hda_nid_t speaker_pins[5]; hda_nid_t speaker_pins[5];
hda_nid_t hp_pin; int hp_outs;
hda_nid_t hp_pins[5];
hda_nid_t input_pins[AUTO_PIN_LAST]; hda_nid_t input_pins[AUTO_PIN_LAST];
hda_nid_t dig_out_pin; hda_nid_t dig_out_pin;
hda_nid_t dig_in_pin; hda_nid_t dig_in_pin;
......
...@@ -2471,7 +2471,7 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec) ...@@ -2471,7 +2471,7 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec)
pin = spec->autocfg.speaker_pins[0]; pin = spec->autocfg.speaker_pins[0];
if (pin) /* connect to front */ if (pin) /* connect to front */
ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
pin = spec->autocfg.hp_pin; pin = spec->autocfg.hp_pins[0];
if (pin) /* connect to front */ if (pin) /* connect to front */
ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
} }
...@@ -2523,7 +2523,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) ...@@ -2523,7 +2523,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
(err = ad1988_auto_create_extra_out(codec, (err = ad1988_auto_create_extra_out(codec,
spec->autocfg.speaker_pins[0], spec->autocfg.speaker_pins[0],
"Speaker")) < 0 || "Speaker")) < 0 ||
(err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pin, (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
"Headphone")) < 0 || "Headphone")) < 0 ||
(err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
return err; return err;
......
...@@ -2753,7 +2753,7 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec) ...@@ -2753,7 +2753,7 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec)
pin = spec->autocfg.speaker_pins[0]; pin = spec->autocfg.speaker_pins[0];
if (pin) /* connect to front */ if (pin) /* connect to front */
alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
pin = spec->autocfg.hp_pin; pin = spec->autocfg.hp_pins[0];
if (pin) /* connect to front */ if (pin) /* connect to front */
alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
} }
...@@ -2794,7 +2794,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec) ...@@ -2794,7 +2794,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
(err = alc880_auto_create_extra_out(spec, (err = alc880_auto_create_extra_out(spec,
spec->autocfg.speaker_pins[0], spec->autocfg.speaker_pins[0],
"Speaker")) < 0 || "Speaker")) < 0 ||
(err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pin, (err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
"Headphone")) < 0 || "Headphone")) < 0 ||
(err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
return err; return err;
...@@ -3736,7 +3736,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, ...@@ -3736,7 +3736,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
return err; return err;
} }
nid = cfg->hp_pin; nid = cfg->hp_pins[0];
if (nid) { if (nid) {
err = alc260_add_playback_controls(spec, nid, "Headphone"); err = alc260_add_playback_controls(spec, nid, "Headphone");
if (err < 0) if (err < 0)
...@@ -3806,7 +3806,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec) ...@@ -3806,7 +3806,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec)
if (nid) if (nid)
alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
nid = spec->autocfg.hp_pin; nid = spec->autocfg.hp_pins[0];
if (nid) if (nid)
alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
} }
...@@ -4526,7 +4526,7 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec) ...@@ -4526,7 +4526,7 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
hda_nid_t pin; hda_nid_t pin;
pin = spec->autocfg.hp_pin; pin = spec->autocfg.hp_pins[0];
if (pin) /* connect to front */ if (pin) /* connect to front */
alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */ alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */
} }
...@@ -5207,7 +5207,7 @@ static void alc883_auto_init_hp_out(struct hda_codec *codec) ...@@ -5207,7 +5207,7 @@ static void alc883_auto_init_hp_out(struct hda_codec *codec)
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
hda_nid_t pin; hda_nid_t pin;
pin = spec->autocfg.hp_pin; pin = spec->autocfg.hp_pins[0];
if (pin) /* connect to front */ if (pin) /* connect to front */
/* use dac 0 */ /* use dac 0 */
alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
...@@ -5630,7 +5630,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct ...@@ -5630,7 +5630,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct
return err; return err;
} }
} }
nid = cfg->hp_pin; nid = cfg->hp_pins[0];
if (nid) { if (nid) {
/* spec->multiout.hp_nid = 2; */ /* spec->multiout.hp_nid = 2; */
if (nid == 0x16) { if (nid == 0x16) {
...@@ -6630,7 +6630,7 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec) ...@@ -6630,7 +6630,7 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec)
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
hda_nid_t pin; hda_nid_t pin;
pin = spec->autocfg.hp_pin; pin = spec->autocfg.hp_pins[0];
if (pin) /* connect to front */ if (pin) /* connect to front */
alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]); alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]);
} }
...@@ -6665,7 +6665,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) ...@@ -6665,7 +6665,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
(err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
(err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0])) < 0 ||
(err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
return err; return err;
......
...@@ -1011,11 +1011,29 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, ...@@ -1011,11 +1011,29 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
return 0; return 0;
} }
/* create volume control/switch for the given prefx type */
static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
{
char name[32];
int err;
sprintf(name, "%s Playback Volume", pfx);
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
if (err < 0)
return err;
sprintf(name, "%s Playback Switch", pfx);
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
if (err < 0)
return err;
return 0;
}
/* add playback controls from the parsed DAC table */ /* add playback controls from the parsed DAC table */
static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec,
const struct auto_pin_cfg *cfg) const struct auto_pin_cfg *cfg)
{ {
char name[32];
static const char *chname[4] = { static const char *chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side" "Front", "Surround", NULL /*CLFE*/, "Side"
}; };
...@@ -1030,26 +1048,15 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, ...@@ -1030,26 +1048,15 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec,
if (i == 2) { if (i == 2) {
/* Center/LFE */ /* Center/LFE */
if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Center Playback Volume", err = create_controls(spec, "Center", nid, 1);
HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) if (err < 0)
return err;
if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "LFE Playback Volume",
HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
return err;
if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Center Playback Switch",
HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
return err; return err;
if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "LFE Playback Switch", err = create_controls(spec, "LFE", nid, 2);
HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) if (err < 0)
return err; return err;
} else { } else {
sprintf(name, "%s Playback Volume", chname[i]); err = create_controls(spec, chname[i], nid, 3);
if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, if (err < 0)
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
return err;
sprintf(name, "%s Playback Switch", chname[i]);
if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
return err; return err;
} }
} }
...@@ -1065,39 +1072,85 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, ...@@ -1065,39 +1072,85 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec,
return 0; return 0;
} }
/* add playback controls for HP output */ static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg)
{ {
struct sigmatel_spec *spec = codec->spec; int i;
hda_nid_t pin = cfg->hp_pin;
hda_nid_t nid;
int i, err;
unsigned int wid_caps;
if (! pin) for (i = 0; i < spec->multiout.num_dacs; i++) {
if (spec->multiout.dac_nids[i] == nid)
return 1;
}
if (spec->multiout.hp_nid == nid)
return 1;
return 0; return 0;
}
wid_caps = get_wcaps(codec, pin); static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
{
if (!spec->multiout.hp_nid)
spec->multiout.hp_nid = nid;
else if (spec->multiout.num_dacs > 4) {
printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
return 1;
} else {
spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
spec->multiout.num_dacs++;
}
return 0;
}
/* add playback controls for Speaker and HP outputs */
static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
struct auto_pin_cfg *cfg)
{
struct sigmatel_spec *spec = codec->spec;
hda_nid_t nid;
int i, old_num_dacs, err;
old_num_dacs = spec->multiout.num_dacs;
for (i = 0; i < cfg->hp_outs; i++) {
unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
if (wid_caps & AC_WCAP_UNSOL_CAP) if (wid_caps & AC_WCAP_UNSOL_CAP)
spec->hp_detect = 1; spec->hp_detect = 1;
nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
for (i = 0; i < cfg->line_outs; i++) { if (check_in_dac_nids(spec, nid))
if (! spec->multiout.dac_nids[i]) nid = 0;
if (! nid)
continue; continue;
if (spec->multiout.dac_nids[i] == nid) add_spec_dacs(spec, nid);
return 0; }
for (i = 0; i < cfg->speaker_outs; i++) {
nid = snd_hda_codec_read(codec, cfg->speaker_pins[0], 0,
AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
if (check_in_dac_nids(spec, nid))
nid = 0;
if (check_in_dac_nids(spec, nid))
nid = 0;
if (! nid)
continue;
add_spec_dacs(spec, nid);
} }
spec->multiout.hp_nid = nid; for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
static const char *pfxs[] = {
/* control HP volume/switch on the output mixer amp */ "Speaker", "External Speaker", "Speaker2",
if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Headphone Playback Volume", };
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) err = create_controls(spec, pfxs[i - old_num_dacs],
spec->multiout.dac_nids[i], 3);
if (err < 0)
return err; return err;
if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Headphone Playback Switch", }
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) if (spec->multiout.hp_nid) {
const char *pfx;
if (old_num_dacs == spec->multiout.num_dacs)
pfx = "Master";
else
pfx = "Headphone";
err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
if (err < 0)
return err; return err;
}
return 0; return 0;
} }
...@@ -1160,11 +1213,20 @@ static void stac92xx_auto_init_multi_out(struct hda_codec *codec) ...@@ -1160,11 +1213,20 @@ static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
static void stac92xx_auto_init_hp_out(struct hda_codec *codec) static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
{ {
struct sigmatel_spec *spec = codec->spec; struct sigmatel_spec *spec = codec->spec;
hda_nid_t pin; int i;
pin = spec->autocfg.hp_pin; for (i = 0; i < spec->autocfg.hp_outs; i++) {
hda_nid_t pin;
pin = spec->autocfg.hp_pins[i];
if (pin) /* connect to front */ if (pin) /* connect to front */
stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
}
for (i = 0; i < spec->autocfg.speaker_outs; i++) {
hda_nid_t pin;
pin = spec->autocfg.speaker_pins[i];
if (pin) /* connect to front */
stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
}
} }
static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in)
...@@ -1210,7 +1272,7 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, ...@@ -1210,7 +1272,7 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
struct auto_pin_cfg *cfg) struct auto_pin_cfg *cfg)
{ {
struct sigmatel_spec *spec = codec->spec; struct sigmatel_spec *spec = codec->spec;
hda_nid_t pin = cfg->hp_pin; hda_nid_t pin = cfg->hp_pins[0];
unsigned int wid_caps; unsigned int wid_caps;
if (! pin) if (! pin)
...@@ -1266,16 +1328,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, ...@@ -1266,16 +1328,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
} }
if (lfe_pin) { if (lfe_pin) {
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, err = create_controls(spec, "LFE", lfe_pin, 1);
"LFE Playback Volume",
HDA_COMPOSE_AMP_VAL(lfe_pin, 1, 0,
HDA_OUTPUT));
if (err < 0)
return err;
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
"LFE Playback Switch",
HDA_COMPOSE_AMP_VAL(lfe_pin, 1, 0,
HDA_OUTPUT));
if (err < 0) if (err < 0)
return err; return err;
} }
...@@ -1363,7 +1416,9 @@ static int stac92xx_init(struct hda_codec *codec) ...@@ -1363,7 +1416,9 @@ static int stac92xx_init(struct hda_codec *codec)
/* set up pins */ /* set up pins */
if (spec->hp_detect) { if (spec->hp_detect) {
/* Enable unsolicited responses on the HP widget */ /* Enable unsolicited responses on the HP widget */
snd_hda_codec_write(codec, cfg->hp_pin, 0, 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, AC_VERB_SET_UNSOLICITED_ENABLE,
STAC_UNSOL_ENABLE); STAC_UNSOL_ENABLE);
/* fake event to set up pins */ /* fake event to set up pins */
...@@ -1447,21 +1502,36 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) ...@@ -1447,21 +1502,36 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
if ((res >> 26) != STAC_HP_EVENT) if ((res >> 26) != STAC_HP_EVENT)
return; return;
presence = snd_hda_codec_read(codec, cfg->hp_pin, 0, presence = 0;
AC_VERB_GET_PIN_SENSE, 0x00) >> 31; 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++;
}
if (presence) { if (presence) {
/* disable lineouts, enable hp */ /* disable lineouts, enable hp */
for (i = 0; i < cfg->line_outs; i++) for (i = 0; i < cfg->line_outs; i++)
stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
AC_PINCTL_OUT_EN); AC_PINCTL_OUT_EN);
stac92xx_set_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); for (i = 0; i < cfg->speaker_outs; i++)
stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
AC_PINCTL_OUT_EN);
for (i = 0; i < cfg->hp_outs; i++)
stac92xx_set_pinctl(codec, cfg->hp_pins[i],
AC_PINCTL_OUT_EN);
} else { } else {
/* enable lineouts, disable hp */ /* enable lineouts, disable hp */
for (i = 0; i < cfg->line_outs; i++) for (i = 0; i < cfg->line_outs; i++)
stac92xx_set_pinctl(codec, cfg->line_out_pins[i], stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
AC_PINCTL_OUT_EN); AC_PINCTL_OUT_EN);
stac92xx_reset_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); for (i = 0; i < cfg->speaker_outs; i++)
stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
AC_PINCTL_OUT_EN);
for (i = 0; i < cfg->hp_outs; i++)
stac92xx_reset_pinctl(codec, cfg->hp_pins[i],
AC_PINCTL_OUT_EN);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment