--- linux-3.0.0~/sound/pci/hda/patch_conexant.c 2011-10-23 05:19:44.000000000 +0200 +++ linux-3.0.0/sound/pci/hda/patch_conexant.c 2011-10-23 05:36:48.183079604 +0200 @@ -791,6 +791,15 @@ snd_hda_sequence_write(codec, mic_jack_off); } +static void cxt5045_lenovo_automic(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_jack_detect(codec, 0x14); + snd_hda_codec_write(codec, 0x1a, 0, + AC_VERB_SET_CONNECT_SEL, + present ? 0x01 : 0x04); +} /* mute internal speaker if HP is plugged */ static void cxt5045_hp_automute(struct hda_codec *codec) @@ -821,6 +830,21 @@ } } +static void cxt5045_lenovo_hp_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + res >>= 26; + switch (res) { + case CONEXANT_HP_EVENT: + cxt5045_hp_automute(codec); + break; + case CONEXANT_MIC_EVENT: + cxt5045_lenovo_automic(codec); + break; + + } +} + static const struct snd_kcontrol_new cxt5045_mixers[] = { HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), @@ -886,6 +910,22 @@ {} }; +static const struct snd_kcontrol_new cxt5045_lenovo_mixers[] = { + HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), + HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = cxt_eapd_info, + .get = cxt_eapd_get, + .put = cxt5045_hp_master_sw_put, + .private_value = 0x10, + }, + + {} +}; + static const struct hda_verb cxt5045_init_verbs[] = { /* Line in, Mic */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, @@ -938,6 +978,34 @@ { } /* end */ }; +static const struct hda_verb cxt5045_lenovo_init_verbs[] = { + /* mic jack, built-in */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + /* HP, Amp */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 }, + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x11, AC_VERB_SET_CONNECT_SEL, 0x1 }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0) }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1) }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3) }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4) }, + /* Record selector: built-in mic */ + { 0x1a, AC_VERB_SET_CONNECT_SEL,0x4 }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17 }, + /* SPDIF route: PCM */ + { 0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 }, + /* EAPD */ + { 0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2 }, /* default on */ + /* pin sensing on mic jack */ + { 0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT }, + { } /* end */ +}; + static const struct hda_verb cxt5045_hp_sense_init_verbs[] = { /* pin sensing on HP jack */ {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, @@ -1081,6 +1149,7 @@ CXT5045_LAPTOP_HPMICSENSE, CXT5045_BENQ, CXT5045_LAPTOP_HP530, + CXT5045_LENOVO, #ifdef CONFIG_SND_DEBUG CXT5045_TEST, #endif @@ -1094,6 +1163,7 @@ [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", [CXT5045_BENQ] = "benq", [CXT5045_LAPTOP_HP530] = "laptop-hp530", + [CXT5045_LENOVO] = "lenovo", #ifdef CONFIG_SND_DEBUG [CXT5045_TEST] = "test", #endif @@ -1101,6 +1171,7 @@ }; static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x20ac, "Lenovo R61/R61i", CXT5045_LENOVO), SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", CXT5045_LAPTOP_HPSENSE), @@ -1203,6 +1274,14 @@ spec->mixers[0] = cxt5045_mixers_hp530; codec->patch_ops.init = cxt5045_init; break; + case CXT5045_LENOVO: + codec->patch_ops.unsol_event = cxt5045_lenovo_hp_unsol_event; + spec->num_init_verbs = 2; + spec->init_verbs[0] = cxt5045_lenovo_init_verbs; + spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; + spec->mixers[0] = cxt5045_lenovo_mixers; + codec->patch_ops.init = cxt5045_init; + break; #ifdef CONFIG_SND_DEBUG case CXT5045_TEST: spec->input_mux = &cxt5045_test_capture_source;