This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

detecting interrupt on GPIO in kernel module

Other Parts Discussed in Thread: AM3517

I am toggling the input into a GPIO line on my BeagleBone from high to low every 500 ms using an Atmel uC. I have registered a handler for this in my Linux Kernel Module, but the handler is not being called for some reason.

My module code is -

#define MY_MAJOR 89
#define MY_MINOR 0
#define GPIO_ANY_GPIO 54

// text below will be seen in 'cat /proc/interrupt' command
#define GPIO_ANY_GPIO_DESC "MyInterrupt"
#define GPIO_ANY_GPIO_DEVICE_DESC "mydevice"

volatile unsigned int val;

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sid");
MODULE_DESCRIPTION("A Simple Character Device Driver module");

static int my_open(struct inode *, struct file *);
static ssize_t my_read(struct file *, char *, size_t, loff_t *);
static ssize_t my_write(struct file *, const char *, size_t, loff_t *);
static int my_close(struct inode *, struct file *);
static void my_tasklet_handler(unsigned long );

static char *msg=NULL;
unsigned long flags;

struct file_operations my_fops = {
read : my_read,
write : my_write,
open : my_open,
release : my_close,
owner : THIS_MODULE
};

struct cdev my_cdev;


short int irq_any_gpio = 0;

unsigned int last_interrupt_time = 0;
static uint64_t epochMilli;

unsigned int millis (void)
{
struct timeval tv ;
uint64_t now ;

do_gettimeofday(&tv) ;
now = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ;

return (uint32_t)(now - epochMilli) ;
}

DECLARE_TASKLET(mytasklet, my_tasklet_handler, 0);

static void my_tasklet_handler(unsigned long flag)
{
tasklet_disable(&mytasklet);

printk(KERN_NOTICE "Interrupt for device was triggered !.\n");

tasklet_enable(&mytasklet);
}

static irqreturn_t r_irq_handler(int irq, void *dev_id, struct pt_regs *regs) {
unsigned int interrupt_time = millis();

if (interrupt_time - last_interrupt_time < 1000)
return IRQ_HANDLED;

last_interrupt_time = interrupt_time;
local_irq_save(flags);
tasklet_schedule(&mytasklet);
local_irq_restore(flags);
return IRQ_HANDLED;
}

void r_int_config(void) {

struct timeval tv ;

do_gettimeofday(&tv) ;
epochMilli = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ;

if (gpio_request(GPIO_ANY_GPIO, GPIO_ANY_GPIO_DESC)) {
printk("GPIO request failure: %s\n", GPIO_ANY_GPIO_DESC);
return;
}

if ( (irq_any_gpio = gpio_to_irq(GPIO_ANY_GPIO)) < 0 ) {
printk("GPIO to IRQ mapping failure %s\n", GPIO_ANY_GPIO_DESC);
return;
}

printk(KERN_NOTICE "Mapped int %d\n", irq_any_gpio);

if (request_irq(irq_any_gpio,
(irq_handler_t ) r_irq_handler,
IRQF_TRIGGER_HIGH,
GPIO_ANY_GPIO_DESC,
GPIO_ANY_GPIO_DEVICE_DESC)) {
printk("Irq Request failure\n");
return;
}

return;
}

void r_int_release(void) {

free_irq(irq_any_gpio, GPIO_ANY_GPIO_DEVICE_DESC);
gpio_free(GPIO_ANY_GPIO);

return;
}

int init_module(void)
{

dev_t devno;
unsigned int count;
int err;

printk("<1>Hello World\n");

devno = MKDEV(MY_MAJOR, MY_MINOR);
register_chrdev_region(devno, 1, "mydevice");

cdev_init(&my_cdev, &my_fops);

my_cdev.owner = THIS_MODULE;
count = 1;
err = cdev_add(&my_cdev, devno, count);
printk("'mknod /dev/mydevice c %d 0'.\n", MY_MAJOR);

msg = (char *)kmalloc(8, GFP_KERNEL);
if (msg !=NULL)
printk("malloc allocator address: 0x%x\n", msg);

if (err < 0)
{
printk("Device Add Error\n");
return -1;
}
r_int_config();

return 0;
}

void cleanup_module(void)
{
dev_t devno;

printk("<1> Goodbye\n");

devno = MKDEV(MY_MAJOR, MY_MINOR);
r_int_release();
if (msg){
/* release the malloc */
kfree(msg);
}
tasklet_kill(&mytasklet);
unregister_chrdev_region(devno, 1);
cdev_del(&my_cdev);
}

