From mboxrd@z Thu Jan 1 00:00:00 1970 From: Takashi Iwai Subject: Re: [PATCH] ALSA: hda - Headphone mic support for an Asus/Conexant device Date: Tue, 16 Jul 2013 11:58:24 +0200 Message-ID: References: <1373968090-11266-1-git-send-email-david.henningsson@canonical.com> Mime-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: Received: from mx2.suse.de (cantor2.suse.de [195.135.220.15]) by alsa0.perex.cz (Postfix) with ESMTP id C383626165C for ; Tue, 16 Jul 2013 11:57:07 +0200 (CEST) In-Reply-To: <1373968090-11266-1-git-send-email-david.henningsson@canonical.com> 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 To: David Henningsson Cc: 1198030@bugs.launchpad.net, alsa-devel@alsa-project.org List-Id: alsa-devel@alsa-project.org At Tue, 16 Jul 2013 11:48:10 +0200, David Henningsson wrote: > > This Conexant codec has a single jack that can be used as either > headphone or mic (but not headset). The existing hp_mic functionality > does not apply here, because the mic and the HP are on separate pins. > > Hence make a lighter version of what has been earlier done for Realtek > codecs. > > BugLink: https://bugs.launchpad.net/bugs/1198030 > Tested-by: Franz Hsieh > Signed-off-by: David Henningsson Thanks, applied. Takashi > --- > sound/pci/hda/patch_conexant.c | 79 +++++++++++++++++++++++++++++++++++++++- > 1 file changed, 78 insertions(+), 1 deletion(-) > > diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c > index de00ce1..4edd2d0 100644 > --- a/sound/pci/hda/patch_conexant.c > +++ b/sound/pci/hda/patch_conexant.c > @@ -66,6 +66,8 @@ struct conexant_spec { > hda_nid_t eapds[4]; > bool dynamic_eapd; > > + unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ > + > #ifdef ENABLE_CXT_STATIC_QUIRKS > const struct snd_kcontrol_new *mixers[5]; > int num_mixers; > @@ -3200,6 +3202,9 @@ static int cx_auto_init(struct hda_codec *codec) > snd_hda_gen_init(codec); > if (!spec->dynamic_eapd) > cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); > + > + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); > + > return 0; > } > > @@ -3224,6 +3229,8 @@ enum { > CXT_PINCFG_LEMOTE_A1205, > CXT_FIXUP_STEREO_DMIC, > CXT_FIXUP_INC_MIC_BOOST, > + CXT_FIXUP_HEADPHONE_MIC_PIN, > + CXT_FIXUP_HEADPHONE_MIC, > }; > > static void cxt_fixup_stereo_dmic(struct hda_codec *codec, > @@ -3246,6 +3253,59 @@ static void cxt5066_increase_mic_boost(struct hda_codec *codec, > (0 << AC_AMPCAP_MUTE_SHIFT)); > } > > +static void cxt_update_headset_mode(struct hda_codec *codec) > +{ > + /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */ > + int i; > + bool mic_mode = false; > + struct conexant_spec *spec = codec->spec; > + struct auto_pin_cfg *cfg = &spec->gen.autocfg; > + > + hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; > + > + for (i = 0; i < cfg->num_inputs; i++) > + if (cfg->inputs[i].pin == mux_pin) { > + mic_mode = !!cfg->inputs[i].is_headphone_mic; > + break; > + } > + > + if (mic_mode) { > + snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */ > + spec->gen.hp_jack_present = false; > + } else { > + snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */ > + spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]); > + } > + > + snd_hda_gen_update_outputs(codec); > +} > + > +static void cxt_update_headset_mode_hook(struct hda_codec *codec, > + struct snd_ctl_elem_value *ucontrol) > +{ > + cxt_update_headset_mode(codec); > +} > + > +static void cxt_fixup_headphone_mic(struct hda_codec *codec, > + const struct hda_fixup *fix, int action) > +{ > + struct conexant_spec *spec = codec->spec; > + > + switch (action) { > + case HDA_FIXUP_ACT_PRE_PROBE: > + spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC; > + break; > + case HDA_FIXUP_ACT_PROBE: > + spec->gen.cap_sync_hook = cxt_update_headset_mode_hook; > + spec->gen.automute_hook = cxt_update_headset_mode; > + break; > + case HDA_FIXUP_ACT_INIT: > + cxt_update_headset_mode(codec); > + break; > + } > +} > + > + > /* ThinkPad X200 & co with cxt5051 */ > static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { > { 0x16, 0x042140ff }, /* HP (seq# overridden) */ > @@ -3302,6 +3362,19 @@ static const struct hda_fixup cxt_fixups[] = { > .type = HDA_FIXUP_FUNC, > .v.func = cxt5066_increase_mic_boost, > }, > + [CXT_FIXUP_HEADPHONE_MIC_PIN] = { > + .type = HDA_FIXUP_PINS, > + .chained = true, > + .chain_id = CXT_FIXUP_HEADPHONE_MIC, > + .v.pins = (const struct hda_pintbl[]) { > + { 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ > + { } > + } > + }, > + [CXT_FIXUP_HEADPHONE_MIC] = { > + .type = HDA_FIXUP_FUNC, > + .v.func = cxt_fixup_headphone_mic, > + }, > }; > > static const struct snd_pci_quirk cxt5051_fixups[] = { > @@ -3311,6 +3384,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = { > > static const struct snd_pci_quirk cxt5066_fixups[] = { > SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), > + SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), > SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), > SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), > SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), > @@ -3395,7 +3469,8 @@ static int patch_conexant_auto(struct hda_codec *codec) > > snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); > > - err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); > + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, > + spec->parse_flags); > if (err < 0) > goto error; > > @@ -3416,6 +3491,8 @@ static int patch_conexant_auto(struct hda_codec *codec) > codec->bus->allow_bus_reset = 1; > } > > + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); > + > return 0; > > error: > -- > 1.7.9.5 >