Linux IIO Trigger Sysfs Interface
Free Linux Kernel Development Course — IIO Framework, Lecture 7
| ← PREV_LEC | NEXT_LEC → |
In the previous lecture of this free Linux device drivers course, we built ep_iio_trigbuf_demo, a driver that consumes an IIO trigger to fill a buffer using devm_iio_triggered_buffer_setup(). That lecture answered “how does a driver react to a trigger?” This lecture answers a different question: “where do triggers actually come from, and how do we create and manage one from user space without any extra hardware?” Understanding the iio trigger sysfs interface is what lets you test triggered-buffer drivers on a virtual machine, a Raspberry Pi, or any board — even when you don’t have a real interrupt source wired up yet.
This Lecture Covers
free embedded linux course
free linux device drivers course
iio trigger sysfs interface
sysfs trigger testing
What You Will Learn
- How an IIO trigger shows up in sysfs once it is registered with the IIO core
- How to tie a trigger to a device using
current_trigger - How to create a fully software sysfs trigger with
add_trigger/remove_trigger, with no hardware at all - How the interrupt trigger interface exposes a real IRQ line as an IIO trigger
- How the modern configfs-based hrtimer trigger is created and removed
- How to test all three trigger types against a triggered-buffer driver, with expected output
Prerequisites
- Completed lddch10_6 — triggered buffer support and
devm_iio_triggered_buffer_setup() - Comfortable with basic sysfs commands (
echo,cat) as root - A Linux kernel 6.x build tree, or a target board/VM with IIO support enabled
Why the IIO Trigger Needs a Sysfs Interface
An IIO trigger is nothing but a named signal that tells one or more devices “capture now.” A trigger does not have to come from the same driver as the sensor — it can come from a GPIO interrupt, a timer, or even a plain write from a shell script. Whatever produces the trigger, the IIO core always exposes it the same way in sysfs, so the consumer side (the buffer driver) never needs to know or care where the trigger originated.
|
+– trigger0/ (created when ANY trigger registers)
| +– name -> e.g. “sysfstrig2” or “irqtrig85”
|
+– iio:device0/
+– trigger/
+– current_trigger (write a trigger’s name here to attach it)
Every registered trigger — regardless of its source — gets a directory /sys/bus/iio/devices/triggerY/, where Y is simply the next free trigger index. The only mandatory file inside is name, which holds the string you will later write into a device’s current_trigger file to associate the two.
# List every trigger currently registered on the system
$ ls /sys/bus/iio/devices/ | grep trigger
trigger0
trigger1
$ cat /sys/bus/iio/devices/trigger0/name
sysfstrig2
# Attach trigger0 to our device from lddch10_6 (ep_iio_trigbuf_demo)
$ echo sysfstrig2 > /sys/bus/iio/devices/iio:device0/trigger/current_trigger
# Detach a trigger by writing an empty string
$ echo "" > /sys/bus/iio/devices/iio:device0/trigger/current_trigger
The Sysfs Trigger: A Trigger With No Hardware
The sysfs trigger interface is enabled with CONFIG_IIO_SYSFS_TRIGGER=y and implemented in drivers/iio/trigger/iio-trig-sysfs.c — this option is still present in current mainline kernels. It is the single most useful trigger type for course work and CI testing, because it lets you fire a capture from a plain shell command instead of needing a real interrupt line.
Once the option is enabled, a management folder appears automatically:
$ ls /sys/bus/iio/devices/iio_sysfs_trigger/
add_trigger remove_trigger
Creating and Removing a Sysfs Trigger
Writing a positive integer into add_trigger creates a new trigger with that number as its ID. The resulting trigger name always follows the pattern sysfstrig{ID}.
# Create a new sysfs trigger with ID 2
$ echo 2 > /sys/bus/iio/devices/iio_sysfs_trigger/add_trigger
# The new trigger appears at trigger2 (index may vary on your system)
$ cat /sys/bus/iio/devices/trigger2/name
sysfstrig2
# Fire it once — every device using "sysfstrig2" as current_trigger
# will capture one sample into its buffer
$ echo 1 > /sys/bus/iio/devices/trigger2/trigger_now
# Remove the trigger when you are done
$ echo 2 > /sys/bus/iio/devices/iio_sysfs_trigger/remove_trigger
Attempting to add a trigger ID that already exists returns an “invalid argument” error, so pick an ID that is not currently in use — checking ls /sys/bus/iio/devices/ first is a good habit.
End-to-End Test With ep_iio_trigbuf_demo
Here is the complete workflow to exercise the triggered-buffer driver we wrote in lddch10_6 using nothing but a sysfs trigger — no hardware interrupt required.
# 1. Load the triggered-buffer demo driver from lddch10_6
$ sudo insmod ep_iio_trigbuf_demo.ko
# 2. Create a software trigger
$ echo 5 > /sys/bus/iio/devices/iio_sysfs_trigger/add_trigger
# 3. Attach it to our IIO device
$ echo sysfstrig5 > /sys/bus/iio/devices/iio:device0/trigger/current_trigger
# 4. Set buffer length and enable capture
$ echo 64 > /sys/bus/iio/devices/iio:device0/buffer/length
$ echo 1 > /sys/bus/iio/devices/iio:device0/buffer/enable
# 5. Fire a capture on demand
$ echo 1 > /sys/bus/iio/devices/trigger5/trigger_now
# 6. Read back the sample from the character device
$ hexdump -C /dev/iio:device0 -n 16
00000000 4d 01 00 00 e1 03 00 00 10 27 00 00 00 00 00 00
00000010
Expected output: a single capture line appears every time trigger_now is written, and each line matches the number of bytes your scan_bytes layout defines from lddch10_3.
The Interrupt Trigger Interface
Real sensors usually raise a hardware interrupt — a GPIO line, a data-ready pin, or a timer peripheral — and the interrupt trigger interface (iio_interrupt_trigger) turns that IRQ directly into an IIO trigger. Its sysfs name always follows the pattern irqtrigX, where X is the virtual IRQ number you can also see listed in /proc/interrupts.
$ cd /sys/bus/iio/devices/trigger0/
$ cat name
irqtrig85
On a device-tree based system, this trigger is described declaratively instead of being registered from board code. Here is an original device tree fragment describing a GPIO line as an interrupt trigger source:
ep_irq_trigger_node: irq_trigger@0 {
compatible = "iio_interrupt_trigger";
interrupt-parent = <&gpio4>;
interrupts = <30 0x0>;
};
This node tells the kernel that GPIO line 30 on controller gpio4 is the interrupt source. Every time the line changes to the configured state, the kernel fires the trigger, and any device whose current_trigger points at irqtrig85 captures a sample automatically — no shell command needed.
# Attach the interrupt trigger to our device
$ echo "irqtrig85" > /sys/bus/iio/devices/iio:device0/trigger/current_trigger
The Hrtimer Trigger: Configfs-Based Periodic Capture
When you need periodic sampling — say, 100 captures per second — rather than reacting to an external event, the hrtimer trigger is the right tool. Unlike the two trigger types above, it is managed entirely through configfs rather than a fixed sysfs directory, which is enabled with CONFIG_IIO_CONFIGFS.
# Mount configfs once (often already mounted by systemd)
$ mkdir -p /config
$ mount -t configfs none /config
# Creating a directory under hrtimer/ IS how you create the trigger
$ mkdir /config/iio/triggers/hrtimer/ep_periodic_trigger
# Set the sampling rate in Hz
$ echo 100 > /config/iio/triggers/hrtimer/ep_periodic_trigger/sampling_frequency
# Attach it like any other trigger
$ echo ep_periodic_trigger > /sys/bus/iio/devices/iio:device0/trigger/current_trigger
# Removing the trigger is just rmdir
$ rmdir /config/iio/triggers/hrtimer/ep_periodic_trigger
This “create by mkdir, destroy by rmdir” pattern is a defining feature of configfs and is different from every other trigger type in this lecture, which is why it deserves special attention when you are debugging why a trigger directory “won’t just appear.”
Comparing the Three Trigger Types
| Trigger Type | Created By | Sysfs Name Pattern | Best Use Case |
|---|---|---|---|
| Sysfs trigger | echo ID > add_trigger |
sysfstrigID |
Manual testing, CI, no hardware available |
| Interrupt trigger | Device tree node / platform code | irqtrigX |
Real GPIO / hardware interrupt sources |
| Hrtimer trigger | mkdir under configfs |
Your chosen directory name | Fixed-rate periodic sampling |
Common Mistakes and Troubleshooting
- “Invalid argument” on add_trigger — the ID you picked is already in use; check existing
triggerYdirectories first. - current_trigger write fails with “No such device” — the trigger name was typed incorrectly; always
catthe trigger’snamefile rather than guessing the pattern. - Buffer never fills after enabling — the buffer must be enabled (
buffer/enable) and its length set before the trigger starts firing, or samples are silently dropped. - configfs directory for hrtimer triggers is missing — the
iio-trig-hrtimermodule is not loaded, or configfs is not mounted at/config.
Best Practices
- Prefer the sysfs trigger during early driver bring-up — it removes hardware timing as a variable while you debug your buffer logic.
- Always remove sysfs and hrtimer triggers you created for testing; leftover triggers can confuse
current_triggerselection on shared test boards. - For production sensors, describe the interrupt trigger through the device tree rather than board files, matching the modern DT-first approach used throughout this course.
Key Takeaways
- Every IIO trigger, regardless of source, appears under
/sys/bus/iio/devices/triggerY/with at least anameattribute - The sysfs trigger interface needs no hardware and is created/removed with
add_trigger/remove_trigger - The interrupt trigger interface exposes a real IRQ line as
irqtrigX, usually declared in the device tree - The hrtimer trigger is managed through configfs using
mkdir/rmdir, not a fixed sysfs file
Conclusion
The iio trigger sysfs interface is what separates “a driver that works only with my exact sensor” from “a driver that can be tested and demonstrated on any machine.” By understanding all three trigger types — sysfs, interrupt, and hrtimer — and how each one surfaces in sysfs or configfs, you can validate a triggered-buffer driver like ep_iio_trigbuf_demo long before real hardware is available. In the next lecture, we turn to the other half of the IIO buffer story: the buffer’s own sysfs attributes — length, enable, and watermark — and how a driver should respond to each one.
Frequently Asked Questions
What is the difference between an IIO trigger and an IIO buffer?
A trigger only signals “capture now” — it carries no data. A buffer is where the captured samples actually get stored and read from user space. A trigger without a buffer has nothing to fill, and a buffer without a trigger only fills on request.
Can one trigger drive more than one IIO device at the same time?
Yes. Any number of devices can set the same trigger name in their current_trigger file, and all of them will capture together whenever that trigger fires.
Do I need CONFIG_IIO_SYSFS_TRIGGER enabled to follow this lecture?
Yes, for the sysfs trigger examples. Check with zcat /proc/config.gz | grep IIO_SYSFS_TRIGGER or look in your kernel’s .config file, and enable it under Device Drivers → Industrial I/O support → Triggers if missing.
Why does my hrtimer trigger directory disappear after a reboot?
Configfs entries are not persistent by design — they exist only in memory. You need to recreate the trigger directory (or script its creation at boot) every time the system restarts.
Is the sysfs trigger suitable for production sensors?
No. It exists mainly for testing and automation. Production drivers should use a real trigger source — an interrupt trigger tied to actual hardware, or an hrtimer trigger for fixed-rate polling.
What happens if I write to current_trigger while a buffer is enabled?
Most drivers reject this and return a “device busy” style error. Disable the buffer first (echo 0 > buffer/enable), change the trigger, then re-enable the buffer.
How is the interrupt trigger name irqtrigX determined?
X is the Linux virtual IRQ number assigned to that interrupt line, the same number you would see listed in /proc/interrupts for that device.
Continue the Free Linux Kernel Development Course
Next up: the IIO buffer’s own sysfs attributes — length, enable, and watermark.
| ← PREV_LEC | NEXT_LEC → |