static int my_open(struct inode *inod, struct file *fil)
{
int major;
int minor;

major = imajor(inod);
minor = iminor(inod);
printk("\n*****Some body is opening me at major %d minor %d*****\n",major, minor);
return 0;
}

static ssize_t my_read(struct file *filp, char *buff, size_t len, loff_t *off)
{
int major;
short count;
major = MAJOR(filp->f_dentry->d_inode->i_rdev);
count = copy_to_user(buff, msg, len);

printk("*****Some body is reading me at major %d*****\n",major);
printk("*****Number of bytes read :: %d *************\n",len);

return 0;
}

static ssize_t my_write(struct file *filp, const char *buff, size_t len, loff_t *off)
{
int minor;
short count;
memset(msg, 0, 100);
count =copy_from_user(msg, buff, len);

minor = MAJOR(filp->f_dentry->d_inode->i_rdev);
printk("*****Some body is writing me at major %d*****\n",minor);
printk("*****Number of bytes written :: %d **********\n",len);

return 0;
}

static int my_close(struct inode *inod, struct file *fil)
{
#if 0
printk(KERN_ALERT "Device closed\n");
return 0;
#endif
int minor;
minor = MAJOR(fil->f_dentry->d_inode->i_rdev);
printk("*****Some body is closing me at major %d*****\n",minor);
return 0;
}

Upon doing - #insmod interrupt.ko I get -

[   76.594543] Hello World                                                      
[   76.597137] Mapped int 214  

Showing that i am getting an irq for the gpio.

But now when I start toggling the input into this gpio pin, the interrupt handler doesn't get called and the message "interrupt received" is not being displayed.

Also, cat /proc/interrupts gives me -

214: 0 GPIO MyInterrupt

Showing that the interrupt handler is not being called.

