diff options
-rw-r--r-- | drivers/video/Kconfig | 1 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 81 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.h | 2 | ||||
-rw-r--r-- | include/video/sh_mobile_lcdc.h | 9 |
4 files changed, 93 insertions, 0 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6bafb51bb437..a222d65ae642 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -2005,6 +2005,7 @@ config FB_SH_MOBILE_LCDC | |||
2005 | select FB_SYS_IMAGEBLIT | 2005 | select FB_SYS_IMAGEBLIT |
2006 | select FB_SYS_FOPS | 2006 | select FB_SYS_FOPS |
2007 | select FB_DEFERRED_IO | 2007 | select FB_DEFERRED_IO |
2008 | select FB_BACKLIGHT | ||
2008 | select SH_MIPI_DSI if SH_LCD_MIPI_DSI | 2009 | select SH_MIPI_DSI if SH_LCD_MIPI_DSI |
2009 | ---help--- | 2010 | ---help--- |
2010 | Frame buffer driver for the on-chip SH-Mobile LCD controller. | 2011 | Frame buffer driver for the on-chip SH-Mobile LCD controller. |
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index bf12e53aed5c..e040e46d7d91 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/ioctl.h> | 21 | #include <linux/ioctl.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/console.h> | 23 | #include <linux/console.h> |
24 | #include <linux/backlight.h> | ||
25 | #include <linux/gpio.h> | ||
24 | #include <video/sh_mobile_lcdc.h> | 26 | #include <video/sh_mobile_lcdc.h> |
25 | #include <asm/atomic.h> | 27 | #include <asm/atomic.h> |
26 | 28 | ||
@@ -618,6 +620,11 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
618 | board_cfg->display_on(board_cfg->board_data, ch->info); | 620 | board_cfg->display_on(board_cfg->board_data, ch->info); |
619 | module_put(board_cfg->owner); | 621 | module_put(board_cfg->owner); |
620 | } | 622 | } |
623 | |||
624 | if (ch->bl) { | ||
625 | ch->bl->props.power = FB_BLANK_UNBLANK; | ||
626 | backlight_update_status(ch->bl); | ||
627 | } | ||
621 | } | 628 | } |
622 | 629 | ||
623 | return 0; | 630 | return 0; |
@@ -648,6 +655,11 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) | |||
648 | sh_mobile_lcdc_clk_on(priv); | 655 | sh_mobile_lcdc_clk_on(priv); |
649 | } | 656 | } |
650 | 657 | ||
658 | if (ch->bl) { | ||
659 | ch->bl->props.power = FB_BLANK_POWERDOWN; | ||
660 | backlight_update_status(ch->bl); | ||
661 | } | ||
662 | |||
651 | board_cfg = &ch->cfg.board_cfg; | 663 | board_cfg = &ch->cfg.board_cfg; |
652 | if (try_module_get(board_cfg->owner) && board_cfg->display_off) { | 664 | if (try_module_get(board_cfg->owner) && board_cfg->display_off) { |
653 | board_cfg->display_off(board_cfg->board_data); | 665 | board_cfg->display_off(board_cfg->board_data); |
@@ -980,6 +992,64 @@ static struct fb_ops sh_mobile_lcdc_ops = { | |||
980 | .fb_check_var = sh_mobile_check_var, | 992 | .fb_check_var = sh_mobile_check_var, |
981 | }; | 993 | }; |
982 | 994 | ||
995 | static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev) | ||
996 | { | ||
997 | struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); | ||
998 | struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg; | ||
999 | int brightness = bdev->props.brightness; | ||
1000 | |||
1001 | if (bdev->props.power != FB_BLANK_UNBLANK || | ||
1002 | bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) | ||
1003 | brightness = 0; | ||
1004 | |||
1005 | return cfg->set_brightness(cfg->board_data, brightness); | ||
1006 | } | ||
1007 | |||
1008 | static int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev) | ||
1009 | { | ||
1010 | struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); | ||
1011 | struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg; | ||
1012 | |||
1013 | return cfg->get_brightness(cfg->board_data); | ||
1014 | } | ||
1015 | |||
1016 | static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev, | ||
1017 | struct fb_info *info) | ||
1018 | { | ||
1019 | return (info->bl_dev == bdev); | ||
1020 | } | ||
1021 | |||
1022 | static struct backlight_ops sh_mobile_lcdc_bl_ops = { | ||
1023 | .options = BL_CORE_SUSPENDRESUME, | ||
1024 | .update_status = sh_mobile_lcdc_update_bl, | ||
1025 | .get_brightness = sh_mobile_lcdc_get_brightness, | ||
1026 | .check_fb = sh_mobile_lcdc_check_fb, | ||
1027 | }; | ||
1028 | |||
1029 | static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent, | ||
1030 | struct sh_mobile_lcdc_chan *ch) | ||
1031 | { | ||
1032 | struct backlight_device *bl; | ||
1033 | |||
1034 | bl = backlight_device_register(ch->cfg.bl_info.name, parent, ch, | ||
1035 | &sh_mobile_lcdc_bl_ops, NULL); | ||
1036 | if (!bl) { | ||
1037 | dev_err(parent, "unable to register backlight device\n"); | ||
1038 | return NULL; | ||
1039 | } | ||
1040 | |||
1041 | bl->props.max_brightness = ch->cfg.bl_info.max_brightness; | ||
1042 | bl->props.brightness = bl->props.max_brightness; | ||
1043 | backlight_update_status(bl); | ||
1044 | |||
1045 | return bl; | ||
1046 | } | ||
1047 | |||
1048 | static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev) | ||
1049 | { | ||
1050 | backlight_device_unregister(bdev); | ||
1051 | } | ||
1052 | |||
983 | static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) | 1053 | static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) |
984 | { | 1054 | { |
985 | switch (bpp) { | 1055 | switch (bpp) { |
@@ -1198,6 +1268,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1198 | init_completion(&ch->vsync_completion); | 1268 | init_completion(&ch->vsync_completion); |
1199 | ch->pan_offset = 0; | 1269 | ch->pan_offset = 0; |
1200 | 1270 | ||
1271 | /* probe the backlight is there is one defined */ | ||
1272 | if (ch->cfg.bl_info.max_brightness) | ||
1273 | ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch); | ||
1274 | |||
1201 | switch (pdata->ch[i].chan) { | 1275 | switch (pdata->ch[i].chan) { |
1202 | case LCDC_CHAN_MAINLCD: | 1276 | case LCDC_CHAN_MAINLCD: |
1203 | ch->enabled = 1 << 1; | 1277 | ch->enabled = 1 << 1; |
@@ -1345,6 +1419,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1345 | } | 1419 | } |
1346 | } | 1420 | } |
1347 | 1421 | ||
1422 | info->bl_dev = ch->bl; | ||
1423 | |||
1348 | error = register_framebuffer(info); | 1424 | error = register_framebuffer(info); |
1349 | if (error < 0) | 1425 | if (error < 0) |
1350 | goto err1; | 1426 | goto err1; |
@@ -1404,6 +1480,11 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) | |||
1404 | framebuffer_release(info); | 1480 | framebuffer_release(info); |
1405 | } | 1481 | } |
1406 | 1482 | ||
1483 | for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { | ||
1484 | if (priv->ch[i].bl) | ||
1485 | sh_mobile_lcdc_bl_remove(priv->ch[i].bl); | ||
1486 | } | ||
1487 | |||
1407 | if (priv->dot_clk) | 1488 | if (priv->dot_clk) |
1408 | clk_put(priv->dot_clk); | 1489 | clk_put(priv->dot_clk); |
1409 | 1490 | ||
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index 9ecee2fba1d7..03a22dcbcc59 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h | |||
@@ -16,6 +16,7 @@ enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, | |||
16 | 16 | ||
17 | struct sh_mobile_lcdc_priv; | 17 | struct sh_mobile_lcdc_priv; |
18 | struct fb_info; | 18 | struct fb_info; |
19 | struct backlight_device; | ||
19 | 20 | ||
20 | struct sh_mobile_lcdc_chan { | 21 | struct sh_mobile_lcdc_chan { |
21 | struct sh_mobile_lcdc_priv *lcdc; | 22 | struct sh_mobile_lcdc_priv *lcdc; |
@@ -26,6 +27,7 @@ struct sh_mobile_lcdc_chan { | |||
26 | u32 pseudo_palette[PALETTE_NR]; | 27 | u32 pseudo_palette[PALETTE_NR]; |
27 | unsigned long saved_ch_regs[NR_CH_REGS]; | 28 | unsigned long saved_ch_regs[NR_CH_REGS]; |
28 | struct fb_info *info; | 29 | struct fb_info *info; |
30 | struct backlight_device *bl; | ||
29 | dma_addr_t dma_handle; | 31 | dma_addr_t dma_handle; |
30 | struct fb_deferred_io defio; | 32 | struct fb_deferred_io defio; |
31 | struct scatterlist *sglist; | 33 | struct scatterlist *sglist; |
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h index daabae5817c6..f2e6ab857fa8 100644 --- a/include/video/sh_mobile_lcdc.h +++ b/include/video/sh_mobile_lcdc.h | |||
@@ -59,6 +59,8 @@ struct sh_mobile_lcdc_board_cfg { | |||
59 | struct sh_mobile_lcdc_sys_bus_ops *sys_ops); | 59 | struct sh_mobile_lcdc_sys_bus_ops *sys_ops); |
60 | void (*display_on)(void *board_data, struct fb_info *info); | 60 | void (*display_on)(void *board_data, struct fb_info *info); |
61 | void (*display_off)(void *board_data); | 61 | void (*display_off)(void *board_data); |
62 | int (*set_brightness)(void *board_data, int brightness); | ||
63 | int (*get_brightness)(void *board_data); | ||
62 | }; | 64 | }; |
63 | 65 | ||
64 | struct sh_mobile_lcdc_lcd_size_cfg { /* width and height of panel in mm */ | 66 | struct sh_mobile_lcdc_lcd_size_cfg { /* width and height of panel in mm */ |
@@ -66,6 +68,12 @@ struct sh_mobile_lcdc_lcd_size_cfg { /* width and height of panel in mm */ | |||
66 | unsigned long height; | 68 | unsigned long height; |
67 | }; | 69 | }; |
68 | 70 | ||
71 | /* backlight info */ | ||
72 | struct sh_mobile_lcdc_bl_info { | ||
73 | const char *name; | ||
74 | int max_brightness; | ||
75 | }; | ||
76 | |||
69 | struct sh_mobile_lcdc_chan_cfg { | 77 | struct sh_mobile_lcdc_chan_cfg { |
70 | int chan; | 78 | int chan; |
71 | int bpp; | 79 | int bpp; |
@@ -76,6 +84,7 @@ struct sh_mobile_lcdc_chan_cfg { | |||
76 | int num_cfg; | 84 | int num_cfg; |
77 | struct sh_mobile_lcdc_lcd_size_cfg lcd_size_cfg; | 85 | struct sh_mobile_lcdc_lcd_size_cfg lcd_size_cfg; |
78 | struct sh_mobile_lcdc_board_cfg board_cfg; | 86 | struct sh_mobile_lcdc_board_cfg board_cfg; |
87 | struct sh_mobile_lcdc_bl_info bl_info; | ||
79 | struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ | 88 | struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ |
80 | }; | 89 | }; |
81 | 90 | ||