GPIO_Interrupt.c
/*
 * Basic Linux Kernel module using GPIO interrupts.
 *
 * Author:
 *     murat demirtas <[email protected]>
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include "raspberry_pi_gpio_irq.h"        //used for debugging based printk()
#include <linux/sched.h>                  //used for getting module infos
#include <linux/vermagic.h>               //used for getting current kernel and process info
#include <linux/gpio.h>              //used for hardware GPIO
#include <linux/interrupt.h>          //used for interrupt handling

/**
 * @brief variables used for this example
 */
#define GPIO_PIN_DESC "For detecting rising edges interrupts"
#define GPIO_IRQ_DESC "Example GPIO Interrupt"
#define MODULE_DEBUG_MODE

/**
 * @brief we want GPIO_17 of BCM2836 (pin 11 on P5 pinout raspberry pi rev. 2 board)
 * to generate interrupt
 */
#define BCM2836_HW_GPIO_PIN 17
short int IRQ_NUMBER_OF_GPIO  = 0;

/**
 * @brief for return code of LKM
 */
enum {
    MODULE_OK,
    GPIO_FAILURE
}ret_code_of_mod;

/**
 * @brief enum for GPIO request return code of ARM BCM2836
 */
enum
{
    NO_ERR,
    GPIO_TO_REQ_ERR,
    GPIO_TO_IRQ_ERR,
    IRQ_TO_REQ_ERR
}gpio_err;

/**
 * @brief enum for detecting edges on GPIO
 */
enum 
{ 
    FALLING,
    RISING,
    BOTH_FALLING_RISING,
}edge_types;

/**
 * @brief function for print module parameters to dmesg log
 * @return none
 */
static void debug_when_init(void)
{
    #ifdef MODULE_DEBUG_MODE
    PINFO("Kernel version is: %s ",UTS_RELEASE);
    PINFO("Process ID is: %d",current->pid);
    PINFO("Module called with:%s ",current->comm);
    #endif
    return;
}

/**
 * @brief module settings.
 */
MODULE_ALIAS("interrupting");     //it will be module alias
MODULE_LICENSE("GPL");           //module license (must be define)
MODULE_AUTHOR("murat demirtas <[email protected]>");   //module author
MODULE_DESCRIPTION("RPi GPIO interrupt with IRQ");  //module description

/**
 * @brief  irq handler cb function, will be fire when interrupt generated
 * @params irq number and device id of GPIO Controller
 * @return irqreturn_t 
 * @attention printk() should not be used for performance and stability
 */
static irqreturn_t r_irq_handler(int irq, void *dev_id)
{
    unsigned long interrupt_flag;
    long int count = 0;
    /**
      * @brief  clear and restore interrupt flags using local_irq_save
     * and restore
     */

    local_irq_save(interrupt_flag);

    //ATTENTION//
    //PRINTK IS BLOCKING CALL  AND SHOULD BE NOT USED IN
    //REAL INTERRUPT APPLICATIONS
    #ifdef MODULE_DEBUG_MODE
    printk(KERN_NOTICE "Rising edge detected,Interrupt! on  GPIO [%d]\n",
            BCM2836_HW_GPIO_PIN);
    #endif


    //////////////////////////////////////////////////////////////////////
    ////////////////////YOUR FUNCTIONS WILL COME HERE/////////////////////
    //////////////////////////////////////////////////////////////////////
    count  = count + 1;

    local_irq_restore(interrupt_flag);

        return IRQ_HANDLED;
}

/**
 * @brief  Setup BCM2836 GPIO Peripherals
 * @params none
 * @return GPIO request return code
 */
static int setup_gpio_interrupt(void)
{

    PDEBUG("Requesting BCM2836 Pin...\n");

    /**
      * @brief request gpio from pinctrl-bcm2835
     */
    if(gpio_request(BCM2836_HW_GPIO_PIN,GPIO_IRQ_DESC))    {
        PERR("GPIO request failure for pin %d\n",BCM2836_HW_GPIO_PIN);
        return GPIO_TO_REQ_ERR;
    }

    /**
      * @brief set direction to input
     */
    gpio_direction_input(BCM2836_HW_GPIO_PIN);           

    /**
      * @brief request map to irq
     */
    IRQ_NUMBER_OF_GPIO = gpio_to_irq(BCM2836_HW_GPIO_PIN);

    if(IRQ_NUMBER_OF_GPIO < 0) {
        PERR("IRQ request failure for pin %d\n",BCM2836_HW_GPIO_PIN);
        return GPIO_TO_IRQ_ERR;
    }

    PDEBUG("IRQ mapped to gpio pin, IRQ no: %d\n",IRQ_NUMBER_OF_GPIO);

    /**
      * @brief try to register irq request to proc and prepare cb functions
     */
    if(request_irq(IRQ_NUMBER_OF_GPIO,(irq_handler_t) r_irq_handler,
            IRQF_TRIGGER_RISING, GPIO_PIN_DESC, GPIO_IRQ_DESC))
    {
        PERR("GPIO request failure for pin %d\n",BCM2836_HW_GPIO_PIN);
        return IRQ_TO_REQ_ERR;
    }

    PDEBUG("IRQ Request successfull:no %d\n",IRQ_NUMBER_OF_GPIO);

    return NO_ERR;
}

/**
 * @brief  for clearing IRQ request and GPIO settings
 * @params none
 * @return error code
 */
static int release_gpio_interrupt(void)
{

    PDEBUG("freeing irq and gpio pin\n");
    free_irq(IRQ_NUMBER_OF_GPIO,GPIO_IRQ_DESC);
    gpio_free(BCM2836_HW_GPIO_PIN);

    return NO_ERR;
}

/**
 * @brief  will fire when module removed
 * @params none
 * @return err code of module
 */
static int __init init_gpio_irq_fn(void)
{
    PINFO("GPIO IRQ module called,debug info:\n");
    debug_when_init();

    if(setup_gpio_interrupt() != NO_ERR)
        return GPIO_FAILURE;

    return MODULE_OK;
}

/**
 * @brief  will fire when module removed
 */
static void __exit exit_gpio_irq_fn(void)
{
    PINFO("GPIO IRQ module removing,IRQ no :%d\n",IRQ_NUMBER_OF_GPIO);
    release_gpio_interrupt();
    return;
}

/**
 * @brief  functions that will fire when module installed and removed
 */
module_init(init_gpio_irq_fn);
module_exit(exit_gpio_irq_fn);

results matching ""

    No results matching ""