diff options
Diffstat (limited to 'sound/pci/hda/alc680_quirks.c')
-rw-r--r-- | sound/pci/hda/alc680_quirks.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/sound/pci/hda/alc680_quirks.c b/sound/pci/hda/alc680_quirks.c new file mode 100644 index 000000000000..0eeb227c7bc2 --- /dev/null +++ b/sound/pci/hda/alc680_quirks.c @@ -0,0 +1,222 @@ +/* + * 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, + + }, +}; |