mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 10:29:37 +00:00
ALSA: hda - Add support of line-out automute for Realtek
Add the common helper function and flags to support the auto-mute per line-out jack detection, and also the mute of line-out jacks. A few model-specific implementations are replaced with the common helpers. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
3b8510ce97
commit
e6a5e1b709
1 changed files with 120 additions and 154 deletions
|
@ -392,9 +392,12 @@ struct alc_spec {
|
|||
/* for pin sensing */
|
||||
unsigned int sense_updated: 1;
|
||||
unsigned int jack_present: 1;
|
||||
unsigned int line_jack_present:1;
|
||||
unsigned int master_sw: 1;
|
||||
unsigned int auto_mic:1;
|
||||
unsigned int automute:1; /* HP automute enabled */
|
||||
unsigned int detect_line:1; /* Line-out detection enabled */
|
||||
unsigned int automute_lines:1; /* automute line-out as well */
|
||||
|
||||
/* other flags */
|
||||
unsigned int no_analog :1; /* digital I/O only */
|
||||
|
@ -1074,54 +1077,96 @@ static int alc_init_jacks(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void alc_hp_automute(struct hda_codec *codec)
|
||||
static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
unsigned int mute;
|
||||
hda_nid_t nid;
|
||||
int i;
|
||||
int i, present = 0;
|
||||
|
||||
if (!spec->automute)
|
||||
return;
|
||||
|
||||
spec->jack_present = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
|
||||
nid = spec->autocfg.hp_pins[i];
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
hda_nid_t nid = pins[i];
|
||||
if (!nid)
|
||||
break;
|
||||
snd_hda_input_jack_report(codec, nid);
|
||||
spec->jack_present |= snd_hda_jack_detect(codec, nid);
|
||||
present |= snd_hda_jack_detect(codec, nid);
|
||||
}
|
||||
return present;
|
||||
}
|
||||
|
||||
mute = spec->jack_present ? HDA_AMP_MUTE : 0;
|
||||
/* Toggle internal speakers muting */
|
||||
for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
|
||||
nid = spec->autocfg.speaker_pins[i];
|
||||
static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
|
||||
bool mute)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
|
||||
unsigned int pin_bits = mute ? 0 : PIN_OUT;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
hda_nid_t nid = pins[i];
|
||||
if (!nid)
|
||||
break;
|
||||
switch (spec->automute_mode) {
|
||||
case ALC_AUTOMUTE_PIN:
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
spec->jack_present ? 0 : PIN_OUT);
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pin_bits);
|
||||
break;
|
||||
case ALC_AUTOMUTE_AMP:
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, mute);
|
||||
HDA_AMP_MUTE, mute_bits);
|
||||
break;
|
||||
case ALC_AUTOMUTE_MIXER:
|
||||
nid = spec->automute_mixer_nid[i];
|
||||
if (!nid)
|
||||
break;
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
|
||||
HDA_AMP_MUTE, mute);
|
||||
HDA_AMP_MUTE, mute_bits);
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
|
||||
HDA_AMP_MUTE, mute);
|
||||
HDA_AMP_MUTE, mute_bits);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Toggle internal speakers muting */
|
||||
static void update_speakers(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
|
||||
spec->autocfg.speaker_pins,
|
||||
spec->jack_present | spec->line_jack_present);
|
||||
|
||||
/* toggle line-out mutes if needed, too */
|
||||
if (!spec->automute_lines)
|
||||
return;
|
||||
do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
|
||||
spec->autocfg.line_out_pins,
|
||||
spec->jack_present);
|
||||
}
|
||||
|
||||
static void alc_hp_automute(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
if (!spec->automute)
|
||||
return;
|
||||
spec->jack_present =
|
||||
detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
|
||||
spec->autocfg.hp_pins);
|
||||
update_speakers(codec);
|
||||
}
|
||||
|
||||
static void alc_line_automute(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
if (!spec->automute || !spec->detect_line)
|
||||
return;
|
||||
spec->line_jack_present =
|
||||
detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
|
||||
spec->autocfg.line_out_pins);
|
||||
update_speakers(codec);
|
||||
}
|
||||
|
||||
static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
|
||||
hda_nid_t nid)
|
||||
{
|
||||
|
@ -1219,6 +1264,9 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
|
|||
case ALC880_HP_EVENT:
|
||||
alc_hp_automute(codec);
|
||||
break;
|
||||
case ALC880_FRONT_EVENT:
|
||||
alc_line_automute(codec);
|
||||
break;
|
||||
case ALC880_MIC_EVENT:
|
||||
alc_mic_automute(codec);
|
||||
break;
|
||||
|
@ -1228,6 +1276,7 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
|
|||
static void alc_inithook(struct hda_codec *codec)
|
||||
{
|
||||
alc_hp_automute(codec);
|
||||
alc_line_automute(codec);
|
||||
alc_mic_automute(codec);
|
||||
}
|
||||
|
||||
|
@ -9551,33 +9600,15 @@ static struct hda_channel_mode alc888_3st_hp_modes[3] = {
|
|||
{ 6, alc888_3st_hp_6ch_init },
|
||||
};
|
||||
|
||||
/* toggle front-jack and RCA according to the hp-jack state */
|
||||
static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
|
||||
static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int present = snd_hda_jack_detect(codec, 0x1b);
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
|
||||
snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
|
||||
}
|
||||
|
||||
/* toggle RCA according to the front-jack state */
|
||||
static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int present = snd_hda_jack_detect(codec, 0x14);
|
||||
|
||||
snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
|
||||
}
|
||||
|
||||
static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
|
||||
unsigned int res)
|
||||
{
|
||||
if ((res >> 26) == ALC880_HP_EVENT)
|
||||
alc888_lenovo_ms7195_front_automute(codec);
|
||||
if ((res >> 26) == ALC880_FRONT_EVENT)
|
||||
alc888_lenovo_ms7195_rca_automute(codec);
|
||||
spec->autocfg.hp_pins[0] = 0x1b;
|
||||
spec->autocfg.line_out_pins[0] = 0x14;
|
||||
spec->autocfg.speaker_pins[0] = 0x15;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_AMP;
|
||||
}
|
||||
|
||||
/* toggle speaker-output according to the hp-jack state */
|
||||
|
@ -9645,31 +9676,17 @@ static void alc883_haier_w66_setup(struct hda_codec *codec)
|
|||
spec->automute_mode = ALC_AUTOMUTE_AMP;
|
||||
}
|
||||
|
||||
static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
|
||||
static void alc883_lenovo_101e_setup(struct hda_codec *codec)
|
||||
{
|
||||
int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
}
|
||||
|
||||
static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
|
||||
{
|
||||
int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
|
||||
|
||||
snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
}
|
||||
|
||||
static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
|
||||
unsigned int res)
|
||||
{
|
||||
if ((res >> 26) == ALC880_HP_EVENT)
|
||||
alc883_lenovo_101e_all_automute(codec);
|
||||
if ((res >> 26) == ALC880_FRONT_EVENT)
|
||||
alc883_lenovo_101e_ispeaker_automute(codec);
|
||||
spec->autocfg.hp_pins[0] = 0x1b;
|
||||
spec->autocfg.line_out_pins[0] = 0x14;
|
||||
spec->autocfg.speaker_pins[0] = 0x15;
|
||||
spec->automute = 1;
|
||||
spec->detect_line = 1;
|
||||
spec->automute_lines = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_AMP;
|
||||
}
|
||||
|
||||
/* toggle speaker-output according to the hp-jack state */
|
||||
|
@ -10584,8 +10601,9 @@ static struct alc_config_preset alc882_presets[] = {
|
|||
.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
|
||||
.channel_mode = alc883_3ST_2ch_modes,
|
||||
.input_mux = &alc883_lenovo_101e_capture_source,
|
||||
.unsol_event = alc883_lenovo_101e_unsol_event,
|
||||
.init_hook = alc883_lenovo_101e_all_automute,
|
||||
.setup = alc883_lenovo_101e_setup,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC883_LENOVO_NB0763] = {
|
||||
.mixers = { alc883_lenovo_nb0763_mixer },
|
||||
|
@ -10610,8 +10628,9 @@ static struct alc_config_preset alc882_presets[] = {
|
|||
.channel_mode = alc883_3ST_6ch_modes,
|
||||
.need_dac_fix = 1,
|
||||
.input_mux = &alc883_capture_source,
|
||||
.unsol_event = alc883_lenovo_ms7195_unsol_event,
|
||||
.init_hook = alc888_lenovo_ms7195_front_automute,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc888_lenovo_ms7195_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC883_HAIER_W66] = {
|
||||
.mixers = { alc883_targa_2ch_mixer},
|
||||
|
@ -18217,39 +18236,17 @@ static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
|
|||
{ } /* end */
|
||||
};
|
||||
|
||||
static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
|
||||
static void alc662_lenovo_101e_setup(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int present;
|
||||
unsigned char bits;
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
present = snd_hda_jack_detect(codec, 0x14);
|
||||
bits = present ? HDA_AMP_MUTE : 0;
|
||||
|
||||
snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
}
|
||||
|
||||
static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int present;
|
||||
unsigned char bits;
|
||||
|
||||
present = snd_hda_jack_detect(codec, 0x1b);
|
||||
bits = present ? HDA_AMP_MUTE : 0;
|
||||
|
||||
snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
}
|
||||
|
||||
static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
|
||||
unsigned int res)
|
||||
{
|
||||
if ((res >> 26) == ALC880_HP_EVENT)
|
||||
alc662_lenovo_101e_all_automute(codec);
|
||||
if ((res >> 26) == ALC880_FRONT_EVENT)
|
||||
alc662_lenovo_101e_ispeaker_automute(codec);
|
||||
spec->autocfg.hp_pins[0] = 0x1b;
|
||||
spec->autocfg.line_out_pins[0] = 0x14;
|
||||
spec->autocfg.speaker_pins[0] = 0x15;
|
||||
spec->automute = 1;
|
||||
spec->detect_line = 1;
|
||||
spec->automute_lines = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_AMP;
|
||||
}
|
||||
|
||||
/* unsolicited event for HP jack sensing */
|
||||
|
@ -18439,53 +18436,21 @@ static void alc663_mode8_setup(struct hda_codec *codec)
|
|||
spec->auto_mic = 1;
|
||||
}
|
||||
|
||||
static void alc663_g71v_hp_automute(struct hda_codec *codec)
|
||||
static void alc663_g71v_setup(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int present;
|
||||
unsigned char bits;
|
||||
|
||||
present = snd_hda_jack_detect(codec, 0x21);
|
||||
bits = present ? HDA_AMP_MUTE : 0;
|
||||
snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
}
|
||||
|
||||
static void alc663_g71v_front_automute(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int present;
|
||||
unsigned char bits;
|
||||
|
||||
present = snd_hda_jack_detect(codec, 0x15);
|
||||
bits = present ? HDA_AMP_MUTE : 0;
|
||||
snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
}
|
||||
|
||||
static void alc663_g71v_unsol_event(struct hda_codec *codec,
|
||||
unsigned int res)
|
||||
{
|
||||
switch (res >> 26) {
|
||||
case ALC880_HP_EVENT:
|
||||
alc663_g71v_hp_automute(codec);
|
||||
break;
|
||||
case ALC880_FRONT_EVENT:
|
||||
alc663_g71v_front_automute(codec);
|
||||
break;
|
||||
case ALC880_MIC_EVENT:
|
||||
alc_mic_automute(codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define alc663_g71v_setup alc663_m51va_setup
|
||||
|
||||
static void alc663_g71v_inithook(struct hda_codec *codec)
|
||||
{
|
||||
alc663_g71v_front_automute(codec);
|
||||
alc663_g71v_hp_automute(codec);
|
||||
alc_mic_automute(codec);
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->autocfg.hp_pins[0] = 0x21;
|
||||
spec->autocfg.line_out_pins[0] = 0x15;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_AMP;
|
||||
spec->detect_line = 1;
|
||||
spec->automute_lines = 1;
|
||||
spec->ext_mic.pin = 0x18;
|
||||
spec->ext_mic.mux_idx = 0;
|
||||
spec->int_mic.pin = 0x12;
|
||||
spec->int_mic.mux_idx = 9;
|
||||
spec->auto_mic = 1;
|
||||
}
|
||||
|
||||
#define alc663_g50v_setup alc663_m51va_setup
|
||||
|
@ -18697,8 +18662,9 @@ static struct alc_config_preset alc662_presets[] = {
|
|||
.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
|
||||
.channel_mode = alc662_3ST_2ch_modes,
|
||||
.input_mux = &alc662_lenovo_101e_capture_source,
|
||||
.unsol_event = alc662_lenovo_101e_unsol_event,
|
||||
.init_hook = alc662_lenovo_101e_all_automute,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc662_lenovo_101e_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC662_ASUS_EEEPC_P701] = {
|
||||
.mixers = { alc662_eeepc_p701_mixer },
|
||||
|
@ -18765,9 +18731,9 @@ static struct alc_config_preset alc662_presets[] = {
|
|||
.dig_out_nid = ALC662_DIGOUT_NID,
|
||||
.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
|
||||
.channel_mode = alc662_3ST_2ch_modes,
|
||||
.unsol_event = alc663_g71v_unsol_event,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc663_g71v_setup,
|
||||
.init_hook = alc663_g71v_inithook,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC663_ASUS_H13] = {
|
||||
.mixers = { alc663_m51va_mixer },
|
||||
|
|
Loading…
Reference in a new issue