aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_realtek.c
diff options
context:
space:
mode:
authorTony Vroon <tony@linx.net>2008-11-06 10:08:49 -0500
committerTakashi Iwai <tiwai@suse.de>2008-11-06 11:32:34 -0500
commit64154835c58a99370c3b7fbf85d2451d6906b3b4 (patch)
tree80d110d1ff1e7fecef442171c4269d547a800ad3 /sound/pci/hda/patch_realtek.c
parent6ce4a3bc1b93e8ca50b142b00dd73bfdb5c4a172 (diff)
ALSA: hda - Add lifebook model for Realtek ALC269
The widget layout of the Fujitsu Lifebook S6420 (which is ICH9M-based and uses an ALC269) is similar but not identical to the Lifebook S6410/E8410 (which are ICH8M-based and use an ALC262). It is named lifebook as fujitsu is in use for Amilo machines. This builds on the Quanta FL1 work and supports all analog inputs & outputs that I am aware of. Microphone autoswitch is implemented. The laptop mic port takes precedence over the dock mic port if both happen to have a jack plugged in. This made sense to me as a design decision (imagine a presentation environment with the dock fully wired in and the presenter quickly wanting to override the mic with a headset). There is mention of a digital audio path on the codec graph, so perhaps the headphone socket is dual-function analog/digital. I will follow up with another patch if I can acquire equipment to test this. Signed-off-by: Tony Vroon <tony@linx.net> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r--sound/pci/hda/patch_realtek.c125
1 files changed, 124 insertions, 1 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 425b0fc86f7d..98a02fd1097e 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -132,6 +132,7 @@ enum {
132 ALC269_ASUS_EEEPC_P703, 132 ALC269_ASUS_EEEPC_P703,
133 ALC269_ASUS_EEEPC_P901, 133 ALC269_ASUS_EEEPC_P901,
134 ALC269_FUJITSU, 134 ALC269_FUJITSU,
135 ALC269_LIFEBOOK,
135 ALC269_AUTO, 136 ALC269_AUTO,
136 ALC269_MODEL_LAST /* last tag */ 137 ALC269_MODEL_LAST /* last tag */
137}; 138};
@@ -11701,6 +11702,31 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
11701 { } 11702 { }
11702}; 11703};
11703 11704
11705static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
11706 /* output mixer control */
11707 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11708 {
11709 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11710 .name = "Master Playback Switch",
11711 .info = snd_hda_mixer_amp_switch_info,
11712 .get = snd_hda_mixer_amp_switch_get,
11713 .put = alc268_acer_master_sw_put,
11714 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11715 },
11716 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11717 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11718 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11719 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11720 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11721 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11722 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
11723 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
11724 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
11725 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
11726 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
11727 { }
11728};
11729
11704/* bind volumes of both NID 0x0c and 0x0d */ 11730/* bind volumes of both NID 0x0c and 0x0d */
11705static struct hda_bind_ctls alc269_epc_bind_vol = { 11731static struct hda_bind_ctls alc269_epc_bind_vol = {
11706 .ops = &snd_hda_bind_vol, 11732 .ops = &snd_hda_bind_vol,
@@ -11751,6 +11777,20 @@ static struct hda_verb alc269_quanta_fl1_verbs[] = {
11751 { } 11777 { }
11752}; 11778};
11753 11779
11780static struct hda_verb alc269_lifebook_verbs[] = {
11781 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11782 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
11783 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11784 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11785 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11786 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11787 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11788 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11789 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11790 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11791 { }
11792};
11793
11754/* toggle speaker-output according to the hp-jack state */ 11794/* toggle speaker-output according to the hp-jack state */
11755static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) 11795static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
11756{ 11796{
@@ -11776,6 +11816,37 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
11776 AC_VERB_SET_PROC_COEF, 0x480); 11816 AC_VERB_SET_PROC_COEF, 0x480);
11777} 11817}
11778 11818
11819/* toggle speaker-output according to the hp-jacks state */
11820static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
11821{
11822 unsigned int present;
11823 unsigned char bits;
11824
11825 /* Check laptop headphone socket */
11826 present = snd_hda_codec_read(codec, 0x15, 0,
11827 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11828
11829 /* Check port replicator headphone socket */
11830 present |= snd_hda_codec_read(codec, 0x1a, 0,
11831 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11832
11833 bits = present ? AMP_IN_MUTE(0) : 0;
11834 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11835 AMP_IN_MUTE(0), bits);
11836 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11837 AMP_IN_MUTE(0), bits);
11838
11839 snd_hda_codec_write(codec, 0x20, 0,
11840 AC_VERB_SET_COEF_INDEX, 0x0c);
11841 snd_hda_codec_write(codec, 0x20, 0,
11842 AC_VERB_SET_PROC_COEF, 0x680);
11843
11844 snd_hda_codec_write(codec, 0x20, 0,
11845 AC_VERB_SET_COEF_INDEX, 0x0c);
11846 snd_hda_codec_write(codec, 0x20, 0,
11847 AC_VERB_SET_PROC_COEF, 0x480);
11848}
11849
11779static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec) 11850static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
11780{ 11851{
11781 unsigned int present; 11852 unsigned int present;
@@ -11786,6 +11857,29 @@ static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
11786 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1); 11857 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
11787} 11858}
11788 11859
11860static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
11861{
11862 unsigned int present_laptop;
11863 unsigned int present_dock;
11864
11865 present_laptop = snd_hda_codec_read(codec, 0x18, 0,
11866 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11867
11868 present_dock = snd_hda_codec_read(codec, 0x1b, 0,
11869 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11870
11871 /* Laptop mic port overrides dock mic port, design decision */
11872 if (present_dock)
11873 snd_hda_codec_write(codec, 0x23, 0,
11874 AC_VERB_SET_CONNECT_SEL, 0x3);
11875 if (present_laptop)
11876 snd_hda_codec_write(codec, 0x23, 0,
11877 AC_VERB_SET_CONNECT_SEL, 0x0);
11878 if (!present_dock && !present_laptop)
11879 snd_hda_codec_write(codec, 0x23, 0,
11880 AC_VERB_SET_CONNECT_SEL, 0x1);
11881}
11882
11789static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, 11883static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
11790 unsigned int res) 11884 unsigned int res)
11791{ 11885{
@@ -11795,12 +11889,27 @@ static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
11795 alc269_quanta_fl1_mic_automute(codec); 11889 alc269_quanta_fl1_mic_automute(codec);
11796} 11890}
11797 11891
11892static void alc269_lifebook_unsol_event(struct hda_codec *codec,
11893 unsigned int res)
11894{
11895 if ((res >> 26) == ALC880_HP_EVENT)
11896 alc269_lifebook_speaker_automute(codec);
11897 if ((res >> 26) == ALC880_MIC_EVENT)
11898 alc269_lifebook_mic_autoswitch(codec);
11899}
11900
11798static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) 11901static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
11799{ 11902{
11800 alc269_quanta_fl1_speaker_automute(codec); 11903 alc269_quanta_fl1_speaker_automute(codec);
11801 alc269_quanta_fl1_mic_automute(codec); 11904 alc269_quanta_fl1_mic_automute(codec);
11802} 11905}
11803 11906
11907static void alc269_lifebook_init_hook(struct hda_codec *codec)
11908{
11909 alc269_lifebook_speaker_automute(codec);
11910 alc269_lifebook_mic_autoswitch(codec);
11911}
11912
11804static struct hda_verb alc269_eeepc_dmic_init_verbs[] = { 11913static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
11805 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, 11914 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11806 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, 11915 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
@@ -12154,7 +12263,8 @@ static const char *alc269_models[ALC269_MODEL_LAST] = {
12154 [ALC269_QUANTA_FL1] = "quanta", 12263 [ALC269_QUANTA_FL1] = "quanta",
12155 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703", 12264 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
12156 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901", 12265 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901",
12157 [ALC269_FUJITSU] = "fujitsu" 12266 [ALC269_FUJITSU] = "fujitsu",
12267 [ALC269_LIFEBOOK] = "lifebook"
12158}; 12268};
12159 12269
12160static struct snd_pci_quirk alc269_cfg_tbl[] = { 12270static struct snd_pci_quirk alc269_cfg_tbl[] = {
@@ -12166,6 +12276,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = {
12166 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", 12276 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
12167 ALC269_ASUS_EEEPC_P901), 12277 ALC269_ASUS_EEEPC_P901),
12168 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), 12278 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
12279 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
12169 {} 12280 {}
12170}; 12281};
12171 12282
@@ -12234,6 +12345,18 @@ static struct alc_config_preset alc269_presets[] = {
12234 .unsol_event = alc269_eeepc_dmic_unsol_event, 12345 .unsol_event = alc269_eeepc_dmic_unsol_event,
12235 .init_hook = alc269_eeepc_dmic_inithook, 12346 .init_hook = alc269_eeepc_dmic_inithook,
12236 }, 12347 },
12348 [ALC269_LIFEBOOK] = {
12349 .mixers = { alc269_lifebook_mixer },
12350 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
12351 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12352 .dac_nids = alc269_dac_nids,
12353 .hp_nid = 0x03,
12354 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12355 .channel_mode = alc269_modes,
12356 .input_mux = &alc269_capture_source,
12357 .unsol_event = alc269_lifebook_unsol_event,
12358 .init_hook = alc269_lifebook_init_hook,
12359 },
12237}; 12360};
12238 12361
12239static int patch_alc269(struct hda_codec *codec) 12362static int patch_alc269(struct hda_codec *codec)