diff options
author | Alexandre Courbot <gnurou@gmail.com> | 2011-02-15 22:49:01 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2011-03-10 06:20:57 -0500 |
commit | 3b0fd9d75598584478d1d3f6551f8a8a9696c34e (patch) | |
tree | aec7b48dbbb6810b15885ea34cf8041798e534bb /drivers/video/sh_mobile_lcdcfb.c | |
parent | 35d34df711e8b44846e759d8cfddb4ec6877cccb (diff) |
fbdev: sh_mobile_lcdcfb: add backlight support
Support for backlight devices controlled through board-specific
routines. Backlights can be defined per-channel and follow fbdev
directives to switch off as the LCD blanks or is turned on/off.
Signed-off-by: Alexandre Courbot <gnurou@gmail.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/video/sh_mobile_lcdcfb.c')
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 81 |
1 files changed, 81 insertions, 0 deletions
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 | ||