Day11 - Multi-GPIO IRQ Driver¶
Overview¶
This lab demonstrates how to build a Linux platform driver that:
- controls multiple GPIO outputs (LEDs)
- reads an input GPIO (button)
- handles button events using IRQ
- exposes a character device interface (
/dev/mygpio)
Quick Start¶
Test:
echo led1=1 | sudo tee /dev/mygpio
echo led2=1 | sudo tee /dev/mygpio
echo all=0 | sudo tee /dev/mygpio
cat /dev/mygpio
Press the button and observe IRQ logs.
Hardware Mapping¶
| Function | GPIO |
|---|---|
| LED1 | GPIO17 |
| LED2 | GPIO27 |
| BTN | GPIO22 |
Architecture Overview¶
User Space
|
| read/write
v
/dev/mygpio (char device)
|
v
mygpio driver (platform driver)
| \
| -> IRQ handler (button)
|
+--> LED1 GPIO (output)
+--> LED2 GPIO (output)
+--> BTN GPIO (input -> IRQ)
Device Tree Overlay¶
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2712";
fragment@0 {
target-path = "/";
__overlay__ {
mygpio: mygpio@0 {
compatible = "myvendor,mygpio-irq";
led1-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
led2-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
btn-gpios = <&gpio 22 GPIO_ACTIVE_LOW>;
};
};
};
};
Driver Design¶
Private Data Structure¶
/**
* @brief Private runtime data for mygpio device
*/
struct mygpio_dev {
struct device *dev;
struct gpio_desc *led1_gpiod;
struct gpio_desc *led2_gpiod;
struct gpio_desc *btn_gpiod;
int btn_irq;
int button_state;
struct mutex lock;
dev_t devt;
struct cdev cdev;
struct class *class;
};
IRQ Flow¶
IRQ Handler¶
static irqreturn_t mygpio_btn_isr(int irq, void *data)
{
struct mygpio_dev *mydev = data;
int value;
/* Keep ISR short and non-blocking */
value = gpiod_get_value(mydev->btn_gpiod);
if (value < 0) {
dev_err(mydev->dev, "IRQ read failed: %d\n", value);
return IRQ_HANDLED;
}
mydev->button_state = value;
dev_info(mydev->dev, "Button IRQ: state=%d\n", value);
return IRQ_HANDLED;
}
Probe Flow¶
1. Allocate device structure (devm_kzalloc)
2. Request GPIOs (devm_gpiod_get)
3. Read initial button state
4. Convert GPIO to IRQ (gpiod_to_irq)
5. Register IRQ (devm_request_irq)
6. Create char device
7. Save driver data (platform_set_drvdata)
Read Interface¶
Returns current device state:
Write Interface¶
Supported commands:
Build¶
Load Driver¶
Load Overlay¶
Verify¶
Expected:
Test LED Control¶
echo led1=1 | sudo tee /dev/mygpio
echo led2=1 | sudo tee /dev/mygpio
echo all=0 | sudo tee /dev/mygpio
Test Read¶
Example:
Test IRQ¶
Press button:
Common Issues¶
1. gpiod_to_irq() fails¶
- overlay not loaded
- wrong GPIO number
- invalid pin
2. No IRQ triggered¶
- wiring issue
- missing pull-up
- wrong polarity
- wrong trigger edge
3. Button state inverted¶
Check:
Key Concepts Learned¶
- Multiple GPIO handling in one driver
- Device Tree GPIO mapping
- Interrupt handling in Linux kernel
- devm_* resource management
- Character device + IRQ integration
Next Steps¶
- Debounce handling
- Toggle LED on button press
- Blocking read (wait queue)
- poll/select support
- threaded IRQ
File Structure¶
docs/labs/day11-multi-gpio-irq/
├── mygpio.c
├── mygpio-irq.dts
├── Makefile
└── day11-multi-gpio-irq.md