fbdev: sh_mobile_lcdc: Don't acknowlege interrupts unintentionally

The LDINTR register caries both interrupt enable and interrupt status
bits. When setting or clearing interrupt enable bits, write all status
bits to 1 to avoid acknowledging interrupts by mistake.

When acknowledging interrupts, write 1 to all non-triggered interrupt
bits to avoid losing interrupts.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
Laurent Pinchart 2011-07-13 12:13:47 +02:00
parent ce1c0b0873
commit dc48665fae

View file

@ -318,19 +318,13 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
{
struct sh_mobile_lcdc_priv *priv = data;
struct sh_mobile_lcdc_chan *ch;
unsigned long tmp;
unsigned long ldintr;
int is_sub;
int k;
/* acknowledge interrupt */
ldintr = tmp = lcdc_read(priv, _LDINTR);
/*
* disable further VSYNC End IRQs, preserve all other enabled IRQs,
* write 0 to bits 0-6 to ack all triggered IRQs.
*/
tmp &= ~LDINTR_STATUS_MASK & ~LDINTR_VEE;
lcdc_write(priv, _LDINTR, tmp);
/* Acknowledge interrupts and disable further VSYNC End IRQs. */
ldintr = lcdc_read(priv, _LDINTR);
lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
/* figure out if this interrupt is for main or sub lcd */
is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
@ -342,7 +336,7 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
if (!ch->enabled)
continue;
/* Frame Start */
/* Frame End */
if (ldintr & LDINTR_FS) {
if (is_sub == lcdc_chan_is_sublcd(ch)) {
ch->frame_end = 1;
@ -971,9 +965,11 @@ static int sh_mobile_wait_for_vsync(struct fb_info *info)
unsigned long ldintr;
int ret;
/* Enable VSync End interrupt */
/* Enable VSync End interrupt and be careful not to acknowledge any
* pending interrupt.
*/
ldintr = lcdc_read(ch->lcdc, _LDINTR);
ldintr |= LDINTR_VEE;
ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
lcdc_write(ch->lcdc, _LDINTR, ldintr);
ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,