It’s only been a few weeks since we last talked about Librem-EC, but here we are again! This time instead of power management, we’re looking at the headset jack, which had two longstanding issues. Although headphones worked, the jack detect did not, so you had to select the output manually. Microphone input has never worked.
How does the OS know when a headset is plugged in? This is a physical jack, so there must be a physical change that is detectable.
Some jacks have normally-closed sense pins that open when you insert a plug. These might be readable as a simple digital I/O – high or low. If you’ve ever wired gadgets onto the GPIO pins of a Raspberry Pi, it’s something like that.
The Librem 14, though, has a normally open sense pin. The plug tip shorts two pins together. The jack’s datasheet has a diagram worth a thousand words:
See how pin 4 and 5 both touch the tip? One of these will just have the left audio signal on it. The other is the sense – either it reads “open” or “left audio signal”. It’s not a clean digital input – this was the first problem.
Because the sense pin isn’t a clean digital signal, the EC has to use its analog-to-digital converter to measure the sense level, then decide whether a plug is inserted.
The digital logic actually worked some of the time. Most of the time, if the signal was quiet, the EC still noticed the plug in event. Testing this properly required cranking up the volume of some very loud music. My office sounded like a Nickelback concert for a little while, but this confirmed that analog sense worked reliably.
This improved the jack detection by the EC, and I reverted the audio verbs in coreboot to re-enable the jack sense. (We had disabled it as a workaround so you could manually select the jack.) The codec still did not report the plug events though.
After the EC notices a plug insertion, it has to inform the codec. That’s the Realtek ALC256 audio codec, and for whatever reason, Realtek is very secretive about what it does and how we configure it. While we were able to get a datasheet for the ALC256, it documents little beyond the HDA verbs, which the hda-verb tool already understands. The actual meaning of the “pin configuration” in those verbs, the codec parameters, and the most of the sense behavior is undocumented.
The codec seemed to simply ignore the signal from the EC, and we could not tell why. The connection between the EC and codec is complex, but it boils down to something like this:
I cleaned out a lot from the real schematic here, but it’s pretty clearly an open-drain signal. The EC, codec, and digital microphone could pull down the signal to signal ‘low’, or leave it alone to signal ‘high’ – the resistor pulls it up by default. (That’s called “tri-stating,” meaning we don’t drive the signal high or low, we set it to “high impedance,” the third state.) Nobody pushes it high.
Except – this was wrong. We got a tip that the EC actually does need to drive the signal high to trigger the jack sense in the codec. I thought this made no sense, but I could also see that when the EC tristated the signal, the signal was not going high. Something was still holding it low. I removed the digital microphone, which confirmed that the codec was still holding it low.
So I tried it – have the EC push high anyway, despite what it looked like. And it worked! Suddenly it could detect both headphones and mic. Evidently the codec is designed for this, it seem to weakly pull the signal low expecting that it could be actively driven high in this situation.
With some testing input from a few others, we found that the codec was happy as long as the EC pushed the line high for about 10 ms following a jack plug, then we can tri-state it. I can only speculate, but I suspect that the codec changes the pin over from digital microphone to GPIO2 as a result of this signal, and it appears to test whether there is actually a microphone present. The codec can tell the difference between plain headphones and a headset with mic in the jack.
With the jack detect working in the EC and codec, we just needed to revert the verbs in coreboot to enable the jack detect.
Coreboot still falls back to the old verbs if the EC hasn’t been updated yet. That way, manual headphone selection still works if a newer coreboot runs with an older EC. To do this, coreboot queries the EC during boot. EC 1.13 adds a flag indicating that the jack sense works, so coreboot can use the updated verbs.
The EC change is released in Librem-EC 1.13. As always, update with our update instructions and check out the source! The updated HDA verbs will be in coreboot 4.19-Purism-1 and PureBoot 25, which we will release soon!
|Librem Mini||In Stock||10 days|
|Librem Servers||Coming Soon||--|
|Librem Key||In Stock||10 days|
|Librem 14||In Stock||10 days|
|Librem 5 USA||In Stock||10 days|
|Librem 5||Currently shipping backlogs||20 weeks|