How to Define an IRQ Handler in a Custom Linux Device Driver Print

 

This note explains how to add an IRQ handler to a custom device driver in the uClinux kernel running on the SmartFusion2.

The specific example below was developed on the Emcraft Systems M2S-FG484 System-On-Module plugged into the SOM-BSB-EXT development baseboard. The example defines an IRQ handler for the user push button on the SOM-BSB-EXT.

The push button input is tied to MSS GPIO_0 in the default Libero design used with the M2S-FG484 SOM. This is IRQ 50 in the NVIC space.

Here is the code that registers the IRQ and enables the interrupt at the GPIO level:

#include <linux/interrupt.h>
...
/*
* Register an IRG handler for the User-push button press event
*/
ret = request_irq(50, sample_irq, 0, "sample", 0);
if (ret < 0) {
printk(KERN_ALERT "%s: request_irg failed with %d\n",
__func__, ret);
goto Done;
}

/*
* Configure GPIO_O as input, enable interrupts, Level Low
*/
* (volatile unsigned int *) (0x40013000 + 0) = (1<<1) | (1<<3) | (1<<5);

Here is the interrupt handler. For the level sensitive interrupts, no explicit clearing is needed, for edge sensitive you would have to add code to explicitly clear the interrupt by writing into the GPIO_IRQ register:

static irqreturn_t sample_irq(int irq, void *dev_id)
{
printk("irq %d\n", irq);

return IRQ_RETVAL(1);
}

Here is how the code was tested on the target.

  1. Load the driver as a kernel module (the driver was developed over NFS):
  2. /mnt # insmod sample.ko
    /mnt #

  3. Push the button, then release it quickly. As can be seen from the snapshot below, the interrupt is triggered as long as there is the hardware event (the push button signal is being low), then there is no interrupt when the push button is released:
  4. /mnt # irq 50
    irq 50
    irq 50
    ...
    irq 50
    /mnt #
    /mnt #
    /mnt # ls
    Makefile            app.c          sample.c         sample.mod.o
    Module.symvers      app.gdb        sample.ko        sample.o
    app                 modules.order  sample.mod.c
    /mnt #