Skip to contentSkip to conversation

ALSA: HDA: conexant support for Lenovo T520/W520

PATCH Daniel Suchy 2 participants 7 messages Oct 18, 2011 – Oct 19, 2011 Sound

lore
Share & tools
lore
#0 lore raw

This is patch for Conexant codec of Intel HDA driver, adding new quirk for Lenovo Thinkpad T520 and W520. Conexant autodetection works fine for T520 (similar subsystem ID is used also in W520 model) and detects more mixer features compared to generic (fallback) Lenovo quirk with hardcoded options in Conexant codec.

Patch was activelly tested with Linux 3.0.4, 3.0.6 and 3.0.7 without any problems.

pci/hda/patch_conexant.c renamed from pci/hda/patch_conexant.c.orig +1 -0
@@ -3097,6 +3097,7 @@
 	SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
 	SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
  	SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
+	SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520 & W520", CXT5066_AUTO),
 	SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD),
 	SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
 	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
Reviewed-by
#1 lore raw

At Tue, 18 Oct 2011 09:42:02 +0200,

Quoted 11 lines · Daniel Suchy

This is patch for Conexant codec of Intel HDA driver, adding new quirk for Lenovo Thinkpad T520 and W520. Conexant autodetection works fine for T520 (similar subsystem ID is used also in W520 model) and detects more mixer features compared to generic (fallback) Lenovo quirk with hardcoded options in Conexant codec.

Patch was activelly tested with Linux 3.0.4, 3.0.6 and 3.0.7 without any problems.

Thanks for the patch. But this is no longer needed for 3.1 kernels since model=auto is selected as default now. Though, it might be good to send this to stable kernel as an exceptional fix for 3.0.x series. In that case, give my ack:

BTW, we are checking whether the current ADC amp handling for the Conexant codecs is correct. Could you give alsa-info.sh output, and check whether both the internal and the external mic recordings work properly?

Check alsa-info.sh output or /proc/asound/card0/codec#0 file. If the node 0x14 contains both "Mic Capture Volume" and "Internal Mic Capture Volume" (or whatever multiple capture volume controls), try to change the mixer value and test whether it really reflects on the recording level correctly.

If not, try the patch below and test the recording level again. Give alsa-info.sh output anyway with the patch.

thanks,

Takashi

---
From: Takashi Iwai <[email protected]>
Subject: [PATCH] ALSA: hda - Fix ADC input-amp handling in Conexant auto-parser

It seems that Conexant chips handle only a single input-amp even when the audio-input widget has multiple sources. This has been never clear, and I implemented in the current way based on the debug information I got at the early time -- the device reacts individual input-amp values for different sources. But it doesn't look correct now.

This patch changes the auto-parser code to handle a single input-amp per audio-in widget. After applying this, you'll see only a single "Capture" volume control instead of separate "Mic" or "Line" captures when the device is set up to use a single ADC.

---
 sound/pci/hda/hda_proc.c       |    7 +++++--
 sound/pci/hda/patch_conexant.c |   38 +++++++++++++++++++++++++++-----------
 2 files changed, 32 insertions(+), 13 deletions(-)
