--- sound/pci/hda/patch_conexant.c 2010/02/12 10:12:04 +++ sound/pci/hda/patch_conexant.c 2010/02/12 11:48:27 @@ -80,6 +80,7 @@ unsigned int num_adc_nids; hda_nid_t *adc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ + hda_nid_t int_mic_nid; /* internal microphone NID; optional */ unsigned int cur_adc_idx; hda_nid_t cur_adc; @@ -1987,38 +1988,65 @@ static void cxt5066_automic(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - struct hda_verb ext_mic_present[] = { - /* enable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, - - /* switch to external mic input */ - {0x17, AC_VERB_SET_CONNECT_SEL, 0}, - - /* disable internal mic, port C */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static struct hda_verb ext_mic_absent[] = { - /* enable internal mic, port C */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - - /* switch to internal mic input */ - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, - - /* disable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; unsigned int present; - present = snd_hda_codec_read(codec, 0x1a, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - if (present) { - snd_printdd("CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); + if (spec->int_mic_nid == 0x23) { + /* IdeaPad microphone detection.. */ + static struct hda_verb ext_mic_present_ideapad[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + }; + static struct hda_verb ext_mic_absent_ideapad[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 2}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + }; + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & + 0x80000000; + if (present) { + snd_printdd("CXT5066: external microphone detected\n"); + snd_hda_sequence_write(codec, ext_mic_present_ideapad); + } else { + snd_printdd("CXT5066: external microphone absent\n"); + snd_hda_sequence_write(codec, ext_mic_absent_ideapad); + } } else { - snd_printdd("CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); + struct hda_verb ext_mic_present[] = { + /* enable external mic, port B */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->ext_mic_bias}, + + /* switch to external mic input */ + {0x17, AC_VERB_SET_CONNECT_SEL, 0}, + + /* disable internal mic, port C */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {} + }; + static struct hda_verb ext_mic_absent[] = { + /* enable internal mic, port C */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + + /* switch to internal mic input */ + {0x17, AC_VERB_SET_CONNECT_SEL, 1}, + + /* disable external mic, port B */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {} + }; + + present = snd_hda_codec_read(codec, 0x1a, 0, + AC_VERB_GET_PIN_SENSE, 0) & + 0x80000000; + if (present) { + snd_printdd("CXT5066: external microphone detected\n"); + snd_hda_sequence_write(codec, ext_mic_present); + } else { + snd_printdd("CXT5066: external microphone absent\n"); + snd_hda_sequence_write(codec, ext_mic_absent); + } } } @@ -2090,6 +2118,7 @@ struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; unsigned int idx; @@ -2103,6 +2132,14 @@ AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | imux->items[idx].index); + if (spec->int_mic_nid) { + /* adjust the internal microphone's gain simultaneously (for + * IdeaPad) */ + snd_hda_codec_write_cache(codec, spec->int_mic_nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT | + imux->items[idx].index); + } return 1; } @@ -2302,6 +2339,64 @@ { } /* end */ }; +static struct hda_verb cxt5066_init_verbs_ideapad[] = { + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ + {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ + + /* Speakers */ + {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* HP, Amp */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* DAC1 */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to int mic */ + + /* Audio input selector */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, + {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ + + /* SPDIF route: PCM */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, + + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* internal microphone */ + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)|0x02}, /* 20dB */ + + /* EAPD */ + {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ + + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + + { } /* end */ +}; + /* initialize jack-sensing, too */ static int cxt5066_init(struct hda_codec *codec) { @@ -2318,6 +2413,7 @@ CXT5066_LAPTOP, /* Laptops w/ EAPD support */ CXT5066_DELL_LAPTOP, /* Dell Laptop */ CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ + CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ CXT5066_MODELS }; @@ -2325,6 +2421,7 @@ [CXT5066_LAPTOP] = "laptop", [CXT5066_DELL_LAPTOP] = "dell-laptop", [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", + [CXT5066_IDEAPAD] = "ideapad", }; static struct snd_pci_quirk cxt5066_cfg_tbl[] = { @@ -2333,6 +2430,7 @@ SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", CXT5066_DELL_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), {} }; @@ -2399,6 +2497,14 @@ /* input source automatically selected */ spec->input_mux = NULL; + break; + case CXT5066_IDEAPAD: + codec->patch_ops.unsol_event = cxt5066_unsol_event; + spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; + spec->mixers[spec->num_mixers++] = cxt5066_mixers; + spec->init_verbs[spec->num_init_verbs++] = cxt5066_init_verbs_ideapad; + spec->int_mic_nid = 0x23; + spec->input_mux = NULL; /* automatic selection */ break; }