提交 6dda9f4a 编写于 作者: K Kailang Yang 提交者: Takashi Iwai

[ALSA] hda - Add ALC663 support

Added the support of ALC663 codec, including specific models for
ASUS M51VA, ASUS G71V, ASUS H13 and ASUS G50V.
Signed-off-by: NKailang Yang <kailang@realtek.com.tw>
Signed-off-by: NTakashi Iwai <tiwai@suse.de>
上级 abbc9d1b
...@@ -845,7 +845,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ...@@ -845,7 +845,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
ALC269 ALC269
basic Basic preset basic Basic preset
ALC662 ALC662/663
3stack-dig 3-stack (2-channel) with SPDIF 3stack-dig 3-stack (2-channel) with SPDIF
3stack-6ch 3-stack (6-channel) 3stack-6ch 3-stack (6-channel)
3stack-6ch-dig 3-stack (6-channel) with SPDIF 3stack-6ch-dig 3-stack (6-channel) with SPDIF
...@@ -853,6 +853,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ...@@ -853,6 +853,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
lenovo-101e Lenovo laptop lenovo-101e Lenovo laptop
eeepc-p701 ASUS Eeepc P701 eeepc-p701 ASUS Eeepc P701
eeepc-ep20 ASUS Eeepc EP20 eeepc-ep20 ASUS Eeepc EP20
m51va ASUS M51VA
g71v ASUS G71V
h13 ASUS H13
g50v ASUS G50V
auto auto-config reading BIOS (default) auto auto-config reading BIOS (default)
ALC882/885 ALC882/885
......
...@@ -163,6 +163,10 @@ enum { ...@@ -163,6 +163,10 @@ enum {
ALC662_LENOVO_101E, ALC662_LENOVO_101E,
ALC662_ASUS_EEEPC_P701, ALC662_ASUS_EEEPC_P701,
ALC662_ASUS_EEEPC_EP20, ALC662_ASUS_EEEPC_EP20,
ALC663_ASUS_M51VA,
ALC663_ASUS_G71V,
ALC663_ASUS_H13,
ALC663_ASUS_G50V,
ALC662_AUTO, ALC662_AUTO,
ALC662_MODEL_LAST, ALC662_MODEL_LAST,
}; };
...@@ -13251,6 +13255,23 @@ static struct hda_input_mux alc662_eeepc_capture_source = { ...@@ -13251,6 +13255,23 @@ static struct hda_input_mux alc662_eeepc_capture_source = {
}, },
}; };
static struct hda_input_mux alc663_capture_source = {
.num_items = 3,
.items = {
{ "Mic", 0x0 },
{ "Front Mic", 0x1 },
{ "Line", 0x2 },
},
};
static struct hda_input_mux alc663_m51va_capture_source = {
.num_items = 2,
.items = {
{ "Ext-Mic", 0x0 },
{ "D-Mic", 0x9 },
},
};
#define alc662_mux_enum_info alc_mux_enum_info #define alc662_mux_enum_info alc_mux_enum_info
#define alc662_mux_enum_get alc_mux_enum_get #define alc662_mux_enum_get alc_mux_enum_get
#define alc662_mux_enum_put alc882_mux_enum_put #define alc662_mux_enum_put alc882_mux_enum_put
...@@ -13431,6 +13452,44 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { ...@@ -13431,6 +13452,44 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
{ } /* end */ { } /* end */
}; };
static struct snd_kcontrol_new alc663_m51va_mixer[] = {
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("DMic Playback Switch", 0x23, 0x9, HDA_INPUT),
{ } /* end */
};
static struct snd_kcontrol_new alc663_g71v_mixer[] = {
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
static struct snd_kcontrol_new alc663_g50v_mixer[] = {
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
{ } /* end */
};
static struct snd_kcontrol_new alc662_chmode_mixer[] = { static struct snd_kcontrol_new alc662_chmode_mixer[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
...@@ -13501,6 +13560,11 @@ static struct hda_verb alc662_init_verbs[] = { ...@@ -13501,6 +13560,11 @@ static struct hda_verb alc662_init_verbs[] = {
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
/* always trun on EAPD */
{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
{ } { }
}; };
...@@ -13571,6 +13635,43 @@ static struct hda_verb alc662_auto_init_verbs[] = { ...@@ -13571,6 +13635,43 @@ static struct hda_verb alc662_auto_init_verbs[] = {
{ } { }
}; };
static struct hda_verb alc663_m51va_init_verbs[] = {
{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
{}
};
static struct hda_verb alc663_g71v_init_verbs[] = {
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
/* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
/* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
{}
};
static struct hda_verb alc663_g50v_init_verbs[] = {
{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
{}
};
/* capture mixer elements */ /* capture mixer elements */
static struct snd_kcontrol_new alc662_capture_mixer[] = { static struct snd_kcontrol_new alc662_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
...@@ -13692,6 +13793,125 @@ static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) ...@@ -13692,6 +13793,125 @@ static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
alc662_eeepc_ep20_automute(codec); alc662_eeepc_ep20_automute(codec);
} }
static void alc663_m51va_speaker_automute(struct hda_codec *codec)
{
unsigned int present;
unsigned char bits;
present = snd_hda_codec_read(codec, 0x21, 0,
AC_VERB_GET_PIN_SENSE, 0)
& AC_PINSENSE_PRESENCE;
bits = present ? HDA_AMP_MUTE : 0;
snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
HDA_AMP_MUTE, bits);
}
static void alc663_m51va_mic_automute(struct hda_codec *codec)
{
unsigned int present;
present = snd_hda_codec_read(codec, 0x18, 0,
AC_VERB_GET_PIN_SENSE, 0)
& AC_PINSENSE_PRESENCE;
snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
}
static void alc663_m51va_unsol_event(struct hda_codec *codec,
unsigned int res)
{
switch (res >> 26) {
case ALC880_HP_EVENT:
alc663_m51va_speaker_automute(codec);
break;
case ALC880_MIC_EVENT:
alc663_m51va_mic_automute(codec);
break;
}
}
static void alc663_m51va_inithook(struct hda_codec *codec)
{
alc663_m51va_speaker_automute(codec);
alc663_m51va_mic_automute(codec);
}
static void alc663_g71v_hp_automute(struct hda_codec *codec)
{
unsigned int present;
unsigned char bits;
present = snd_hda_codec_read(codec, 0x21, 0,
AC_VERB_GET_PIN_SENSE, 0)
& AC_PINSENSE_PRESENCE;
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_codec_read(codec, 0x15, 0,
AC_VERB_GET_PIN_SENSE, 0)
& AC_PINSENSE_PRESENCE;
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:
alc662_eeepc_mic_automute(codec);
break;
}
}
static void alc663_g71v_inithook(struct hda_codec *codec)
{
alc663_g71v_front_automute(codec);
alc663_g71v_hp_automute(codec);
alc662_eeepc_mic_automute(codec);
}
static void alc663_g50v_unsol_event(struct hda_codec *codec,
unsigned int res)
{
switch (res >> 26) {
case ALC880_HP_EVENT:
alc663_m51va_speaker_automute(codec);
break;
case ALC880_MIC_EVENT:
alc662_eeepc_mic_automute(codec);
break;
}
}
static void alc663_g50v_inithook(struct hda_codec *codec)
{
alc663_m51va_speaker_automute(codec);
alc662_eeepc_mic_automute(codec);
}
#ifdef CONFIG_SND_HDA_POWER_SAVE #ifdef CONFIG_SND_HDA_POWER_SAVE
#define alc662_loopbacks alc880_loopbacks #define alc662_loopbacks alc880_loopbacks
#endif #endif
...@@ -13714,14 +13934,24 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { ...@@ -13714,14 +13934,24 @@ static const char *alc662_models[ALC662_MODEL_LAST] = {
[ALC662_LENOVO_101E] = "lenovo-101e", [ALC662_LENOVO_101E] = "lenovo-101e",
[ALC662_ASUS_EEEPC_P701] = "eeepc-p701", [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
[ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
[ALC663_ASUS_M51VA] = "m51va",
[ALC663_ASUS_G71V] = "g71v",
[ALC663_ASUS_H13] = "h13",
[ALC663_ASUS_G50V] = "g50v",
[ALC662_AUTO] = "auto", [ALC662_AUTO] = "auto",
}; };
static struct snd_pci_quirk alc662_cfg_tbl[] = { static struct snd_pci_quirk alc662_cfg_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS G71V", ALC663_ASUS_G71V),
SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V),
SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
{} {}
}; };
...@@ -13809,7 +14039,53 @@ static struct alc_config_preset alc662_presets[] = { ...@@ -13809,7 +14039,53 @@ static struct alc_config_preset alc662_presets[] = {
.unsol_event = alc662_eeepc_ep20_unsol_event, .unsol_event = alc662_eeepc_ep20_unsol_event,
.init_hook = alc662_eeepc_ep20_inithook, .init_hook = alc662_eeepc_ep20_inithook,
}, },
[ALC663_ASUS_M51VA] = {
.mixers = { alc663_m51va_mixer, alc662_capture_mixer},
.init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
.dig_out_nid = ALC662_DIGOUT_NID,
.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
.channel_mode = alc662_3ST_2ch_modes,
.input_mux = &alc663_m51va_capture_source,
.unsol_event = alc663_m51va_unsol_event,
.init_hook = alc663_m51va_inithook,
},
[ALC663_ASUS_G71V] = {
.mixers = { alc663_g71v_mixer, alc662_capture_mixer},
.init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
.dig_out_nid = ALC662_DIGOUT_NID,
.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
.channel_mode = alc662_3ST_2ch_modes,
.input_mux = &alc662_eeepc_capture_source,
.unsol_event = alc663_g71v_unsol_event,
.init_hook = alc663_g71v_inithook,
},
[ALC663_ASUS_H13] = {
.mixers = { alc663_m51va_mixer, alc662_capture_mixer},
.init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
.channel_mode = alc662_3ST_2ch_modes,
.input_mux = &alc663_m51va_capture_source,
.unsol_event = alc663_m51va_unsol_event,
.init_hook = alc663_m51va_inithook,
},
[ALC663_ASUS_G50V] = {
.mixers = { alc663_g50v_mixer, alc662_capture_mixer},
.init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
.num_dacs = ARRAY_SIZE(alc662_dac_nids),
.dac_nids = alc662_dac_nids,
.dig_out_nid = ALC662_DIGOUT_NID,
.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
.channel_mode = alc662_3ST_6ch_modes,
.input_mux = &alc663_capture_source,
.unsol_event = alc663_g50v_unsol_event,
.init_hook = alc663_g50v_inithook,
},
}; };
...@@ -14108,11 +14384,17 @@ static int patch_alc662(struct hda_codec *codec) ...@@ -14108,11 +14384,17 @@ static int patch_alc662(struct hda_codec *codec)
if (board_config != ALC662_AUTO) if (board_config != ALC662_AUTO)
setup_preset(spec, &alc662_presets[board_config]); setup_preset(spec, &alc662_presets[board_config]);
spec->stream_name_analog = "ALC662 Analog"; if (codec->vendor_id == 0x10ec0663) {
spec->stream_name_analog = "ALC663 Analog";
spec->stream_name_digital = "ALC663 Digital";
} else {
spec->stream_name_analog = "ALC662 Analog";
spec->stream_name_digital = "ALC662 Digital";
}
spec->stream_analog_playback = &alc662_pcm_analog_playback; spec->stream_analog_playback = &alc662_pcm_analog_playback;
spec->stream_analog_capture = &alc662_pcm_analog_capture; spec->stream_analog_capture = &alc662_pcm_analog_capture;
spec->stream_name_digital = "ALC662 Digital";
spec->stream_digital_playback = &alc662_pcm_digital_playback; spec->stream_digital_playback = &alc662_pcm_digital_playback;
spec->stream_digital_capture = &alc662_pcm_digital_capture; spec->stream_digital_capture = &alc662_pcm_digital_capture;
...@@ -14151,6 +14433,7 @@ struct hda_codec_preset snd_hda_preset_realtek[] = { ...@@ -14151,6 +14433,7 @@ struct hda_codec_preset snd_hda_preset_realtek[] = {
.patch = patch_alc883 }, .patch = patch_alc883 },
{ .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
.patch = patch_alc662 }, .patch = patch_alc662 },
{ .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册