sound/pci/hda/hda_proc.c +5 -2
index 2c981b5..9431369 100644
@@ -646,12 +646,15 @@ static void print_codec_info(struct snd_info_entry *entry,
 							   HDA_MAX_CONNECTIONS);
 
 		if (wid_caps & AC_WCAP_IN_AMP) {
+			int nums = conn_len;
 			snd_iprintf(buffer, "  Amp-In caps: ");
 			print_amp_caps(buffer, codec, nid, HDA_INPUT);
 			snd_iprintf(buffer, "  Amp-In vals: ");
+			if (wid_type == AC_WID_PIN ||
+			    (wid_type == AC_WID_AUD_IN && codec->pin_amp_workaround))
+				nums = 1;
 			print_amp_vals(buffer, codec, nid, HDA_INPUT,
-				       wid_caps & AC_WCAP_STEREO,
-				       wid_type == AC_WID_PIN ? 1 : conn_len);
+				       wid_caps & AC_WCAP_STEREO, nums);
 		}
 		if (wid_caps & AC_WCAP_OUT_AMP) {
 			snd_iprintf(buffer, "  Amp-Out caps: ");
sound/pci/hda/patch_conexant.c +27 -11
index feef775..f2d4933 100644
@@ -4251,16 +4251,20 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
 	struct conexant_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux;
 	const char *prev_label;
-	int input_conn[HDA_MAX_NUM_INPUTS];
-	int i, err, cidx;
+	int i, j, err, cidx;
 	int multi_connection;
 
+	if (!imux->num_items)
+		return 0;
+
 	multi_connection = 0;
 	for (i = 0; i < imux->num_items; i++) {
 		cidx = get_input_connection(codec, spec->imux_info[i].adc,
 					    spec->imux_info[i].pin);
-		input_conn[i] = (spec->imux_info[i].adc << 8) | cidx;
-		if (i > 0 && input_conn[i] != input_conn[0])
+		if (cidx < 0)
+			continue;
+		if (i > 0 && !multi_connection &&
+		    spec->imux_info[i].adc != spec->imux_info[0].adc)
 			multi_connection = 1;
 	}
 
@@ -4282,15 +4286,27 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
 		if (err < 0)
 			return err;
 
-		if (!multi_connection) {
-			if (i > 0)
+		if (multi_connection) {
+			bool found = false;
+			for (j = 0; j < i; j++) {
+				if (spec->imux_info[j].adc == spec->imux_info[i].adc) {
+					found = true;
+					break;
+				}
+			}
+			if (found)
 				continue;
-			err = cx_auto_add_capture_volume(codec, nid,
-							 "Capture", "", cidx);
-		} else {
-			err = cx_auto_add_capture_volume(codec, nid,
-							 label, " Capture", cidx);
+			err = cx_auto_add_capture_volume(codec, nid, label,
+							 " Capture", cidx);
+			if (err < 0)
+				return err;
 		}
+	}
+
+	if (!multi_connection) {
+		err = cx_auto_add_volume_idx(codec, "Capture", "", 0,
+					     spec->imux_info[0].adc,
+					     HDA_INPUT, 0);
 		if (err < 0)
 			return err;
 	}
Signature · 1 line
1.7.7
#2 lore raw

Hello,
thanks for information.

My output from alsa-info is available at
http://www.alsa-project.org/db/?f=94efb9fda4bcf6771ca4868c62b11994dc4dc776

Internal microphone works fine for me, but I don't have external one for testing at this time. FYI, T520 also doesn't have external microphone input, it's available only over docking station (Minidock 3). I'll perform more tests in upcoming days (generally, I don't use audio inputs too much), also with your patch.

There's another issue I observed related to audio outputs, but I'm not sure about the reason. With docking station, audio isn't working over audio output on the Minidock 3. Internal speakers are cutted off properly, but there's no sound output on the connector. Audio output on T520 directly works as expected, only output on minidock has this problem. If you have any hints, let me know. This happens even with autodetection enabled (this was my initial motivation for looking into the driver source, and also CXT5066_THINKPAD quirk, which I tested previously has this problem).

With regards,
Daniel

Quoted 148 lines · Takashi Iwai

At Tue, 18 Oct 2011 09:42:02 +0200,

Quoted 11 lines · Daniel Suchy

This is patch for Conexant codec of Intel HDA driver, adding new quirk for Lenovo Thinkpad T520 and W520. Conexant autodetection works fine for T520 (similar subsystem ID is used also in W520 model) and detects more mixer features compared to generic (fallback) Lenovo quirk with hardcoded options in Conexant codec.

Patch was activelly tested with Linux 3.0.4, 3.0.6 and 3.0.7 without any problems.

Thanks for the patch. But this is no longer needed for 3.1 kernels since model=auto is selected as default now. Though, it might be good to send this to stable kernel as an exceptional fix for 3.0.x series. In that case, give my ack:

BTW, we are checking whether the current ADC amp handling for the Conexant codecs is correct. Could you give alsa-info.sh output, and check whether both the internal and the external mic recordings work properly?

Check alsa-info.sh output or /proc/asound/card0/codec#0 file. If the node 0x14 contains both "Mic Capture Volume" and "Internal Mic Capture Volume" (or whatever multiple capture volume controls), try to change the mixer value and test whether it really reflects on the recording level correctly.

If not, try the patch below and test the recording level again. Give alsa-info.sh output anyway with the patch.

thanks,

Takashi

---
From: Takashi Iwai <[email protected]>
Subject: [PATCH] ALSA: hda - Fix ADC input-amp handling in Conexant auto-parser

It seems that Conexant chips handle only a single input-amp even when the audio-input widget has multiple sources. This has been never clear, and I implemented in the current way based on the debug information I got at the early time -- the device reacts individual input-amp values for different sources. But it doesn't look correct now.

This patch changes the auto-parser code to handle a single input-amp per audio-in widget. After applying this, you'll see only a single "Capture" volume control instead of separate "Mic" or "Line" captures when the device is set up to use a single ADC.

---
 sound/pci/hda/hda_proc.c       |    7 +++++--
 sound/pci/hda/patch_conexant.c |   38 +++++++++++++++++++++++++++-----------
 2 files changed, 32 insertions(+), 13 deletions(-)
sound/pci/hda/hda_proc.c +5 -2
index 2c981b5..9431369 100644
@@ -646,12 +646,15 @@ static void print_codec_info(struct snd_info_entry *entry,
 							   HDA_MAX_CONNECTIONS);
 
 		if (wid_caps & AC_WCAP_IN_AMP) {
+			int nums = conn_len;
 			snd_iprintf(buffer, "  Amp-In caps: ");
 			print_amp_caps(buffer, codec, nid, HDA_INPUT);
 			snd_iprintf(buffer, "  Amp-In vals: ");
+			if (wid_type == AC_WID_PIN ||
+			    (wid_type == AC_WID_AUD_IN && codec->pin_amp_workaround))
+				nums = 1;
 			print_amp_vals(buffer, codec, nid, HDA_INPUT,
-				       wid_caps & AC_WCAP_STEREO,
-				       wid_type == AC_WID_PIN ? 1 : conn_len);
+				       wid_caps & AC_WCAP_STEREO, nums);
 		}
 		if (wid_caps & AC_WCAP_OUT_AMP) {
 			snd_iprintf(buffer, "  Amp-Out caps: ");
sound/pci/hda/patch_conexant.c +27 -11
index feef775..f2d4933 100644
@@ -4251,16 +4251,20 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
 	struct conexant_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux;
 	const char *prev_label;
-	int input_conn[HDA_MAX_NUM_INPUTS];
-	int i, err, cidx;
+	int i, j, err, cidx;
 	int multi_connection;
 
+	if (!imux->num_items)
+		return 0;
+
 	multi_connection = 0;
 	for (i = 0; i < imux->num_items; i++) {
 		cidx = get_input_connection(codec, spec->imux_info[i].adc,
 					    spec->imux_info[i].pin);
-		input_conn[i] = (spec->imux_info[i].adc << 8) | cidx;
-		if (i > 0 && input_conn[i] != input_conn[0])
+		if (cidx < 0)
+			continue;
+		if (i > 0 && !multi_connection &&
+		    spec->imux_info[i].adc != spec->imux_info[0].adc)
 			multi_connection = 1;
 	}
 
@@ -4282,15 +4286,27 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
 		if (err < 0)
 			return err;
 
-		if (!multi_connection) {
-			if (i > 0)
+		if (multi_connection) {
+			bool found = false;
+			for (j = 0; j < i; j++) {
+				if (spec->imux_info[j].adc == spec->imux_info[i].adc) {
+					found = true;
+					break;
+				}
+			}
+			if (found)
 				continue;
-			err = cx_auto_add_capture_volume(codec, nid,
-							 "Capture", "", cidx);
-		} else {
-			err = cx_auto_add_capture_volume(codec, nid,
-							 label, " Capture", cidx);
+			err = cx_auto_add_capture_volume(codec, nid, label,
+							 " Capture", cidx);
+			if (err < 0)
+				return err;
 		}
+	}
+
+	if (!multi_connection) {
+		err = cx_auto_add_volume_idx(codec, "Capture", "", 0,
+					     spec->imux_info[0].adc,
+					     HDA_INPUT, 0);
 		if (err < 0)
 			return err;
 	}
#3 lore raw

At Tue, 18 Oct 2011 11:00:01 +0200,

Quoted 4 lines · Daniel Suchy

Hello,
thanks for information.

Quoted 8 lines

My output from alsa-info is available at
http://www.alsa-project.org/db/?f=94efb9fda4bcf6771ca4868c62b11994dc4dc776

Internal microphone works fine for me, but I don't have external one for testing at this time. FYI, T520 also doesn't have external microphone input, it's available only over docking station (Minidock 3). I'll perform more tests in upcoming days (generally, I don't use audio inputs too much), also with your patch.

Wait, did you test "Internal Mic" or "Mic" volume?
In your case, only the former volume should affect the recording level from the built-in mic, not the latter. If the latter changes the recording level, it's a bug. And the patch I attached in the previous mail should fix it.

Quoted 9 lines

There's another issue I observed related to audio outputs, but I'm not sure about the reason. With docking station, audio isn't working over audio output on the Minidock 3. Internal speakers are cutted off properly, but there's no sound output on the connector. Audio output on T520 directly works as expected, only output on minidock has this problem. If you have any hints, let me know. This happens even with autodetection enabled (this was my initial motivation for looking into the driver source, and also CXT5066_THINKPAD quirk, which I tested previously has this problem).

Might be an EAPD issue? There is another pending patch. Attached below.

thanks,

Takashi

---
From: Takashi Iwai <[email protected]>
Subject: [PATCH] ALSA: hda - Keep EAPD turned on for old Conexant chips

In the old Conexant chips (5045, 5047, 5051 and 5066), a single EAPD may handle both headphone and speaker outputs while it's assigned only to one of them. Turning off dynamically leads to the unexpected silent output in such a configuration with the auto-mute function.

Since it's difficult to know how the EAPD is handled in the actual h/w implementation, better to keep EAPD on while running for such codecs.

---
 sound/pci/hda/patch_conexant.c |   43 ++++++++++++++++++++-------------------
 1 files changed, 22 insertions(+), 21 deletions(-)
sound/pci/hda/patch_conexant.c +22 -21
index aa0e4b9..feef775 100644
@@ -136,6 +136,7 @@ struct conexant_spec {
 	unsigned int thinkpad:1;
 	unsigned int hp_laptop:1;
 	unsigned int asus:1;
+	unsigned int pin_eapd_ctrls:1;
 
 	unsigned int adc_switching:1;
 
@@ -3429,12 +3430,14 @@ static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
 static void do_automute(struct hda_codec *codec, int num_pins,
 			hda_nid_t *pins, bool on)
 {
+	struct conexant_spec *spec = codec->spec;
 	int i;
 	for (i = 0; i < num_pins; i++)
 		snd_hda_codec_write(codec, pins[i], 0,
 				    AC_VERB_SET_PIN_WIDGET_CONTROL,
 				    on ? PIN_OUT : 0);
-	cx_auto_turn_eapd(codec, num_pins, pins, on);
+	if (spec->pin_eapd_ctrls)
+		cx_auto_turn_eapd(codec, num_pins, pins, on);
 }
 
 static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
@@ -3459,9 +3462,12 @@ static void cx_auto_update_speakers(struct hda_codec *codec)
 	int on = 1;
 
 	/* turn on HP EAPD when HP jacks are present */
-	if (spec->auto_mute)
-		on = spec->hp_present;
-	cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
+	if (spec->pin_eapd_ctrls) {
+		if (spec->auto_mute)
+			on = spec->hp_present;
+		cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
+	}
+
 	/* mute speakers in auto-mode if HP or LO jacks are plugged */
 	if (spec->auto_mute)
 		on = !(spec->hp_present ||
@@ -3888,20 +3894,10 @@ static void cx_auto_parse_beep(struct hda_codec *codec)
 #define cx_auto_parse_beep(codec)
 #endif
 
-static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
-	int i;
-	for (i = 0; i < nums; i++)
-		if (list[i] == nid)
-			return true;
-	return false;
-}
-
-/* parse extra-EAPD that aren't assigned to any pins */
+/* parse EAPDs */
 static void cx_auto_parse_eapd(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
 	hda_nid_t nid, end_nid;
 
 	end_nid = codec->start_nid + codec->num_nodes;
@@ -3910,14 +3906,18 @@ static void cx_auto_parse_eapd(struct hda_codec *codec)
 			continue;
 		if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
 			continue;
-		if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) ||
-		    found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) ||
-		    found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs))
-			continue;
 		spec->eapds[spec->num_eapds++] = nid;
 		if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
 			break;
 	}
