diff options
author | Tony Vroon <tony@linx.net> | 2008-11-06 10:08:49 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-11-06 11:32:34 -0500 |
commit | 64154835c58a99370c3b7fbf85d2451d6906b3b4 (patch) | |
tree | 80d110d1ff1e7fecef442171c4269d547a800ad3 /sound | |
parent | 6ce4a3bc1b93e8ca50b142b00dd73bfdb5c4a172 (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')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 125 |
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 | ||
11705 | static 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 */ |
11705 | static struct hda_bind_ctls alc269_epc_bind_vol = { | 11731 | static 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 | ||
11780 | static 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 */ |
11755 | static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) | 11795 | static 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 */ | ||
11820 | static 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 | |||
11779 | static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec) | 11850 | static 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 | ||
11860 | static 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 | |||
11789 | static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, | 11883 | static 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 | ||
11892 | static 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 | |||
11798 | static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) | 11901 | static 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 | ||
11907 | static void alc269_lifebook_init_hook(struct hda_codec *codec) | ||
11908 | { | ||
11909 | alc269_lifebook_speaker_automute(codec); | ||
11910 | alc269_lifebook_mic_autoswitch(codec); | ||
11911 | } | ||
11912 | |||
11804 | static struct hda_verb alc269_eeepc_dmic_init_verbs[] = { | 11913 | static 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 | ||
12160 | static struct snd_pci_quirk alc269_cfg_tbl[] = { | 12270 | static 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 | ||
12239 | static int patch_alc269(struct hda_codec *codec) | 12362 | static int patch_alc269(struct hda_codec *codec) |