External Microphone via 3.5mm Jack (Librem 14)

Hello All,

Was anyone able to make external microphone to work via 3.5mm jack on Librem 14?

Should this be resolved in Pureboot or Embedded Controller?


(notify @MrChromebox & @nicole.faerber)

1 Like

unresolved, as of yet, and unsure where the fix will lie


After some research and guessing I was able to get the external microphone to work. However, it’s of very poor quality (lots of hiss) and the jack detection doesn’t function.

The HDA codec chip is the Realtek ALC256. Its node 0x20 is essentially undocumented, but reading through the patch_realtek.c file in Linux gives a few clues. The register 0x45 seems to control the jack type (CTIA vs. OMTP, etc.), and the register 0x4a seems to control its functionality (but I have no actual clue about this since there’s no docs). I found that after setting:

  • 0x45 := 0xd489
  • 0x4a := 0x000e

the combo jack microphone input works. You can do this manually by using hda-verb from the alsa-tools package:

hda-verb /dev/snd/hwC0D0 0x20 SET_COEF_INDEX 0x045
hda-verb /dev/snd/hwC0D0 0x20 SET_PROC_COEF 0xd489
hda-verb /dev/snd/hwC0D0 0x20 SET_COEF_INDEX 0x04a
hda-verb /dev/snd/hwC0D0 0x20 SET_PROC_COEF 0x000e

I can confirm that this works! But the result is indeed full of noise even though I have used the same external mic to get better audio before.

Curiously, the node 0x20 is not listed by other programs in the alsa-tools and alsa-tools-gui packages. For example I tried hdajackretask and the following:

~ $ sudo hdajacksensetest -c 0 -a
Pin 0x12 (Internal Mic): present = No
Pin 0x13 (Not connected): present = No
Pin 0x14 (Internal Speaker): present = No
Pin 0x18 (Not connected): present = No
Pin 0x19 (Black Mic, Right side): present = No
Pin 0x1a (Not connected): present = No
Pin 0x1b (Not connected): present = No
Pin 0x1d (Not connected): present = No
Pin 0x1e (Not connected): present = No
Pin 0x21 (Black Headphone, Right side): present = No

Is there any hope to get rid of the noise/hiss and to jack detection in the future? Are these just software problems or hardware limitations?

Is there any hope to get rid of the noise/hiss and to jack detection in the future? Are these just software problems or hardware limitations?

Since you get the same noise/hiss, I’m more confident now that it’s a codec configuration issue rather than a hardware defect. Good news!

Judging from the Linux commit history on patch_reatek.c, most of the work supporting various Realtek HDA codec deployments like our ALC256 is done by Realtek employees. Makes sense because they presumably have the magic secret document about the hidden registers.

I’ve requested advice from one of these developers, but I think it might be helpful if a representative from Purism contacted Realtek to demand a kernel patch.

Curiously, the node 0x20 is not listed by other programs in the alsa-tools and alsa-tools-gui packages. For example I tried hdajackretask and the following:

0x20 is a vendor-specific register node (along with 0x57 and 0x53) so these tools don’t show it. You can see the values in 0x20 by enabling the dump_coef parameter on snd_hda_codec and then cating/proc/asound/card0/codec#0.

I’ve managed to get jack detection to work by building a very recent revision of linux (ddf21bd8ab984ccaa924f090fc7f515bb6d51414, 5.15.0-rc1) with the following patch:

diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 8b7a389b6aed..67c32eebb1be 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -6646,6 +6646,7 @@ enum {
 static const struct hda_fixup alc269_fixups[] = {
@@ -8236,6 +8237,16 @@ static const struct hda_fixup alc269_fixups[] = {
 		.chained = true,
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{0x20, AC_VERB_SET_COEF_INDEX, 0x45},
+			{0x20, AC_VERB_SET_PROC_COEF,  0xd429}, /* ctia jack type */
+			{0x20, AC_VERB_SET_COEF_INDEX, 0x4a},
+			{0x20, AC_VERB_SET_PROC_COEF,  0x000e}, /* Combo jack config */
+			{ }
+		},
+	},
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -8667,6 +8678,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
 	SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED),
 	SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10),
