From postmarketOS


Note Triggers are typically locked to "pattern" by feedbackd's udev rule

There are two types of triggers: simple and complex.[1] Simple triggers are provided by other subsystems. Complex triggers need to be enabled in kernel configs. For a list of complex triggers, see LEDs#List of kernel LED triggers.

Both trigger types are merged together in the trigger file. To see the available triggers, cat the trigger file, e.g. cat /sys/class/leds/tm2-touchkey/trigger. The active trigger is shown in brackets.

[none] usb-gadget usb-host rfkill-any rfkill-none kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock timer heartbeat cpu cpu0 cpu1 cpu2 cpu3 default-on panic mmc1 mmc0 rfkill0 rt5033-battery-charging-or-full rt5033-battery-charging rt5033-battery-full rt5033-battery-charging-blink-full-solid bluetooth-power hci0-power rfkill1 phy0rx phy0tx phy0assoc phy0radio rfkill2

To assign a trigger, echo the trigger name to the trigger file, e.g. echo heartbeat | sudo tee /sys/class/leds/tm2-touchkey/trigger

When rebooting, the trigger is lost again. To make it permanent, it needs to be set by an udev rule. If you're not sure about the udev matching and assignment keys, you can look them up by e.g. udevadm info --attribute-walk /sys/class/leds/tm2-touchkey. To set up the udev rule, do something like:

  • sudo vi /etc/udev/rules.d/30-tm2-touchkey-leds.rules (new file)
ACTION=="add", SUBSYSTEM=="leds", KERNEL=="tm2-touchkey", ATTR{trigger}="heartbeat"

Most of the complex triggers are tristate in the kernel configs, they can be compiled as a module. The configs can be checked by e.g. cat /boot/config | grep LEDS*_TRIGGER. (The asterisk after the S includes LED trigger that are missing the S like LED_TRIGGER_PHY.)

If a trigger is set as a module, let's say for example CONFIG_LEDS_TRIGGER_HEARTBEAT=m, the module needs to be loaded by:

# modprobe ledtrig-heartbeat

before it becomes available in the trigger list. To use it permanently by an udev rule like described above, the module needs to be added to /etc/modules.

List of kernel LED triggers

For more information on a specific trigger, see the referenced links.

drivers/leds/trigger/Kconfig [2]
drivers/usb/core/Kconfig [20]
drivers/net/phy/Kconfig [22]
CONFIG_LED_TRIGGER_PHY [23] (note the "missing" S in LED)
net/netfilter/Kconfig [24]

ULED driver

The kernel documentation mentions an ULED driver.[26] Including this into a userspace program written in C creates a node in /dev/uleds, which can be accessed by the program. There is an example at tools/leds/uledmon.c.[27]

Access via sysfs

LEDs are available in /sys/class/leds. They can be turned on/off by echoing a value to brightness. However, root access is required. The range of brightness can be checked by e.g. cat /sys/class/leds/tm2-touchkey/max_brightness. In the example tm2-touchkey LED, the max_brightnes is 1, so for this LED it's just on or off. Changing the brightness of a LED with sudo can be done like e.g.

echo 1 | sudo tee /sys/class/leds/tm2-touchkey/brightness


sudo /bin/sh -c 'echo 1 > /sys/class/leds/tm2-touchkey/brightness'


To use the commands in shell scripts without typing the password, the command(s) can be added to the sudoers file, e.g.:

sudo visudo


## Allow user to access tm2-touchkey leds withouth password
user ALL=NOPASSWD: /usr/bin/tee /sys/class/leds/tm2-touchkey/brightness

The command echo 1 | sudo tee /sys/class/leds/tm2-touchkey/brightness now works without password prompt.

Changing permissions in sysfs

Alternatively, to change the LED brightness without sudo, permissions in sysfs can be changed. This seems to be rather unconventional. A project modifying game controllers suggests the follwing approach to change permission on all LEDs[28]:

# Assign any new nodes in the 'leds' subsystem (nodes in /sys/class/leds) to the group 'leds' to write without root
# Create a new group 'leds' before this will do anything!
SUBSYSTEM=="leds", ACTION=="add", RUN+="/bin/chgrp -R leds /sys%p", RUN+="/bin/chmod -R g=u /sys%p"
SUBSYSTEM=="leds", ACTION=="change", ENV{TRIGGER}!="none", RUN+="/bin/chgrp -R leds /sys%p", RUN+="/bin/chmod -R g=u /sys%p"

This changes the owning group from root to leds and transcribes the permission from user (root) to group (leds). It needs to be done on action "add" as well as on action "change" because when the kernel performes changes, the group permissions would be overwritten to root again.

Based on this approach, for the tm2-tochkey leds udev rules were implemented to file /lib/udev/rules.d/20-tm2-touchkey-leds.rules after stable release v21.06 that look like this:

# allow users in group "input" to control the tm2-touchkey leds
ACTION=="add", SUBSYSTEM=="leds", KERNEL=="tm2-touchkey", RUN+="/bin/chgrp -R input /sys%p", RUN+="/bin/chmod -R g=u /sys%p"
ACTION=="change", SUBSYSTEM=="leds", KERNEL=="tm2-touchkey", ENV{TRIGGER}!="none", RUN+="/bin/chgrp -R input /sys%p", RUN+="/bin/chmod -R g=u /sys%p"

This permission change is limited to tm2-touchkey. And the permissions are changed to group input (postmarketOS users are usually already member of group input). Additionally, the order of the udev rule keys were put in a different order (has no technical effect).

It's not fully clear if ENV{TRIGGER}!="none" in the last line is required. A comment on unix.stackexchange.com says it would be needed for kernel older than 4.9.[29]

However, with these udev rules in place, an unpriviliged user that's member of the group input can now turn on the tm2-touchkey leds by simply echo 1 > /sys/class/leds/tm2-touchkey/brightness without sudo. That's especially helpful for usage in shell scripts.

Sync with backlight

See LEDs:Sync with backlight.


  1. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/leds/leds-class.rst
  2. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/leds/trigger/Kconfig
  3. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_TIMER.html
  4. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_ONESHOT.html
  5. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_DISK.html
  6. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_MTD.html
  7. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_HEARTBEAT.html
  8. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_BACKLIGHT.html
  9. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_CPU.html
  10. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_ACTIVITY.html
  11. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_GPIO.html
  12. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_DEFAULT_ON.html
  13. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_TRANSIENT.html
  14. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_CAMERA.html
  15. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_PANIC.html
  16. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_NETDEV.html
  17. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_PATTERN.html
  18. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_AUDIO.html
  19. https://cateee.net/lkddb/web-lkddb/LEDS_TRIGGER_TTY.html
  20. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/usb/core/Kconfig
  21. https://cateee.net/lkddb/web-lkddb/USB_LEDS_TRIGGER_USBPORT.html
  22. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/net/phy/Kconfig
  23. https://cateee.net/lkddb/web-lkddb/LED_TRIGGER_PHY.html
  24. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/netfilter/Kconfig
  25. https://cateee.net/lkddb/web-lkddb/NETFILTER_XT_TARGET_LED.html
  26. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/leds/uleds.rst.
  27. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/leds/uledmon.c
  28. https://approxeng.github.io/approxeng.input/sys.html#version-2-6-1-2-6-2
  29. https://unix.stackexchange.com/questions/20125/how-can-i-change-the-permissions-in-sys-to-alter-the-state-of-a-led-light-using/202870#202870