Guide on how to customize you pwm fan curve

Now the new kernel has used pwm-fan kernel driver to deal with the fan control, so the old pwm fan scripts won’t work. Here is a guide on how to customize your onw pwm fan curve since different cases/environment/fans need different fan curve.
I will take armbian’s kernel as example because I use armbian as my daily use os. But it will be similar if you’re using official radxa’s kernel, radxa’s kernel uses different cooling levels.

If you take a look at the devicetree of rock5b, there is a node fan0 with this property:

cooling-levels = <72 94 117 139 162 184 207 229 255>;

This property works togather with property trips defined in node soc_thermal
Here is the default pwm fan curve defined in armbian’s kernel devicetree:

cooling level value trip temp defined in device tree working temperature
72 temp < 45
94 45 45-50
117 50 50-55
139 55 55-60
162 60 60-65
184 65 65-70
207 70 70-75
229 75 75-80
255 80 temp > 80

Cooling level vaule ranges from 0 to 255, which is the pwm value of the fan. It doesn’t start from 0 in the devicetree because I want the fan keeps spinning at its lowest speed so that I can get a stable temperature when it’s idle.
So we need another 9 pwm values like 72 94 117 139 162 184 207 229 255 for our own fan. Here is how to do it:

  • Login to root, and set the thermal policy to user_space:
echo user_space > /sys/class/thermal/thermal_zone0/policy
  • Then you can set the fan speed by setting pwm value, for example, if you want to set the speed to max, just set it to 255:
echo 255 > /sys/devices/platform/pwm-fan/hwmon/hwmon8/pwm1
  • Find the miminal pwm value that makes the fan spinning. I set the default value to 72 because it’s the minimal value of my fan.
  • After you get your minimal pwm value, let’s make it 120 as an example, we just have to fill the other 7 values between 120 and 255, like 120 135 150 165 180 195 210 235 255
  • Then create a devicetree overlay to set the new pwm fan curve:
/ {
        fragment@0 {
                target = <&fan0>;
                __overlay__ {
                        cooling-levels = <120 135 150 165 180 195 210 235 255>;
  • If you save the devicetree overlay as filename pwm-fan.dts, then use the following command to apply it:
sudo armbian-add-overlay pwm-fan.dts
  • Then reboot to see if it is applied. Make sure you’re using step_wise for your thermal_zone0:
$ cat /sys/class/thermal/thermal_zone0/policy
  • And check if your pwm value changes with temperature:
watch -n1 cat /sys/devices/platform/pwm-fan/hwmon/hwmon8/pwm1 /sys/class/thermal/thermal_zone0/temp

Thank you very much!

Thanks for the guide. I noticed the fan spinning up due to the old fan control now working anymore.

I tried following your guide but i get this error:

echo 255 > /sys/devices/platform/pwm-fan/hwmon/hwmon8/pwm1

-bash: /sys/devices/platform/pwm-fan/hwmon/hwmon8/pwm1: No such file or directory

running: Armbian 23.02.2 Jammy with Linux 5.10.110-rockchip-rk3588

You have to update the kernel to latest:

For some reason my WiFi on rock5b (Radxa A8) doesn’t work on this kernel. Where should I report this?

You can create an issue at


on my 5a it’s /sys/devices/platform/pwm-fan/hwmon/hwmon7/pwm1

Yes, the number on 5A is different.

As far as I know the 2pin fans are still brushless with an internal controller and why I just get gpio fans and diy.
I have both Opi5 & Rock5b but there are 20, 30, 40mm 3 pin pwm fans from Pihut to aliexpress and assign pwm to gpio.
I thought I would ask /sys/class/pwm/pwmchip2/pwm0/period is that milliseconds? Or is the 25000000 period 25kHz wrong.

I successfully turned on the fan manually with the certain speed, but I understand nothing when overlays comes to play.
How can I set different levels of speed on radxa debian image and how to make it run on startup?
Rsetup does not contain any settings except changing policy (step_wise, user_space…).

Is the kernel driver even present in the Radxa debían kernel?

Overlay makes fan control on kernel level which should work on every situation as per the rules, while manual or running custom script on boot is userspace control which make or may not work reliably in every situation.

Userspace control can stop working if any crash happens at userlevel .

I hope you get the point i am trying to make here

I wouldn’t say there is that much of a difference as a crash is a crash at least with the Rpi5 that the fan stops even when high wattage is pulled. I noticed that when I was trying various OC and really the abstraction of a true BIOS fan control or fan control board has more guarantee.

Driving a 2 pin fan with PWM is hack with a limited fan curve and be it kernel or user side it could stop functioning even if wattage is pulled.

It works ok for relatively low cost SBC but non of its ideal, with much just being personal pref.
With OC & OOM type crashes I have seen the kernel side fan stop as the kernel has, but somehow frooze still pulling wattage.

I get the point and thank you for the explanation.

Next thing is how can I set fan configuration so its starts spinning on a “turn on”?

Just set a low initial temp and find a speed that moves the fan every time.

I would like to, but I do not know where this config file is.

Armbian has a script armbian-add-overlay to compile overlay dts to dtbo and install to system. On radxa’s image you have to compile with dtc command by yourself, and install the dtbo manually. I don’t know detail about it.


I’m testing with Linux rock-5b 6.1.43-vendor-rk35xx #1 SMP Sat May 11 13:15:57 CEST 2024 aarch64 aarch64 aarch64 GNU/Linux, couldn’t make the fan spin, anyone had success with this version?

Which operating system are you using?

I’m using Armbian