+
+	/* NOTE: below is a wild guess; if we have more than two EAPDs,
+	 * it's a new chip, where EAPDs are supposed to be associated to
+	 * pins, and we can control EAPD per pin.
+	 * OTOH, if only one or two EAPDs are found, it's an old chip,
+	 * thus it might control over all pins.
+	 */
+	spec->pin_eapd_ctrls = spec->num_eapds > 2;
 }
 
 static int cx_auto_parse_auto_config(struct hda_codec *codec)
@@ -4023,8 +4023,9 @@ static void cx_auto_init_output(struct hda_codec *codec)
 		}
 	}
 	cx_auto_update_speakers(codec);
-	/* turn on/off extra EAPDs, too */
-	cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
+	/* turn on all EAPDs if no individual EAPD control is available */
+	if (!spec->pin_eapd_ctrls)
+		cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
 }
 
 static void cx_auto_init_input(struct hda_codec *codec)
Signature · 1 line
1.7.7
#4 lore raw

Hello,

Quoted 10 lines · Takashi Iwai
Quoted 9 lines

There's another issue I observed related to audio outputs, but I'm not sure about the reason. With docking station, audio isn't working over audio output on the Minidock 3. Internal speakers are cutted off properly, but there's no sound output on the connector. Audio output on T520 directly works as expected, only output on minidock has this problem. If you have any hints, let me know. This happens even with autodetection enabled (this was my initial motivation for looking into the driver source, and also CXT5066_THINKPAD quirk, which I tested previously has this problem).

