Skip to content

Commit

Permalink
fbdev: sh_mobile_lcdc: Don't acknowlege interrupts unintentionally
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Laurent Pinchart committed Aug 19, 2011
1 parent ce1c0b0 commit dc48665
Showing 1 changed file with 8 additions and 12 deletions.
20 changes: 8 additions & 12 deletions drivers/video/sh_mobile_lcdcfb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit dc48665

Please sign in to comment.