+	SND_PCI_QUIRK(0x8086, 0x7270, "Purism Librem 14", ALC256_FIXUP_PURISM_LIBREM_14),
 #if 0
 	/* Below is a quirk table taken from the old code.

This just does the jack setup fix that I gave earlier. Presumably there were some other changes since 5.10 which have caused jack detection to work. The noise/hiss also seems to be a bit better (but still unacceptably bad), although I may be imagining that…

what? why would we patch the kernel when we can fix it in firmware? And good luck getting a reply from Realtek, as if we haven’t tried already.

I don’t see that in patch_realtek, where did you draw that from?

this isn’t right, the subvendor ID isn’t unique (that’s the FSP default) and doing this will apply to any devices running coreboot which don’t override the SVID (ie, a lot)

1 Like

We patch it in the kernel because it fixes the problem for the user, right now. A firmware fix would be welcome of course, but customers like me need a fix now.

Trial and error. I found that other quirks were setting 0x4a on node 0x20, for example in alc_headset_mode_default.

Thanks, I didn’t know this. What should we do instead? I believe there is a mechanism for quriking based on subvendor ID and default pin configurations, so perhaps that’s the way to go.

1 Like

this again seems backwards to me. Purism can push a firmware fix a lot quicker than a patch can get into the kernel, and solves the problem at the root.

we shouldn’t do this at all, it should be fixed in firmware

1 Like

It’s important to be pragmatic here. As far as I know, Purism has not yet pushed a firmware fix. Is there one available?

On the other hand, the kernel patch I’ve given can be applied by other users right now. They don’t have to wait for it to reach mainline.

But the users are not interested in what should be done, we’re interested in a fix that we can use right now.

how many people here are building their own kernels? I’d wager it can be counted on one hand.

1 Like

Instructions are widely available. It’s a well-known process that is not vendor-specific like a firmware upgrade. Given the egregiousness of the bug, I believe many users would be motivated to go through the process.

you’re vastly overestimating the ability of the average user. Building a kernel with the proper config is a timing consuming process. Even moreso when going from a downstream kernel to a mainline one.

Either way, I’m not yet convinced these verbs are the correct solution. Mic detect is glitchy, and while insertion switches to the headphones, removal does not switch back to the internal speakers

1 Like

Indeed, there’s more work to be done. I have another laptop with an ALC256 which does work with an unpatched kernel, so I may be able to get some more leads by checking what verbs it sends.

those verbs are likely board-specific in their config and not applicable to the L14. I have plenty of other verb sets from other boards with the ALC256, they are not helpful with the L14

I will probably speak on behalf of many people who prefer to wait patiently for @MrChromebox and the team to continue to work the the firmware.

@avieth but thank you for sharing your findings that can be beneficial for someone who can’t wait for the firmware update and will consider to compile their kernel.

1 Like

I’m not sure setting the jack type to CTIA is necessary, or that the coefficient value 0xd429 is correct - the Linux driver uses 0xd489 for the ALC256 (and others). But it doesn’t seem to have an effect either way.

Setting the jack detect to auto (setting coefficient 0x4a to 0xe) works for the headphone/output, but causes the external mic to register as always connected. We can work around this by disabling the jack detect on the external mic (and making it manually selectable) but that’s what we have now, so only improvement is the headphone jack detect. Which works exactly once, and then gets stuck inserted (at least on kernels 5.14 and earlier)

Did it not make the microphone input work for you? For me it made the jack detect work for the output device but not the input, but the main improvement is that the mic input actually produces a signal.

yes, leaving JD off for the mic and manually selecting allows the external mic to work, albeit with significant background noise

Hello @MrChromebox! I am curious if there has been any progress made to make Microphone via 3.5 Jack to work?