diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2011-09-18 08:14:46 -0400 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2012-03-12 17:40:52 -0400 |
commit | ecd29947862a9a145c07098499c76c22ed5b8eb3 (patch) | |
tree | 70ff60ebf9048025795dbe2882a361154eb5f00d | |
parent | 458981c3886133667e020900f53538f1fbc3ea1d (diff) |
sh_mobile_lcdc: Add display notify callback to sh_mobile_lcdc_chan
The callback implements 3 notification events:
- SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT notifies the LCDC that the
display has been connected
- SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT notifies the LCDC that the
display has been disconnected
- SH_MOBILE_LCDC_EVENT_DISPLAY_MODE notifies that LCDC that a display
mode has been detected
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 84 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.h | 10 |
2 files changed, 94 insertions, 0 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 5a19ef3f215c..128eb7793a60 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
@@ -364,6 +364,89 @@ static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch) | |||
364 | ch->tx_dev->ops->display_off(ch->tx_dev); | 364 | ch->tx_dev->ops->display_off(ch->tx_dev); |
365 | } | 365 | } |
366 | 366 | ||
367 | static bool | ||
368 | sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch, | ||
369 | const struct fb_var_screeninfo *new_var) | ||
370 | { | ||
371 | struct fb_var_screeninfo *old_var = &ch->display_var; | ||
372 | struct fb_videomode old_mode; | ||
373 | struct fb_videomode new_mode; | ||
374 | |||
375 | fb_var_to_videomode(&old_mode, old_var); | ||
376 | fb_var_to_videomode(&new_mode, new_var); | ||
377 | |||
378 | dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n", | ||
379 | old_mode.xres, old_mode.yres, new_mode.xres, new_mode.yres); | ||
380 | |||
381 | if (fb_mode_is_equal(&old_mode, &new_mode)) { | ||
382 | /* It can be a different monitor with an equal video-mode */ | ||
383 | old_var->width = new_var->width; | ||
384 | old_var->height = new_var->height; | ||
385 | return false; | ||
386 | } | ||
387 | |||
388 | dev_dbg(ch->info->dev, "Switching %u -> %u lines\n", | ||
389 | old_mode.yres, new_mode.yres); | ||
390 | *old_var = *new_var; | ||
391 | |||
392 | return true; | ||
393 | } | ||
394 | |||
395 | static int sh_mobile_check_var(struct fb_var_screeninfo *var, | ||
396 | struct fb_info *info); | ||
397 | |||
398 | static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch, | ||
399 | enum sh_mobile_lcdc_entity_event event, | ||
400 | struct fb_var_screeninfo *var) | ||
401 | { | ||
402 | struct fb_info *info = ch->info; | ||
403 | int ret = 0; | ||
404 | |||
405 | switch (event) { | ||
406 | case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT: | ||
407 | /* HDMI plug in */ | ||
408 | if (lock_fb_info(info)) { | ||
409 | console_lock(); | ||
410 | |||
411 | if (!sh_mobile_lcdc_must_reconfigure(ch, var) && | ||
412 | info->state == FBINFO_STATE_RUNNING) { | ||
413 | /* First activation with the default monitor. | ||
414 | * Just turn on, if we run a resume here, the | ||
415 | * logo disappears. | ||
416 | */ | ||
417 | info->var.width = var->width; | ||
418 | info->var.height = var->height; | ||
419 | sh_mobile_lcdc_display_on(ch); | ||
420 | } else { | ||
421 | /* New monitor or have to wake up */ | ||
422 | fb_set_suspend(info, 0); | ||
423 | } | ||
424 | |||
425 | console_unlock(); | ||
426 | unlock_fb_info(info); | ||
427 | } | ||
428 | break; | ||
429 | |||
430 | case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT: | ||
431 | /* HDMI disconnect */ | ||
432 | if (lock_fb_info(info)) { | ||
433 | console_lock(); | ||
434 | fb_set_suspend(info, 1); | ||
435 | console_unlock(); | ||
436 | unlock_fb_info(info); | ||
437 | } | ||
438 | break; | ||
439 | |||
440 | case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE: | ||
441 | /* Validate a proposed new mode */ | ||
442 | var->bits_per_pixel = info->var.bits_per_pixel; | ||
443 | ret = sh_mobile_check_var(var, info); | ||
444 | break; | ||
445 | } | ||
446 | |||
447 | return ret; | ||
448 | } | ||
449 | |||
367 | /* ----------------------------------------------------------------------------- | 450 | /* ----------------------------------------------------------------------------- |
368 | * Format helpers | 451 | * Format helpers |
369 | */ | 452 | */ |
@@ -1591,6 +1674,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, | |||
1591 | int i; | 1674 | int i; |
1592 | 1675 | ||
1593 | mutex_init(&ch->open_lock); | 1676 | mutex_init(&ch->open_lock); |
1677 | ch->notify = sh_mobile_lcdc_display_notify; | ||
1594 | 1678 | ||
1595 | /* Allocate the frame buffer device. */ | 1679 | /* Allocate the frame buffer device. */ |
1596 | ch->info = framebuffer_alloc(0, priv->dev); | 1680 | ch->info = framebuffer_alloc(0, priv->dev); |
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index 6fb956c8e603..e2eb7af438f7 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h | |||
@@ -30,6 +30,12 @@ struct sh_mobile_lcdc_entity_ops { | |||
30 | void (*display_off)(struct sh_mobile_lcdc_entity *entity); | 30 | void (*display_off)(struct sh_mobile_lcdc_entity *entity); |
31 | }; | 31 | }; |
32 | 32 | ||
33 | enum sh_mobile_lcdc_entity_event { | ||
34 | SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT, | ||
35 | SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT, | ||
36 | SH_MOBILE_LCDC_EVENT_DISPLAY_MODE, | ||
37 | }; | ||
38 | |||
33 | struct sh_mobile_lcdc_entity { | 39 | struct sh_mobile_lcdc_entity { |
34 | struct module *owner; | 40 | struct module *owner; |
35 | const struct sh_mobile_lcdc_entity_ops *ops; | 41 | const struct sh_mobile_lcdc_entity_ops *ops; |
@@ -70,6 +76,10 @@ struct sh_mobile_lcdc_chan { | |||
70 | unsigned long base_addr_y; | 76 | unsigned long base_addr_y; |
71 | unsigned long base_addr_c; | 77 | unsigned long base_addr_c; |
72 | unsigned int pitch; | 78 | unsigned int pitch; |
79 | |||
80 | int (*notify)(struct sh_mobile_lcdc_chan *ch, | ||
81 | enum sh_mobile_lcdc_entity_event event, | ||
82 | struct fb_var_screeninfo *var); | ||
73 | }; | 83 | }; |
74 | 84 | ||
75 | #endif | 85 | #endif |