Skip to content

Day73 - Platform Driver Development

Objective

Understand how a platform driver:

  • Acquires hardware resources
  • Stores private driver state
  • Obtains IRQ resources
  • Registers interrupt handlers
  • Uses devm-managed resources
  • Implements delayed work debounce

Background

Previous sessions covered:

  • Linux Driver Model
  • Platform Bus Internals
  • Device Tree → platform_device creation
  • platform_driver matching and probe flow

This lab focuses on the next stage:

Device Tree
platform_device
Resource Acquisition
Driver Initialization
IRQ Registration

Lab 1 - Platform Resource Acquisition

Device Tree Overlay

demo@10000000 {
    compatible = "demo,platform-lab";

    reg = <0x0 0x10000000 0x1000>;

    interrupt-parent = <&rp1_gpio>;
    interrupts = <23 2>;

    status = "okay";
};

Probe Flow

priv = devm_kzalloc(...);

res = platform_get_resource(
            pdev,
            IORESOURCE_MEM,
            0);

irq = platform_get_irq(
            pdev,
            0);

platform_set_drvdata(
            pdev,
            priv);

Validation

Expected output:

probe enter

MEM start=0x10000000
MEM end=0x10000fff
MEM size=0x1000

IRQ=<linux irq>

Observed:

MEM start=0x0000000010000000
MEM end=0x0000000010000fff
MEM size=0x0000000000001000
IRQ=165

Key Observation

The Linux IRQ number is not necessarily identical to the Device Tree interrupt specifier.

Interrupt mapping is performed through the irqdomain framework.


Lab 2 - Driver Private Data

Private Data Structure

struct demo_priv {
    struct resource *mem_res;
    int irq;
    int magic;
};

Store Driver Data

platform_set_drvdata(
        pdev,
        priv);

Retrieve Driver Data

priv = platform_get_drvdata(
            pdev);

Validation

Probe:

magic=12345

Remove:

magic=12345

Result

Verified driver state persistence across:

probe()
platform_set_drvdata()
remove()
platform_get_drvdata()

Lab 3 - IRQ Registration

Interrupt Handler

static irqreturn_t demo_irq_handler(
        int irq,
        void *data)
{
    ...
}

Register IRQ

ret = devm_request_irq(
            &pdev->dev,
            priv->irq,
            demo_irq_handler,
            0,
            dev_name(&pdev->dev),
            priv);

Result

GPIO23 successfully generated interrupts.

Observed:

demo irq handler:
irq=165

Key Observation

The private data pointer passed to:

devm_request_irq()

is received by:

irq_handler()

through the handler context argument.


Lab 4 - Delayed Work Debounce

Motivation

Mechanical switches generate multiple interrupts due to contact bouncing.

Observed behavior:

Single button press
Multiple IRQ events

Delayed Work Initialization

INIT_DELAYED_WORK(
        &priv->irq_work,
        demo_irq_work);

Debounce Logic

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

Debounce Flow

IRQ
mod_delayed_work()
50ms timeout
worker executes

Repeated interrupts refresh the timeout instead of scheduling multiple workers.

Result

Multiple bounce interrupts were merged into a single delayed work execution.


Platform Driver Initialization Flow

Final initialization sequence:

probe()


devm_kzalloc()


platform_get_resource()


platform_get_irq()


platform_set_drvdata()


devm_request_irq()


INIT_DELAYED_WORK()


Ready

Conclusion

This lab verified the complete platform driver initialization path:

Device Tree
platform_device
resource acquisition
private driver state
IRQ registration
delayed work handling

The driver now demonstrates the typical structure used by many real-world platform drivers.