Omarchy 4 on 12" MacBook8,1

#linux #macbook #omarchy #arch

Episode three of my ongoing love affair w/ the MacBook Retina, 12-inch, Early 2015: after elementary OS 6 “Odin” (2021) and Clear Linux (2022), the fanless wonder now runs Omarchy 4—Arch + Hyprland, opinionated, fast, tiling. 🤓

The installation itself: smooth and uneventful. The first boot into the installed system: also smooth—right up to the LUKS passphrase prompt, where the built-in keyboard and touchpad were… dead. 💀 Not “load a kernel module” dead like back in the Clear Linux days, but properly dead: external USB keyboard required for everything, and the kernel log drowning in

applespi spi-APP000D:00: SPI transfer timed out
applespi spi-APP000D:00: Error reading from device: -110
spi_master spi1: failed to transfer one message from queue

Turns out I’m not alone: omarchy#1954 and omarchy#2099 describe exactly this, with an impressive list of unsuccessful workarounds (irqpoll, DKMS drivers, older kernels, udev incantations…). But I knew this hardware could do better—it did in 2021 and 2022. So, down the rabbit hole. 🐇

The plot twist: it’s not applespi

After an evening of pair-debugging w/ Claude Code (poking IRQ counters, unbinding PCI devices at runtime, reading way too many kernel logs), the actual root cause turned out to be upstream of the keyboard driver:

The keyboard/touchpad sit on an Intel GSPI controller (00:15.4) that does its transfers through a companion DesignWare DMA engine (00:15.0, dw_dmac_pci, built into the Arch kernel). And on this machine those DMA transfers simply never complete. No DMA completion → no interrupt → timeout, forever.

The fix is gloriously blunt—don’t let that DMA driver register at all:

initcall_blacklist=dw_pci_driver_init

With that single kernel parameter the SPI driver shrugs, logs no DMA channels available, using PIO—and the keyboard and touchpad just work. Add the applespi modules to the initramfs and they work at the LUKS prompt, too. 💪

Sleep, the boss level

Of course it wouldn’t be a 12" MacBook post without a boss level:

All of it now works. Suspend, wake, type. Hibernate, power off, power on, passphrase—and the session is back, wifi and all. Close the lid on battery and the machine naps for two hours, then tucks itself into hibernation. On a machine two GitHub issues had written off. 😎

The script

Everything is bundled into one idempotent script—kernel parameter, initramfs modules + hook, sleep hook, hibernate config, rebind service:

→ fix-macbook-spi.sh (gist)

Tested on: MacBook8,1, Omarchy 4.0.0, kernel 7.1.8/7.1.9-arch1. If you own one of these (or the 9,1 sibling), please give it a spin and report back in omarchy#1954, where I posted a summary of these findings—once a few more machines confirm, I’ll offer a proper PR to Omarchy (there’s precedent: Omarchy already ships an NVMe suspend fix for MacBooks).

Update 2026-09-06: that took less than two weeks. 🚀 Three more MacBook8,1s confirmed the fix in the issue thread, one reader contributed register-level measurements proving the DMA engine never services the SPI requests, an upstream kernel quirk is in the works—and there’s now a first-party PR, omarchy#9735, shipping the PIO switch on MacBook8,1 out of the box. The script meanwhile grew the suspend-then-hibernate setup described above.

Update 2026-10-03: and then the hook bit me. 🙈 Battery nearly empty, UPower pulled the emergency brake w/ a suspend-then-hibernate (mid-omarchy-update, inhibitors be damned), I plugged in the charger twelve seconds later—and woke up to a MacBook w/o keyboard, touchpad and wifi. Forced reboot. The culprit: my “did the RTC alarm fire?” check. systemd’s hibernate timer never shows up in the RTC wakealarm, so that check was true on every wake, and any early wake from the suspend phase was mistaken for the transition to hibernate → drivers stay detached, and no hibernate ever follows. The revised script

If you installed the script before today: please re-run the current version from the gist.

…and a caveat, same evening: the early-wake fix held up, but the first real two-hour nap on the freshly updated kernel (7.2.5-omarchy) ended in a hang right at the hibernate step—no image written, hard reset. 😬 I then spent the evening trying to make it happen again: five more hibernates (plain, right after a short suspend, lid open, lid closed) all went through cleanly. So for now it’s filed under “intermittent, or something about the long suspend”, and auto-hibernate stays on. The script’s hook now keeps the kernel console alive and chatty during the hibernate step only, so the next hang at least says where it died. If your MacBook8,1 does the same, I’d love to hear about it in omarchy#1954.

Known quirks

The 2015 MacBook: still not done. ❤️