| /* |
| * ALC680 quirk models |
| * included by patch_realtek.c |
| */ |
| |
| /* ALC680 models */ |
| enum { |
| ALC680_AUTO, |
| ALC680_BASE, |
| ALC680_MODEL_LAST, |
| }; |
| |
| #define ALC680_DIGIN_NID ALC880_DIGIN_NID |
| #define ALC680_DIGOUT_NID ALC880_DIGOUT_NID |
| #define alc680_modes alc260_modes |
| |
| static const hda_nid_t alc680_dac_nids[3] = { |
| /* Lout1, Lout2, hp */ |
| 0x02, 0x03, 0x04 |
| }; |
| |
| static const hda_nid_t alc680_adc_nids[3] = { |
| /* ADC0-2 */ |
| /* DMIC, MIC, Line-in*/ |
| 0x07, 0x08, 0x09 |
| }; |
| |
| /* |
| * Analog capture ADC cgange |
| */ |
| static hda_nid_t alc680_get_cur_adc(struct hda_codec *codec) |
| { |
| static hda_nid_t pins[] = {0x18, 0x19}; |
| static hda_nid_t adcs[] = {0x08, 0x09}; |
| int i; |
| |
| for (i = 0; i < ARRAY_SIZE(pins); i++) { |
| if (!is_jack_detectable(codec, pins[i])) |
| continue; |
| if (snd_hda_jack_detect(codec, pins[i])) |
| return adcs[i]; |
| } |
| return 0x07; |
| } |
| |
| static void alc680_rec_autoswitch(struct hda_codec *codec) |
| { |
| struct alc_spec *spec = codec->spec; |
| hda_nid_t nid = alc680_get_cur_adc(codec); |
| if (spec->cur_adc && nid != spec->cur_adc) { |
| __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); |
| spec->cur_adc = nid; |
| snd_hda_codec_setup_stream(codec, nid, |
| spec->cur_adc_stream_tag, 0, |
| spec->cur_adc_format); |
| } |
| } |
| |
| static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, |
| struct hda_codec *codec, |
| unsigned int stream_tag, |
| unsigned int format, |
| struct snd_pcm_substream *substream) |
| { |
| struct alc_spec *spec = codec->spec; |
| hda_nid_t nid = alc680_get_cur_adc(codec); |
| |
| spec->cur_adc = nid; |
| spec->cur_adc_stream_tag = stream_tag; |
| spec->cur_adc_format = format; |
| snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); |
| return 0; |
| } |
| |
| static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, |
| struct hda_codec *codec, |
| struct snd_pcm_substream *substream) |
| { |
| struct alc_spec *spec = codec->spec; |
| snd_hda_codec_cleanup_stream(codec, spec->cur_adc); |
| spec->cur_adc = 0; |
| return 0; |
| } |
| |
| static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = { |
| .substreams = 1, /* can be overridden */ |
| .channels_min = 2, |
| .channels_max = 2, |
| /* NID is set in alc_build_pcms */ |
| .ops = { |
| .prepare = alc680_capture_pcm_prepare, |
| .cleanup = alc680_capture_pcm_cleanup |
| }, |
| }; |
| |
| static const struct snd_kcontrol_new alc680_base_mixer[] = { |
| /* output mixer control */ |
| HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), |
| HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), |
| HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), |
| HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), |
| HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT), |
| HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), |
| HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT), |
| { } |
| }; |
| |
| static const struct hda_bind_ctls alc680_bind_cap_vol = { |
| .ops = &snd_hda_bind_vol, |
| .values = { |
| HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), |
| HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), |
| HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), |
| 0 |
| }, |
| }; |
| |
| static const struct hda_bind_ctls alc680_bind_cap_switch = { |
| .ops = &snd_hda_bind_sw, |
| .values = { |
| HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), |
| HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), |
| HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), |
| 0 |
| }, |
| }; |
| |
| static const struct snd_kcontrol_new alc680_master_capture_mixer[] = { |
| HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), |
| HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), |
| { } /* end */ |
| }; |
| |
| /* |
| * generic initialization of ADC, input mixers and output mixers |
| */ |
| static const struct hda_verb alc680_init_verbs[] = { |
| {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
| {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
| {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
| |
| {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
| {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
| {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
| {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
| {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
| {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
| |
| {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
| {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
| {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
| {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
| {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
| |
| {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, |
| {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, |
| {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, |
| |
| { } |
| }; |
| |
| /* toggle speaker-output according to the hp-jack state */ |
| static void alc680_base_setup(struct hda_codec *codec) |
| { |
| struct alc_spec *spec = codec->spec; |
| |
| spec->autocfg.hp_pins[0] = 0x16; |
| spec->autocfg.speaker_pins[0] = 0x14; |
| spec->autocfg.speaker_pins[1] = 0x15; |
| spec->autocfg.num_inputs = 2; |
| spec->autocfg.inputs[0].pin = 0x18; |
| spec->autocfg.inputs[0].type = AUTO_PIN_MIC; |
| spec->autocfg.inputs[1].pin = 0x19; |
| spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN; |
| spec->automute = 1; |
| spec->automute_mode = ALC_AUTOMUTE_AMP; |
| } |
| |
| static void alc680_unsol_event(struct hda_codec *codec, |
| unsigned int res) |
| { |
| if ((res >> 26) == ALC_HP_EVENT) |
| alc_hp_automute(codec); |
| if ((res >> 26) == ALC_MIC_EVENT) |
| alc680_rec_autoswitch(codec); |
| } |
| |
| static void alc680_inithook(struct hda_codec *codec) |
| { |
| alc_hp_automute(codec); |
| alc680_rec_autoswitch(codec); |
| } |
| |
| /* |
| * configuration and preset |
| */ |
| static const char * const alc680_models[ALC680_MODEL_LAST] = { |
| [ALC680_BASE] = "base", |
| [ALC680_AUTO] = "auto", |
| }; |
| |
| static const struct snd_pci_quirk alc680_cfg_tbl[] = { |
| SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), |
| {} |
| }; |
| |
| static const struct alc_config_preset alc680_presets[] = { |
| [ALC680_BASE] = { |
| .mixers = { alc680_base_mixer }, |
| .cap_mixer = alc680_master_capture_mixer, |
| .init_verbs = { alc680_init_verbs }, |
| .num_dacs = ARRAY_SIZE(alc680_dac_nids), |
| .dac_nids = alc680_dac_nids, |
| .dig_out_nid = ALC680_DIGOUT_NID, |
| .num_channel_mode = ARRAY_SIZE(alc680_modes), |
| .channel_mode = alc680_modes, |
| .unsol_event = alc680_unsol_event, |
| .setup = alc680_base_setup, |
| .init_hook = alc680_inithook, |
| |
| }, |
| }; |