Gpio irda interrupts lost


#1

Hi everyone:
I use the GPIO90 as external ir receiver pin, and binds with interrupt EINT13, .when I press the IR remote controller, the cpu can catch interrupts from the GPIO90, about 36 interrupts, but sometime, the cpu only catchs 30 or fewer interrupts.

I use the code below to initialize the interrupt
ret = request_irq(irrx_irq,&gpio_irc_interrupt,IRQF_TRIGGER_FALLING ,“IRRX-eint”,ddata);

can somebody help me, thanks very mush.


#2

Interrupt can be lost, there is no guaranty on Linux to not miss any interrupt. I’m not familiar with IR, so I don’t know if a same data chunk is always encoded with a same IR frame, so maybe it’s expected. Moreover you can not deduct data value from a pulse count, I assume you need the pulses length/position, right ?

I suggest you to have a look at the gpio-ir-recv kernel driver (linux/drivers/media/rc) which allows RC IR data decoding from GPIO/IRQ.

Can you share your interrupt handler ?


#3

Hi Loic:
Thank you very much,I found the interrupt handler function mt_eint_demux() in irq-mt-eic.c , and from the count this function called, the cpu lost some interrupts。 I think when this function is processing, next interrupt comes, so it is not processed in time. so, is there some suggestions?

static irqreturn_t mt_eint_demux(unsigned irq, struct irq_desc *desc)
{
unsigned int index, rst;
unsigned long base;
unsigned int status = 0;
unsigned int status_check;
unsigned int reg_base, offset;
unsigned long long t1 = 0;
unsigned long long t2 = 0;
int mask_status = 0;
struct irq_chip *chip = irq_get_chip(irq);
struct eint_chip *eint_chip = irq_get_handler_data(irq);

chained_irq_enter(chip, desc);

/*
 * NoteXXX: Need to get the wake up for 0.5 seconds when an EINT intr tirggers.
 *          This is used to prevent system from suspend such that other drivers
 *          or applications can have enough time to obtain their own wake lock.
 *          (This information is gotten from the power management owner.)
 */

tasklet_schedule(&eint_tasklet);
dbgmsg("EINT Module - %s ISR Start\n", __func__);

for (reg_base = 0; reg_base < EINT_MAX_CHANNEL; reg_base += 32) {
	/* read status register every 32 interrupts */
	status = mt_eint_get_status(reg_base);
	if (status)
		dbgmsg("EINT Module - index:%d,EINT_STA = 0x%x\n", reg_base, status);
	else
		continue;

	for (offset = 0; offset < 32; offset++) {
		index = reg_base + offset;
		if (index >= EINT_MAX_CHANNEL)
			break;

		status_check = status & (1 << (index % 32));
		if (!status_check)
			continue;

		/* we got an eint */
		EINT_FUNC.count[index]++;

		/* deal with EINT from request_irq() */
		dbgmsg("Got EINT %d: go with new mt_eint\n", index);
		//printk(KERN_ALERT"Got EINT %d: go with new mt_eint\n", index);
		if ((EINT_FUNC.is_deb_en[index] == 1)
				&& (index >= MAX_HW_DEBOUNCE_CNT)) {
			/* if its debounce is enable and it is a sw debounce */
			mt_eint_mask(index);
			dbgmsg("got sw index %d\n", index);
			mt_eint_set_timer_event(index);
		} else {
			dbgmsg("got hw index %d\n", index);
			t1 = sched_clock();
			generic_handle_irq(index + EINT_IRQ_BASE);
			t2 = sched_clock();
			if ((EINT_FUNC.is_deb_en[index] == 1)
					&& (index < MAX_HW_DEBOUNCE_CNT)) {
				mask_status = (mt_eint_get_mask(index) == 1) ? 1 : 0;
				mt_eint_mask(index);

				/* Don't need to use reset ? */
				/* reset debounce counter */
				base = (index / 4) * 4 + EINT_DBNC_SET_BASE;
				rst = (EINT_DBNC_RST_BIT <<
						EINT_DBNC_SET_RST_BITS) << ((index % 4) * 8);
				mt_reg_sync_writel(rst, base);

				if (mask_status == 0)
					mt_eint_unmask(index);
			}

#if (EINT_DEBUG == 1)
dbgmsg(“EINT Module - EINT_STA after ack = 0x%x\n”,
mt_eint_get_status(index));
#endif

			if ((t2 - t1) > EINT_DELAY_WARNING)
				pr_warn("[EINT]Warn!EINT:%d run too long,s:%llu,e:%llu,total:%llu\n",
						index, t1, t2, (t2 - t1));
		}

		if (eint_chip->dual_edges[index])
			mt_eint_flip_edge(eint_chip, index);
	}

#ifdef CONFIG_MTK_EIC_HISTORY_DUMP
insert_trigger_entity(index, 1, t1);
#endif
}

dbgmsg("EINT Module - %s ISR END\n", __func__);
chained_irq_exit(chip, desc);
return IRQ_HANDLED;

}