Timeline
Timeline
2025-11-15
init
This article introduces the concept and role of the platform bus in the Linux kernel, pointing out that it serves as an abstraction layer connecting platform devices and platform drivers, primarily used for devices directly integrated on SoCs or motherboards. The article also summarizes the advantages of the platform bus model in improving code reusability by separating devices and drivers, and discusses in detail core structures such as platform_device and resource, along with their parameter configuration methods.
Linux Driver Notes
| Table of Contents | Links |
|---|---|
| 1. Linux Driver Framework | |
| 2. Linux Driver Loading Logic | |
| 3. Character Device Basics | |
| 4. Concurrency and Race Conditions | |
| 5. Advanced Character Device Progression | |
| 6. Interrupts | |
| 7. Platform Bus | |
| 8. Device Tree | |
| 9. Device Model | |
| 10. Hot Plug | |
| 11. pinctrl Subsystem | |
| 12. GPIO Subsystem | |
| 13. Input Subsystem | |
| 14. Single Bus | |
| 15. I2C | |
| 16. SPI | |
| 17. UART | |
| 18. PWM | |
| 19. RTC | |
| 20. Watchdog | |
| 21. CAN | |
| 22. Network Device | |
| 23. ADC | |
| 24. IIO | |
| 25. USB | |
| 26. LCD |
Platform Bus
Inthe Linux Kernel,the Platform Busis a mechanism for managing and connectingplatform devicesandplatform driverabstraction layer. It acts as a bridge between platform devices and platform drivers, responsible for matching and binding them.
It is mainly used for devices thatare not discovered through standard buses (such as PCI, USB, I²C, SPI), but aredirectly integrated into the SoC (System on Chip) or on the motherboard。

