aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_conexant.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r--sound/pci/hda/patch_conexant.c99
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
340static bool is_2_1_speaker(struct conexant_spec *spec);
341
340static int conexant_build_pcms(struct hda_codec *codec) 342static 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
474static const char * const slave_pfxs[] = { 479static 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
3457static int cx_automute_mode_get(struct snd_kcontrol *kcontrol, 3447static 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
4109static 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
4119static int cx_auto_build_output_controls(struct hda_codec *codec) 4123static 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 = {
4405enum { 4417enum {
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
4411static void cxt_fixup_stereo_dmic(struct hda_codec *codec, 4426static 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
4433static 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 */
4419static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { 4447static 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 */
4464static 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
4435static const struct hda_fixup cxt_fixups[] = { 4475static 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
4450static const struct snd_pci_quirk cxt5051_fixups[] = { 4504static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -4453,6 +4507,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
4453}; 4507};
4454 4508
4455static const struct snd_pci_quirk cxt5066_fixups[] = { 4509static 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