aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Henningsson <david.henningsson@canonical.com>2013-07-16 05:48:10 -0400
committerTakashi Iwai <tiwai@suse.de>2013-07-16 05:57:37 -0400
commite4c3bce26de240457370d00ce396602cc98bb3cc (patch)
tree47aa906c59bf0f195405345b31c7515f438db94b
parent68593c9340847662ac1d337b3c5621a1f4ca05db (diff)
ALSA: hda - Headphone mic support for an Asus/Conexant device
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 <franz.hsieh@canonical.com> Signed-off-by: David Henningsson <david.henningsson@canonical.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/patch_conexant.c79
1 files changed, 78 insertions, 1 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index de00ce166470..4edd2d0f9a3c 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -66,6 +66,8 @@ struct conexant_spec {
66 hda_nid_t eapds[4]; 66 hda_nid_t eapds[4];
67 bool dynamic_eapd; 67 bool dynamic_eapd;
68 68
69 unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
70
69#ifdef ENABLE_CXT_STATIC_QUIRKS 71#ifdef ENABLE_CXT_STATIC_QUIRKS
70 const struct snd_kcontrol_new *mixers[5]; 72 const struct snd_kcontrol_new *mixers[5];
71 int num_mixers; 73 int num_mixers;
@@ -3200,6 +3202,9 @@ static int cx_auto_init(struct hda_codec *codec)
3200 snd_hda_gen_init(codec); 3202 snd_hda_gen_init(codec);
3201 if (!spec->dynamic_eapd) 3203 if (!spec->dynamic_eapd)
3202 cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); 3204 cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
3205
3206 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
3207
3203 return 0; 3208 return 0;
3204} 3209}
3205 3210
@@ -3224,6 +3229,8 @@ enum {
3224 CXT_PINCFG_LEMOTE_A1205, 3229 CXT_PINCFG_LEMOTE_A1205,
3225 CXT_FIXUP_STEREO_DMIC, 3230 CXT_FIXUP_STEREO_DMIC,
3226 CXT_FIXUP_INC_MIC_BOOST, 3231 CXT_FIXUP_INC_MIC_BOOST,
3232 CXT_FIXUP_HEADPHONE_MIC_PIN,
3233 CXT_FIXUP_HEADPHONE_MIC,
3227}; 3234};
3228 3235
3229static void cxt_fixup_stereo_dmic(struct hda_codec *codec, 3236static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
@@ -3246,6 +3253,59 @@ static void cxt5066_increase_mic_boost(struct hda_codec *codec,
3246 (0 << AC_AMPCAP_MUTE_SHIFT)); 3253 (0 << AC_AMPCAP_MUTE_SHIFT));
3247} 3254}
3248 3255
3256static void cxt_update_headset_mode(struct hda_codec *codec)
3257{
3258 /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */
3259 int i;
3260 bool mic_mode = false;
3261 struct conexant_spec *spec = codec->spec;
3262 struct auto_pin_cfg *cfg = &spec->gen.autocfg;
3263
3264 hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
3265
3266 for (i = 0; i < cfg->num_inputs; i++)
3267 if (cfg->inputs[i].pin == mux_pin) {
3268 mic_mode = !!cfg->inputs[i].is_headphone_mic;
3269 break;
3270 }
3271
3272 if (mic_mode) {
3273 snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */
3274 spec->gen.hp_jack_present = false;
3275 } else {
3276 snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */
3277 spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]);
3278 }
3279
3280 snd_hda_gen_update_outputs(codec);
3281}
3282
3283static void cxt_update_headset_mode_hook(struct hda_codec *codec,
3284 struct snd_ctl_elem_value *ucontrol)
3285{
3286 cxt_update_headset_mode(codec);
3287}
3288
3289static void cxt_fixup_headphone_mic(struct hda_codec *codec,
3290 const struct hda_fixup *fix, int action)
3291{
3292 struct conexant_spec *spec = codec->spec;
3293
3294 switch (action) {
3295 case HDA_FIXUP_ACT_PRE_PROBE:
3296 spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC;
3297 break;
3298 case HDA_FIXUP_ACT_PROBE:
3299 spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
3300 spec->gen.automute_hook = cxt_update_headset_mode;
3301 break;
3302 case HDA_FIXUP_ACT_INIT:
3303 cxt_update_headset_mode(codec);
3304 break;
3305 }
3306}
3307
3308
3249/* ThinkPad X200 & co with cxt5051 */ 3309/* ThinkPad X200 & co with cxt5051 */
3250static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { 3310static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
3251 { 0x16, 0x042140ff }, /* HP (seq# overridden) */ 3311 { 0x16, 0x042140ff }, /* HP (seq# overridden) */
@@ -3302,6 +3362,19 @@ static const struct hda_fixup cxt_fixups[] = {
3302 .type = HDA_FIXUP_FUNC, 3362 .type = HDA_FIXUP_FUNC,
3303 .v.func = cxt5066_increase_mic_boost, 3363 .v.func = cxt5066_increase_mic_boost,
3304 }, 3364 },
3365 [CXT_FIXUP_HEADPHONE_MIC_PIN] = {
3366 .type = HDA_FIXUP_PINS,
3367 .chained = true,
3368 .chain_id = CXT_FIXUP_HEADPHONE_MIC,
3369 .v.pins = (const struct hda_pintbl[]) {
3370 { 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
3371 { }
3372 }
3373 },
3374 [CXT_FIXUP_HEADPHONE_MIC] = {
3375 .type = HDA_FIXUP_FUNC,
3376 .v.func = cxt_fixup_headphone_mic,
3377 },
3305}; 3378};
3306 3379
3307static const struct snd_pci_quirk cxt5051_fixups[] = { 3380static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -3311,6 +3384,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
3311 3384
3312static const struct snd_pci_quirk cxt5066_fixups[] = { 3385static const struct snd_pci_quirk cxt5066_fixups[] = {
3313 SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), 3386 SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
3387 SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
3314 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), 3388 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
3315 SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), 3389 SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
3316 SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), 3390 SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
@@ -3395,7 +3469,8 @@ static int patch_conexant_auto(struct hda_codec *codec)
3395 3469
3396 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); 3470 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
3397 3471
3398 err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); 3472 err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
3473 spec->parse_flags);
3399 if (err < 0) 3474 if (err < 0)
3400 goto error; 3475 goto error;
3401 3476
@@ -3416,6 +3491,8 @@ static int patch_conexant_auto(struct hda_codec *codec)
3416 codec->bus->allow_bus_reset = 1; 3491 codec->bus->allow_bus_reset = 1;
3417 } 3492 }
3418 3493
3494 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
3495
3419 return 0; 3496 return 0;
3420 3497
3421 error: 3498 error: