diff options
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 99 |
1 files changed, 78 insertions, 21 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 03b1dc317ff0..60890bfecc19 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -337,6 +337,8 @@ static const struct hda_pcm_stream cx5051_pcm_analog_capture = { | |||
337 | }, | 337 | }, |
338 | }; | 338 | }; |
339 | 339 | ||
340 | static bool is_2_1_speaker(struct conexant_spec *spec); | ||
341 | |||
340 | static int conexant_build_pcms(struct hda_codec *codec) | 342 | static int conexant_build_pcms(struct hda_codec *codec) |
341 | { | 343 | { |
342 | struct conexant_spec *spec = codec->spec; | 344 | struct conexant_spec *spec = codec->spec; |
@@ -351,6 +353,9 @@ static int conexant_build_pcms(struct hda_codec *codec) | |||
351 | spec->multiout.max_channels; | 353 | spec->multiout.max_channels; |
352 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | 354 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = |
353 | spec->multiout.dac_nids[0]; | 355 | spec->multiout.dac_nids[0]; |
356 | if (is_2_1_speaker(spec)) | ||
357 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = | ||
358 | snd_pcm_2_1_chmaps; | ||
354 | if (spec->capture_stream) | 359 | if (spec->capture_stream) |
355 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; | 360 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; |
356 | else { | 361 | else { |
@@ -472,7 +477,7 @@ static const struct snd_kcontrol_new cxt_beep_mixer[] = { | |||
472 | #endif | 477 | #endif |
473 | 478 | ||
474 | static const char * const slave_pfxs[] = { | 479 | static const char * const slave_pfxs[] = { |
475 | "Headphone", "Speaker", "Front", "Surround", "CLFE", | 480 | "Headphone", "Speaker", "Bass Speaker", "Front", "Surround", "CLFE", |
476 | NULL | 481 | NULL |
477 | }; | 482 | }; |
478 | 483 | ||
@@ -3430,28 +3435,13 @@ static int cx_automute_mode_info(struct snd_kcontrol *kcontrol, | |||
3430 | { | 3435 | { |
3431 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 3436 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
3432 | struct conexant_spec *spec = codec->spec; | 3437 | struct conexant_spec *spec = codec->spec; |
3433 | static const char * const texts2[] = { | ||
3434 | "Disabled", "Enabled" | ||
3435 | }; | ||
3436 | static const char * const texts3[] = { | 3438 | static const char * const texts3[] = { |
3437 | "Disabled", "Speaker Only", "Line Out+Speaker" | 3439 | "Disabled", "Speaker Only", "Line Out+Speaker" |
3438 | }; | 3440 | }; |
3439 | const char * const *texts; | ||
3440 | 3441 | ||
3441 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 3442 | if (spec->automute_hp_lo) |
3442 | uinfo->count = 1; | 3443 | return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); |
3443 | if (spec->automute_hp_lo) { | 3444 | return snd_hda_enum_bool_helper_info(kcontrol, uinfo); |
3444 | uinfo->value.enumerated.items = 3; | ||
3445 | texts = texts3; | ||
3446 | } else { | ||
3447 | uinfo->value.enumerated.items = 2; | ||
3448 | texts = texts2; | ||
3449 | } | ||
3450 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
3451 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
3452 | strcpy(uinfo->value.enumerated.name, | ||
3453 | texts[uinfo->value.enumerated.item]); | ||
3454 | return 0; | ||
3455 | } | 3445 | } |
3456 | 3446 | ||
3457 | static int cx_automute_mode_get(struct snd_kcontrol *kcontrol, | 3447 | static int cx_automute_mode_get(struct snd_kcontrol *kcontrol, |
@@ -4116,11 +4106,26 @@ static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac, | |||
4116 | return 0; | 4106 | return 0; |
4117 | } | 4107 | } |
4118 | 4108 | ||
4109 | static bool is_2_1_speaker(struct conexant_spec *spec) | ||
4110 | { | ||
4111 | int i, type, num_spk = 0; | ||
4112 | |||
4113 | for (i = 0; i < spec->dac_info_filled; i++) { | ||
4114 | type = spec->dac_info[i].type; | ||
4115 | if (type == AUTO_PIN_LINE_OUT) | ||
4116 | type = spec->autocfg.line_out_type; | ||
4117 | if (type == AUTO_PIN_SPEAKER_OUT) | ||
4118 | num_spk++; | ||
4119 | } | ||
4120 | return (num_spk == 2 && spec->autocfg.line_out_type != AUTO_PIN_LINE_OUT); | ||
4121 | } | ||
4122 | |||
4119 | static int cx_auto_build_output_controls(struct hda_codec *codec) | 4123 | static int cx_auto_build_output_controls(struct hda_codec *codec) |
4120 | { | 4124 | { |
4121 | struct conexant_spec *spec = codec->spec; | 4125 | struct conexant_spec *spec = codec->spec; |
4122 | int i, err; | 4126 | int i, err; |
4123 | int num_line = 0, num_hp = 0, num_spk = 0; | 4127 | int num_line = 0, num_hp = 0, num_spk = 0; |
4128 | bool speaker_2_1; | ||
4124 | static const char * const texts[3] = { "Front", "Surround", "CLFE" }; | 4129 | static const char * const texts[3] = { "Front", "Surround", "CLFE" }; |
4125 | 4130 | ||
4126 | if (spec->dac_info_filled == 1) | 4131 | if (spec->dac_info_filled == 1) |
@@ -4128,6 +4133,8 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) | |||
4128 | spec->dac_info[0].pin, | 4133 | spec->dac_info[0].pin, |
4129 | "Master", 0); | 4134 | "Master", 0); |
4130 | 4135 | ||
4136 | speaker_2_1 = is_2_1_speaker(spec); | ||
4137 | |||
4131 | for (i = 0; i < spec->dac_info_filled; i++) { | 4138 | for (i = 0; i < spec->dac_info_filled; i++) { |
4132 | const char *label; | 4139 | const char *label; |
4133 | int idx, type; | 4140 | int idx, type; |
@@ -4146,8 +4153,13 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) | |||
4146 | idx = num_hp++; | 4153 | idx = num_hp++; |
4147 | break; | 4154 | break; |
4148 | case AUTO_PIN_SPEAKER_OUT: | 4155 | case AUTO_PIN_SPEAKER_OUT: |
4149 | label = "Speaker"; | 4156 | if (speaker_2_1) { |
4150 | idx = num_spk++; | 4157 | label = num_spk++ ? "Bass Speaker" : "Speaker"; |
4158 | idx = 0; | ||
4159 | } else { | ||
4160 | label = "Speaker"; | ||
4161 | idx = num_spk++; | ||
4162 | } | ||
4151 | break; | 4163 | break; |
4152 | } | 4164 | } |
4153 | err = try_add_pb_volume(codec, dac, | 4165 | err = try_add_pb_volume(codec, dac, |
@@ -4405,7 +4417,10 @@ static const struct hda_codec_ops cx_auto_patch_ops = { | |||
4405 | enum { | 4417 | enum { |
4406 | CXT_PINCFG_LENOVO_X200, | 4418 | CXT_PINCFG_LENOVO_X200, |
4407 | CXT_PINCFG_LENOVO_TP410, | 4419 | CXT_PINCFG_LENOVO_TP410, |
4420 | CXT_PINCFG_LEMOTE_A1004, | ||
4421 | CXT_PINCFG_LEMOTE_A1205, | ||
4408 | CXT_FIXUP_STEREO_DMIC, | 4422 | CXT_FIXUP_STEREO_DMIC, |
4423 | CXT_FIXUP_INC_MIC_BOOST, | ||
4409 | }; | 4424 | }; |
4410 | 4425 | ||
4411 | static void cxt_fixup_stereo_dmic(struct hda_codec *codec, | 4426 | static void cxt_fixup_stereo_dmic(struct hda_codec *codec, |
@@ -4415,6 +4430,19 @@ static void cxt_fixup_stereo_dmic(struct hda_codec *codec, | |||
4415 | spec->fixup_stereo_dmic = 1; | 4430 | spec->fixup_stereo_dmic = 1; |
4416 | } | 4431 | } |
4417 | 4432 | ||
4433 | static void cxt5066_increase_mic_boost(struct hda_codec *codec, | ||
4434 | const struct hda_fixup *fix, int action) | ||
4435 | { | ||
4436 | if (action != HDA_FIXUP_ACT_PRE_PROBE) | ||
4437 | return; | ||
4438 | |||
4439 | snd_hda_override_amp_caps(codec, 0x17, HDA_OUTPUT, | ||
4440 | (0x3 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4441 | (0x4 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4442 | (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4443 | (0 << AC_AMPCAP_MUTE_SHIFT)); | ||
4444 | } | ||
4445 | |||
4418 | /* ThinkPad X200 & co with cxt5051 */ | 4446 | /* ThinkPad X200 & co with cxt5051 */ |
4419 | static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { | 4447 | static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { |
4420 | { 0x16, 0x042140ff }, /* HP (seq# overridden) */ | 4448 | { 0x16, 0x042140ff }, /* HP (seq# overridden) */ |
@@ -4432,6 +4460,18 @@ static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = { | |||
4432 | {} | 4460 | {} |
4433 | }; | 4461 | }; |
4434 | 4462 | ||
4463 | /* Lemote A1004/A1205 with cxt5066 */ | ||
4464 | static const struct hda_pintbl cxt_pincfg_lemote[] = { | ||
4465 | { 0x1a, 0x90a10020 }, /* Internal mic */ | ||
4466 | { 0x1b, 0x03a11020 }, /* External mic */ | ||
4467 | { 0x1d, 0x400101f0 }, /* Not used */ | ||
4468 | { 0x1e, 0x40a701f0 }, /* Not used */ | ||
4469 | { 0x20, 0x404501f0 }, /* Not used */ | ||
4470 | { 0x22, 0x404401f0 }, /* Not used */ | ||
4471 | { 0x23, 0x40a701f0 }, /* Not used */ | ||
4472 | {} | ||
4473 | }; | ||
4474 | |||
4435 | static const struct hda_fixup cxt_fixups[] = { | 4475 | static const struct hda_fixup cxt_fixups[] = { |
4436 | [CXT_PINCFG_LENOVO_X200] = { | 4476 | [CXT_PINCFG_LENOVO_X200] = { |
4437 | .type = HDA_FIXUP_PINS, | 4477 | .type = HDA_FIXUP_PINS, |
@@ -4441,10 +4481,24 @@ static const struct hda_fixup cxt_fixups[] = { | |||
4441 | .type = HDA_FIXUP_PINS, | 4481 | .type = HDA_FIXUP_PINS, |
4442 | .v.pins = cxt_pincfg_lenovo_tp410, | 4482 | .v.pins = cxt_pincfg_lenovo_tp410, |
4443 | }, | 4483 | }, |
4484 | [CXT_PINCFG_LEMOTE_A1004] = { | ||
4485 | .type = HDA_FIXUP_PINS, | ||
4486 | .chained = true, | ||
4487 | .chain_id = CXT_FIXUP_INC_MIC_BOOST, | ||
4488 | .v.pins = cxt_pincfg_lemote, | ||
4489 | }, | ||
4490 | [CXT_PINCFG_LEMOTE_A1205] = { | ||
4491 | .type = HDA_FIXUP_PINS, | ||
4492 | .v.pins = cxt_pincfg_lemote, | ||
4493 | }, | ||
4444 | [CXT_FIXUP_STEREO_DMIC] = { | 4494 | [CXT_FIXUP_STEREO_DMIC] = { |
4445 | .type = HDA_FIXUP_FUNC, | 4495 | .type = HDA_FIXUP_FUNC, |
4446 | .v.func = cxt_fixup_stereo_dmic, | 4496 | .v.func = cxt_fixup_stereo_dmic, |
4447 | }, | 4497 | }, |
4498 | [CXT_FIXUP_INC_MIC_BOOST] = { | ||
4499 | .type = HDA_FIXUP_FUNC, | ||
4500 | .v.func = cxt5066_increase_mic_boost, | ||
4501 | }, | ||
4448 | }; | 4502 | }; |
4449 | 4503 | ||
4450 | static const struct snd_pci_quirk cxt5051_fixups[] = { | 4504 | static const struct snd_pci_quirk cxt5051_fixups[] = { |
@@ -4453,6 +4507,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = { | |||
4453 | }; | 4507 | }; |
4454 | 4508 | ||
4455 | static const struct snd_pci_quirk cxt5066_fixups[] = { | 4509 | static const struct snd_pci_quirk cxt5066_fixups[] = { |
4510 | SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), | ||
4456 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), | 4511 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), |
4457 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), | 4512 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), |
4458 | SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), | 4513 | SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), |
@@ -4461,6 +4516,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { | |||
4461 | SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), | 4516 | SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), |
4462 | SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), | 4517 | SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), |
4463 | SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), | 4518 | SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), |
4519 | SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004), | ||
4520 | SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205), | ||
4464 | {} | 4521 | {} |
4465 | }; | 4522 | }; |
4466 | 4523 | ||