]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
[ALSA] hda-codec - model for alc262 to support Lenovo 3000
authorJiang zhe <zhe.jiang@intel.com>
Thu, 20 Mar 2008 11:12:39 +0000 (12:12 +0100)
committerTakashi Iwai <tiwai@suse.de>
Thu, 24 Apr 2008 10:00:29 +0000 (12:00 +0200)
This model is to support the Lenovo 3000 y410.
ALSA bug#3856:
https://bugtrack.alsa-project.org/alsa-bug/view.php?id=3856

Signed-off-by: Jiang zhe <zhe.jiang@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_realtek.c

index eb40f4820c8b1cd261e1e58e5d68cf69bc03e368..8b819072af3a216492afb29d73ec100c2ae1ac46 100644 (file)
@@ -98,6 +98,7 @@ enum {
        ALC262_SONY_ASSAMD,
        ALC262_BENQ_T31,
        ALC262_ULTRA,
+       ALC262_LENOVO_3000,
        ALC262_AUTO,
        ALC262_MODEL_LAST /* last tag */
 };
@@ -8728,6 +8729,12 @@ static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
        {}
 };
 
+static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {}
+};
+
 static struct hda_input_mux alc262_fujitsu_capture_source = {
        .num_items = 3,
        .items = {
@@ -8808,6 +8815,46 @@ static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
        },
 };
 
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int mute;
+
+       if (force || !spec->sense_updated) {
+               unsigned int present_int_hp;
+               /* need to execute and sync at first */
+               snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
+               present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
+                                       AC_VERB_GET_PIN_SENSE, 0);
+               spec->jack_present = (present_int_hp & 0x80000000) != 0;
+               spec->sense_updated = 1;
+       }
+       if (spec->jack_present) {
+               /* mute internal speaker */
+               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+               snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+       } else {
+               /* unmute internal speaker if necessary */
+               mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
+               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+               snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+       }
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
+                                      unsigned int res)
+{
+       if ((res >> 26) != ALC_HP_EVENT)
+               return;
+       alc262_lenovo_3000_automute(codec, 1);
+}
+
 /* bind hp and internal speaker mute (with plug check) */
 static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
@@ -8849,6 +8896,44 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
        { } /* end */
 };
 
+/* bind hp and internal speaker mute (with plug check) */
+static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int change;
+
+       change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
+                                                HDA_AMP_MUTE,
+                                                valp ? 0 : HDA_AMP_MUTE);
+
+       if (change)
+               alc262_lenovo_3000_automute(codec, 0);
+       return change;
+}
+
+static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = alc262_lenovo_3000_master_sw_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+       },
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
 /* additional init verbs for Benq laptops */
 static struct hda_verb alc262_EAPD_verbs[] = {
        {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
@@ -9398,6 +9483,7 @@ static const char *alc262_models[ALC262_MODEL_LAST] = {
        [ALC262_BENQ_T31]       = "benq-t31",
        [ALC262_SONY_ASSAMD]    = "sony-assamd",
        [ALC262_ULTRA]          = "ultra",
+       [ALC262_LENOVO_3000]    = "lenovo-3000",
        [ALC262_AUTO]           = "auto",
 };
 
@@ -9434,6 +9520,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
        SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
        SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
+       SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
        SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
        SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
        SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
@@ -9596,6 +9683,19 @@ static struct alc_config_preset alc262_presets[] = {
                .unsol_event = alc262_ultra_unsol_event,
                .init_hook = alc262_ultra_automute,
        },
+       [ALC262_LENOVO_3000] = {
+               .mixers = { alc262_lenovo_3000_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
+                               alc262_lenovo_3000_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC262_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_fujitsu_capture_source,
+               .unsol_event = alc262_lenovo_3000_unsol_event,
+       },
 };
 
 static int patch_alc262(struct hda_codec *codec)