How do I solve this ? What's causing the problem?

  • Hi Siddharth,

        status = request_irq(irq_any_gpio, (irq_handler_t ) r_irq_handler, 0, GPIO_ANY_GPIO_DESC,GPIO_ANY_GPIO_DEVICE_DESC);

    OR

        status = request_irq(irq_any_gpio, (irq_handler_t ) r_irq_handler, IRQF_SHARED, GPIO_ANY_GPIO_DESC,GPIO_ANY_GPIO_DEVICE_DESC);

    OR

        status = request_irq(irq_any_gpio, (irq_handler_t ) r_irq_handler, 0, GPIO_ANY_GPIO_DESC,MY_MAJOR);

    Try to use the below "request_irq" function.

    	int status = 0;
    
    	status = request_irq(irq_any_gpio, (irq_handler_t ) r_irq_handler, 0, GPIO_ANY_GPIO_DESC,MY_MAJOR);
    
    	irq_set_irq_type(irq_any_gpio,IRQ_TYPE_EDGE_BOTH);	/* Try to use other types of trigger */
    
    
    	if (status == -EINVAL) {
    		printk("<1> EINVAL \n");
    		} 
    	else if (status == -ENOMEM) {
    		printk("<1> ENOMEM ");
    		} 		
    		
    	if (status < 0) {
    		printk("<1> gpio_request_irq : Failed to Register IRQ %d  \n",
    		       irq_any_gpio);
    		printk("<1> gpio_request_irq : return status is %d  \n",
    		       status);
    

  • Hi Siddharth,

    I was able to detect the irq by following these steps.

    1. Before calling the function request_irq, you have to configure the GPIO registers. ie GPIO_CLK, GPIO_OE, GPIO_LEVEL_DETECT(Falling / Level) and GPIO_IRQ_STATUS_SET registers. Load appropriate value into these registers by referring the data sheet. If required wakeup the GPIO channels.

    2. The last parameter of request_irq is usually NULL and the 4th parameter should be the device name instead of interrupt name (GPIO_ANY_GPIO_DESC). I think in your case it will be "mydevice".

    3. Also verify the GPIO_BANK, since I am not sure how many banks are available in your board.

    Kind regards,

    Dino

  • Hey Dino,

    Thanks for the suggestions.  Will give these a go

    Quick question on configuring the GPIO Pins. Below is my user-space program on using /dev/mem to enable a GPIO Pin for input or output. Is this how I would go about configuring the GPIO Pins in the kernel module as well? Could I use this method in a function that gets called from init_module followed by the setting up for the interrupt handler?

    int i=1;
    printf("opening memory device\n");
    int fd = open("/dev/mem", O_RDWR);
    if(fd<0)
    {
    perror("error in opening file\n");
    }

    volatile void *gpio1Addr = NULL;
    volatile unsigned long *gpioOE = NULL;
    volatile unsigned long *gpioSETDATAOUT = NULL;

    gpio1Addr = mmap(0, GPIO1_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO1_START_ADDR);
    gpioOE = gpio1Addr + GPIO1_OE;
    // gpioSETDATAOUT = gpio1Addr + GPIO1_SETDATAOUT;
    // gpioCLEARDATAOUT = gpio1Addr + GPIO1_CLEARDATAOUT;
    gpioSETDATAOUT = (gpio1Addr + GPIO1_DATAOUT);

    if(gpio1Addr == MAP_FAILED) {
    printf("Unable to map GPIO\n");
    exit(1);
    }

    unsigned int offset = 1;
    unsigned int pin;

    printf("Enter offset: ");
    scanf("%u", &offset);
    printf("You entered %u\n", offset);

    pin = (1 << offset);
    unsigned int creg = *gpioOE;
    creg = creg & ~pin;
    *gpioOE = creg;

    printf(" toggling LED \n");
    while(i<10000) {

    *gpioSETDATAOUT = *gpioSETDATAOUT | pin;

    *gpioSETDATAOUT = *gpioSETDATAOUT & ~pin;

    i++;

    }

    I would make a few changes to the above code, but is my method suitable for being implemented in the module?

    @Titusrathinaraj Stalin - Thanks for your reply. i will give these a go.

  • Hi Siddharth,

    I think this has to work but I haven't use this mapping of user space to kernel space.

    I have configured the registers in kernel space using the standard API's (request_mem_region and ioremap) and then using iowrite32 / ioread32 to alter the registers from their default value.


    Kind regards,

    Dino

  • Hey Dino, 

    Thanks for the reply. I am trying to use GPIO pin 54 (1x32 + 22) as input pin

    Its located on GPIO1 bank with start address given as below, the Output Enable offset is also shown below and the technical reference manual says that to configure the pin as input we need to put 0x1 on the respective bit ie (1<<22)

    Now, I haven't used the API's that you mentioned above. I have seen them a few times here and there and I think it's better if I use them. Could you please show me how to set OE(Output Enable) equal to 1 for the 22nd bit using the above API's you mentioned? That way I could go on to properly configure the rest of the funcitons for my GPIO such as IRQENABLE RISING DETECT etc

    #define GPIO1_START_ADDR 0x49050000//0x48310000
    #define GPIO1_SIZE (32 * 4096)
    #define GPIO1_OE 0x034

    Thanks!

  • Hi Siddharth,

    Edit 1: Make sure the declaration for gpio1_base as

    static void __iomem *gpio1_base;

    You can configure like the below mentioned code. Use the below mentioned code at "open" or "init".

    /* This API is for confirming that the requested memory region is not used by other module. Sometimes this may fail but still works. Just comment it out */
    r = request_mem_region(base_address_of_GPIO, SIZE, DEVICE_NAME);
      if(r == NULL)
      {
        printk(KERN_ERR "requesting mem region unsuccessful\n");
        return -1;
      }
    /* This API converts the base address of GPIO to virtual base address and hence therefore should be considered as base address of GPIO in kernel space */
    if((gpio1_base = ioremap(base_address_of_GPIO, SIZE)) == NULL)
      {
        printk(KERN_ERR "Mapping GPIO5_BASE unsuccessful\n");
        return -1;
      }

    After this configuration write the data to new virtual address ie gpio1_base just before the request_irq is called. The code below gives an example

    l = ioread32(gpio1_base + GPIO_OE);//GPIO_OE is the offset
      l &= ~GPIO1_BIT_22;//Either use &/| for setting / clearing
      iowrite32(l, gpio1_base + GPIO_OE);	/* Enable gpio */

    Kind regards,

    Dino

  • @Dino @Stalin.

    Hey Guys,

    I have tried all that you said and I am now facing a few strange issues. The code I am using is -

    #define GPIO_ANY_GPIO 55

    #define GPIO_ANY_GPIO_DESC "Some gpio pin description"

    //added code
    #define GPIO1_START_ADDR 0x49050000
    #define GPIO1_SIZE (32 * 4096)
    #define GPIO1_OE 0x034
    #define GPIO1_IRQENABLE 0x01C
    #define GPIO1_RISINGDETECT 0x048
    #define GPIO1_LEVELDETECT 0x044 //High Level Interrupt Enable
    #define GPIO1_SETIRQENABLE 0x064
    #define PIN (1<<23)

    volatile unsigned long l;
    short int irq_any_gpio = 0;

    static irqreturn_t r_irq_handler(int irq, void *dev_id, struct pt_regs *regs) {

    unsigned long flags;
    local_irq_save(flags);

    printk(KERN_NOTICE "Interrupt [%d] was triggered !.\n", irq);

    local_irq_restore(flags);
    return IRQ_HANDLED;
    }

    void r_int_config(void)
    {
    int status = 0;

    if (gpio_request(GPIO_ANY_GPIO, GPIO_ANY_GPIO_DESC)) {
    printk("GPIO request faiure: %s\n", GPIO_ANY_GPIO_DESC);
    return;
    }

    if ( (irq_any_gpio = gpio_to_irq(GPIO_ANY_GPIO)) < 0 ) {
    printk("GPIO to IRQ mapping faiure %s\n", GPIO_ANY_GPIO_DESC);
    return;
    }

    printk(KERN_NOTICE "Mapped int %d\n", irq_any_gpio);

    status = request_irq(irq_any_gpio, (irq_handler_t ) r_irq_handler,0, GPIO_ANY_GPIO_DESC, NULL);
    set_irq_type(irq_any_gpio,IRQ_TYPE_LEVEL_HIGH);

    printk(KERN_NOTICE "the status value is %d\n", status);
    if (status == -EINVAL) {
    printk("<1> EINVAL \n");
    }
    else if (status == -ENOMEM) {
    printk("<1> ENOMEM ");
    }

    if (status < 0) {
    printk("<1> gpio_request_irq : Failed to Register IRQ %d \n",irq_any_gpio);
    printk("<1> gpio_request_irq : return status is %d \n",status);
    }

    return;
    }

    void r_gpio_config(void)
    {

    static void __iomem *gpio1_base;

    /*if(request_mem_region(GPIO1_START_ADDR, GPIO1_SIZE, NULL) == NULL)
    {
    printk(KERN_ERR "requesting mem region unsuccessful\n");
    return ;
    }*/

    if((gpio1_base = ioremap(GPIO1_START_ADDR, GPIO1_SIZE)) == NULL)
    {
    printk(KERN_ERR "Mapping GPIO5_BASE unsuccessful\n");
    return ;
    }
    //output enable
    l = ioread32(gpio1_base + GPIO1_OE);
    l |= PIN;
    iowrite32(l, gpio1_base + GPIO1_OE);

    //irqenable
    l = ioread32(gpio1_base + GPIO1_IRQENABLE);
    l |= PIN;
    iowrite32(l, gpio1_base + GPIO1_IRQENABLE);

    //leveldetect
    l = ioread32(gpio1_base + GPIO1_LEVELDETECT);
    l |= PIN;
    iowrite32(l, gpio1_base + GPIO1_LEVELDETECT);

    //setirqenable
    //l = ioread32(gpio1_base + GPIO1_SETIRQENABLE);
    //l |= PIN;
    //iowrite32(l, gpio1_base + GPIO1_SETIRQENABLE);

    //rising detect
    l = ioread32(gpio1_base + GPIO1_RISINGDETECT);
    l |= PIN;
    iowrite32(l, gpio1_base + GPIO1_RISINGDETECT);

    printk(KERN_NOTICE "Successfully configured GPIO\n");
    return;


    }

    When I put set_irq_type to IRQ_TYPE_LEVEL_LOW, the interrupt handler gets called infinitely and there is no way to escape it. This was when I had enabled Low Level Interrupt Enable. But when I put any other value into the set_irq_type function be it for high level or edge irq detection, nothing happens. I have enabled the irq detection on edges and on high levels in the above code. Can you tell me as to what I may have done wrong?

    Moreover, even when there is no input to the GPIO pin, the interrupt handler gets called infinitely in the low level interrupt detection case.

    Also, even though I have disabled low level detection, on putting set_irq_type to IRQ_TYPE_LEVEL_LOW, its getting called infinitely. 

    Thanks!

  • Hi Siddharth,

    Also, even though I have disabled low level detection, on putting set_irq_type to IRQ_TYPE_LEVEL_LOW, its getting called infinitely.


    This behavior seems to be the GPIO is always driven LOW

    So, try to probe that gpio and confirm.

    How did you get the signal (type of the signal) on the GPIO ?

    LOW to HIGH or HIGH to LOW or remains HIGH or LOW remains.

    What you have connected on this GPIO (54) ?

    switch or anything else ?

  • another thing that I want to clarify is that -

    I am using r_gpio_config function to explicitly configure the gpio and then I am calling the gpio_request function from r_int_config, isn't this counter productive? Wont this nullify the changes I make explicitly by calling a function that sets the default setting?

  • Hey Stalin,

    I am toggling the gpio pin on an atmel uC and i have connected this output to the gpio pin 54.

    I did cd /sys/class/gpio/gpio54/ (just to debug)

    echo "in" > direction and 

    cat value-> its always driven low. I know that my uC is working fine. Why is it not picking up the values?

  • Hi Siddharth,

    I am toggling the gpio pin on an atmel uC and i have connected this output to the gpio pin 54.

    I did cd /sys/class/gpio/gpio54/ (just to debug)

    echo "in" > direction and 

    cat value-> its always driven low. I know that my uC is working fine. Why is it not picking up the values?

    Is there any pull up between these lines ?

    Are you working with custom board or any TI EVM ?

    What processor are you using ?

    The below diagram shows the switch connection to generate a interrupt.

    GPIO SYSFS debugging is good idea.

    I have tried to run the below code for GPIO interrupt generation and able to get interrupts as I expected.

    /*
     * Sample driver for making GPIO to interrupt
     *
     * This file is subject to the terms and conditions of the GNU General Public
     * License.
     *
     * AUTHOR : Titusrathinaraj Stalin
     * EMAIL  : x0213399@ti.com
     *	
     */
    
    
    
    /* Include linux kernel header files */
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <asm/uaccess.h>
    #include <linux/device.h>
    #include <asm/gpio.h>
    #include <linux/interrupt.h>
    #include <asm/irq.h>
    #include <linux/sched.h>
    #include <linux/irq.h>
    #include <linux/delay.h>
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Titus S");
    MODULE_DESCRIPTION("GPIO interrupt sample driver");
    
    /* OMAPL138_LCDK : S3 switch */
    
    #define GPIO_INT 37
    
    /* GPIO No 141 -> GPIO8[12] : OMAPL138_LCDK : J15[16] */
    
    //#define GPIO_INT 165 //input key for SDI OMAPL138
    //#define GPIO_INT1 166 //output led1 for SDI OMAPL138
    //#define GPIO_INT2 167 //output led2 for SDI OMAPL138
    
    #define gpio_int "gpio_int"
    
    /* local functions */
    static int gpio_irq_open (struct inode *inode, struct file *filp);
    static int gpio_irq_release (struct inode *inode, struct file *filp);
    static int gpio_irq_fasync(int fd, struct file *filp, int on);
    
    static int major;
    static struct class *class_gpio_int;
    static struct device *dev_gpio_int;
    
    
    static struct fasync_struct *gpio_irq_async_queue;
    
    /* declare file operation structure */
    static struct file_operations gpio_irq_fops = {
    	.owner = THIS_MODULE,
    	.open  = gpio_irq_open,
    	.release = gpio_irq_release,
    	.fasync	= gpio_irq_fasync,
    };
    
    /*Interrupt Handler */
    static irqreturn_t gpio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
    {
    	printk("\n GPIO interrupt raised; IRQ No : %d\n",irq);
    	kill_fasync(&gpio_irq_async_queue, SIGIO, POLL_IN);
    	return IRQ_HANDLED;
    }
    
    /***************************************************************************
     * Function             - gpio_request_irq
     * Functionality        - Registers Handlers to the IRQ's of GPIO's by request_irq
     * Input Params - 
     * Return Value - None
     * Note                 - None
     ****************************************************************************/
    void gpio_request_irq(int irq_num)
    {
    	int status = 0;
    
    //	irq_set_irq_type(irq_num,IRQ_TYPE_EDGE_BOTH);
    
    	status = request_irq(irq_num, gpio_interrupt,0,"gpio_int", NULL);
    
    /* Need to use 'IRQ_TYPE_EDGE_FALLING' since the switch S3 is pulled high and it should raise interrupt when we pressed switch (ie falling edge) */
    
    	irq_set_irq_type(irq_num,IRQ_TYPE_EDGE_FALLING);
    
    	printk(KERN_WARNING "gpio_request_irq %d status %d\n",
    			   irq_num, status);
    
    	if (status == -EINVAL) {
    		printk("<1> EINVAL \n");
    		} 
    	else if (status == -ENOMEM) {
    		printk("<1> ENOMEM ");
    		} 		
    		
    	if (status < 0) {
    		printk("<1> gpio_request_irq : Failed to Register IRQ %d  \n",
    		       irq_num);
    		printk("<1> gpio_request_irq : return status is %d  \n",
    		       status);
    	}
    
    }
    
    /***************************************************************************
     * Function             - gpio_unrequest_irq
     * Functionality        - Free Handlers o the IRQ's of GPIO's
     * Input Params - 
     * Return Value - None
     * Note                 - None
     ****************************************************************************/
    void gpio_unrequest_irq(int irq_num)
    {
    	free_irq(irq_num, NULL);
    //	gpio_free(GPIO_INT1);
    //	gpio_free(GPIO_INT2);
    	printk("<1> gpio_unrequest_irq :  Freeing IRQ %d  \n", irq_num);
    
    }
    /****************************************************************************/
    
    
    static int gpio_irq_fasync(int fd, struct file *filp, int on)
    {
    	int temp;
    	temp = fasync_helper(fd, filp, on, &gpio_irq_async_queue);
    	if (fd != -1)
    		kill_fasync(&gpio_irq_async_queue, SIGIO, POLL_IN);
    	return(temp);
    }
    
    void gpio_init(void)
    {
    	unsigned int status,tmp;
    
    	status = gpio_request(GPIO_INT, "gpio_ctrl");
    	printk(KERN_ALERT "gpio_ctrl : GPIO NO: %d Status %d\n",GPIO_INT,status);
    //	status = gpio_request(GPIO_INT1, "gpio_ctrl");
    //	printk(KERN_ALERT "gpio_ctrl : GPIO NO: %d Status %d\n",GPIO_INT1,status);
    //	status = gpio_request(GPIO_INT2, "gpio_ctrl");
    //	printk(KERN_ALERT "gpio_ctrl : GPIO NO: %d Status %d\n",GPIO_INT2,status);
    
    //	gpio_direction_output(GPIO_INT1, 0);
    //	gpio_direction_output(GPIO_INT2, 0);
    	gpio_direction_input(GPIO_INT);
    
    
    	tmp = gpio_to_irq(GPIO_INT);
    	printk(KERN_ALERT "IRQ is %d\n",tmp);
    	gpio_request_irq(tmp);
    }
    
    /******************************************************************************
     * gpio_irq_open - do nothing 
     *****************************************************************************/
    static int gpio_irq_open (struct inode *inode, struct file *filp)
    {
        return 0;
    }    
    
    /******************************************************************************
     * gpio_irq_release - do nothing 
     *****************************************************************************/
    static int gpio_irq_release (struct inode *inode, struct file *filp)
    {
    	if (filp->f_flags & FASYNC) {
    		gpio_irq_fasync (-1, filp, 0);
    	}
    	return 0;
    } 
    
    /*****************************************************************************
     * initialise user gpio module
     ****************************************************************************/
    static int gpio_irq_init(void)
    {
    	static int status;
    
    	void *ptr_err;
    	if ((major = register_chrdev(0, gpio_int, &gpio_irq_fops)) < 0)
    		return major;
    
    	class_gpio_int = class_create(THIS_MODULE, gpio_int);
    	if (IS_ERR(ptr_err = class_gpio_int))
    		goto err2;
    
    	dev_gpio_int = device_create(class_gpio_int, NULL, MKDEV(major, 0), NULL, gpio_int);
    	if (IS_ERR(ptr_err = dev_gpio_int))
    		goto err;
    
        	gpio_init();
    
    	printk(KERN_ALERT "GPIO IRQ device is inserted sucessfully\n");
    
        	return 0;
    
    err:
    	class_destroy(class_gpio_int);
    err2:
    	unregister_chrdev(major, gpio_int);
    	return PTR_ERR(ptr_err);
    
    }
    
    /*****************************************************************************
     * cleanup user gpio module
     ****************************************************************************/
    static void gpio_irq_exit(void)
    {
    
    //	gpio_direction_output(GPIO_INT1,0);
    //	gpio_direction_output(GPIO_INT2,0);
    
    mdelay(500);
    //printk("Im done...\n");
    //	gpio_direction_output(GPIO_INT1,1);
    //	gpio_direction_output(GPIO_INT2,1);
    
    //mdelay(1000);
    //printk("Im down...\n");
    
    	gpio_unrequest_irq(gpio_to_irq(GPIO_INT));
    
    	device_destroy(class_gpio_int, MKDEV(major, 0));
    	class_destroy(class_gpio_int);
    	printk(KERN_ALERT "GPIO IRQ device is ejected sucessfully\n");
    }
    
    module_init(gpio_irq_init);
    module_exit(gpio_irq_exit);

  • I dont think there are any pull up lines in betweeen. I am using the TI AM-3517 on an Adlink Base Board. Its called LEC-3517.

    http://www.adlinktech.com/PD/web/PD_detail.php?cKind=&pid=1263&seq=&id=&sid=&source=&utm_source= 

  • Hi Siddharth,

    Do you have any switches on your board ?

    I am toggling the gpio pin on an atmel uC and i have connected this output to the gpio pin 54.

    For debugging purpose,

    Try to feed HIGH or LOW from uC to the GPIO-54 and check it whether the GPIO fires the interrupt.

    Please try to probe the line and confirm that the GPIO behavior is good.

    I presume that the GPIO pinmux is good.

    Please ensure that you have done proper pinmuxing in board file for the GPIO-54 and not used any where.

    I am toggling the gpio pin on an atmel uC and i have connected this output to the gpio pin 54.

    I did cd /sys/class/gpio/gpio54/ (just to debug)

    echo "in" > direction and 

    cat value-> its always driven low. I know that my uC is working fine. Why is it not picking up the values?

    Have you probed the GPIO-54 when you toggling this GPIO from uC ?

    Just try to send one "low to high and remains hight" or "high to low and remains low" then check and not like toggling.

  • I have finally managed to get it to work!

    @Stalin- you were right! it was that the pin was always being pulled low. Such a silly thing! I used another pin and voila!

    For some reason the pin i was  using - GPIO54 , if configured as input its always pulled low, I would really love to know why that's the case or how to go about hacking it. @Stalin, any thoughts or ideas on that?

    1) I have probed the GPIO54 pin and if I keep my input into this pin HIGH, the value is always low ie cat value->0(always)

    The GPIO behaviour isnt' good

    2) " I presume that the GPIO pinmux is good." How do I check that?

    3) "Please ensure that you have done proper pinmuxing in board file for the GPIO-54 and not used any where."

    I have ensured that the GPIO54 is not used anywhere while checking for the interrupts, but I haven't really done any pin muxing, I have just used them straight away. How do I check that or go about doing that? I checked the /arch/arm/mach-omap2/board-am3517evm.c but didnt see anything there. 

    I also wanted to thank you and @Dino for the speedy replies and all the help

  • Hi Siddharth,

    I have ensured that the GPIO54 is not used anywhere while checking for the interrupts, but I haven't really done any pin muxing, I have just used them straight away. How do I check that or go about doing that? I checked the /arch/arm/mach-omap2/board-am3517evm.c but didnt see anything there.

    Share your schematics "GPIO" part alone, need to check that how the GPIO-54 pin has been used.

    2) " I presume that the GPIO pinmux is good." How do I check that?

    You have to do "pinmux" for the processor pin to select the particular peripheral (SPI/GPIO/I2C/) before going to use that peripheral.

  • Hi Siddharth,

    You have to add the below line in mux function at board file to use the GPIO_54 pin as GPIO.

    Also, you can enable internal pull up/down too.

    OMAP3_MUX(GPMC_NCS3, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLDOWN),

    To know more about pinmux, please refer the AM3517 TRM and TI wikis.

    Ex:

    arch/arm/mach-omap2/board-am3517evm.c

    #ifdef CONFIG_OMAP_MUX
    static struct omap_board_mux board_mux[] __initdata = {
    	/* USB OTG DRVVBUS offset = 0x212 */
    	OMAP3_MUX(SAD2D_MCAD23, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
    	OMAP3_MUX(GPMC_NCS3, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLDOWN),	/* Titus Debug : enable GPIO_54 and internal PULL UP */
    	{ .reg_offset = OMAP_MUX_TERMINATOR },
    };
    #endif
    

    Please refer to the following files in linux source.

    arch/arm/mach-omap2/board-am3517evm.c

    arch/arm/mach-omap2/mux34xx.c

    Ex:

    arch/arm/mach-omap2/mux34xx.c

    	_OMAP3_MUXENTRY(GPMC_NCS3, 54,
    		"gpmc_ncs3", "sys_ndmareq0", NULL, NULL,
    		"gpio_54", NULL, NULL, "safe_mode"),
    

     

    arch/arm/mach-omap2/mux34xx.c

  • Hey Stalin,

    I had a look in arch/arm/mach-omap2/mux34xx.c - the following entry was already present for GPIO54 -

    _OMAP3_MUXENTRY(GPMC_NCS3, 54,
    "gpmc_ncs3", "sys_ndmareq0", NULL, NULL,
    "gpio_54", NULL, NULL, "safe_mode"),

    I don't see any pull up /pull down enabled here. Not sure then why the pin value is always 0 as input

    Moreover, 

    the GPIO pin that I am able to use is GPIO29 with entry -

    _OMAP3_MUXENTRY(ETK_D15, 29,
    "etk_d15", NULL, NULL, "hsusb2_data1",
    "gpio_29", "mm2_txse0", "hsusb2_tll_data1", "hw_dbg17"),

    I don't see alot of difference between the two, how is it that I am able to work properly with 29 but not 54(mind you that I can use 54 as an output pin just fine).

    Moreover, this structure is defined in arch/arm/mach-omap2/board-am3517evm.c

    #ifdef CONFIG_OMAP_MUX
    static struct omap_board_mux board_mux[] __initdata = {
    /* USB OTG DRVVBUS offset = 0x212 */
    OMAP3_MUX(SAD2D_MCAD23, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
    OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
    OMAP3_MUX(GPMC_NCS4, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLDOWN),
    OMAP3_MUX(SYS_NRESWARM, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
    { .reg_offset = OMAP_MUX_TERMINATOR },
    };
    #endif

    I notice that there is a missing definition for GPMC_NCS3 here which is one of the keywords for GPIO54 as seen above. Would that cause anything? I just wanted to make sure before editing anything.

    Thanks!

     

  • Hi,

    I had a look in arch/arm/mach-omap2/mux34xx.c - the following entry was already present for GPIO54 -

    Actually, this is default file for OMAP3 processors and generic too, so it will be the same.

    I notice that there is a missing definition for GPMC_NCS3 here which is one of the keywords for GPIO54 as seen above. Would that cause anything? I just wanted to make sure before editing anything.

    For GPIO_54 pinmux,

    You should add the below line in "board_mux" structure.

    Ex:

    #ifdef CONFIG_OMAP_MUX
    static struct omap_board_mux board_mux[] __initdata = {
    /* USB OTG DRVVBUS offset = 0x212 */
    OMAP3_MUX(SAD2D_MCAD23, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
    OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
    OMAP3_MUX(GPMC_NCS4, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLDOWN),
    OMAP3_MUX(SYS_NRESWARM, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
     OMAP3_MUX(GPMC_NCS3, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP), /* Titus Debug : enable GPIO_54 and internal PULL UP */
    { .reg_offset = OMAP_MUX_TERMINATOR },
    };
    #endif

  • Hi Stalin,

    I added that line the board-mux structure, recompiled the kernel and tried out /sys/ probe on GPIO 54, but it didnt change the pins behaviour. 

    Do you reckon I could add a device tree overlay to override the behaviour being set at the kernel boot process? If so  how and where would I place it?

    Thanks!

  • Hi Siddharth,

    @Stalin- you were right! it was that the pin was always being pulled low. Such a silly thing! I used another pin and voila!

    You told me that you able to generate interrupt through different GPIO, have you checked the hw configuration of that GPIO, that whether has external pull up or pull down.

    Could you please tell us that what GPIO pin have you used ?

  • hey Stalin, 

    I used gpio pin 29 whose reference in /arch/arm/mach-omap2/mux34xx.c is

    _OMAP3_MUXENTRY(ETK_D15, 29,
    "etk_d15", NULL, NULL, "hsusb2_data1",
    "gpio_29", "mm2_txse0", "hsusb2_tll_data1", NULL),

    but I see no reference of this pin in /arch/arm/mach-omap2/board-am3517evm.c

    Any ideas as to why I am able to use pin 29 as an input pin without any issues and not pin 54?

    I have attached the schematics and board-am3517evm.c for your referral. i saw no pullup/pulldowns on the gpio in the schematics.

    I added this line after your post -

    OMAP3_MUX(GPMC_NCS3, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLDOWN),  /* Siddharth Debug : enable GPIO_54 and internal PULL UP */

    this is okay right?

    Looking fo0576.lec-3517 schematics.pdf3652.board-am3517evm.c7587.mux34xx.crward to hearing from you 

    Thanks1

  • Hi Siddharth,

    From your schematics, I'm able to see that "GPIO_29" pin was connected to HDMI transmitter IC of TX_INT (sil9022), so this GPIO pinmux configurations might have done in u-boot itself.

    OMAP3_MUX(GPMC_NCS3, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),  /* Siddharth Debug : enable GPIO_54 and internal PULL UP */

    this is okay right?

    Yes, this pinmux configuration is sufficient. ( I have changed to pullup from pulldown)

    The second options is try to enable pinmux configurations in u-boot source.