maxime_coquelin schreef:
> Hi everybody,
>
> For my project, I need to use the PA0 pin as an interrupt to handle
> the \int pin of the pcf8574 chip (which is a I2C-8-bit controller). I
> have used the work done by calzo(Foxdoc.pdf on lugman.net, thank's to
> him).
> I succeed in building the module and the IRQ is well requested. To do
> that, I have to invert the \int pin of the pcf8574.
>
> The problem I have is that the interrupt is handeld on the high state
> (and not on the front), so, when a logic state change on the pcf8574,
> the PA0 pin goes to high, and it generates thousand of interrupts,
> whereas I need only one.
>
> Here is the code made by Calzo :
>
> #include <linux/interrupt.h>
> #include <linux/module.h>
> #include <asm/io.h> //provide access to GPIO port and other
> MODULE_LICENSE("DUAL GPL/BSD");
> MODULE_VERSION("0.1");
> #define IRQ_PA_MASK 0x01 //interrupt sul pulsante
> static DEFINE_SPINLOCK(gpio_lock_irq);
>
> /***** FUNZIONE DI INTERRUPT ******
> * In questa funzione viene disabilitata temporaneamente la
> * possibilità di ricevere altri interrupt fino a che non è
> * soddisfatta la funzione seguente
> * ********************************/
> static irqreturn_t
> irqPA_interrupt(int irq, void *dev_id, struct pt_regs *regs)
> {
> *R_IRQ_MASK1_CLR = 0;
> *R_PORT_PA_DATA = 0; //fondamentale!
> printk(KERN_ALERT "calzo - irq servito\n");
> return IRQ_HANDLED;
> }
> /****************************************
> * INITIALIZATION & CLEANUP functions
> ****************************************/
> /// Funzione di inizializzazione del modulo
> int irqPA_init_module(void) {
> if (request_irq(PA_IRQ_NBR, irqPA_interrupt,
> SA_INTERRUPT,"calzo gpio PA interrupt", NULL))
> {
> printk(KERN_CRIT "err: PA irq for gpio (calzo)\n");
> return -ERESTART;
> }
> //setto su quale pin vi è línterrupt valido
> *R_IRQ_MASK1_SET = IRQ_PA_MASK;
> return 0;
> }
> ///Funzione di scaricamento del modulo
> void irqPA_cleanup_module(void) {
> spin_lock_irq(&gpio_lock_irq);
> *R_IRQ_MASK1_SET = 0;
> *R_IRQ_MASK1_CLR = 0;
> free_irq(PA_IRQ_NBR, NULL);
> spin_unlock_irq(&gpio_lock_irq);
> }
> /***************************************
> * INIT & EXIT
> ***************************************/
> module_init(irqPA_init_module);
> module_exit(irqPA_cleanup_module);
>
> Do you understand my problem? And do you see how to disable the irq
> once one is received?
>
> Thank's in advance.
>
> Maxime Coquelin
>
>
I see your problem.
What I can tell it works like this :
1) you get an interrupt, you set flag and disable further interrupts
from this pin
2) you read the contents of your pc8574 which clears the interrupt (from
tasklet)
3) you reset flag and enable interrupts again (from tasklet)
note: you can not lose events this way from your i2c device if you
enable interrupts again directly after the
read from the device. The device will keep on interrupting you again
until you do a i2c read or write.
Just my opinion, you should also talk to john Crispin, he knows about
this stuff.
check out page 274 of Linux Device Drivers 3rd edition and the functions
local_irq_save(unsigned long flags);
local_irq_restore(unsigned long flags);
You might want to split this in a top and bottom half (page 275) using a
tasklet.
Good luck,
Edwin van den Oetelaar