Quoted 3 lines

Might be an EAPD issue? There is another pending patch. Attached below.

I tried all patches you provided, but the problem with output persists. Tested on 3.1-rc10. I'll look on the recording issue tomorrow.

With regards,
Daniel

#5 lore raw

At Wed, 19 Oct 2011 00:13:05 +0200,

Quoted 14 lines · Daniel Suchy

Hello,

Quoted 10 lines · Takashi Iwai
Quoted 9 lines

There's another issue I observed related to audio outputs, but I'm not sure about the reason. With docking station, audio isn't working over audio output on the Minidock 3. Internal speakers are cutted off properly, but there's no sound output on the connector. Audio output on T520 directly works as expected, only output on minidock has this problem. If you have any hints, let me know. This happens even with autodetection enabled (this was my initial motivation for looking into the driver source, and also CXT5066_THINKPAD quirk, which I tested previously has this problem).

Quoted 6 lines
Quoted 3 lines

Might be an EAPD issue? There is another pending patch. Attached below.

I tried all patches you provided, but the problem with output persists. Tested on 3.1-rc10. I'll look on the recording issue tomorrow.

OK, then could you give alsa-info.sh outputs (run with --no-upload) at docked (non-working) and undocked (working) states with model=auto? If the dock-output works with your patch, give alsa-info.sh output at that state, too, for comparison.

The alsa-info.sh output is the best material to track down a HD-audio issue, since I can run an emulator here with it.

thanks,

Takashi

#6 lore raw
In reply to Takashi Iwai

At Tue, 18 Oct 2011 10:17:20 +0200,

Quoted 10 lines · Takashi Iwai

At Tue, 18 Oct 2011 09:42:02 +0200,

Quoted 7 lines · Daniel Suchy

This is patch for Conexant codec of Intel HDA driver, adding new quirk for Lenovo Thinkpad T520 and W520. Conexant autodetection works fine for T520 (similar subsystem ID is used also in W520 model) and detects more mixer features compared to generic (fallback) Lenovo quirk with hardcoded options in Conexant codec.

Quoted 7 lines
Quoted 4 lines

Patch was activelly tested with Linux 3.0.4, 3.0.6 and 3.0.7 without any problems.

Thanks for the patch. But this is no longer needed for 3.1 kernels since model=auto is selected as default now.

OK, I see the issue with alsa-info.sh output now.
As default, the driver takes model=lenovo, which is wrong for your device. I'll take your patch in.

In anyway, it'd be helpful if you can test further the recording issue with your device.

thanks,

Takashi