Skip to content

Platform Driver Development

Overview

Platform drivers are commonly used for on-chip peripherals that do not reside on discoverable buses such as PCIe or USB.

Typical examples include:

  • GPIO controllers
  • UART controllers
  • SPI controllers
  • I2C controllers
  • Watchdogs
  • Timers
  • SoC-specific peripherals

A platform driver obtains hardware resources from a platform device and initializes the corresponding hardware instance.


Architecture

Device Tree
of_platform_populate()
platform_device
platform_match()
platform_driver
probe()

The platform driver does not create hardware resources.

Resources are created during platform device creation and passed to the driver during probe.


Platform Resources

Hardware resources are represented using:

struct resource

Common resource types:

Resource Type Description
IORESOURCE_MEM Memory-mapped I/O region
IORESOURCE_IRQ Interrupt resource
IORESOURCE_DMA DMA channel resource
IORESOURCE_IO Legacy I/O port resource

Resource Acquisition

Memory Resource

Acquire MMIO resources:

struct resource *res;

res = platform_get_resource(
            pdev,
            IORESOURCE_MEM,
            0);

Arguments:

Parameter Description
pdev Platform device
IORESOURCE_MEM Resource type
0 Resource index

IRQ Resource

Acquire interrupt resources:

int irq;

irq = platform_get_irq(
            pdev,
            0);

The returned value is a Linux IRQ number after irqdomain mapping.

It is not necessarily identical to the interrupt specifier defined in Device Tree.


Driver Private Data

Most platform drivers maintain instance-specific state.

Typical structure:

struct demo_priv {
    void __iomem *base;
    int irq;
};

Each device instance owns its own private data.

Avoid using global variables for per-device state.


Storing Driver Data

Attach private data to the platform device:

platform_set_drvdata(
        pdev,
        priv);

Retrieve later:

priv = platform_get_drvdata(
            pdev);

Common users:

  • remove()
  • IRQ handlers
  • sysfs callbacks
  • file_operations
  • worker threads

Managed Resource Allocation

Modern Linux drivers typically use devm-managed APIs.

Examples:

devm_kzalloc()

devm_request_irq()

devm_ioremap_resource()

Benefits:

Automatic cleanup
Reduced error handling
Simpler remove path

General flow:

probe()
Acquire resources
Device removed
Resources automatically released

Interrupt Registration

Register an interrupt handler:

ret = devm_request_irq(
            &pdev->dev,
            irq,
            handler,
            flags,
            name,
            priv);

The private data pointer is passed back to the interrupt handler:

static irqreturn_t handler(
        int irq,
        void *data)
{
    struct demo_priv *priv = data;

    ...
}

Delayed Work Integration

Interrupt handlers should remain short and non-blocking.

A common pattern:

IRQ
Schedule delayed work
Worker executes later

Example:

mod_delayed_work(
        system_wq,
        &priv->irq_work,
        msecs_to_jiffies(50));

Common use cases:

  • GPIO debounce
  • Deferred processing
  • Event aggregation
  • Retry operations

Typical Platform Driver Probe Flow

probe()


devm_kzalloc()


platform_get_resource()


platform_get_irq()


platform_set_drvdata()


devm_request_irq()


Driver Ready

Relationship to Platform Bus

Linux Driver Model
Platform Bus
Platform Device
Platform Driver
Resource Acquisition
Hardware Initialization

Platform driver development builds on the platform bus infrastructure and focuses on acquiring resources and initializing hardware.

  • Linux Driver Model Fundamentals
  • Platform Bus Internals
  • Device Tree and Platform Devices
  • GPIO Driver Development
  • Workqueue and Delayed Work
  • Threaded IRQ
  • platform_get_resource()
  • platform_get_irq()
  • platform_set_drvdata()
  • platform_get_drvdata()
  • devm_kzalloc()
  • devm_request_irq()
  • devm_ioremap_resource()