If you run a SunFounder Pironman 5 case on your Raspberry Pi 5 and you recently ran sudo apt dist-upgrade, you may have noticed the case fan spinning at full speed constantly — even when the CPU is idle and cool. Here's what's actually happening and how to fix it permanently (not just until the next kernel update).
The symptom
After updating and rebooting, the fan on the back of the Pironman 5 case runs non-stop, regardless of temperature. The Pi 5's own active-cooler PWM fan (if you have one) still behaves normally and idles correctly — it's specifically the Pironman 5's own case fan that's misbehaving.
Diagnosis
Checking the Pironman5 service logs told the real story:
$ journalctl -u pironman5 -n 30
...
Init GPIO Fan with pin: 6
/usr/lib/python3/dist-packages/gpiozero/devices.py:300: PinFactoryFallback: Falling back from lgpio: 'can not open gpiochip'
GPIO Fan init error: Cannot determine SOC peripheral base address
[WARNING] GPIO Fan init failed, disable gpio_fan control
Init PWM Fan
The Pironman 5's case fan is switched by the software over a single GPIO pin (pin 6, via gpiozero), separately from the Pi 5's own kernel-managed PWM fan header. When gpiozero's lgpio backend fails to initialize that pin, the control loop just... never touches it again. Whatever state the pin happened to be in when control was lost is where it stays — and on this case's fan circuit, that means on.
Root cause
Raspberry Pi 5's GPIO header isn't wired directly to the SoC anymore — it's behind a separate southbridge chip (RP1), exposed to Linux as a gpiochip character device (/dev/gpiochipN). Which chip number the RP1 pins show up as depends on driver probe order, and that's not guaranteed to stay the same across kernel versions.
gpiozero's lgpio pin factory has a hardcoded expectation of which chip number the header GPIOs live on (gpiochip4, as of the current gpiozero/lgpio release). A kernel update can quietly shift the actual chip number the RP1 pins get enumerated as — on my Pi, after updating to kernel 6.12.96, the header GPIOs ended up on gpiochip15 instead. gpiozero kept trying gpiochip4, found nothing usable there, and gave up.
This is apparently a recurring issue — SunFounder's own forum has a thread about the exact same failure mode showing up after kernel 6.6.45. Their suggested fixes at the time were either a one-off ln -s gpiochip0 /dev/gpiochip4 (doesn't survive reboot) or downgrading the kernel entirely and pinning it there (loses security patches, and doesn't actually fix anything — just avoids triggering the bug).
The fix: a self-healing udev rule
Instead of a static symlink or a kernel pin, I set up a udev rule that dynamically creates /dev/gpiochip4 pointing at whatever chip is actually driven by the pinctrl-rp1 driver — no matter what number the kernel decides to assign it:
# /etc/udev/rules.d/99-gpiochip4-pironman5.rules
SUBSYSTEM=="gpio", KERNEL=="gpiochip*", DRIVERS=="pinctrl-rp1", SYMLINK+="gpiochip4"
Apply it and restart the fan service:
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=gpio --action=add
sudo systemctl restart pironman5
Verify the symlink exists and that GPIO 6 is actually claimed:
$ ls -la /dev/gpiochip4
lrwxrwxrwx 1 root root 10 ... /dev/gpiochip4 -> gpiochip15
$ gpioinfo /dev/gpiochip4 | grep 'line 6'
line 6: "GPIO6" "lg" output active-high [used]
Once lgpio could open the right chip, the Pironman5 logs came up clean (no more PinFactoryFallback / Cannot determine SOC peripheral base address), and the fan control loop started actively managing the pin again — fan off at idle, as expected.
Why this approach over the alternatives
-
A plain
ln -sin/devdoesn't survive a reboot — you'd be re-running it after every update. - Pinning/downgrading the kernel trades a cosmetic-but-annoying bug for giving up all future security and driver updates on the box, and doesn't actually fix anything for when you eventually do update.
-
A udev rule matching on the driver name (
pinctrl-rp1) rather than a specific chip number is resilient to this happening again — if a future kernel shuffles GPIO chip numbers once more, the symlink target just updates itself on the next boot, no manual intervention needed.
Debugging tips if you hit something similar
A few commands that were useful for narrowing this down:
-
journalctl -u pironman5 -n 40— service logs showed the exact init failure. -
gpiodetect/gpioinfo— listgpiochipdevices and see which one has 40+ lines and is driven bypinctrl-rp1(that's your header). -
udevadm info -a -n /dev/gpiochipN— walk the device's udev attribute chain to find a stable match key (in this case, the parent device'sDRIVERSattribute, since there's nolabelattribute exposed directly on the chardev).
If your Pironman 5 (or any other case with a GPIO-switched fan) starts running full blast after an update, check whether its control library is hardcoded to a specific /dev/gpiochip* number — it might just need the same kind of stable alias.
— Cor, Skyblue Soft
Top comments (0)