A common Linux driver problem looks like this: the driver is built into the kernel, the Device Tree node exists, but probe never runs. Or probe runs but cannot obtain resources. Or the module loads successfully, but no device node appears.
If you only stare at the driver C file, this kind of problem is easy to misread.
A Linux driver is not “a hardware library function called by an application.” It first has to enter the kernel device model. The kernel needs to know which devices exist, which drivers exist, and what rules match them. Only after a match succeeds does the driver get a chance to initialize the hardware.
The safest first model is this: device means a hardware instance exists in the system, driver means code that can operate a class of hardware, and bus defines how the two are matched and how their lifecycle is managed. After a match succeeds, the kernel calls the driver’s probe.
hardware description / enumeration
-> device is created
-> driver is registered
-> bus match
-> probe
-> resources are acquired and hardware is initialized
-> interface is exposed to user space or a kernel subsystem
So probe is not a driver entry manually called by user code. It is the result of the kernel device model matching a device with a driver.
device Is a Hardware Instance
device means there is a concrete device in the system.
It is not driver code, and it is not the /dev/xxx node seen by user space. It is a kernel object that represents “this hardware instance exists.”
The device may come from different sources:
- Device Tree node
- ACPI table
- enumerable buses such as PCI or USB
- platform code
- MFD child devices
- child devices created by another driver at runtime
In embedded Linux, many board-level peripherals cannot enumerate themselves like PCI or USB devices. The kernel has to learn from Device Tree or board description that this board has a UART, an I2C controller, a sensor, or a GPIO-controlled reset line.
After a Device Tree node is parsed, the kernel creates the corresponding device according to bus semantics. A node on the platform bus becomes a platform device. A child node under an I2C bus becomes an I2C device.
So the first question is not whether the driver wrote a probe function. It is whether the corresponding device was created.
driver Is How a Class of Hardware Is Operated
driver means the kernel has code that knows how to operate a class of hardware.
It usually contains:
- match tables
probeinitialization entryremovecleanup entry- power-management callbacks such as suspend/resume
- interrupt, DMA, register, and buffer management logic
- interfaces exposed to upper kernel subsystems or user space
A driver should not hardcode every wiring detail of a board. It should describe how this kind of hardware works. Concrete resources such as register ranges, interrupt numbers, clocks, power supplies, GPIOs, and DMA channels are provided by the device.
That is why one driver can support multiple boards, or multiple variants in the same chip family.
Registering a driver with the kernel does not mean it immediately runs. The kernel calls its probe only when the bus finds a matching device.
bus Matches device and driver
In Linux, bus does not only mean a physical bus. It is more like a set of rules for organizing devices and drivers.
It is responsible for:
- managing devices attached to this bus
- managing drivers registered on this bus
- defining how devices and drivers match
- calling probe after a match succeeds
- dispatching lifecycle callbacks during remove, driver unload, shutdown, or power-state changes
PCI, USB, I2C, SPI, and platform all have different bus semantics.
PCI and USB devices can be discovered by hardware enumeration, and matching usually uses vendor ID, device ID, class, and similar fields.
I2C and SPI devices usually cannot be discovered by the bus itself; the kernel must learn that they exist from Device Tree, ACPI, or board code.
The platform bus is common for SoC internal peripherals and fixed board devices. Matching often uses compatible, device name, or ACPI ID.
So the bus decides how the system knows a device exists, and which fields a driver uses to match it.
probe Is the Initialization Entry After Matching
probe happens after a device and driver match.
A driver usually does this work in probe:
- read resources such as registers, interrupts, clocks, supplies, resets, pinctrl, GPIOs, and DMA channels
- map register addresses
- request interrupts
- allocate buffers or DMA resources
- initialize hardware
- register a character device, network device, input device, IIO device, or another subsystem object
- create necessary sysfs/debugfs entries
- prepare runtime PM or system suspend/resume state
This explains a common observation: entering probe does not mean the device is usable by the application. probe only means the driver has started taking ownership of the device. Resource acquisition, hardware initialization, or subsystem registration can still fail.
After probe returns success, the kernel considers this driver bound to this device.
remove, shutdown, and suspend/resume Are Also Lifecycle
A driver is not only probe.
After a device is bound to a driver, it may go through other lifecycle callbacks:
remove: release resources when the device is removed or the driver is unloadedshutdown: put hardware into a safe state before system shutdown or rebootsuspend: save state and stop I/O before system sleep or device low powerresume: restore registers, queues, interrupts, and hardware state after wakeup- runtime PM: suspend or resume an individual device while the system is still running
If these callbacks are wrong, a device may work on first boot but fail after module unload, reboot, sleep/wake, or low-power recovery.
The driver model does not manage only one initialization event. It manages the full lifecycle after device-driver binding.
Why platform driver Is Common in Embedded Linux
Embedded SoCs contain many fixed peripherals: UART, I2C controller, SPI controller, PWM, watchdog, GPIO controller, clock controller, interrupt controller, display controller, and more.
They are usually mapped into the SoC address space. They do not announce their identity after being plugged in like USB devices, and they do not enumerate through a standard configuration space like PCI devices.
These devices are often described by Device Tree:
uart0: serial@10000000 {
compatible = "vendor,soc-uart";
reg = <0x10000000 0x1000>;
interrupts = <5>;
clocks = <&clk 3>;
status = "okay";
};
After parsing this node, the kernel creates a platform device. The platform driver has a match table:
static const struct of_device_id uart_of_match[] = {
{ .compatible = "vendor,soc-uart" },
{ }
};
When compatible matches, the platform bus calls the driver’s probe. The driver then reads resources such as reg, interrupts, and clocks from the device.
So in embedded Linux, platform driver and Device Tree are often two sides of the same problem: Device Tree describes the hardware instance, and the platform driver operates that kind of hardware.
A Device Node Is Not the Same as a driver-model device
When user space says “device node,” it usually means files such as /dev/ttyS0, /dev/input/event0, or /dev/watchdog0.
That is not the same layer as struct device in the kernel driver model.
The kernel’s device/driver/bus model solves how a hardware instance and driver code are matched, bound, and managed. A /dev node solves how user space obtains a file descriptor for a device interface.
One possible path is:
platform device
-> platform driver probe
-> register tty/input/misc/char subsystem object
-> udev or devtmpfs creates device node
-> application open/read/write/ioctl
So probe can succeed without a /dev node if the driver did not register a user-space interface, subsystem registration failed, or udev/devtmpfs rules are wrong.
The reverse is also true: a /dev node does not prove the hardware is fully working. The node is only a user-space entry. Real I/O still depends on driver state, hardware state, interrupts, DMA, and power management.
What to Check When probe Does Not Run
When a driver does not enter probe, do not start by changing register code inside probe.
Split the path first.
First, check whether the device was created. Verify that the Device Tree node exists, status is okay, the parent bus is enabled, and runtime /proc/device-tree matches expectations.
Second, check whether the driver was registered. Is the driver built into the kernel, or is the module loaded? Does the match table exist? Are module dependencies satisfied?
Third, check whether bus matching can succeed. For platform, check compatible or name. For I2C/SPI, check how the device is created and which match table is used. For PCI/USB, check the ID table.
Fourth, check whether probe was deferred. If required resources are not ready, the driver may return -EPROBE_DEFER, for example when a clock, regulator, GPIO provider, or other dependency has not probed yet.
Fifth, check where probe failed. Resource acquisition, register mapping, interrupt request, DMA allocation, hardware reset, and subsystem registration all fail in different ways and usually leave different logs.
Sixth, check whether the user-space interface was created after successful probe. Look at the relevant subsystem, /sys, /dev, udev/devtmpfs, and permissions.
Once these layers are separated, a probe problem is less likely to be misdiagnosed as “the driver code did not execute.”
What to Remember in Practice
The core of the Linux driver model is not putting driver functions into the kernel. It is managing hardware instances, driver code, and matching rules separately.
device says what hardware exists in the system.
driver says how a class of hardware is operated.
bus says how the two are matched, bound, and managed through their lifecycle.
probe is the initialization entry after a successful match, not a function directly called by an application.
In embedded Linux, Device Tree, platform device, platform driver, resource acquisition, subsystem registration, and /dev nodes are often mixed into one vague issue. Splitting the chain makes it possible to tell whether the problem is in hardware description, driver matching, resource readiness, hardware initialization, or the user-space interface.