Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Alexandre Courbot and committed by
Paul Mundt
3b0fd9d7 35d34df7

+93
+1
drivers/video/Kconfig
··· 2005 2005 select FB_SYS_IMAGEBLIT 2006 2006 select FB_SYS_FOPS 2007 2007 select FB_DEFERRED_IO 2008 + select FB_BACKLIGHT 2008 2009 select SH_MIPI_DSI if SH_LCD_MIPI_DSI 2009 2010 ---help--- 2010 2011 Frame buffer driver for the on-chip SH-Mobile LCD controller.
+81
drivers/video/sh_mobile_lcdcfb.c
··· 21 21 #include <linux/ioctl.h> 22 22 #include <linux/slab.h> 23 23 #include <linux/console.h> 24 + #include <linux/backlight.h> 25 + #include <linux/gpio.h> 24 26 #include <video/sh_mobile_lcdc.h> 25 27 #include <asm/atomic.h> 26 28 ··· 620 618 board_cfg->display_on(board_cfg->board_data, ch->info); 621 619 module_put(board_cfg->owner); 622 620 } 621 + 622 + if (ch->bl) { 623 + ch->bl->props.power = FB_BLANK_UNBLANK; 624 + backlight_update_status(ch->bl); 625 + } 623 626 } 624 627 625 628 return 0; ··· 653 646 fb_deferred_io_cleanup(ch->info); 654 647 ch->info->fbdefio = NULL; 655 648 sh_mobile_lcdc_clk_on(priv); 649 + } 650 + 651 + if (ch->bl) { 652 + ch->bl->props.power = FB_BLANK_POWERDOWN; 653 + backlight_update_status(ch->bl); 656 654 } 657 655 658 656 board_cfg = &ch->cfg.board_cfg; ··· 992 980 .fb_check_var = sh_mobile_check_var, 993 981 }; 994 982 983 + static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev) 984 + { 985 + struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); 986 + struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg; 987 + int brightness = bdev->props.brightness; 988 + 989 + if (bdev->props.power != FB_BLANK_UNBLANK || 990 + bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) 991 + brightness = 0; 992 + 993 + return cfg->set_brightness(cfg->board_data, brightness); 994 + } 995 + 996 + static int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev) 997 + { 998 + struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); 999 + struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg; 1000 + 1001 + return cfg->get_brightness(cfg->board_data); 1002 + } 1003 + 1004 + static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev, 1005 + struct fb_info *info) 1006 + { 1007 + return (info->bl_dev == bdev); 1008 + } 1009 + 1010 + static struct backlight_ops sh_mobile_lcdc_bl_ops = { 1011 + .options = BL_CORE_SUSPENDRESUME, 1012 + .update_status = sh_mobile_lcdc_update_bl, 1013 + .get_brightness = sh_mobile_lcdc_get_brightness, 1014 + .check_fb = sh_mobile_lcdc_check_fb, 1015 + }; 1016 + 1017 + static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent, 1018 + struct sh_mobile_lcdc_chan *ch) 1019 + { 1020 + struct backlight_device *bl; 1021 + 1022 + bl = backlight_device_register(ch->cfg.bl_info.name, parent, ch, 1023 + &sh_mobile_lcdc_bl_ops, NULL); 1024 + if (!bl) { 1025 + dev_err(parent, "unable to register backlight device\n"); 1026 + return NULL; 1027 + } 1028 + 1029 + bl->props.max_brightness = ch->cfg.bl_info.max_brightness; 1030 + bl->props.brightness = bl->props.max_brightness; 1031 + backlight_update_status(bl); 1032 + 1033 + return bl; 1034 + } 1035 + 1036 + static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev) 1037 + { 1038 + backlight_device_unregister(bdev); 1039 + } 1040 + 995 1041 static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) 996 1042 { 997 1043 switch (bpp) { ··· 1268 1198 init_completion(&ch->vsync_completion); 1269 1199 ch->pan_offset = 0; 1270 1200 1201 + /* probe the backlight is there is one defined */ 1202 + if (ch->cfg.bl_info.max_brightness) 1203 + ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch); 1204 + 1271 1205 switch (pdata->ch[i].chan) { 1272 1206 case LCDC_CHAN_MAINLCD: 1273 1207 ch->enabled = 1 << 1; ··· 1419 1345 } 1420 1346 } 1421 1347 1348 + info->bl_dev = ch->bl; 1349 + 1422 1350 error = register_framebuffer(info); 1423 1351 if (error < 0) 1424 1352 goto err1; ··· 1478 1402 priv->ch[i].dma_handle); 1479 1403 fb_dealloc_cmap(&info->cmap); 1480 1404 framebuffer_release(info); 1405 + } 1406 + 1407 + for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 1408 + if (priv->ch[i].bl) 1409 + sh_mobile_lcdc_bl_remove(priv->ch[i].bl); 1481 1410 } 1482 1411 1483 1412 if (priv->dot_clk)
+2
drivers/video/sh_mobile_lcdcfb.h
··· 16 16 17 17 struct sh_mobile_lcdc_priv; 18 18 struct fb_info; 19 + struct backlight_device; 19 20 20 21 struct sh_mobile_lcdc_chan { 21 22 struct sh_mobile_lcdc_priv *lcdc; ··· 27 26 u32 pseudo_palette[PALETTE_NR]; 28 27 unsigned long saved_ch_regs[NR_CH_REGS]; 29 28 struct fb_info *info; 29 + struct backlight_device *bl; 30 30 dma_addr_t dma_handle; 31 31 struct fb_deferred_io defio; 32 32 struct scatterlist *sglist;
+9
include/video/sh_mobile_lcdc.h
··· 59 59 struct sh_mobile_lcdc_sys_bus_ops *sys_ops); 60 60 void (*display_on)(void *board_data, struct fb_info *info); 61 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 66 struct sh_mobile_lcdc_lcd_size_cfg { /* width and height of panel in mm */ 65 67 unsigned long width; 66 68 unsigned long height; 69 + }; 70 + 71 + /* backlight info */ 72 + struct sh_mobile_lcdc_bl_info { 73 + const char *name; 74 + int max_brightness; 67 75 }; 68 76 69 77 struct sh_mobile_lcdc_chan_cfg { ··· 84 76 int num_cfg; 85 77 struct sh_mobile_lcdc_lcd_size_cfg lcd_size_cfg; 86 78 struct sh_mobile_lcdc_board_cfg board_cfg; 79 + struct sh_mobile_lcdc_bl_info bl_info; 87 80 struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ 88 81 }; 89 82