diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2011-07-13 06:13:47 -0400 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2011-08-19 02:22:38 -0400 |
commit | dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4 (patch) | |
tree | ea56c195386fc5b997961b033d7868e0c0c8a1bc /drivers/video/sh_mobile_lcdcfb.c | |
parent | ce1c0b0873bf4e970970a49612105cf6c36d81e3 (diff) |
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>
Diffstat (limited to 'drivers/video/sh_mobile_lcdcfb.c')
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 20 |
1 files changed, 8 insertions, 12 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 84504d574986..99656f593de4 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
@@ -318,19 +318,13 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) | |||
318 | { | 318 | { |
319 | struct sh_mobile_lcdc_priv *priv = data; | 319 | struct sh_mobile_lcdc_priv *priv = data; |
320 | struct sh_mobile_lcdc_chan *ch; | 320 | struct sh_mobile_lcdc_chan *ch; |
321 | unsigned long tmp; | ||
322 | unsigned long ldintr; | 321 | unsigned long ldintr; |
323 | int is_sub; | 322 | int is_sub; |
324 | int k; | 323 | int k; |
325 | 324 | ||
326 | /* acknowledge interrupt */ | 325 | /* Acknowledge interrupts and disable further VSYNC End IRQs. */ |
327 | ldintr = tmp = lcdc_read(priv, _LDINTR); | 326 | ldintr = lcdc_read(priv, _LDINTR); |
328 | /* | 327 | lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE); |
329 | * disable further VSYNC End IRQs, preserve all other enabled IRQs, | ||
330 | * write 0 to bits 0-6 to ack all triggered IRQs. | ||
331 | */ | ||
332 | tmp &= ~LDINTR_STATUS_MASK & ~LDINTR_VEE; | ||
333 | lcdc_write(priv, _LDINTR, tmp); | ||
334 | 328 | ||
335 | /* figure out if this interrupt is for main or sub lcd */ | 329 | /* figure out if this interrupt is for main or sub lcd */ |
336 | is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0; | 330 | 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) | |||
342 | if (!ch->enabled) | 336 | if (!ch->enabled) |
343 | continue; | 337 | continue; |
344 | 338 | ||
345 | /* Frame Start */ | 339 | /* Frame End */ |
346 | if (ldintr & LDINTR_FS) { | 340 | if (ldintr & LDINTR_FS) { |
347 | if (is_sub == lcdc_chan_is_sublcd(ch)) { | 341 | if (is_sub == lcdc_chan_is_sublcd(ch)) { |
348 | ch->frame_end = 1; | 342 | ch->frame_end = 1; |
@@ -971,9 +965,11 @@ static int sh_mobile_wait_for_vsync(struct fb_info *info) | |||
971 | unsigned long ldintr; | 965 | unsigned long ldintr; |
972 | int ret; | 966 | int ret; |
973 | 967 | ||
974 | /* Enable VSync End interrupt */ | 968 | /* Enable VSync End interrupt and be careful not to acknowledge any |
969 | * pending interrupt. | ||
970 | */ | ||
975 | ldintr = lcdc_read(ch->lcdc, _LDINTR); | 971 | ldintr = lcdc_read(ch->lcdc, _LDINTR); |
976 | ldintr |= LDINTR_VEE; | 972 | ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK; |
977 | lcdc_write(ch->lcdc, _LDINTR, ldintr); | 973 | lcdc_write(ch->lcdc, _LDINTR, ldintr); |
978 | 974 | ||
979 | ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, | 975 | ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, |