By using the platform bus model, device drivers and platform devices are separated. This way, we only need to write a generic driver code, and then configure it for different platform devices, which greatly reduces the workload of rewriting code and improves the reusability of driver code.
When we need to port the driver to a different platform, we only need to adapt the hardware-related parts, while the rest can remain unchanged.
Under the platform bus,devices (platform_device) and drivers (platform_driver) are two independent objects。
- Devices come from DT/board-level files/platform code
- Drivers come from module loading/compilation into the kernel
- Driver unloading does not mean device disappearance
Register platform device
struct platform_device
1 | // include/linux/platform_device.h |
const char *name: Device name, used to uniquely identify the device. A unique name must be provided so that the kernel can correctly identify and manage the device.int id: Device ID, used to distinguish different instances of the same device. This parameter is optional; if ID-based differentiation is not needed, it can be set to -1struct device dev: Represents the struct device corresponding to the platform device, used for basic device management and operations. A valid struct device object must be provided for this parameter,The release method of this structure must be implemented, otherwise a compilation error will occur。u32 num_resources: The number of device resources. If the device has resources (such as memory regions, interrupts, etc.), the number of resources needs to be provided.struct resource *resource: A pointer to the device resources. If the device has resources, a pointer to the resource array needs to be provided. This structure will be explained in detail in the next subsection.
struct resource
1 | //include/linux/ioport.h |
The most important are the first four parameters, and the specific introduction of each parameter is as follows:
resource_size_t start: The start address of the resource. It indicates the starting position of the resource or the address of the starting register.resource_size_t end: The end address of the resource. It indicates the ending position of the resource or the address of the ending register.const char *name: The name of the resource. It is a string used to identify and describe the resource.unsigned long flags: The flags of the resource. It contains specific flags used to indicate the attributes or characteristics of the resource. For example, flags can be used to indicate the availability, shareability, cache attributes, etc., of the resource. The specific values and meanings of the flags parameter can be defined and interpreted according to the system and driver requirements, but typically, it is used to represent the attributes, characteristics, or configuration options of the resource. Below are some common flags and their possible meanings
| Category | Flags | Description |
|---|---|---|
| Resource TypeRelated Flags | IORESOURCE_IO | Resource is I/O port resource |
IORESOURCE_MEM | Resource is memory resource | |
IORESOURCE_REG | Resource is register offset | |
IORESOURCE_IRQ | Resource is interrupt resource | |
IORESOURCE_DMA | Resource is DMA (Direct Memory Access) resource | |
IORESOURCE_BUS | Bus | |
| Resource Attributes and CharacteristicsRelated Flags | IORESOURCE_PREFETCH | Resource is side-effect-free prefetchable resource |
IORESOURCE_READONLY | Resource is read-only | |
IORESOURCE_CACHEABLE | Resource supports caching | |
IORESOURCE_RANGELENGTH | Resource range length | |
IORESOURCE_SHADOWABLE | Resource can be replaced by shadow resource | |
IORESOURCE_SIZEALIGN | Resource size field alignment | |
IORESOURCE_STARTALIGN | Start address field alignment | |
IORESOURCE_MEM_64 | Resource is a 64-bit memory resource | |
IORESOURCE_WINDOW | Resource forwarded by bridge | |
IORESOURCE_MUXED | Resource reused by software | |
IORESOURCE_SYSRAM | Resource is system RAM (modifier) | |
| Status and ControlRelated flags | IORESOURCE_EXCLUSIVE | User space cannot map this resource |
IORESOURCE_DISABLED | Resource is currently disabled | |
IORESOURCE_UNSET | Address not yet assigned to resource | |
IORESOURCE_AUTO | Address automatically assigned by system | |
IORESOURCE_BUSY | Driver marks resource as busy |
Embedded instruct platform_deviceinstruct resourcecan be retrieved viaplatform_get_resource()function. The following isplatform_get_resourceprototype:
1 | struct resource *platform_get_resource(struct platform_device *pdev, unsigned int type, unsigned int num); |
- The first parameter is the instance of the platform device itself.
- The second parameter specifies what kind of resource is needed. For memory, it should be
IORESOURCE_MEM。 - The num parameter is an index indicating which resource type is needed. Zero means the first, and so on.
If it is an interrupt resource, you must use:
1 | int platform_get_irq(struct platform_device *dev, unsigned int num); |
platform_device_register()
| Item | Description |
|---|---|
| Function Definition | int platform_device_register(struct platform_device *pdev); |
| Header File | #include <linux/platform_device.h> |
| Parameter pdev | Pointer toplatform_devicestructure pointer, describing the platform device to be registered, including device name, resources, device ID, etc. |
| Function | Register the platform device with the kernel, enabling it to participate in device resource allocation and driver matching. |
| Return Value | Success: returns 0; Failure: returns a negative error code |
1 | // include/linux/platform_device.h |
device_initialize(&pdev->dev)Initializepdev->dev.pdev->devisstruct platform_devicea member of the structure, representing the platform device’s correspondingstruct devicestructure. By calling thedevice_initializefunction, perform basic initialization onpdev->dev, such as setting the device’s reference count and device type.setup_pdev_dma_masksSet the architecture-specific data of pdev based on the platform device’s architecture data. The specific implementation of this function may be architecture-dependent, and it is mainly used to perform specific settings for the platform device under different architectures.platform_device_addfunction adds the platform device pdev to the kernel.platform_device_addfunction completes the addition of the platform device, including adding the device to the device hierarchy and adding the device’s resources. It returns an int result indicating the outcome of the device addition.
platform_device_registerThe main function of this function is toplatform_deviceregister the platform device described by the structure into the kernel, including device initialization, adding to the platform bus and device hierarchy, and adding device resources.
Through this function, after the platform device is registered, it can participate in the device resource allocation and driver matching process. The return value of the function can be used to determine whether the device registration is successful.
platform_device_unregister()
| Item | Description |
|---|---|
| Function Definition | void platform_device_unregister(struct platform_device *pdev); |
| Header File | #include <linux/platform_device.h> |
| Parameter pdev | Pointer to the platform device to be unregisteredplatform_devicestructure pointer |
| Function | Unregister a registered platform device, remove the device from the kernel, and perform resource cleanup. |
| Return Value | No return value |
1 | // drivers/base/platform.c |
platform_device_delFunction to remove the device from the device list of the platform bus. It removes the device from the device hierarchy and stops device resource allocation and driver matching.platform_device_putfunction, used to decrease the reference count of a device. This function checks the device’s reference count; if the count drops to zero, it releases the device structure and related resources. By decreasing the reference count, it ensures that the device can be freed when no longer in use.
platform_device_unregisterThe function is used to unregister a previously registered platform device, removing it from the kernel. It first callsplatform_device_delfunction to remove the device from the device hierarchy, and then callsplatform_device_putfunction to decrease the device’s reference count, ensuring the device can be freed when no longer in use.
Example
In lower kernel versionsplatform_devicethe release callback function must be implemented, otherwise compilation may fail
1 |
|
After loading, in the/sys/bus/platform/devicesdirectory, we can see themy_platform_devicedevice
1 | ~ # insmod platform_device_test.ko |
Register platform driver
struct platform_driver
1 | // include/linux/platform_device.h |
probe: Probe function pointer for platform device. When the system detects a platform device matching this driver, this function is called to initialize and configure the device.remove: Remove function pointer for platform device. When a platform device is removed from the system, this function is called to perform cleanup and resource release operations.shutdown: Shutdown function pointer for platform device. When the system shuts down, this function is called to perform shutdown operations related to the platform device.suspend: Suspend function pointer for platform device. When the system enters a suspend state, this function is called to perform suspend operations related to the platform device.resume: Resume function pointer for platform device. When the system resumes from a suspend state, this function is called to perform resume operations related to the platform device.driver: Contains generic data related to the device driver, which is an instance of typestruct device_driver. It includes information such as the driver’s name, bus type, module owner, and pointer to an array of attribute groups.id_table: Pointer tostruct platform_device_ida pointer to an array of structs, used to match the association between platform devices and drivers. Only upon successful matching can the probe function be entered, but its priority is lower thanplatform_driver.driver.of_match_tableprevent_deferred_probe: A boolean value used to determine whether to prevent deferred probing. If set to true, deferred probing will be disabled.
Note: The probe function is not a replacement for the init function. The probe function is called whenever a given device matches a driver, while the init function runs only once when the module is loaded.
You can use
MODULE_DEVICE_TABLE(type, name);to export the device ID tableplatform_driver.driver.of_match_tableinto the module’s ELF section, allowing userspace (udev/modprobe) to automatically load the driver.
struct device_driver
struct device_driveristhe Device Model layer)abstraction, which describes theidentity and behavior of the driver itself, for example:
- driver name, bus type, module information
- device match table (device tree, ACPI)
- driver operation callbacks:
probe/remove/suspend/resume - sysfs attributes and power management
Core idea:It focuses on the matching and lifecycle management between drivers and devices。
1 | // include/linux/device/driver.h |
platform_driver_register()
| Item | Description |
|---|---|
| Function Definition | int platform_driver_register(struct platform_driver *driver); |
| Header File | #include <linux/platform_device.h> |
| Parameter driver | Pointer toplatform_drivera pointer to the structure describing the platform driver to be registered, including attributes and callbacks. |
| Function | Registers the platform driver with the kernel, enabling the kernel to match it with specific platform devices and invoke the corresponding callbacks. |
| Return value | Success: returns 0; Failure: returns a negative error code |
1 |
|
This macro is used to simplify the registration process of platform drivers. It associates the actual registration function__platform_driver_registerwith the current module (driver). The macro parameter drv is a pointer tostruct platform_drivera structure that describes the properties and callback functions of the platform driver to be registered.THIS_MODULEis a macro used to obtain the pointer of the current module.
1 | // drivers/base/platform.c |
Through these operations,__platform_driver_registerthe function associates the platform driver with the kernel, ensuring that the kernel can correctly identify and call the various callback functions of the driver to achieve interaction and management with platform devices. The return value of the function indicates the execution status of the registration process, allowing for error handling when necessary.
platform_driver_register(): Registers the driver and places it into the driver list maintained by the kernel, so that whenever a new match is found, its probe() function can be called on demand.platform_driver_probe(): After calling this function, the kernel immediately runs a matching loop to check if there is a platform device name match; if matched, it calls the driver’sprobe(), meaning the device exists; otherwise, the driver is ignored. This method prevents deferred probing because it does not register the driver on the system. Here, the probe function is placed in the__initsection, which is freed when kernel startup completes, thus preventing deferred probing and reducing the driver’s memory footprint. Use this method if you are 100% sure the device exists in the system.
platform_driver_unregister()
| Item | Description |
|---|---|
| Function Definition | int platform_driver_register(struct platform_driver *driver); |
| Header File | #include <linux/platform_device.h> |
| Parameter driver | Pointer toplatform_driverstructure pointer, describing the platform driver to be registered, including attributes and callback functions. |
| Function | Registers the platform driver with the kernel, enabling the kernel to match it with specific platform devices and call the corresponding callback functions. |
| Return Value | Success: returns 0; Failure: returns a negative error code |
1 | // include/linux/platform_device.h |
bus_remove_driverFunction to remove the device driver from the bus. This function performs the following operations:- Remove the specified device driver from the bus driver list.
- Call the remove callback function associated with the device driver (if defined).
- Release the resources and memory occupied by the device driver.
- Finally destroy the data structure of the device driver.
By calling thedriver_unregisterfunction, the device driver can be properly unregistered, and necessary cleanup work is performed during the unregistration process. This avoids resource leaks and other issues. After calling this function, avoid continuing to use the pointer of the unregistered device driver, as the driver no longer exists in the kernel
platform_get_resource()
Obtain resource information of the platform device in the driver, and perform subsequent operations and configurations based on this information
| Item | Description |
|---|---|
| Function Definition | struct resource *platform_get_resource(struct platform_device *pdev, unsigned int type, unsigned int num); |
| Header file | #include <linux/platform_device.h> |
| Parameter pdev | Pointer to the platform device from which to obtain resources (platform_device) structure pointer |
| Parameter type | Resource type, such as:IORESOURCE_MEM: Memory resourceIORESOURCE_IO: I/O resourceIORESOURCE_IRQ: Interrupt resource |
| Parameter num | Resource index number, used to select thenum-th resource of the same type** in the device |
| Function | Retrieve resource information of a specified type and index from the platform device’s resource array |
| Return value | On success: returns a pointer tostruct resourcepointer;On failure or resource not found: returns NULL |
helper_macro
1 | /* module_platform_driver() - Helper macro for drivers that don't do |
module_platform_driver(driver)
📌 Purpose
Used forloadable kernel module(.ko), and the driver structure has been fully defined with.probe,.removeand other members.
🔧 Expanded effect
1 | static int __init driver_init(void) |
✅ Prerequisites
driveris a completestruct platform_drivervariable;- Implemented
.probe,.removeand other callback functions.
1 | static struct platform_driver my_driver = { |
builtin_platform_driver(driver)
📌 Purpose
Used fordrivers compiled into the kernel (not as modules), and the driver structureis fully defined。
🔧 Expanded effect
1 | static int __init driver_init(void) |
❗ No
exitpart (because built-in drivers are usually not unloaded).
✅ Applicable scenarios
- Driver statically linked to the kernel (
CONFIG_MY_DRIVER=y); - no need to support runtime unloading.
module_platform_driver_probe(driver, probe_fn)
📌 Purpose
Used forloadable modules, but you only want to provide a.probefunction, without manually defining the completeplatform_driverstruct (especially when you don’t need.removeand other callbacks).
🔧 Expanded Effect
1 | static int __init driver_init(void) |
⚠️ Key Points
platform_driver_probe()is alightweight registration method:- It only supports
.probe, and does not support.remove、.shutdownetc.; - drivercannot be unloaded and then reloaded(because internally it sets
driver->prevent_deferred_probe = true); - Applicable toSimple, one-time probedevices (such as certain SoC built-in controllers).
- It only supports
📝 Example
1 | static int my_probe(struct platform_device *pdev) |
💡 At this point,
my_driverno need to write in.probe = my_probe**, the macro will automatically associate.
builtin_platform_driver_probe(driver, probe_fn)
📌 Usage
module_platform_driver_probeofbuilt-in version(compiled into the kernel, not removable).
🔧 Expansion effect
1 | static int __init driver_init(void) |
Similarlyno exit path, suitable for simple built-in drivers.
Example
1 |
|
Test:
1 | ~ # insmod platform_device_test.ko |
LED Platform Bus Example
platform_device
1 |
|
platform_driver
1 |
|
A platform_driver may be used by multiple platform_devices. If written in the module_exit function, resources will not be released when the device is hot-plugged (or removed via sysfs). Therefore, resource cleanup logic should be placed in the remove function.

