Linux: 2.6.31
Processor: AT91SAM9XE

There are two types of interrupts you can create for an AT91.  An external interrupt or a GPIO interrupt.  An external interrupt does not have the additional overhead of going through the GPIO controller.  I will explain how to create an external and GPIO interrupt for an AT91.  I do these things for my own personal notes for the future.  The instructions for creating the interrupts are in arch/arm/mach-at91/gpio.c around line 338.  I will be using pin PC12.  This pin can be used as an external interrupt (IRQ0) or a GPIO interrupt.

External Interrupt
This will create an external interrupt with IRQ0 on pin AT91_PIN_PC12.  I will using a falling edge to trigger.  For an external interrupt, you can use any trigger.  On a GPIO interrupt you can only use BOTH (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING) or NONE.

/** Set pin as GPIO input, without internal pull up */
if(at91_set_gpio_input(AT91_PIN_PC12, 0)) {
    printk(KERN_DEBUG"Could not set pin %i for GPIO input.\n", AT91_PIN_PC12);
}

/** Set deglitch for pin */
if(at91_set_deglitch(AT91_PIN_PC12, 1)) {
    printk(KERN_DEBUG"Could not set pin %i for GPIO deglitch.\n", AT91_PIN_PC12);
}

/** Set the IRQ0 pin to Periph A */
at91_set_A_periph(AT91_PIN_PC12,0);

/** Request IRQ for pin */
if(request_irq(AT91SAM9260_ID_IRQ0, interrupt_handler_function, IRQF_TRIGGER_FALLING, "my_interrupt", NULL))  {
    printk(KERN_DEBUG"Can't register IRQ %d\n", AT91_PIN_PC12);
    return -EIO;
}

GPIO Interrupt
This will create an GPIO interrupt with IRQ 108.  The main difference between this way and the external interrupt and this can be used for any GPIO pin.  It must use BOTH (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING) or NONE for trigger and it does not have a defined IRQ value.  This also goes through the overhead of using the GPIO controller.

/** Set pin as GPIO periph, without internal pull up */
at91_set_GPIO_periph(AT91_PIN_PC12,0);

/** Set pin as GPIO input, without internal pull up */
if(at91_set_gpio_input(AT91_PIN_PC12, 0)) {
    printk(KERN_DEBUG"Could not set pin %i for GPIO input.\n", AT91_PIN_PC12);
}

/** Set deglitch for pin */
if(at91_set_deglitch(AT91_PIN_PC12, 1)) {
    printk(KERN_DEBUG"Could not set pin %i for GPIO deglitch.\n", AT91_PIN_PC12);
}

/** Request IRQ for pin */
if(request_irq(AT91_PIN_PC12, interrupt_handler_function, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "my_interrupt", NULL))  {
    printk(KERN_DEBUG"Can't register IRQ %d\n", AT91_PIN_PC12);
    return -EIO;
}

Interrupt handler function

/**
 * Called when an interrupt is triggered
 */

irqreturn_t interrupt_handler_function(int irq, void *dev_id)
{
    /* Start tasklet */
    return IRQ_HANDLED;
}

Kill IRQ
Use the free_irq for the type of interrupt you used.

free_irq(AT91SAM9260_ID_IRQ0,0);
free_irq(AT91_PIN_PC12,0);

Tasklet
Next post i will show how to make a tasklet to go with this interrupt.

转自:http://rico-studio.com/linux/at91-gpio-interrupt/