Updated October 8, 2026. This tutorial explains the Linux platform-driver model and shows a minimal driver that can bind to a matching firmware-described device. It is a learning example, not a driver for real hardware: the compatible string and binding must be supplied by a board or device-tree binding that actually describes the device.
A platform driver does not create or discover arbitrary hardware by itself. The kernel enumerates a platform device—commonly from Device Tree, ACPI, or board setup—and the driver core matches it to a registered platform_driver. Only then does the core call probe().
When to use a platform driver
The platform bus is commonly used for SoC-integrated peripherals and some legacy devices with directly addressable resources. Devices on buses with their own discovery and driver models, such as PCI, USB, I2C, or SPI, should normally use that bus’s driver model instead. See the current Linux platform-device documentation before choosing the bus.
1. Prepare a safe development environment
Build against the headers and configuration for the target kernel. A virtual machine or QEMU test system is preferable while learning: an incorrect kernel module can crash or corrupt the running system. Do not load experimental modules on a production device.
On a cross-compiled embedded target, use that target’s kernel source, configuration, and toolchain rather than the headers for your development PC. Kernel APIs change over time, so the target kernel tree is the final authority.
2. Write a minimal matching platform driver
This example only logs when the driver binds and unbinds; it does not access registers or control hardware. The placeholder compatible value must be replaced with a real binding string already used by the target device tree. Without a matching enumerated device, the module can load successfully and probe() will not run.
The empty final entry in the match table is required. MODULE_DEVICE_TABLE() makes the match information available to module tooling. Current upstream kernels use a void remove() callback; older kernel branches may use a different signature, so compile against the exact target headers and follow that tree’s platform_driver definition.
3. Build the external module
Save the source as example_platform.c and create a Makefile in the same directory:
Run make using the matching build tree. A successful build produces example_platform.ko. A module may still be rejected at load time if its vermagic, signing requirements, architecture, or kernel configuration do not match the running target.
4. Describe real hardware with a binding
For a Device Tree system, the device node is part of the board description and must follow the device’s documented binding. A node may describe resources such as registers, interrupts, clocks, resets, and power domains, but their addresses and specifiers are specific to the SoC and board. Do not copy fabricated addresses or interrupt numbers from a generic tutorial.
For upstreamable drivers, add or update a YAML schema under Documentation/devicetree/bindings/ and validate it with the kernel’s Device Tree checks. Read the Device Tree usage model and the binding documentation for the target subsystem.
Platform devices may also be enumerated through ACPI or board setup. An OF match table alone only matches Device Tree devices; add ACPI or platform-ID matching only when the hardware and target kernel require it.
5. Acquire resources in probe()
A real probe function should validate the device and acquire each resource through the device-managed APIs where appropriate. Common helpers include platform_get_resource() with devm_ioremap_resource() for a memory resource, platform_get_irq() for an IRQ, and the clock, reset, regulator, GPIO, and DMA frameworks for their respective resources. Check every return value, propagate errors, and use -EPROBE_DEFER when a required supplier is not ready yet.
Do not dereference a missing resource, invent register layouts, or access MMIO before the resource has been reserved and mapped. Use the subsystem’s established helpers rather than raw addresses. Keep interrupt handlers short and move work that may sleep into a threaded handler or workqueue.
6. Build, bind, and debug
Confirm that the device exists in the target’s firmware description and that its compatible string matches the driver table.
Check /sys/bus/platform/devices/ and /sys/bus/platform/drivers/ to inspect enumerated devices and registered drivers.
Read the exact kernel log message with dmesg or the system journal; distinguish a module-load failure from a device-match or probe failure.
Check the probe return value and resource errors. A deferred probe is different from a failed match.
Use a VM, QEMU, or a dedicated development board for module-load tests; remove the module and restore the test system if it becomes unstable.
Expecting probe() to run without an enumerated device that matches the driver.
Registering a fake platform device from the same driver module as a shortcut; device enumeration normally belongs to firmware or board setup.
Copying Device Tree register addresses, interrupt cells, or clock names from another board.
Ignoring errors from resource helpers or suppressing deferred-probe errors.
Using a remove() signature from a different kernel version or adding manual cleanup for resources already managed by devm APIs.
Treating a character device and a platform driver as alternatives: a platform driver binds hardware to a bus; a character-device interface is a separate userspace API that may be added when the hardware requires one.
Learn how to build a Linux Character Driver from scratch with this beginner-friendly guide. Step-by-step tutorial covering kernel modules, file operations, device files, and real-world driver examples.
If you’ve ever wanted to understand how Linux actually talks to hardware, learning a Linux Character Driver is one of the best places to start.
This guide is not just theory. We’ll go step by step, from zero to a working driver, and explain things like you’re sitting next to me with a coffee asking real questions.
By the end, you’ll:
Understand what a Linux Character Driver is
Know where it’s used in real systems (UART, GPIO, etc.)
Build a complete driver from scratch
Write a user-space program to interact with it
Learn how real production drivers are structured
What is a Linux Character Driver?
A Linux Character Driver is a type of device driver that communicates with hardware one byte (character) at a time.
Think of it like reading a book letter by letter instead of jumping pages.
Examples:
UART (serial communication)
Keyboard input
GPIO pins
Sensors
These are all handled using character device drivers in Linux.
Character vs Block Drivers
Let’s make this super simple.
Imagine you’re reading data like you read content in real life.
Character Driver (One by One Data)
A Linux Character Driver works like reading a message letter by letter.
You don’t jump around. You go in order.
Example:
Think of:
Typing on keyboard
Reading from a serial port
Getting sensor data
All of these send data continuously and sequentially.
That’s why they use a character device driver in Linux
Real Devices:
/dev/ttyS0 (UART)
/dev/input/event0 (keyboard/mouse)
/dev/gpiochip0 (GPIO)
Block Driver (Data in Chunks)
A Block Driver works like reading a book where you can:
Jump to page 10
Then page 50
Then page 2
No need to go in order.
Example:
Think of:
Hard disk
SSD
USB storage
You can directly access any part of data.
That’s why they use block device drivers
Real Devices:
/dev/sda (hard disk)
/dev/mmcblk0 (SD card)
Simple Comparison
Feature
Character Driver
Block Driver
Data Access
Sequential
Random
Data Type
Stream (byte-by-byte)
Blocks (chunks)
Example
UART, GPIO
Hard disk
Speed
Usually slower
Faster (optimized)
Buffering
Minimal
Heavy buffering
Easy Analogy (Best Way to Remember)
Character Driver → Like listening to a song live 🎧 You hear it as it plays (no jumping)
Block Driver → Like YouTube video 📺 You can skip anywhere
Golden Rule
Ask this question:
👉 “Do I need to access data randomly or sequentially?”
Sequential → Linux Character Driver
Random → Block Driver
In real linux driver development beginner journey:
First drivers you learn → Character Drivers
Advanced storage systems → Block Drivers
Because character drivers are:
Easier to write
Closer to hardware
Great for learning linux kernel programming basics
If data flows like a stream → Character Driver If data is accessed like storage → Block Driver
Code difference between char vs block driver
Where Are Character Drivers Used?
A Linux Character Driver isn’t just a textbook concept. It’s used everywhere Linux needs to handle stream-based, byte-by-byte communication with hardware.
Think of any device where data flows continuously rather than in chunks. That’s your signal that a character device driver in Linux is probably involved.
Let’s break down the most common real-world use cases.
UART Driver
Used for serial communication between devices.
GPIO Driver
Used to control pins (LED, buttons).
Sensors
Temperature, pressure sensors send data continuously.
So yes — when you asked earlier:
“Is UART, GPIO implemented using character driver?”
==> Yes, most of the time : absolutely.
Basic Architecture of Linux Character Driver
High-Level Architecture
Here’s the overall flow:
User Space Application
│
▼
System Calls (open, read, write, close)
│
▼
VFS (Virtual File System)
│
▼
Character Driver (Your Code)
│
▼
Hardware Device
In real embedded Linux driver development, drivers are more complex:
Use platform_driver
Device Tree (DTS)
Interrupt handling
DMA
Hardware registers
Debugging Linux Drivers
Essential for real work.
Use:
dmesg
Add logs:
printk(KERN_INFO "Debug Message\n");
Advanced:
ftrace
kgdb
Common Mistakes Beginners Make
Forgetting copy_to_user
Not checking return values
Memory leaks
Wrong device permissions
Linux Driver Interview Questions
You’ll definitely face these:
Q1: What is character driver?
Ans : Sequential data transfer driver
Q2: What is file_operations?
Ans : Structure linking user calls to kernel
Q3: Difference between user and kernel space?
Ans : Security and access level separation
Best Practices
Always validate user input
Use snprintf instead of sprintf
Follow kernel coding style
Keep driver modular
Advanced Topics (Next Step)
Once you’re comfortable:
Interrupt handling
Platform drivers + DTS
SPI/I2C drivers
Kernel synchronization
Final Thoughts
Learning a Linux Character Driver is like opening the door to kernel-level programming.
At first, it feels confusing:
Kernel space
File operations
Device numbers
But once you build one working driver, everything clicks
FAQ : Linux Character Driver
1.What is a Linux Character Driver?
A Linux Character Driver is a type of device driver that allows communication between user space and hardware devices one byte at a time (stream-based data transfer). These drivers are commonly used for devices like UART, keyboards, GPIO, and sensors.
2.How does a Linux Character Driver work?
A Linux Character Driver works through a layered architecture:
User application calls open(), read(), write()
System calls reach the kernel via VFS (Virtual File System)
Kernel invokes driver functions defined in file_operations
Driver interacts with hardware
3.What is file_operations in a character driver?
file_operations is a structure that maps user-space system calls to driver functions.
Example:
open() → my_open()
read() → my_read()
write() → my_write()
It acts as the core interface between user space and kernel space.
4.What is the difference between Character Driver and Block Driver?
Feature
Character Driver
Block Driver
Data Access
Byte-by-byte
Block (chunks)
Example
UART, GPIO
Hard Disk
Buffering
Minimal
Uses cache
Access Type
Sequential
Random
5.What are major and minor numbers?
Major Number → Identifies the driver
Minor Number → Identifies the device instance
These numbers help the kernel route operations to the correct driver.
6.What is /dev in Linux Character Drivers?
/dev is a directory where device files are created.
Example:
/dev/my_device
This file acts as the entry point for user applications to interact with the driver.
7.What is printk() in Linux drivers?
printk() is used for kernel-level logging, similar to printf() in user space.
Example:
printk(KERN_INFO "Driver Loaded\n");
You can view logs using:
dmesg
8.What is __init and __exit in Linux drivers?
__init → Marks initialization function (freed after loading)
__exit → Marks cleanup function (used during module removal)
These help optimize memory usage in the kernel.
9.How do you load and unload a character driver?
Load driver:
sudo insmod driver.ko
Unload driver:
sudo rmmod driver
Check logs:
dmesg
10.What is a kernel module in Linux?
A kernel module is a piece of code that can be loaded/unloaded into the kernel dynamically. A Linux Character Driver is typically implemented as a kernel module.
11.Where are Linux Character Drivers used?
They are used in real-world scenarios like:
UART communication
GPIO control
Sensor interfacing
Embedded systems
Serial devices
12.Do I need hardware to learn character drivers?
No. You can start with a virtual character driver (dummy driver) and simulate read/write operations without real hardware.
13.What are common mistakes beginners make?
Forgetting cleanup in __exit
Not handling copy_to_user() properly
Incorrect major/minor number handling
Missing error checks in init function
14.Is Linux Character Driver development hard?
Initially, it may feel complex, but with step-by-step practice:
Start with a simple module
Learn file_operations
Build a dummy driver
It becomes much easier over time.
15.What is the difference between read() and write() in drivers?
read() → Kernel → User space (sending data)
write() → User space → Kernel (receiving data)
16.Can I build a production-level driver with character drivers?
Yes. Many real-world drivers (UART, I2C user interfaces, debug interfaces) are built using character drivers.
For detailed understanding of Platform Devices and Drivers on Linux, refer to the official Linux documentation on
Platform Devices and Drivers
.
Learn Platform Devices and Drivers in Linux from scratch with clear explanations, device tree examples, driver code, testing steps, and real-world insights.
If you are getting into Linux device drivers, especially embedded Linux, you will keep hearing one phrase again and again: Platform Devices and Drivers.
At first, it sounds complicated. Platform bus, platform_device, platform_driver, device tree, probe function, resources, matching. It feels like too many moving parts.
But once you understand the why behind platform devices and drivers, everything starts to click.
This guide is written for beginners, but with expert depth, so it also helps during interviews and real projects.
What Are Platform Devices and Drivers in Linux?
In simple words:
Platform Devices and Drivers are used in Linux to handle on-chip hardware that is not discoverable automatically.
That single sentence explains 80 percent of the concept.
Unlike PCI or USB devices, many embedded peripherals are:
Built directly into the SoC
Always present
Not hot-pluggable
Not discoverable by scanning a bus
Examples include:
GPIO controllers
I2C controllers
SPI controllers
UARTs
Timers
Watchdogs
On-chip ADCs
Linux still needs a clean way to represent these hardware blocks. That is where Platform Devices and Drivers come in.
Why Platform Devices and Drivers Exist
To understand platform drivers, first understand what Linux expects from hardware.
Linux follows a simple model:
A device describes hardware
A driver knows how to control that hardware
The kernel matches them and binds them
For PCI or USB, the kernel can discover devices automatically. For embedded hardware, there is no discovery mechanism.
So Linux needed:
A way to describe fixed hardware
A bus that does not rely on enumeration
A matching mechanism that still feels clean
That solution is the platform bus.
What Is the Platform Bus?
The platform bus is a virtual bus inside the Linux kernel.
It is not a real hardware bus like I2C or SPI.
Think of it as a logical meeting place where:
Platform devices are registered
Platform drivers are registered
The kernel matches them by name or device tree
This bus makes sure Linux can treat on-chip hardware the same way it treats external devices.
Platform Device vs Platform Driver
This confusion is very common, especially for beginners.
Let us clear it properly.
Platform Device
A platform device represents the hardware.
It describes things like:
Base memory address
IRQ number
DMA channels
Clock names
Device name
The platform device does not contain logic. It only describes what exists.
Platform Driver
A platform driver contains the software logic.
It knows:
How to initialize the hardware
How to read and write registers
How to handle interrupts
How to expose functionality to user space
The driver does the actual work.
How Platform Devices Were Defined Earlier
Before device tree became common, platform devices were defined in board files.
make -C /lib/modules/$(uname -r)/build M=$PWD modules
Step 13: Insert and Test
sudo insmod my_platform_driver.ko
dmesg | tail
Expected output:
Platform driver probed
Step 14: Verify Binding
ls /sys/bus/platform/devices
ls /sys/bus/platform/drivers/my_platform_driver
If your device appears → success
Key Interview Points
Platform drivers are for non-discoverable devices
Device tree creates platform devices
Matching happens via compatible
probe() initializes hardware
devm_ APIs simplify cleanup
What You Should Do Next
If you want real mastery, next steps:
Add character device interface
Add IRQ handling
Add sysfs attributes
Convert to GPIO / LED driver
Learn power management callbacks
Why Platform Devices and Drivers Matter for Your Career
Understanding Platform Devices and Drivers shows that you:
Understand Linux internals
Can work close to hardware
Can read device tree files
Can debug kernel issues
This skill separates application developers from embedded engineers.
FAQ: Platform Devices and Drivers in Linux
1. What are platform devices and drivers in Linux?
Platform devices and drivers in Linux are used to manage hardware that is built directly into the system, such as GPIO controllers, UARTs, and timers. These devices cannot be auto-detected, so Linux uses the platform bus and device tree to describe and bind them to drivers.
2. Why are platform drivers needed in embedded Linux?
Platform drivers are needed in embedded Linux because most on-chip peripherals do not support hardware discovery. The platform driver framework allows Linux to cleanly separate hardware description from driver logic using device tree.
3. What is the difference between a platform device and a platform driver?
A platform device represents the hardware information like memory address and interrupts, while a platform driver contains the code that controls the hardware. Linux matches them and calls the driver’s probe function.
4. How does device tree work with platform devices and drivers?
The device tree describes hardware in a structured format. During boot, the Linux kernel parses the device tree and automatically creates platform devices, which are then matched with platform drivers using compatible strings.
5. What is the platform bus in Linux?
The platform bus is a virtual bus inside the Linux kernel that connects platform devices with platform drivers. It is mainly used for fixed hardware present on the SoC.
6. How does Linux match a platform driver to a platform device?
Linux matches a platform driver to a platform device using the compatible string defined in the device tree and the of_match_table in the driver code.
7. What happens inside the probe function of a platform driver?
The probe function is called when the driver matches a device. It initializes hardware, maps registers, requests interrupts, and prepares the device for use.
8. Is a platform driver the same as a character driver?
No. A platform driver defines how the driver binds to hardware, while a character driver defines how user space interacts with the driver. A platform driver can internally register a character driver.
9. Do platform drivers always require a device tree?
In modern Linux systems, platform drivers usually rely on device tree. Older systems used board files, but device tree is now the standard and recommended approach.
10. How can I test if my platform driver is working correctly?
You can test a platform driver by checking kernel logs using dmesg, verifying device creation in /sys/bus/platform, and confirming that the probe function is executed successfully.
11. What are common mistakes when writing platform devices and drivers?
Common mistakes include mismatched compatible strings, incorrect memory addresses in device tree, forgetting the of_match_table, and improper resource handling in the probe function.
12. Where are platform devices and drivers used in real projects?
Platform devices and drivers are widely used in automotive systems, industrial controllers, IoT devices, medical equipment, and consumer electronics running embedded Linux.