aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-07-13 06:13:47 -0400
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-08-19 02:22:38 -0400
commitdc48665fae5aa360e80dfdb2d6cab4fa58b27ee4 (patch)
treeea56c195386fc5b997961b033d7868e0c0c8a1bc /drivers/video
parentce1c0b0873bf4e970970a49612105cf6c36d81e3 (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')
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c20
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,