raspberry-pilinux-kernelinterruptgpio

Check Interrupt Flag in a Linux kernel module


I am trying to check the interrupt flag (rising flag, falling flag) in a interrupt handler in a Linux kernel module. Is there a way to solve it by using irq_data?
Or is the only option to read the input value of the input pin inside the interrupt handler to check if a falling edge or a rising edge occur?

My Hardware is a Raspberry Pi 3b+. My code where I can´t differentiate between rising and falling edge:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqnr.h>

/* Meta Information */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("");
MODULE_DESCRIPTION("");

/** variable contains pin number o interrupt controller to which GPIO 17 is mapped to */
#define InputPinLine1 17
unsigned int IrqNumberInputLine1;

static irq_handler_t IrqCallbackInputLine1(unsigned int irq, void *dev_id, struct pt_regs *regs) 
{
    struct irq_data *data = irq_get_irq_data(irq);
    uint8_t  trigger_type = irqd_get_trigger_type(data);

    printk("------Line 1 ISR\n");
    printk("trigger:%d\n", trigger_type);

    return (irq_handler_t) IRQ_HANDLED; 
}

static int __init ModuleInit(void) 
{
    printk("Loading module... ");

    // Setup Interrupt for Line 1 
    if (gpio_request(InputPinLine1, "rpi-gpio-17")) {
        printk("Error!\nCan not allocate GPIO InputPinLine1\n");
        return -1;
    }
    if (gpio_direction_input(InputPinLine1)) {
        printk("Error!\nCan not set GPIO 17 to input!\n");
        gpio_free(InputPinLine1);
        return -1;
    }
    IrqNumberInputLine1 = gpio_to_irq(InputPinLine1);
    if (request_irq(IrqNumberInputLine1, (irq_handler_t) IrqCallbackInputLine1, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "IrqCallbackInputLine1", NULL) != 0) {
        printk("Error!\nCan not request interrupt nr.: %d\n", IrqNumberInputLine1);
        gpio_free(InputPinLine1);
        return -1;
    }

    return 0;
}

static void __exit ModuleExit(void) 
{
    printk("Unloading module... ");
    free_irq(IrqNumberInputLine1, NULL);
    gpio_free(InputPinLine1);
}

module_init(ModuleInit);
module_exit(ModuleExit);

This only prints a value 3, it doesn't matter which Interrupt (rising, falling) occur:

static irq_handler_t IrqCallbackInputLine1(unsigned int irq, void *dev_id, struct pt_regs *regs) 
{
    struct irq_data *data = irq_get_irq_data(irq);
    uint8_t  trigger_type = irqd_get_trigger_type(data);

    printk("------Line 1 ISR\n");
    printk("trigger:%d\n", trigger_type);

    return (irq_handler_t) IRQ_HANDLED; 
}

Is there a way to get the interrupt flag rising or falling by using the struct irq_data?
If anyone has a solution for this, it would be cool.


Solution

  • Looking at page 96 of BCM2837 ARM Peripherals manual, there is a single event detection status bit for each GPIO line in the GPEDSn (GPEDS0 and GPEDS1) registers. That is what the GPIO interrupt controller uses to check which GPIO interrupts are pending. It is a single bit, so cannot tell which type of event occurred if several types of event are enabled for the same GPIO line.

    You are stuck with checking the level of the GPIO line in the interrupt handler, and hope you have not missed any transitions.