Skip to content

Day 9 - GPIO Driver with gpiod and Device Tree

๐ŸŽฏ Objective

Learn how to control real hardware (GPIO) from a Linux kernel driver using:

  • Platform driver
  • Device Tree (DT)
  • Descriptor-based GPIO API (gpiod_*)
  • Character device interface (/dev/mygpio)

๐Ÿง  Key Concepts

1. From Legacy GPIO to gpiod

Old (deprecated):

gpio_request(17, "mygpio");
gpio_set_value(17, 1);

Problems: - GPIO number is not portable - Platform dependent - Hard to integrate with Device Tree


New (recommended):

gpiod = devm_gpiod_get(dev, "led", GPIOD_OUT_LOW);
gpiod_set_value(gpiod, 1);

Advantages: - No global GPIO number dependency - Works with Device Tree - Portable across platforms


2. Device Tree Binding

Device Tree defines hardware mapping:

mygpio_led {
    compatible = "myvendor,mygpio-led";
    led-gpios = <&gpio 17 0>;
};

Driver retrieves GPIO using:

devm_gpiod_get(dev, "led", GPIOD_OUT_LOW);

Mapping rule:

DT property gpiod_get argument
led-gpios "led"

3. Platform Driver Flow

Device Tree
    โ†“
platform device
    โ†“
driver probe()
    โ†“
gpiod_get()
    โ†“
character device (/dev/mygpio)

4. Character Device Interface

User space interacts via:

echo 1 > /dev/mygpio
cat /dev/mygpio

Driver implements:

  • write() โ†’ control GPIO
  • read() โ†’ read GPIO state

๐Ÿ”ง Implementation Highlights

write()

gpiod_set_value(mydev->led_gpiod, value);
  • Accepts 0 or 1
  • Controls GPIO output

read()

value = gpiod_get_value(mydev->led_gpiod);

Returns:

  • "0\n" or "1\n"

EOF Handling

if (*offset != 0)
    return 0;
  • Required for cat to terminate
  • Standard char driver pattern

๐Ÿงช Testing

Setup

./cleanup.sh
./rebuild.sh
./setup.sh

GPIO Control

echo 1 | sudo tee /dev/mygpio
echo 0 | sudo tee /dev/mygpio

GPIO Read

cat /dev/mygpio

Live Debug

sudo dmesg -w

๐Ÿž Debug Notes

1. Legacy GPIO issue on Raspberry Pi 5

Using:

gpio_request(17, ...)

failed because:

  • GPIO number โ‰  BCM number
  • Requires global GPIO index
  • Not reliable on modern platforms

2. "write() not working" false alarm

Observed:

  • No GPIO set to X in dmesg
  • Assumed write() was not called

Actual cause:

  • dmesg | tail missed logs
  • Driver was reloaded multiple times
  • Logs overwritten by probe/remove messages

3. System state inconsistency

Repeated:

  • dtoverlay
  • insmod / rmmod

caused:

  • Multiple probe/remove cycles
  • Confusing runtime state

4. Reboot fixed the issue

After reboot:

  • GPIO behavior returned to normal
  • Driver worked as expected

Conclusion:

Issue was caused by stale runtime state, not code logic.


๐Ÿ“Š What I Learned

  • Modern Linux uses gpiod, not gpio_request
  • Device Tree defines hardware, driver should not hardcode GPIO
  • Platform driver + DT is the standard model
  • Char device bridges user space and kernel
  • Debugging requires careful log observation (dmesg -w)

๐Ÿš€ Next Steps

  • Add interrupt support (GPIO button)
  • Learn IRQ handling
  • Explore poll / event-driven driver design

๐Ÿงฉ Summary

Day 9 marks the transition from:

"virtual driver"
โ†’
"real hardware driver"

Key achievement:

โœ” Successfully controlled GPIO via Linux kernel driver
โœ” Integrated Device Tree + platform driver
โœ” Implemented read/write interface
โœ” Understood modern GPIO architecture