Commit e6a5e1b7 authored by Takashi Iwai's avatar Takashi Iwai

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: default avatarTakashi Iwai <tiwai@suse.de>
parent 3b8510ce
...@@ -392,9 +392,12 @@ struct alc_spec { ...@@ -392,9 +392,12 @@ struct alc_spec {
/* for pin sensing */ /* for pin sensing */
unsigned int sense_updated: 1; unsigned int sense_updated: 1;
unsigned int jack_present: 1; unsigned int jack_present: 1;
unsigned int line_jack_present:1;
unsigned int master_sw: 1; unsigned int master_sw: 1;
unsigned int auto_mic:1; unsigned int auto_mic:1;
unsigned int automute:1; /* HP automute enabled */ 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 */ /* other flags */
unsigned int no_analog :1; /* digital I/O only */ unsigned int no_analog :1; /* digital I/O only */
...@@ -1074,54 +1077,96 @@ static int alc_init_jacks(struct hda_codec *codec) ...@@ -1074,54 +1077,96 @@ static int alc_init_jacks(struct hda_codec *codec)
return 0; 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; int i, present = 0;
unsigned int mute;
hda_nid_t nid;
int i;
if (!spec->automute) for (i = 0; i < num_pins; i++) {
return; hda_nid_t nid = pins[i];
spec->jack_present = 0;
for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
nid = spec->autocfg.hp_pins[i];
if (!nid) if (!nid)
break; break;
snd_hda_input_jack_report(codec, nid); 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; static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
/* Toggle internal speakers muting */ bool mute)
for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { {
nid = spec->autocfg.speaker_pins[i]; 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) if (!nid)
break; break;
switch (spec->automute_mode) { switch (spec->automute_mode) {
case ALC_AUTOMUTE_PIN: case ALC_AUTOMUTE_PIN:
snd_hda_codec_write(codec, nid, 0, snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, AC_VERB_SET_PIN_WIDGET_CONTROL,
spec->jack_present ? 0 : PIN_OUT); pin_bits);
break; break;
case ALC_AUTOMUTE_AMP: case ALC_AUTOMUTE_AMP:
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
HDA_AMP_MUTE, mute); HDA_AMP_MUTE, mute_bits);
break; break;
case ALC_AUTOMUTE_MIXER: case ALC_AUTOMUTE_MIXER:
nid = spec->automute_mixer_nid[i]; nid = spec->automute_mixer_nid[i];
if (!nid) if (!nid)
break; break;
snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, 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, snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
HDA_AMP_MUTE, mute); HDA_AMP_MUTE, mute_bits);
break; 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, static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
hda_nid_t nid) hda_nid_t nid)
{ {
...@@ -1219,6 +1264,9 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) ...@@ -1219,6 +1264,9 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
case ALC880_HP_EVENT: case ALC880_HP_EVENT:
alc_hp_automute(codec); alc_hp_automute(codec);
break; break;
case ALC880_FRONT_EVENT:
alc_line_automute(codec);
break;
case ALC880_MIC_EVENT: case ALC880_MIC_EVENT:
alc_mic_automute(codec); alc_mic_automute(codec);
break; break;
...@@ -1228,6 +1276,7 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) ...@@ -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) static void alc_inithook(struct hda_codec *codec)
{ {
alc_hp_automute(codec); alc_hp_automute(codec);
alc_line_automute(codec);
alc_mic_automute(codec); alc_mic_automute(codec);
} }
...@@ -9551,33 +9600,15 @@ static struct hda_channel_mode alc888_3st_hp_modes[3] = { ...@@ -9551,33 +9600,15 @@ static struct hda_channel_mode alc888_3st_hp_modes[3] = {
{ 6, alc888_3st_hp_6ch_init }, { 6, alc888_3st_hp_6ch_init },
}; };
/* toggle front-jack and RCA according to the hp-jack state */ static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
{
unsigned int present = snd_hda_jack_detect(codec, 0x1b);
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); struct alc_spec *spec = codec->spec;
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, spec->autocfg.hp_pins[0] = 0x1b;
unsigned int res) spec->autocfg.line_out_pins[0] = 0x14;
{ spec->autocfg.speaker_pins[0] = 0x15;
if ((res >> 26) == ALC880_HP_EVENT) spec->automute = 1;
alc888_lenovo_ms7195_front_automute(codec); spec->automute_mode = ALC_AUTOMUTE_AMP;
if ((res >> 26) == ALC880_FRONT_EVENT)
alc888_lenovo_ms7195_rca_automute(codec);
} }
/* toggle speaker-output according to the hp-jack state */ /* toggle speaker-output according to the hp-jack state */
...@@ -9645,31 +9676,17 @@ static void alc883_haier_w66_setup(struct hda_codec *codec) ...@@ -9645,31 +9676,17 @@ static void alc883_haier_w66_setup(struct hda_codec *codec)
spec->automute_mode = ALC_AUTOMUTE_AMP; 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, spec->autocfg.hp_pins[0] = 0x1b;
unsigned int res) spec->autocfg.line_out_pins[0] = 0x14;
{ spec->autocfg.speaker_pins[0] = 0x15;
if ((res >> 26) == ALC880_HP_EVENT) spec->automute = 1;
alc883_lenovo_101e_all_automute(codec); spec->detect_line = 1;
if ((res >> 26) == ALC880_FRONT_EVENT) spec->automute_lines = 1;
alc883_lenovo_101e_ispeaker_automute(codec); spec->automute_mode = ALC_AUTOMUTE_AMP;
} }
/* toggle speaker-output according to the hp-jack state */ /* toggle speaker-output according to the hp-jack state */
...@@ -10584,8 +10601,9 @@ static struct alc_config_preset alc882_presets[] = { ...@@ -10584,8 +10601,9 @@ static struct alc_config_preset alc882_presets[] = {
.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
.channel_mode = alc883_3ST_2ch_modes, .channel_mode = alc883_3ST_2ch_modes,
.input_mux = &alc883_lenovo_101e_capture_source, .input_mux = &alc883_lenovo_101e_capture_source,
.unsol_event = alc883_lenovo_101e_unsol_event, .setup = alc883_lenovo_101e_setup,
.init_hook = alc883_lenovo_101e_all_automute, .unsol_event = alc_sku_unsol_event,
.init_hook = alc_inithook,
}, },
[ALC883_LENOVO_NB0763] = { [ALC883_LENOVO_NB0763] = {
.mixers = { alc883_lenovo_nb0763_mixer }, .mixers = { alc883_lenovo_nb0763_mixer },
...@@ -10610,8 +10628,9 @@ static struct alc_config_preset alc882_presets[] = { ...@@ -10610,8 +10628,9 @@ static struct alc_config_preset alc882_presets[] = {
.channel_mode = alc883_3ST_6ch_modes, .channel_mode = alc883_3ST_6ch_modes,
.need_dac_fix = 1, .need_dac_fix = 1,
.input_mux = &alc883_capture_source, .input_mux = &alc883_capture_source,
.unsol_event = alc883_lenovo_ms7195_unsol_event, .unsol_event = alc_sku_unsol_event,
.init_hook = alc888_lenovo_ms7195_front_automute, .setup = alc888_lenovo_ms7195_setup,
.init_hook = alc_inithook,
}, },
[ALC883_HAIER_W66] = { [ALC883_HAIER_W66] = {
.mixers = { alc883_targa_2ch_mixer}, .mixers = { alc883_targa_2ch_mixer},
...@@ -18217,39 +18236,17 @@ static struct snd_kcontrol_new alc272_auto_capture_mixer[] = { ...@@ -18217,39 +18236,17 @@ static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
{ } /* end */ { } /* 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; struct alc_spec *spec = codec->spec;
unsigned char bits;
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, spec->autocfg.hp_pins[0] = 0x1b;
unsigned int res) spec->autocfg.line_out_pins[0] = 0x14;
{ spec->autocfg.speaker_pins[0] = 0x15;
if ((res >> 26) == ALC880_HP_EVENT) spec->automute = 1;
alc662_lenovo_101e_all_automute(codec); spec->detect_line = 1;
if ((res >> 26) == ALC880_FRONT_EVENT) spec->automute_lines = 1;
alc662_lenovo_101e_ispeaker_automute(codec); spec->automute_mode = ALC_AUTOMUTE_AMP;
} }
/* unsolicited event for HP jack sensing */ /* unsolicited event for HP jack sensing */
...@@ -18439,53 +18436,21 @@ static void alc663_mode8_setup(struct hda_codec *codec) ...@@ -18439,53 +18436,21 @@ static void alc663_mode8_setup(struct hda_codec *codec)
spec->auto_mic = 1; 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; struct alc_spec *spec = codec->spec;
unsigned char bits; spec->autocfg.hp_pins[0] = 0x21;
spec->autocfg.line_out_pins[0] = 0x15;
present = snd_hda_jack_detect(codec, 0x15); spec->autocfg.speaker_pins[0] = 0x14;
bits = present ? HDA_AMP_MUTE : 0; spec->automute = 1;
snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, spec->automute_mode = ALC_AUTOMUTE_AMP;
HDA_AMP_MUTE, bits); spec->detect_line = 1;
} spec->automute_lines = 1;
spec->ext_mic.pin = 0x18;
static void alc663_g71v_unsol_event(struct hda_codec *codec, spec->ext_mic.mux_idx = 0;
unsigned int res) spec->int_mic.pin = 0x12;
{ spec->int_mic.mux_idx = 9;
switch (res >> 26) { spec->auto_mic = 1;
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);
} }
#define alc663_g50v_setup alc663_m51va_setup #define alc663_g50v_setup alc663_m51va_setup
...@@ -18697,8 +18662,9 @@ static struct alc_config_preset alc662_presets[] = { ...@@ -18697,8 +18662,9 @@ static struct alc_config_preset alc662_presets[] = {
.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
.channel_mode = alc662_3ST_2ch_modes, .channel_mode = alc662_3ST_2ch_modes,
.input_mux = &alc662_lenovo_101e_capture_source, .input_mux = &alc662_lenovo_101e_capture_source,
.unsol_event = alc662_lenovo_101e_unsol_event, .unsol_event = alc_sku_unsol_event,
.init_hook = alc662_lenovo_101e_all_automute, .setup = alc662_lenovo_101e_setup,
.init_hook = alc_inithook,
}, },
[ALC662_ASUS_EEEPC_P701] = { [ALC662_ASUS_EEEPC_P701] = {
.mixers = { alc662_eeepc_p701_mixer }, .mixers = { alc662_eeepc_p701_mixer },
...@@ -18765,9 +18731,9 @@ static struct alc_config_preset alc662_presets[] = { ...@@ -18765,9 +18731,9 @@ static struct alc_config_preset alc662_presets[] = {
.dig_out_nid = ALC662_DIGOUT_NID, .dig_out_nid = ALC662_DIGOUT_NID,
.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
.channel_mode = 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, .setup = alc663_g71v_setup,
.init_hook = alc663_g71v_inithook, .init_hook = alc_inithook,
}, },
[ALC663_ASUS_H13] = { [ALC663_ASUS_H13] = {
.mixers = { alc663_m51va_mixer }, .mixers = { alc663_m51va_mixer },
......
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