From patchwork Thu Aug 6 06:03:23 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raymond Yau X-Patchwork-Id: 6956071 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 3C8BF9F38B for ; Thu, 6 Aug 2015 06:03:47 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7A84C20670 for ; Thu, 6 Aug 2015 06:03:45 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id E42D92062B for ; Thu, 6 Aug 2015 06:03:42 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id A803D2604A9; Thu, 6 Aug 2015 08:03:40 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 8271E2604AA; Thu, 6 Aug 2015 08:03:32 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 3FEB72604AC; Thu, 6 Aug 2015 08:03:31 +0200 (CEST) Received: from mail-ob0-f179.google.com (mail-ob0-f179.google.com [209.85.214.179]) by alsa0.perex.cz (Postfix) with ESMTP id C1BD72604A9 for ; Thu, 6 Aug 2015 08:03:24 +0200 (CEST) Received: by obdeg2 with SMTP id eg2so48592722obd.0 for ; Wed, 05 Aug 2015 23:03:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=5i5yJ/xL4snV8RjxG5yv9sE2ls0zVzmNQ858hrfeDe0=; b=P91Zpoak/vePxf03p5dC/R2X1uklj9zhNJDL3V6JIIX2NR8I5gcl2zR+/GdwGG53n3 BGzspl/dhj+SJgiDu4fzp8ilgP3ZSrpKIaeDTcpFWX1fRyALNy5sCOQLymioqDHzLkLk L7QvkxFwszZhIUiSjGe1H5IGv8yZJ7ekAbg+gS77d34U4SYTxw54gj0U/3fwmIn+Ejyz G/ilRP4pwZsNEWYQpgZz8htd7E6VqeazR8R8axIEKdd/woZQ82aFvTr6xU3DPu0/Vyqp jzPGNw1+XofvxMQAahtyuPHeeoiJtQPajIv2NrWWyjhrrQ4c7/eRxR4whUVkgnaPwLpg zSLg== MIME-Version: 1.0 X-Received: by 10.60.93.42 with SMTP id cr10mr11950787oeb.74.1438841003584; Wed, 05 Aug 2015 23:03:23 -0700 (PDT) Received: by 10.202.63.197 with HTTP; Wed, 5 Aug 2015 23:03:23 -0700 (PDT) In-Reply-To: References: Date: Thu, 6 Aug 2015 14:03:23 +0800 Message-ID: From: Raymond Yau To: Arthur Borsboom X-Content-Filtered-By: Mailman/MimeDel 2.1.14 Cc: tiwai@suse.de, ALSA Development Mailing List , kailang@realtek.com, David Henningsson Subject: Re: [alsa-devel] [ALC668]: Asus N751JK - mic selection not working X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP > > I have applied the patch against the mainline kernel 4.2.0-rc5. > I have created the file /etc/modprobe.d/alsa-base.conf and added this line and rebooted. > > options snd_hda_intel model=,asus-headset > > Works > --------- > Subwoofer > Plugging and unplugging 3,5mm jack: PA switches from speakers to headphones and from internal microphone to headset microphone. > Playing music on speakers > Playing music on headset > > Does not work > ------------------- > Microphone: My voice by the headset is not getting to PA. > When playing music the VU meters of the Headphones (= good) and the Microphone (= not good) in PA show both the music playing. Please try alc668_asus_dell_alienware.patch 1) add debug statement to show "Mic 0x1b plugged" or "Internal Mic selected" in snd_hda_gen_mic_autoswitch() 2) show mux_pin before and after calling snd_hda_gen_mic_autoswitch() in alc_update_headset_mode() 3) change codec_dbg() related to headset mode to codec_info() 4) add dell-alienware model to demonstrate the usage of headset jack new_headset_mode alway change to ALC_HEADSET_MODE_HEADSET when hp_pin is plugged if (!snd_hda_jack_detect(codec, hp_pin)) new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED; + else if (codec->core.vendor_id == 0x10ec0668 && + spec->gen.hs_mic_use_hp_sense) + new_headset_mode = ALC_HEADSET_MODE_HEADSET; else if (mux_pin == spec->headset_mic_pin) new_headset_mode = ALC_HEADSET_MODE_HEADSET; else if (mux_pin == spec->headphone_mic_pin) 5) change the "Headphone Playback Volume" and "Headphone Playback Switch" to "Headset Playback Volume" and "Headset Playback Switch" for those combo jack which support headset only Headphone Jack and Headset Mic Jack kctls should return same value at any time and this mean that it won't support headphone As internal mic is only connected to audio input node 0x07 and driver use dynamic ADC switching , headset mic use audio input node 0x08 The stream tag of Converter of one of Audio Output (0x07/0x08) is non zero when the connected mic is selected Converter: stream=0, channel=0 Can you post the output of alsa-info.sh while recording from headset mic with dump_coef =1 which dump the coeffs in vendor defined widget node 0x20 ? https://bugzilla.kernel.org/show_bug.cgi?id=87771#c17 Node 0x20 [Vendor Defined Widget] wcaps 0xf00040: Mono Processing caps: benign=0, ncoeff=197 Please check the system log a) "mic 0x1b plugged" and "Internal Mic select" when you plug and unplug headset b) whether the driver set your headset to CITA (IPhone) or OMTP (Nokia) case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); alc_write_coef_idx(codec, 0xb7, 0x802b); alc_write_coef_idx(codec, 0x15, 0x0d60); alc_write_coef_idx(codec, 0xc3, 0x0c00); msleep(300); val = alc_read_coef_idx(codec, 0xbe); is_ctia = (val & 0x1c02) == 0x1c02; break; } snd_printdd("Headset jack detected iPhone-style headset: %s\n", is_ctia ? "yes" : "no"); spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP; diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index b077bb6..b2f7c43 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -1166,6 +1166,17 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch, /* for multi-io case, only the primary out */ if (ch && spec->multi_ios) break; + if (ch > 0) { + *index = 0; + switch (ch) { + case 1: + return "Headphone2"; + case 2: + return "Headphone3"; + case 3: + return "Headphone4"; + } + } *index = ch; return "Headphone"; case AUTO_PIN_LINE_OUT: @@ -2092,19 +2103,70 @@ static int create_multi_out_ctls(struct hda_codec *codec, return 0; } +#define is_dock_pin(codec, nid) \ + ((get_defcfg_location(snd_hda_codec_get_pincfg(codec, nid)) & 0x30) \ + == AC_JACK_LOC_SEPARATE) + +char *get_hp_pfx(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (is_dock_pin(codec, nid)) + return "Dock Headphone"; + if ((nid == auto_cfg_hp_pins(cfg)[0]) && (spec->hs_mic_use_hp_sense)) + return "Headset"; + return "Headphone"; +} + static int create_extra_out(struct hda_codec *codec, int path_idx, const char *pfx, int cidx) { struct nid_path *path; - int err; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + hda_nid_t nid; + const hda_nid_t *p; + int err, i; + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; path = snd_hda_get_path_from_idx(codec, path_idx); if (!path) return 0; - err = add_stereo_vol(codec, pfx, cidx, path); + if (strcmp(pfx, "Headphone") == 0) { + p = auto_cfg_hp_pins(cfg); + nid = path->ctls[NID_PATH_VOL_CTL]; + if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN) + strcpy(name, get_hp_pfx(codec, nid)); + else { + strcpy(name, get_hp_pfx(codec, *p)); + for (i = 1; i < auto_cfg_hp_outs(cfg); i++) { + p++; + strcat(name, "+"); + strcat(name, get_hp_pfx(codec, *p)); + } + } + err = add_stereo_vol(codec, name, cidx, path); + } else + err = add_stereo_vol(codec, pfx, cidx, path); if (err < 0) return err; - err = add_stereo_sw(codec, pfx, cidx, path); + if (strcmp(pfx, "Headphone") == 0) { + p = auto_cfg_hp_pins(cfg); + nid = path->ctls[NID_PATH_MUTE_CTL]; + if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN) + strcpy(name, get_hp_pfx(codec, nid)); + else { + strcpy(name, get_hp_pfx(codec, *p)); + for (i = 1; i < auto_cfg_hp_outs(cfg); i++) { + p++; + strcat(name, "+"); + strcat(name, get_hp_pfx(codec, *p)); + } + } + err = add_stereo_sw(codec, name, cidx, path); + } else + err = add_stereo_sw(codec, pfx, cidx, path); if (err < 0) return err; return 0; @@ -4385,10 +4447,12 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) continue; if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) { + codec_info(codec, "Mic 0x%x plugged\n", pin); mux_select(codec, 0, spec->am_entry[i].idx); return; } } + codec_info(codec, "Internal Mic selected\n"); mux_select(codec, 0, spec->am_entry[0].idx); } EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch); @@ -4665,7 +4729,9 @@ static int check_auto_mic_availability(struct hda_codec *codec) if (!spec->line_in_auto_switch && cfg->inputs[i].type != AUTO_PIN_MIC) return 0; /* only mic is allowed */ - if (!is_jack_detectable(codec, nid)) + if (!is_jack_detectable(codec, nid) && + !(spec->hs_mic_use_hp_sense && + cfg->inputs[i].is_headset_mic)) return 0; /* no unsol support */ break; } diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 56e4139..96f8214 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -236,6 +236,7 @@ struct hda_gen_spec { unsigned int indep_hp_enabled:1; /* independent HP enabled */ unsigned int have_aamix_ctl:1; unsigned int hp_mic_jack_modes:1; + unsigned int hs_mic_use_hp_sense:1; /* additional mute flags (only effective with auto_mute_via_amp=1) */ u64 mute_bits; diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 366efbf..a2cd980 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -19,6 +19,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" +#include "hda_generic.h" /** * is_jack_detectable - Check whether the given pin is jack-detectable @@ -157,7 +158,15 @@ static void jack_detect_update(struct hda_codec *codec, if (jack->phantom_jack) jack->pin_sense = AC_PINSENSE_PRESENCE; else - jack->pin_sense = read_pin_sense(codec, jack->nid); + jack->pin_sense = read_pin_sense(codec, + jack->sense_nid ? jack->sense_nid : jack->nid); + + if (jack->slave_nid) { + struct hda_jack_tbl *slave = + snd_hda_jack_tbl_get(codec, jack->slave_nid); + if (slave) + slave->pin_sense = jack->pin_sense; + } /* A gating jack indicates the jack is invalid if gating is unplugged */ if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack)) @@ -209,6 +218,8 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) jack_detect_update(codec, jack); return jack->pin_sense; } + if (jack->sense_nid) + return read_pin_sense(codec, jack->sense_nid); return read_pin_sense(codec, nid); } EXPORT_SYMBOL_GPL(snd_hda_pin_sense); @@ -384,7 +395,7 @@ static void hda_free_jack_priv(struct snd_jack *jack) * will have the given name and index. */ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, - const char *name, bool phantom_jack) + const char *name, bool phantom_jack, hda_nid_t sense_nid) { struct hda_jack_tbl *jack; int err, state, type; @@ -405,6 +416,7 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, jack->type = type; jack->jack->private_data = jack; jack->jack->private_free = hda_free_jack_priv; + jack->sense_nid = sense_nid; state = snd_hda_jack_detect(codec, nid); snd_jack_report(jack->jack, state ? jack->type : 0); @@ -422,7 +434,7 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, const char *name) { - return __snd_hda_jack_add_kctl(codec, nid, name, false); + return __snd_hda_jack_add_kctl(codec, nid, name, false, nid); } EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl); @@ -451,7 +463,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, if (phantom_jack) /* Example final name: "Internal Mic Phantom Jack" */ strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); - err = __snd_hda_jack_add_kctl(codec, nid, name, phantom_jack); + err = __snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, nid); if (err < 0) return err; @@ -460,6 +472,14 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, return 0; } +#define is_subwoofer(codec, nid, i) ((i == 1) && \ + get_defcfg_device(snd_hda_codec_get_pincfg(codec, nid)) \ + == AC_JACK_SPEAKER) + +#define is_external_pin(codec, nid) \ +((get_defcfg_location(snd_hda_codec_get_pincfg(codec, nid)) & 0x30) \ + == AC_JACK_LOC_EXTERNAL) + /** * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg * @codec: the HDA codec @@ -469,6 +489,9 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { const hda_nid_t *p; + struct hda_jack_tbl *jack; + hda_nid_t headset_mic_nid = 0; + struct hda_gen_spec *spec = codec->spec; int i, err; for (i = 0; i < cfg->num_inputs; i++) { @@ -482,6 +505,14 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, "Headphone Mic"); } else + if (cfg->inputs[i].is_headset_mic && + spec->hs_mic_use_hp_sense && + is_jack_detectable(codec, auto_cfg_hp_pins(cfg)[0]) && + !is_jack_detectable(codec, cfg->inputs[i].pin)) { + headset_mic_nid = cfg->inputs[i].pin; + err = __snd_hda_jack_add_kctl(codec, cfg->inputs[i].pin, + "Headset Mic", false, auto_cfg_hp_pins(cfg)[0]); + } else err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, NULL); if (err < 0) @@ -489,7 +520,10 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, } for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { - err = add_jack_kctl(codec, *p, cfg, NULL); + if (is_subwoofer(codec, *p, i) && is_external_pin(codec, *p)) + err = add_jack_kctl(codec, *p, cfg, "Ext Subwoofer"); + else + err = add_jack_kctl(codec, *p, cfg, NULL); if (err < 0) return err; } @@ -499,6 +533,11 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, err = add_jack_kctl(codec, *p, cfg, NULL); if (err < 0) return err; + if ((i == 0) && spec->hs_mic_use_hp_sense) { + jack = snd_hda_jack_tbl_get(codec, *p); + if (jack) + jack->slave_nid = headset_mic_nid; + } } for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { if (*p == *cfg->line_out_pins) /* might be duplicated */ diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 387d309..ef3d162 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -41,6 +41,8 @@ struct hda_jack_tbl { hda_nid_t gated_jack; /* gated is dependent on this jack */ int type; struct snd_jack *jack; + hda_nid_t sense_nid; + hda_nid_t slave_nid; }; struct hda_jack_tbl * diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c456c04..db768cf 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3593,7 +3593,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) alc_process_coef_fw(codec, coef0668); break; } - codec_dbg(codec, "Headset jack set to unplugged mode.\n"); + codec_info(codec, "Headset jack set to unplugged mode.\n"); } @@ -3683,7 +3683,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; } - codec_dbg(codec, "Headset jack set to mic-in mode.\n"); + codec_info(codec, "Headset jack set to mic-in mode.\n"); } static void alc_headset_mode_default(struct hda_codec *codec) @@ -3752,7 +3752,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) alc_process_coef_fw(codec, coef0688); break; } - codec_dbg(codec, "Headset jack set to headphone (default) mode.\n"); + codec_info(codec, "Headset jack set to headphone (default) mode.\n"); } /* Iphone type */ @@ -3823,7 +3823,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) alc_process_coef_fw(codec, coef0688); break; } - codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); + codec_info(codec, "Headset jack set to iPhone-style headset mode.\n"); } /* Nokia type */ @@ -3894,7 +3894,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) alc_process_coef_fw(codec, coef0688); break; } - codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n"); + codec_info(codec, "Headset jack set to Nokia-style headset mode.\n"); } static void alc_determine_headset_type(struct hda_codec *codec) @@ -3970,7 +3970,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) break; } - codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n", + codec_info(codec, "Headset jack detected iPhone-style headset: %s\n", is_ctia ? "yes" : "no"); spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP; } @@ -3984,8 +3984,21 @@ static void alc_update_headset_mode(struct hda_codec *codec) int new_headset_mode; + if (codec->core.vendor_id == 0x10ec0668 && + spec->gen.hs_mic_use_hp_sense) { + if (spec->gen.auto_mic) { + codec_info(codec, "mux_pin before 0x%x\n", mux_pin); + snd_hda_gen_mic_autoswitch(codec, NULL); + mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; + codec_info(codec, "mux_pin after 0x%x\n", mux_pin); + } + } + if (!snd_hda_jack_detect(codec, hp_pin)) new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED; + else if (codec->core.vendor_id == 0x10ec0668 && + spec->gen.hs_mic_use_hp_sense) + new_headset_mode = ALC_HEADSET_MODE_HEADSET; else if (mux_pin == spec->headset_mic_pin) new_headset_mode = ALC_HEADSET_MODE_HEADSET; else if (mux_pin == spec->headphone_mic_pin) @@ -6232,6 +6245,77 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec, } } +static void alc668_fixup_dell_alienware(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + const struct hda_pintbl pincfgs[] = { + { 0x1a, 0x99130112 }, /* subwoofer */ + { 0x1b, 0x03a1113c }, /* headset mic */ + { } + }; + static hda_nid_t preferred_pair[] = { + 0x14, 0x03, + 0x1a, 0x04, + 0x15, 0x02, + 0x16, 0x02, + 0 + }; + + struct alc_spec *spec = codec->spec; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_apply_pincfgs(codec, pincfgs); + spec->gen.preferred_dacs = preferred_pair; + spec->gen.hs_mic_use_hp_sense = 1; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + break; + case HDA_FIXUP_ACT_PROBE: + alc_probe_headset_mode(codec); + break; + case HDA_FIXUP_ACT_INIT: + spec->current_headset_mode = 0; + alc_update_headset_mode(codec); + break; + case HDA_FIXUP_ACT_BUILD: +/* + better to use default hda 2.1 chmap instead of asus 2.1 chmap + alc_fixup_bass_chmap(codec, fix, action); +*/ + break; + } +} + +static void alc668_fixup_asus_headset(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + const struct hda_pintbl pincfgs[] = { + { 0x1a, 0x04110011 }, /* external subwoofer */ + { 0x1b, 0x03a1113c }, /* headset mic */ + { } + }; + + struct alc_spec *spec = codec->spec; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_apply_pincfgs(codec, pincfgs); + spec->gen.hs_mic_use_hp_sense = 1; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + break; + case HDA_FIXUP_ACT_PROBE: + alc_probe_headset_mode(codec); + break; + case HDA_FIXUP_ACT_INIT: + spec->current_headset_mode = 0; + alc_update_headset_mode(codec); + break; + case HDA_FIXUP_ACT_BUILD: + alc_fixup_bass_chmap(codec, fix, action); + break; + } +} + /* avoid D3 for keeping GPIO up */ static unsigned int gpio_led_power_filter(struct hda_codec *codec, hda_nid_t nid, @@ -6313,6 +6397,8 @@ enum { ALC662_FIXUP_INV_DMIC, ALC662_FIXUP_DELL_MIC_NO_PRESENCE, ALC668_FIXUP_DELL_MIC_NO_PRESENCE, + ALC668_FIXUP_DELL_ALIENWARE, + ALC668_FIXUP_ASUS_HEADSET, ALC662_FIXUP_HEADSET_MODE, ALC668_FIXUP_HEADSET_MODE, ALC662_FIXUP_BASS_MODE4_CHMAP, @@ -6530,6 +6616,14 @@ static const struct hda_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC668_FIXUP_HEADSET_MODE }, + [ALC668_FIXUP_DELL_ALIENWARE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc668_fixup_dell_alienware, + }, + [ALC668_FIXUP_ASUS_HEADSET] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc668_fixup_asus_headset, + }, [ALC668_FIXUP_HEADSET_MODE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode_alc668, @@ -6667,6 +6761,8 @@ static const struct hda_model_fixup alc662_fixup_models[] = { {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"}, {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"}, {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"}, + {.id = ALC668_FIXUP_DELL_ALIENWARE, .name = "dell-alienware"}, + {.id = ALC668_FIXUP_ASUS_HEADSET, .name = "asus-headset"}, {} };