From d0ea6d270bd9f1883f716f92e7837152a4146cf7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 6 Jun 2014 18:17:31 +0200 Subject: ALSA: hda - Remove the obsoleted static quirk codes from patch_conexant.c The static quirk code has been disabled for a while and it seems working fine, so it's time to actually get rid of it. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 2715 +--------------------------------------- 1 file changed, 51 insertions(+), 2664 deletions(-) (limited to 'sound/pci/hda/patch_conexant.c') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 1dc7e974f3b1..7627a69ca6d7 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -34,2671 +34,65 @@ #include "hda_jack.h" #include "hda_generic.h" -#undef ENABLE_CXT_STATIC_QUIRKS - -#define CXT_PIN_DIR_IN 0x00 -#define CXT_PIN_DIR_OUT 0x01 -#define CXT_PIN_DIR_INOUT 0x02 -#define CXT_PIN_DIR_IN_NOMICBIAS 0x03 -#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04 - -#define CONEXANT_HP_EVENT 0x37 -#define CONEXANT_MIC_EVENT 0x38 -#define CONEXANT_LINE_EVENT 0x39 - -/* Conexant 5051 specific */ - -#define CXT5051_SPDIF_OUT 0x12 -#define CXT5051_PORTB_EVENT 0x38 -#define CXT5051_PORTC_EVENT 0x39 - -#define AUTO_MIC_PORTB (1 << 1) -#define AUTO_MIC_PORTC (1 << 2) - -struct conexant_spec { - struct hda_gen_spec gen; - - unsigned int beep_amp; - - /* extra EAPD pins */ - unsigned int num_eapds; - hda_nid_t eapds[4]; - bool dynamic_eapd; - - unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ - - /* OPLC XO specific */ - bool recording; - bool dc_enable; - unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */ - struct nid_path *dc_mode_path; - -#ifdef ENABLE_CXT_STATIC_QUIRKS - const struct snd_kcontrol_new *mixers[5]; - int num_mixers; - hda_nid_t vmaster_nid; - - const struct hda_verb *init_verbs[5]; /* initialization verbs - * don't forget NULL - * termination! - */ - unsigned int num_init_verbs; - - /* playback */ - struct hda_multi_out multiout; /* playback set-up - * max_channels, dacs must be set - * dig_out_nid and hp_nid are optional - */ - unsigned int cur_eapd; - unsigned int hp_present; - unsigned int line_present; - unsigned int auto_mic; - - /* capture */ - unsigned int num_adc_nids; - const hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; /* digital-in NID; optional */ - - unsigned int cur_adc_idx; - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; - - const struct hda_pcm_stream *capture_stream; - - /* capture source */ - const struct hda_input_mux *input_mux; - const hda_nid_t *capsrc_nids; - unsigned int cur_mux[3]; - - /* channel model */ - const struct hda_channel_mode *channel_mode; - int num_channel_mode; - - /* PCM information */ - struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ - - unsigned int spdif_route; - - unsigned int port_d_mode; - unsigned int dell_automute:1; - unsigned int dell_vostro:1; - unsigned int ideapad:1; - unsigned int thinkpad:1; - unsigned int hp_laptop:1; - unsigned int asus:1; - - unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ -#endif /* ENABLE_CXT_STATIC_QUIRKS */ -}; - - -#ifdef CONFIG_SND_HDA_INPUT_BEEP -static inline void set_beep_amp(struct conexant_spec *spec, hda_nid_t nid, - int idx, int dir) -{ - spec->gen.beep_nid = nid; - spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); -} -/* additional beep mixers; the actual parameters are overwritten at build */ -static const struct snd_kcontrol_new cxt_beep_mixer[] = { - HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), - HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), - { } /* end */ -}; - -/* create beep controls if needed */ -static int add_beep_ctls(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int err; - - if (spec->beep_amp) { - const struct snd_kcontrol_new *knew; - for (knew = cxt_beep_mixer; knew->name; knew++) { - struct snd_kcontrol *kctl; - kctl = snd_ctl_new1(knew, codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - } - } - return 0; -} -#else -#define set_beep_amp(spec, nid, idx, dir) /* NOP */ -#define add_beep_ctls(codec) 0 -#endif - - -#ifdef ENABLE_CXT_STATIC_QUIRKS -static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, - format, substream); -} - -static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int conexant_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int conexant_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 conexant_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - return 0; -} - - - -static const struct hda_pcm_stream conexant_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = conexant_playback_pcm_open, - .prepare = conexant_playback_pcm_prepare, - .cleanup = conexant_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream conexant_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = conexant_capture_pcm_prepare, - .cleanup = conexant_capture_pcm_cleanup - }, -}; - - -static const struct hda_pcm_stream conexant_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = conexant_dig_playback_pcm_open, - .close = conexant_dig_playback_pcm_close, - .prepare = conexant_dig_playback_pcm_prepare - }, -}; - -static const struct hda_pcm_stream conexant_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static int cx5051_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 conexant_spec *spec = codec->spec; - spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - return 0; -} - -static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_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 cx5051_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = cx5051_capture_pcm_prepare, - .cleanup = cx5051_capture_pcm_cleanup - }, -}; - -static int conexant_build_pcms(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "CONEXANT Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dac_nids[0]; - if (spec->capture_stream) - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; - else { - if (codec->vendor_id == 0x14f15051) - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - cx5051_pcm_analog_capture; - else { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - conexant_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids; - } - } - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - - if (spec->multiout.dig_out_nid) { - info++; - codec->num_pcms++; - info->name = "Conexant Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - conexant_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dig_out_nid; - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - conexant_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->dig_in_nid; - } - } - - return 0; -} - -static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->capsrc_nids[adc_idx], - &spec->cur_mux[adc_idx]); -} - -static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state) -{ - if (power_state == AC_PWRST_D3) - msleep(100); - snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, - power_state); - /* partial workaround for "azx_get_response timeout" */ - if (power_state == AC_PWRST_D0) - msleep(10); - snd_hda_codec_set_power_to_all(codec, fg, power_state); -} - -static int conexant_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); - return 0; -} - -static void conexant_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -static const struct snd_kcontrol_new cxt_capture_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put - }, - {} -}; - -static const char * const slave_pfxs[] = { - "Headphone", "Speaker", "Bass Speaker", "Front", "Surround", "CLFE", - NULL -}; - -static int conexant_build_controls(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int i; - int err; - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid); - if (err < 0) - return err; - } - - /* if we have no master control, let's create it */ - if (spec->vmaster_nid && - !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, - HDA_OUTPUT, vmaster_tlv); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, slave_pfxs, - "Playback Volume"); - if (err < 0) - return err; - } - if (spec->vmaster_nid && - !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_pfxs, - "Playback Switch"); - if (err < 0) - return err; - } - - if (spec->input_mux) { - err = snd_hda_add_new_ctls(codec, cxt_capture_mixers); - if (err < 0) - return err; - } - - err = add_beep_ctls(codec); - if (err < 0) - return err; - - return 0; -} - -static const struct hda_codec_ops conexant_patch_ops = { - .build_controls = conexant_build_controls, - .build_pcms = conexant_build_pcms, - .init = conexant_init, - .free = conexant_free, - .set_power_state = conexant_set_power, -}; - -static int patch_conexant_auto(struct hda_codec *codec); -/* - * EAPD control - * the private value = nid | (invert << 8) - */ - -#define cxt_eapd_info snd_ctl_boolean_mono_info - -static int cxt_eapd_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; - if (invert) - ucontrol->value.integer.value[0] = !spec->cur_eapd; - else - ucontrol->value.integer.value[0] = spec->cur_eapd; - return 0; - -} - -static int cxt_eapd_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; - hda_nid_t nid = kcontrol->private_value & 0xff; - unsigned int eapd; - - eapd = !!ucontrol->value.integer.value[0]; - if (invert) - eapd = !eapd; - if (eapd == spec->cur_eapd) - return 0; - - spec->cur_eapd = eapd; - snd_hda_codec_write_cache(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); - return 1; -} - -/* controls for test mode */ -#ifdef CONFIG_SND_DEBUG - -#define CXT_EAPD_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = cxt_eapd_info, \ - .get = cxt_eapd_get, \ - .put = cxt_eapd_put, \ - .private_value = nid | (mask<<16) } - - - -static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - spec->multiout.max_channels); -} - -static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->multiout.max_channels); - return err; -} - -#define CXT_PIN_MODE(xname, nid, dir) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = conexant_ch_mode_info, \ - .get = conexant_ch_mode_get, \ - .put = conexant_ch_mode_put, \ - .private_value = nid | (dir<<16) } - -#endif /* CONFIG_SND_DEBUG */ - -/* Conexant 5045 specific */ - -static const hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; -static const hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; -static const hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; -#define CXT5045_SPDIF_OUT 0x18 - -static const struct hda_channel_mode cxt5045_modes[1] = { - { 2, NULL }, -}; - -static const struct hda_input_mux cxt5045_capture_source = { - .num_items = 2, - .items = { - { "Internal Mic", 0x1 }, - { "Mic", 0x2 }, - } -}; - -static const struct hda_input_mux cxt5045_capture_source_benq = { - .num_items = 4, - .items = { - { "Internal Mic", 0x1 }, - { "Mic", 0x2 }, - { "Line", 0x3 }, - { "Mixer", 0x0 }, - } -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle internal speakers mute depending of presence of - * the headphone jack - */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - - bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x11, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - return 1; -} - -/* bind volumes of both NID 0x10 and 0x11 */ -static const struct hda_bind_ctls cxt5045_hp_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5045_hp_automic(struct hda_codec *codec) -{ - static const struct hda_verb mic_jack_on[] = { - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - static const struct hda_verb mic_jack_off[] = { - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x12); - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - - -/* mute internal speaker if HP is plugged */ -static void cxt5045_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - spec->hp_present = snd_hda_jack_detect(codec, 0x11); - - bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5045_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_hp_automic(codec); - break; - - } -} - -static const struct snd_kcontrol_new cxt5045_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x2, 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 snd_kcontrol_new cxt5045_benq_mixers[] = { - HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x3, HDA_INPUT), - - {} -}; - -static const struct hda_verb cxt5045_init_verbs[] = { - /* Line in, Mic */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - /* 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: Internal mic */ - {0x1a, AC_VERB_SET_CONNECT_SEL,0x1}, - {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 */ - { } /* end */ -}; - -static const struct hda_verb cxt5045_benq_init_verbs[] = { - /* Internal Mic, Mic */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - /* Line In,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_IN}, - {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: Internal mic */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1}, - {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 */ - { } /* 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}, - { } /* end */ -}; - -static const struct hda_verb cxt5045_mic_sense_init_verbs[] = { - /* pin sensing on HP jack */ - {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -#ifdef CONFIG_SND_DEBUG -/* Test configuration for debugging, modelled after the ALC260 test - * configuration. - */ -static const struct hda_input_mux cxt5045_test_capture_source = { - .num_items = 5, - .items = { - { "MIXER", 0x0 }, - { "MIC1 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "HP-OUT pin", 0x3 }, - { "CD pin", 0x4 }, - }, -}; - -static const struct snd_kcontrol_new cxt5045_test_mixer[] = { - - /* Output controls */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("HP-OUT Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("HP-OUT Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("LINE1 Playback Switch", 0x12, 0x0, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT), - CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT), - - /* EAPD Switch Control */ - CXT_EAPD_SWITCH("External Amplifier", 0x10, 0x0), - - /* Loopback mixer controls */ - - HDA_CODEC_VOLUME("PCM Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("PCM Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("MIC1 pin Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 pin Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("LINE1 pin Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("LINE1 pin Switch", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("HP-OUT pin Volume", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("HP-OUT pin Switch", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("CD pin Volume", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD pin Switch", 0x17, 0x4, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put, - }, - /* Audio input controls */ - HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb cxt5045_test_init_verbs[] = { - /* Set connections */ - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { 0x12, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* Enable retasking pins as output, initially without power amp */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - - { } -}; -#endif - - -/* initialize jack-sensing, too */ -static int cxt5045_init(struct hda_codec *codec) -{ - conexant_init(codec); - cxt5045_hp_automute(codec); - return 0; -} - - -enum { - CXT5045_LAPTOP_HPSENSE, - CXT5045_LAPTOP_MICSENSE, - CXT5045_LAPTOP_HPMICSENSE, - CXT5045_BENQ, -#ifdef CONFIG_SND_DEBUG - CXT5045_TEST, -#endif - CXT5045_AUTO, - CXT5045_MODELS -}; - -static const char * const cxt5045_models[CXT5045_MODELS] = { - [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", - [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", - [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", - [CXT5045_BENQ] = "benq", -#ifdef CONFIG_SND_DEBUG - [CXT5045_TEST] = "test", -#endif - [CXT5045_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { - SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), - SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), - SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", - CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK_MASK(0x1631, 0xff00, 0xc100, "Packard Bell", - CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE), - {} -}; - -static int patch_cxt5045(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, - cxt5045_models, - cxt5045_cfg_tbl); - if (board_config < 0) - board_config = CXT5045_AUTO; /* model=auto as default */ - if (board_config == CXT5045_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->single_adc_amp = 1; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids); - spec->multiout.dac_nids = cxt5045_dac_nids; - spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = cxt5045_adc_nids; - spec->capsrc_nids = cxt5045_capsrc_nids; - spec->input_mux = &cxt5045_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = cxt5045_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5045_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes); - spec->channel_mode = cxt5045_modes; - - set_beep_amp(spec, 0x16, 0, 1); - - codec->patch_ops = conexant_patch_ops; - - switch (board_config) { - case CXT5045_LAPTOP_HPSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - case CXT5045_LAPTOP_MICSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - default: - case CXT5045_LAPTOP_HPMICSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 3; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->init_verbs[2] = cxt5045_mic_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - case CXT5045_BENQ: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source_benq; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5045_benq_init_verbs; - spec->mixers[0] = cxt5045_mixers; - spec->mixers[1] = cxt5045_benq_mixers; - spec->num_mixers = 2; - codec->patch_ops.init = cxt5045_init; - break; -#ifdef CONFIG_SND_DEBUG - case CXT5045_TEST: - spec->input_mux = &cxt5045_test_capture_source; - spec->mixers[0] = cxt5045_test_mixer; - spec->init_verbs[0] = cxt5045_test_init_verbs; - break; - -#endif - } - - switch (codec->subsystem_id >> 16) { - case 0x103c: - case 0x1631: - case 0x1734: - case 0x17aa: - /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have - * really bad sound over 0dB on NID 0x17. Fix max PCM level to - * 0 dB (originally it has 0x2b steps with 0dB offset 0x14) - */ - snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, - (0x14 << AC_AMPCAP_OFFSET_SHIFT) | - (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - - return 0; -} - - -/* Conexant 5047 specific */ -#define CXT5047_SPDIF_OUT 0x11 - -static const hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ -static const hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; -static const hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; - -static const struct hda_channel_mode cxt5047_modes[1] = { - { 2, NULL }, -}; - -static const struct hda_input_mux cxt5047_toshiba_capture_source = { - .num_items = 2, - .items = { - { "ExtMic", 0x2 }, - { "Line-In", 0x1 }, - } -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle internal speakers mute depending of presence of - * the headphone jack - */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; - /* NOTE: Conexat codec needs the index for *OUTPUT* amp of - * pin widgets unlike other codecs. In this case, we need to - * set index 0x01 for the volume from the mixer amp 0x19. - */ - snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, - HDA_AMP_MUTE, bits); - bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - return 1; -} - -/* mute internal speaker if HP is plugged */ -static void cxt5047_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - spec->hp_present = snd_hda_jack_detect(codec, 0x13); - - bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; - /* See the note in cxt5047_hp_master_sw_put */ - snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, - HDA_AMP_MUTE, bits); -} - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5047_hp_automic(struct hda_codec *codec) -{ - static const struct hda_verb mic_jack_on[] = { - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {} - }; - static const struct hda_verb mic_jack_off[] = { - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {} - }; - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x15); - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5047_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5047_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5047_hp_automic(codec); - break; - } -} - -static const struct snd_kcontrol_new cxt5047_base_mixers[] = { - HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5047_hp_master_sw_put, - .private_value = 0x13, - }, - - {} -}; - -static const struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { - /* See the note in cxt5047_hp_master_sw_put */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), - { } /* end */ -}; - -static const struct hda_verb cxt5047_init_verbs[] = { - /* Line in, Mic, Built-in Mic */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, - /* HP, Speaker */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, /* mixer(0x19) */ - {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mixer(0x19) */ - /* Record selector: Mic */ - {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - {0x1A, AC_VERB_SET_CONNECT_SEL,0x02}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, - /* SPDIF route: PCM */ - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* Enable unsolicited events */ - {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -/* configuration for Toshiba Laptops */ -static const struct hda_verb cxt5047_toshiba_init_verbs[] = { - {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ - {} -}; - -/* Test configuration for debugging, modelled after the ALC260 test - * configuration. - */ -#ifdef CONFIG_SND_DEBUG -static const struct hda_input_mux cxt5047_test_capture_source = { - .num_items = 4, - .items = { - { "LINE1 pin", 0x0 }, - { "MIC1 pin", 0x1 }, - { "MIC2 pin", 0x2 }, - { "CD pin", 0x3 }, - }, -}; - -static const struct snd_kcontrol_new cxt5047_test_mixer[] = { - - /* Output only controls */ - HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line1-Out Playback Volume", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line1-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line2-Out Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line2-Out Playback Switch", 0x15, 0x0, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT), - CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT), - - /* EAPD Switch Control */ - CXT_EAPD_SWITCH("External Amplifier", 0x13, 0x0), - - /* Loopback mixer controls */ - HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x12, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 Playback Switch", 0x12, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x12, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("MIC2 Playback Switch", 0x12, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LINE Playback Volume", 0x12, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("LINE Playback Switch", 0x12, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x12, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x12, 0x04, HDA_INPUT), - - HDA_CODEC_VOLUME("Capture-1 Volume", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture-1 Switch", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-2 Volume", 0x19, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Capture-2 Switch", 0x19, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-3 Volume", 0x19, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Capture-3 Switch", 0x19, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-4 Volume", 0x19, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Capture-4 Switch", 0x19, 0x3, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put, - }, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), - - { } /* end */ -}; - -static const struct hda_verb cxt5047_test_init_verbs[] = { - /* Enable retasking pins as output, initially without power amp */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure mic1, mic2, line1 pin widgets take input from the - * OUT1 sum bus when acting as an output. - */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; -#endif - - -/* initialize jack-sensing, too */ -static int cxt5047_hp_init(struct hda_codec *codec) -{ - conexant_init(codec); - cxt5047_hp_automute(codec); - return 0; -} - - -enum { - CXT5047_LAPTOP, /* Laptops w/o EAPD support */ - CXT5047_LAPTOP_HP, /* Some HP laptops */ - CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */ -#ifdef CONFIG_SND_DEBUG - CXT5047_TEST, -#endif - CXT5047_AUTO, - CXT5047_MODELS -}; - -static const char * const cxt5047_models[CXT5047_MODELS] = { - [CXT5047_LAPTOP] = "laptop", - [CXT5047_LAPTOP_HP] = "laptop-hp", - [CXT5047_LAPTOP_EAPD] = "laptop-eapd", -#ifdef CONFIG_SND_DEBUG - [CXT5047_TEST] = "test", -#endif - [CXT5047_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5047_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", - CXT5047_LAPTOP), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), - {} -}; - -static int patch_cxt5047(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, - cxt5047_models, - cxt5047_cfg_tbl); - if (board_config < 0) - board_config = CXT5047_AUTO; /* model=auto as default */ - if (board_config == CXT5047_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->pin_amp_workaround = 1; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids); - spec->multiout.dac_nids = cxt5047_dac_nids; - spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = cxt5047_adc_nids; - spec->capsrc_nids = cxt5047_capsrc_nids; - spec->num_mixers = 1; - spec->mixers[0] = cxt5047_base_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5047_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes), - spec->channel_mode = cxt5047_modes, - - codec->patch_ops = conexant_patch_ops; - - switch (board_config) { - case CXT5047_LAPTOP: - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_spk_mixers; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - break; - case CXT5047_LAPTOP_HP: - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_only_mixers; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - codec->patch_ops.init = cxt5047_hp_init; - break; - case CXT5047_LAPTOP_EAPD: - spec->input_mux = &cxt5047_toshiba_capture_source; - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_spk_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5047_toshiba_init_verbs; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - break; -#ifdef CONFIG_SND_DEBUG - case CXT5047_TEST: - spec->input_mux = &cxt5047_test_capture_source; - spec->mixers[0] = cxt5047_test_mixer; - spec->init_verbs[0] = cxt5047_test_init_verbs; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; -#endif - } - spec->vmaster_nid = 0x13; - - switch (codec->subsystem_id >> 16) { - case 0x103c: - /* HP laptops have really bad sound over 0 dB on NID 0x10. - * Fix max PCM level to 0 dB (originally it has 0x1e steps - * with 0 dB offset 0x17) - */ - snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - } - - return 0; -} - -/* Conexant 5051 specific */ -static const hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; -static const hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; - -static const struct hda_channel_mode cxt5051_modes[1] = { - { 2, NULL }, -}; - -static void cxt5051_update_speaker(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int pinctl; - /* headphone pin */ - pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0; - snd_hda_set_pin_ctl(codec, 0x16, pinctl); - /* speaker pin */ - pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; - snd_hda_set_pin_ctl(codec, 0x1a, pinctl); - /* on ideapad there is an additional speaker (subwoofer) to mute */ - if (spec->ideapad) - snd_hda_set_pin_ctl(codec, 0x1b, pinctl); -} - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - cxt5051_update_speaker(codec); - return 1; -} - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5051_portb_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int present; - - if (!(spec->auto_mic & AUTO_MIC_PORTB)) - return; - present = snd_hda_jack_detect(codec, 0x17); - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_CONNECT_SEL, - present ? 0x01 : 0x00); -} - -/* switch the current ADC according to the jack state */ -static void cxt5051_portc_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int present; - hda_nid_t new_adc; - - if (!(spec->auto_mic & AUTO_MIC_PORTC)) - return; - present = snd_hda_jack_detect(codec, 0x18); - if (present) - spec->cur_adc_idx = 1; - else - spec->cur_adc_idx = 0; - new_adc = spec->adc_nids[spec->cur_adc_idx]; - if (spec->cur_adc && spec->cur_adc != new_adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = new_adc; - snd_hda_codec_setup_stream(codec, new_adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - } -} - -/* mute internal speaker if HP is plugged */ -static void cxt5051_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - - spec->hp_present = snd_hda_jack_detect(codec, 0x16); - cxt5051_update_speaker(codec); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5051_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5051_hp_automute(codec); - break; - case CXT5051_PORTB_EVENT: - cxt5051_portb_automic(codec); - break; - case CXT5051_PORTC_EVENT: - cxt5051_portc_automic(codec); - break; - } -} - -static const struct snd_kcontrol_new cxt5051_playback_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5051_hp_master_sw_put, - .private_value = 0x1a, - }, - {} -}; - -static const struct snd_kcontrol_new cxt5051_capture_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Switch", 0x15, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_hp_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x15, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_f700_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), - {} -}; - -static const struct hda_verb cxt5051_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5051_f700_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, - unsigned int event) -{ - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | event); -} - -static const struct hda_verb cxt5051_ideapad_init_verbs[] = { - /* Subwoofer */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } /* end */ -}; - -/* initialize jack-sensing, too */ -static int cxt5051_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - - conexant_init(codec); - - if (spec->auto_mic & AUTO_MIC_PORTB) - cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT); - if (spec->auto_mic & AUTO_MIC_PORTC) - cxt5051_init_mic_port(codec, 0x18, CXT5051_PORTC_EVENT); - - if (codec->patch_ops.unsol_event) { - cxt5051_hp_automute(codec); - cxt5051_portb_automic(codec); - cxt5051_portc_automic(codec); - } - return 0; -} - - -enum { - CXT5051_LAPTOP, /* Laptops w/ EAPD support */ - CXT5051_HP, /* no docking */ - CXT5051_HP_DV6736, /* HP without mic switch */ - CXT5051_F700, /* HP Compaq Presario F700 */ - CXT5051_TOSHIBA, /* Toshiba M300 & co */ - CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ - CXT5051_AUTO, /* auto-parser */ - CXT5051_MODELS -}; - -static const char *const cxt5051_models[CXT5051_MODELS] = { - [CXT5051_LAPTOP] = "laptop", - [CXT5051_HP] = "hp", - [CXT5051_HP_DV6736] = "hp-dv6736", - [CXT5051_F700] = "hp-700", - [CXT5051_TOSHIBA] = "toshiba", - [CXT5051_IDEAPAD] = "ideapad", - [CXT5051_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), - SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), - SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), - SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba M30x", CXT5051_TOSHIBA), - SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", - CXT5051_LAPTOP), - SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD), - {} -}; - -static int patch_cxt5051(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, - cxt5051_models, - cxt5051_cfg_tbl); - if (board_config < 0) - board_config = CXT5051_AUTO; /* model=auto as default */ - if (board_config == CXT5051_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->pin_amp_workaround = 1; - - codec->patch_ops = conexant_patch_ops; - codec->patch_ops.init = cxt5051_init; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids); - spec->multiout.dac_nids = cxt5051_dac_nids; - spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; - spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ - spec->adc_nids = cxt5051_adc_nids; - spec->num_mixers = 2; - spec->mixers[0] = cxt5051_capture_mixers; - spec->mixers[1] = cxt5051_playback_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5051_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes); - spec->channel_mode = cxt5051_modes; - spec->cur_adc = 0; - spec->cur_adc_idx = 0; - - set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); - - codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; - - spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; - switch (board_config) { - case CXT5051_HP: - spec->mixers[0] = cxt5051_hp_mixers; - break; - case CXT5051_HP_DV6736: - spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; - spec->mixers[0] = cxt5051_hp_dv6736_mixers; - spec->auto_mic = 0; - break; - case CXT5051_F700: - spec->init_verbs[0] = cxt5051_f700_init_verbs; - spec->mixers[0] = cxt5051_f700_mixers; - spec->auto_mic = 0; - break; - case CXT5051_TOSHIBA: - spec->mixers[0] = cxt5051_toshiba_mixers; - spec->auto_mic = AUTO_MIC_PORTB; - break; - case CXT5051_IDEAPAD: - spec->init_verbs[spec->num_init_verbs++] = - cxt5051_ideapad_init_verbs; - spec->ideapad = 1; - break; - } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - - return 0; -} - -/* Conexant 5066 specific */ - -static const hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; -static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; -static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; -static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; - -static const struct hda_channel_mode cxt5066_modes[1] = { - { 2, NULL }, -}; - -#define HP_PRESENT_PORT_A (1 << 0) -#define HP_PRESENT_PORT_D (1 << 1) -#define hp_port_a_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_A) -#define hp_port_d_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_D) - -static void cxt5066_update_speaker(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int pinctl; - - codec_dbg(codec, - "CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n", - spec->hp_present, spec->cur_eapd); - - /* Port A (HP) */ - pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0; - snd_hda_set_pin_ctl(codec, 0x19, pinctl); - - /* Port D (HP/LO) */ - pinctl = spec->cur_eapd ? spec->port_d_mode : 0; - if (spec->dell_automute || spec->thinkpad) { - /* Mute if Port A is connected */ - if (hp_port_a_present(spec)) - pinctl = 0; - } else { - /* Thinkpad/Dell doesn't give pin-D status */ - if (!hp_port_d_present(spec)) - pinctl = 0; - } - snd_hda_set_pin_ctl(codec, 0x1c, pinctl); - - /* CLASS_D AMP */ - pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; - snd_hda_set_pin_ctl(codec, 0x1f, pinctl); -} - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - cxt5066_update_speaker(codec); - return 1; -} - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_vostro_automic(struct hda_codec *codec) -{ - unsigned int present; - - struct hda_verb ext_mic_present[] = { - /* enable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - - /* switch to external mic input */ - {0x17, AC_VERB_SET_CONNECT_SEL, 0}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - - /* disable internal digital mic */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb ext_mic_absent[] = { - /* enable internal mic, port C */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* switch to internal mic input */ - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - - /* disable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - present = snd_hda_jack_detect(codec, 0x1a); - if (present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_ideapad_automic(struct hda_codec *codec) -{ - unsigned int present; - - struct hda_verb ext_mic_present[] = { - {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 const struct hda_verb ext_mic_absent[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - present = snd_hda_jack_detect(codec, 0x1b); - if (present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_asus_automic(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x1b); - codec_dbg(codec, "CXT5066: external microphone present=%d\n", present); - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, - present ? 1 : 0); -} - - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_hp_laptop_automic(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x1b); - codec_dbg(codec, "CXT5066: external microphone present=%d\n", present); - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, - present ? 1 : 3); -} - - -/* toggle input of built-in digital mic and mic jack appropriately - order is: external mic -> dock mic -> interal mic */ -static void cxt5066_thinkpad_automic(struct hda_codec *codec) -{ - unsigned int ext_present, dock_present; - - static const struct hda_verb ext_mic_present[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb dock_mic_present[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb ext_mic_absent[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - ext_present = snd_hda_jack_detect(codec, 0x1b); - dock_present = snd_hda_jack_detect(codec, 0x1a); - if (ext_present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else if (dock_present) { - codec_dbg(codec, "CXT5066: dock microphone detected\n"); - snd_hda_sequence_write(codec, dock_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - -/* mute internal speaker if HP is plugged */ -static void cxt5066_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int portA, portD; - - /* Port A */ - portA = snd_hda_jack_detect(codec, 0x19); - - /* Port D */ - portD = snd_hda_jack_detect(codec, 0x1c); - - spec->hp_present = portA ? HP_PRESENT_PORT_A : 0; - spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0; - codec_dbg(codec, "CXT5066: hp automute portA=%x portD=%x present=%d\n", - portA, portD, spec->hp_present); - cxt5066_update_speaker(codec); -} - -/* Dispatch the right mic autoswitch function */ -static void cxt5066_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; +struct conexant_spec { + struct hda_gen_spec gen; - if (spec->dell_vostro) - cxt5066_vostro_automic(codec); - else if (spec->ideapad) - cxt5066_ideapad_automic(codec); - else if (spec->thinkpad) - cxt5066_thinkpad_automic(codec); - else if (spec->hp_laptop) - cxt5066_hp_laptop_automic(codec); - else if (spec->asus) - cxt5066_asus_automic(codec); -} + unsigned int beep_amp; -/* unsolicited event for jack sensing */ -static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) -{ - codec_dbg(codec, "CXT5066: unsol event %x (%x)\n", res, res >> 26); - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5066_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5066_automic(codec); - break; - } -} + /* extra EAPD pins */ + unsigned int num_eapds; + hda_nid_t eapds[4]; + bool dynamic_eapd; + unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ -static const struct hda_input_mux cxt5066_analog_mic_boost = { - .num_items = 5, - .items = { - { "0dB", 0 }, - { "10dB", 1 }, - { "20dB", 2 }, - { "30dB", 3 }, - { "40dB", 4 }, - }, + /* OPLC XO specific */ + bool recording; + bool dc_enable; + unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */ + struct nid_path *dc_mode_path; }; -static void cxt5066_set_mic_boost(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | - cxt5066_analog_mic_boost.items[spec->mic_boost].index); - if (spec->ideapad || spec->thinkpad) { - /* adjust the internal mic as well...it is not through 0x17 */ - snd_hda_codec_write_cache(codec, 0x23, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT | - cxt5066_analog_mic_boost. - items[spec->mic_boost].index); - } -} - -static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - return snd_hda_input_mux_info(&cxt5066_analog_mic_boost, uinfo); -} - -static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->mic_boost; - return 0; -} - -static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, - 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; - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - - spec->mic_boost = idx; - cxt5066_set_mic_boost(codec); - return 1; -} -static void conexant_check_dig_outs(struct hda_codec *codec, - const hda_nid_t *dig_pins, - int num_pins) +#ifdef CONFIG_SND_HDA_INPUT_BEEP +static inline void set_beep_amp(struct conexant_spec *spec, hda_nid_t nid, + int idx, int dir) { - struct conexant_spec *spec = codec->spec; - hda_nid_t *nid_loc = &spec->multiout.dig_out_nid; - int i; - - for (i = 0; i < num_pins; i++, dig_pins++) { - unsigned int cfg = snd_hda_codec_get_pincfg(codec, *dig_pins); - if (get_defcfg_connect(cfg) == AC_JACK_PORT_NONE) - continue; - if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1) - continue; - } + spec->gen.beep_nid = nid; + spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); } - -static const struct hda_input_mux cxt5066_capture_source = { - .num_items = 4, - .items = { - { "Mic B", 0 }, - { "Mic C", 1 }, - { "Mic E", 2 }, - { "Mic F", 3 }, - }, -}; - -static const struct hda_bind_ctls cxt5066_bind_capture_vol_others = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), - 0 - }, -}; - -static const struct hda_bind_ctls cxt5066_bind_capture_sw_others = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new cxt5066_mixer_master[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5066_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5066_hp_master_sw_put, - .private_value = 0x1d, - }, - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Mic Boost Capture Enum", - .info = cxt5066_mic_boost_mux_enum_info, - .get = cxt5066_mic_boost_mux_enum_get, - .put = cxt5066_mic_boost_mux_enum_put, - }, - - HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), - HDA_BIND_SW("Capture Switch", &cxt5066_bind_capture_sw_others), - {} -}; - -static const struct snd_kcontrol_new cxt5066_vostro_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Internal Mic Boost Capture Enum", - .info = cxt5066_mic_boost_mux_enum_info, - .get = cxt5066_mic_boost_mux_enum_get, - .put = cxt5066_mic_boost_mux_enum_put, - .private_value = 0x23 | 0x100, - }, - {} -}; - -static const struct hda_verb cxt5066_init_verbs[] = { - {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)}, - - /* no digital microphone support yet */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Audio input selector */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, - - /* 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}, - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* not handling these yet */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {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 */ -}; - -static const struct hda_verb cxt5066_init_verbs_vostro[] = { - /* Port A: headphones */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port B: external microphone */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port C: unused */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port D: unused */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port E: unused, but has primary EAPD */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* Port F: unused */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port G: internal speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* DAC2: unused */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - - /* Digital microphone port */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* Audio input selectors */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - - /* Disable SPDIF */ - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* enable unsolicited events for Port A and B */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const 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 internal 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 internal mic */ - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_thinkpad[] = { - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ - - /* Port G: internal speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port A: HP, Amp */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port B: Mic Dock */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port C: Mic */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port D: HP Dock, Amp */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {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 internal 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 internal mic */ - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* enable unsolicited events for Port A, B, C and D */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_portd_lo[] = { - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { } /* end */ -}; - - -static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, +/* additional beep mixers; the actual parameters are overwritten at build */ +static const struct snd_kcontrol_new cxt_beep_mixer[] = { + HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), + HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), { } /* end */ }; -/* initialize jack-sensing, too */ -static int cxt5066_init(struct hda_codec *codec) -{ - codec_dbg(codec, "CXT5066: init\n"); - conexant_init(codec); - if (codec->patch_ops.unsol_event) { - cxt5066_hp_automute(codec); - cxt5066_automic(codec); - } - cxt5066_set_mic_boost(codec); - return 0; -} - -enum { - CXT5066_LAPTOP, /* Laptops w/ EAPD support */ - CXT5066_DELL_LAPTOP, /* Dell Laptop */ - CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ - CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ - CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ - CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */ - CXT5066_HP_LAPTOP, /* HP Laptop */ - CXT5066_AUTO, /* BIOS auto-parser */ - CXT5066_MODELS -}; - -static const char * const cxt5066_models[CXT5066_MODELS] = { - [CXT5066_LAPTOP] = "laptop", - [CXT5066_DELL_LAPTOP] = "dell-laptop", - [CXT5066_DELL_VOSTRO] = "dell-vostro", - [CXT5066_IDEAPAD] = "ideapad", - [CXT5066_THINKPAD] = "thinkpad", - [CXT5066_ASUS] = "asus", - [CXT5066_HP_LAPTOP] = "hp-laptop", - [CXT5066_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { - SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS), - SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS), - SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS), - SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", - CXT5066_LAPTOP), - SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), - {} -}; - -static int patch_cxt5066(struct hda_codec *codec) +/* create beep controls if needed */ +static int add_beep_ctls(struct hda_codec *codec) { - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, - cxt5066_models, cxt5066_cfg_tbl); - if (board_config < 0) - board_config = CXT5066_AUTO; /* model=auto as default */ - if (board_config == CXT5066_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - - codec->patch_ops = conexant_patch_ops; - codec->patch_ops.init = conexant_init; - - spec->dell_automute = 0; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); - spec->multiout.dac_nids = cxt5066_dac_nids; - conexant_check_dig_outs(codec, cxt5066_digout_pin_nids, - ARRAY_SIZE(cxt5066_digout_pin_nids)); - spec->num_adc_nids = 1; - spec->adc_nids = cxt5066_adc_nids; - spec->capsrc_nids = cxt5066_capsrc_nids; - spec->input_mux = &cxt5066_capture_source; - - spec->port_d_mode = PIN_HP; - - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5066_init_verbs; - spec->num_channel_mode = ARRAY_SIZE(cxt5066_modes); - spec->channel_mode = cxt5066_modes; - spec->cur_adc = 0; - spec->cur_adc_idx = 0; - - set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); - - switch (board_config) { - default: - case CXT5066_LAPTOP: - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - break; - case CXT5066_DELL_LAPTOP: - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - - spec->port_d_mode = PIN_OUT; - spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_portd_lo; - spec->num_init_verbs++; - spec->dell_automute = 1; - break; - case CXT5066_ASUS: - case CXT5066_HP_LAPTOP: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->init_verbs[spec->num_init_verbs] = - cxt5066_init_verbs_hp_laptop; - spec->num_init_verbs++; - spec->hp_laptop = board_config == CXT5066_HP_LAPTOP; - spec->asus = board_config == CXT5066_ASUS; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - /* no S/PDIF out */ - if (board_config == CXT5066_HP_LAPTOP) - spec->multiout.dig_out_nid = 0; - /* input source automatically selected */ - spec->input_mux = NULL; - spec->port_d_mode = 0; - spec->mic_boost = 3; /* default 30dB gain */ - break; + struct conexant_spec *spec = codec->spec; + int err; - case CXT5066_DELL_VOSTRO: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->init_verbs[0] = cxt5066_init_verbs_vostro; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; - spec->port_d_mode = 0; - spec->dell_vostro = 1; - spec->mic_boost = 3; /* default 30dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; - case CXT5066_IDEAPAD: - codec->patch_ops.init = cxt5066_init; - 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[0] = cxt5066_init_verbs_ideapad; - spec->port_d_mode = 0; - spec->ideapad = 1; - spec->mic_boost = 2; /* default 20dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; - case CXT5066_THINKPAD: - codec->patch_ops.init = cxt5066_init; - 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[0] = cxt5066_init_verbs_thinkpad; - spec->thinkpad = 1; - spec->port_d_mode = PIN_OUT; - spec->mic_boost = 2; /* default 20dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; + if (spec->beep_amp) { + const struct snd_kcontrol_new *knew; + for (knew = cxt_beep_mixer; knew->name; knew++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, 0, kctl); + if (err < 0) + return err; + } } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - return 0; } - -#endif /* ENABLE_CXT_STATIC_QUIRKS */ - +#else +#define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#define add_beep_ctls(codec) 0 +#endif /* * Automatic parser for CX20641 & co @@ -3487,35 +881,28 @@ static int patch_conexant_auto(struct hda_codec *codec) return err; } -#ifndef ENABLE_CXT_STATIC_QUIRKS -#define patch_cxt5045 patch_conexant_auto -#define patch_cxt5047 patch_conexant_auto -#define patch_cxt5051 patch_conexant_auto -#define patch_cxt5066 patch_conexant_auto -#endif - /* */ static const struct hda_codec_preset snd_hda_preset_conexant[] = { { .id = 0x14f15045, .name = "CX20549 (Venice)", - .patch = patch_cxt5045 }, + .patch = patch_conexant_auto }, { .id = 0x14f15047, .name = "CX20551 (Waikiki)", - .patch = patch_cxt5047 }, + .patch = patch_conexant_auto }, { .id = 0x14f15051, .name = "CX20561 (Hermosa)", - .patch = patch_cxt5051 }, + .patch = patch_conexant_auto }, { .id = 0x14f15066, .name = "CX20582 (Pebble)", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15068, .name = "CX20584", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15069, .name = "CX20585", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f1506c, .name = "CX20588", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f1506e, .name = "CX20590", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15097, .name = "CX20631", .patch = patch_conexant_auto }, { .id = 0x14f15098, .name = "CX20632", -- cgit v1.2.3 From 61074c1a2d798be90e149a9ed4ce0e3596c00a38 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Aug 2014 11:39:57 +0200 Subject: ALSA: hda - Set TLV_DB_SCALE_MUTE bit for cx5051 vmaster Conexnat HD-audio driver has a workaround for cx5051 (aka CX20561) chip to add fake mute controls to each amp (commit 3868137e). This implies the minimum-as-mute TLV bit in TLV for each corresponding control. Meanwhile we build the virtual master from these, but the TLV bit is missing, even though the slaves have it. This patch simply adds the missing TLV_DB_SCALE_MUTE bit for vmaster, as already done in patch_sigmatel.c. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/pci/hda/patch_conexant.c') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 7627a69ca6d7..6f2fa838b635 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "hda_codec.h" #include "hda_local.h" @@ -859,6 +860,11 @@ static int patch_conexant_auto(struct hda_codec *codec) if (err < 0) goto error; + if (codec->vendor_id == 0x14f15051) { + /* minimum value is actually mute */ + spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; + } + codec->patch_ops = cx_auto_patch_ops; /* Some laptops with Conexant chips show stalls in S3 resume, -- cgit v1.2.3 From ff50479ad61069f3ee14863225aebe36d598e93e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Sep 2014 14:26:49 +0200 Subject: ALSA: hda - Fix digital mic on Acer Aspire 3830TG Acer Aspire 3830TG with CX20588 codec has a digital built-in mic that has the same problem like many others, the inverted signal in stereo. Apply the same fixup to this machine, too. Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda/patch_conexant.c') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6f2fa838b635..6e5d0cb4e3d7 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -217,6 +217,7 @@ enum { CXT_FIXUP_HEADPHONE_MIC_PIN, CXT_FIXUP_HEADPHONE_MIC, CXT_FIXUP_GPIO1, + CXT_FIXUP_ASPIRE_DMIC, CXT_FIXUP_THINKPAD_ACPI, CXT_FIXUP_OLPC_XO, CXT_FIXUP_CAP_MIX_AMP, @@ -664,6 +665,12 @@ static const struct hda_fixup cxt_fixups[] = { { } }, }, + [CXT_FIXUP_ASPIRE_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_stereo_dmic, + .chained = true, + .chain_id = CXT_FIXUP_GPIO1, + }, [CXT_FIXUP_THINKPAD_ACPI] = { .type = HDA_FIXUP_FUNC, .v.func = hda_fixup_thinkpad_acpi, @@ -744,7 +751,7 @@ static const struct hda_model_fixup cxt5051_fixup_models[] = { static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), - SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1), + SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), -- cgit v1.2.3 From 8245b3634516e6b7eb1c94594c0fd41d233502aa Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Fri, 19 Sep 2014 14:57:02 +0800 Subject: ALSA: hda - Add fixup model name lookup for Lemote A1205 Lemote A1004 is already added in commit a2dd933d01f (ALSA: hda - Add fixup name lookup for CX5051 and 5066 codecs), but Lemote A1205 has missing. Signed-off-by: Huacai Chen Cc: # 3.15+ Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda/patch_conexant.c') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6e5d0cb4e3d7..47ccb8f44adb 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -777,6 +777,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" }, { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" }, { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" }, + { .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" }, { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" }, {} }; -- cgit v1.2.3