summaryrefslogtreecommitdiff
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorKailang Yang <kailang@realtek.com.tw>2008-05-27 10:05:31 (GMT)
committerTakashi Iwai <tiwai@suse.de>2008-05-27 13:56:21 (GMT)
commit6dda9f4a95905f2b38e79e3737da5e25397e6acb (patch)
tree0434dd0ca776f373386e6a4f093914c0e3c216ed /sound/pci/hda
parentabbc9d1b25637b1948a4718fa8f7b257233136bc (diff)
downloadlinux-6dda9f4a95905f2b38e79e3737da5e25397e6acb.tar.xz
[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: Kailang Yang <kailang@realtek.com.tw> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/patch_realtek.c289
1 files changed, 286 insertions, 3 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index b0a2a26..c659588 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -163,6 +163,10 @@ enum {
ALC662_LENOVO_101E,
ALC662_ASUS_EEEPC_P701,
ALC662_ASUS_EEEPC_EP20,
+ ALC663_ASUS_M51VA,
+ ALC663_ASUS_G71V,
+ ALC663_ASUS_H13,
+ ALC663_ASUS_G50V,
ALC662_AUTO,
ALC662_MODEL_LAST,
};
@@ -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_get alc_mux_enum_get
#define alc662_mux_enum_put alc882_mux_enum_put
@@ -13431,6 +13452,44 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
{ } /* 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[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -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(2)},
{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[] = {
{ }
};
+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 */
static struct snd_kcontrol_new alc662_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
@@ -13692,6 +13793,125 @@ static void alc662_eeepc_ep20_inithook(struct hda_codec *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
#define alc662_loopbacks alc880_loopbacks
#endif
@@ -13714,14 +13934,24 @@ static const char *alc662_models[ALC662_MODEL_LAST] = {
[ALC662_LENOVO_101E] = "lenovo-101e",
[ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
[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",
};
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, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
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[] = {
.unsol_event = alc662_eeepc_ep20_unsol_event,
.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)
if (board_config != ALC662_AUTO)
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_capture = &alc662_pcm_analog_capture;
- spec->stream_name_digital = "ALC662 Digital";
spec->stream_digital_playback = &alc662_pcm_digital_playback;
spec->stream_digital_capture = &alc662_pcm_digital_capture;
@@ -14151,6 +14433,7 @@ struct hda_codec_preset snd_hda_preset_realtek[] = {
.patch = patch_alc883 },
{ .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
.patch = patch_alc662 },
+ { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },