From fbd65e0ecdeffe5e50ad850fb7240888b1af6b22 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 24 May 2010 14:33:52 -0700 Subject: fbdev: bfin-lq035q1-fb: respect new PPI mode platform field This lets us support the new BF527-EZKIT V2.1 via platform resources tweaks only. Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Cc: Bryan Wu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/bfin-lq035q1-fb.c | 252 +++++++++++++++++++++++----------------- 1 file changed, 146 insertions(+), 106 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c index 2baac7cc1425..c8e1f04941bd 100644 --- a/drivers/video/bfin-lq035q1-fb.c +++ b/drivers/video/bfin-lq035q1-fb.c @@ -61,47 +61,13 @@ #define LCD_X_RES 320 /* Horizontal Resolution */ #define LCD_Y_RES 240 /* Vertical Resolution */ #define DMA_BUS_SIZE 16 +#define U_LINE 4 /* Blanking Lines */ -#define USE_RGB565_16_BIT_PPI - -#ifdef USE_RGB565_16_BIT_PPI -#define LCD_BPP 16 /* Bit Per Pixel */ -#define CLOCKS_PER_PIX 1 -#define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */ -#endif /* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD) * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 */ -#ifdef USE_RGB565_8_BIT_PPI -#define LCD_BPP 16 /* Bit Per Pixel */ -#define CLOCKS_PER_PIX 2 -#define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */ -#endif - -#ifdef USE_RGB888_8_BIT_PPI -#define LCD_BPP 24 /* Bit Per Pixel */ -#define CLOCKS_PER_PIX 3 -#define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */ -#endif - - /* - * HS and VS timing parameters (all in number of PPI clk ticks) - */ - -#define U_LINE 4 /* Blanking Lines */ - -#define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */ -#define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */ -#define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */ -#define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */ - -#define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */ -#define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */ -#define V_PERIOD (H_PERIOD * V_LINES) /* VS period */ - -#define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8)) #define BFIN_LCD_NBR_PALETTE_ENTRIES 256 @@ -110,12 +76,6 @@ #define PPI_PORT_CFG_01 0x10 #define PPI_POLS_1 0x8000 -#if (CLOCKS_PER_PIX > 1) -#define PPI_PMODE (DLEN_8 | PACK_EN) -#else -#define PPI_PMODE (DLEN_16) -#endif - #define LQ035_INDEX 0x74 #define LQ035_DATA 0x76 @@ -139,6 +99,15 @@ struct bfin_lq035q1fb_info { int irq; spinlock_t lock; /* lock */ u32 pseudo_pal[16]; + + u32 lcd_bpp; + u32 h_actpix; + u32 h_period; + u32 h_pulse; + u32 h_start; + u32 v_lines; + u32 v_pulse; + u32 v_period; }; static int nocursor; @@ -234,16 +203,69 @@ static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg) return 0; } +static int bfin_lq035q1_calc_timing(struct bfin_lq035q1fb_info *fbi) +{ + unsigned long clocks_per_pix, cpld_pipeline_delay_cor; + + /* + * Interface 16/18-bit TFT over an 8-bit wide PPI using a small + * Programmable Logic Device (CPLD) + * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 + */ + + switch (fbi->disp_info->ppi_mode) { + case USE_RGB565_16_BIT_PPI: + fbi->lcd_bpp = 16; + clocks_per_pix = 1; + cpld_pipeline_delay_cor = 0; + break; + case USE_RGB565_8_BIT_PPI: + fbi->lcd_bpp = 16; + clocks_per_pix = 2; + cpld_pipeline_delay_cor = 3; + break; + case USE_RGB888_8_BIT_PPI: + fbi->lcd_bpp = 24; + clocks_per_pix = 3; + cpld_pipeline_delay_cor = 5; + break; + default: + return -EINVAL; + } + + /* + * HS and VS timing parameters (all in number of PPI clk ticks) + */ + + fbi->h_actpix = (LCD_X_RES * clocks_per_pix); /* active horizontal pixel */ + fbi->h_period = (336 * clocks_per_pix); /* HS period */ + fbi->h_pulse = (2 * clocks_per_pix); /* HS pulse width */ + fbi->h_start = (7 * clocks_per_pix + cpld_pipeline_delay_cor); /* first valid pixel */ + + fbi->v_lines = (LCD_Y_RES + U_LINE); /* total vertical lines */ + fbi->v_pulse = (2 * clocks_per_pix); /* VS pulse width (1-5 H_PERIODs) */ + fbi->v_period = (fbi->h_period * fbi->v_lines); /* VS period */ + + return 0; +} + static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi) { - bfin_write_PPI_DELAY(H_START); - bfin_write_PPI_COUNT(H_ACTPIX - 1); - bfin_write_PPI_FRAME(V_LINES); + unsigned ppi_pmode; + + if (fbi->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI) + ppi_pmode = DLEN_16; + else + ppi_pmode = (DLEN_8 | PACK_EN); + + bfin_write_PPI_DELAY(fbi->h_start); + bfin_write_PPI_COUNT(fbi->h_actpix - 1); + bfin_write_PPI_FRAME(fbi->v_lines); bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ - PPI_PMODE | /* 8/16 bit data length / PACK_EN? */ + ppi_pmode | /* 8/16 bit data length / PACK_EN? */ PPI_POLS_1); /* faling edge syncs POLS */ } @@ -272,19 +294,19 @@ static void bfin_lq035q1_stop_timers(void) } -static void bfin_lq035q1_init_timers(void) +static void bfin_lq035q1_init_timers(struct bfin_lq035q1fb_info *fbi) { bfin_lq035q1_stop_timers(); - set_gptimer_period(TIMER_HSYNC_id, H_PERIOD); - set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE); + set_gptimer_period(TIMER_HSYNC_id, fbi->h_period); + set_gptimer_pwidth(TIMER_HSYNC_id, fbi->h_pulse); set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | TIMER_TIN_SEL | TIMER_CLK_SEL| TIMER_EMU_RUN); - set_gptimer_period(TIMER_VSYNC_id, V_PERIOD); - set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE); + set_gptimer_period(TIMER_VSYNC_id, fbi->v_period); + set_gptimer_pwidth(TIMER_VSYNC_id, fbi->v_pulse); set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | TIMER_TIN_SEL | TIMER_CLK_SEL | TIMER_EMU_RUN); @@ -294,21 +316,21 @@ static void bfin_lq035q1_init_timers(void) static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi) { + set_dma_config(CH_PPI, set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, INTR_DISABLE, DIMENSION_2D, DATA_SIZE_16, DMA_NOSYNC_KEEP_DMA_BUF)); - set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); + set_dma_x_count(CH_PPI, (LCD_X_RES * fbi->lcd_bpp) / DMA_BUS_SIZE); set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); - set_dma_y_count(CH_PPI, V_LINES); + set_dma_y_count(CH_PPI, fbi->v_lines); set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); } -#if (CLOCKS_PER_PIX == 1) static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, @@ -316,22 +338,27 @@ static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15, 0}; -#else -static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + +static const u16 ppi0_req_8[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, 0}; -#endif -static inline void bfin_lq035q1_free_ports(void) +static inline void bfin_lq035q1_free_ports(unsigned ppi16) { - peripheral_free_list(ppi0_req_16); + if (ppi16) + peripheral_free_list(ppi0_req_16); + else + peripheral_free_list(ppi0_req_8); + if (ANOMALY_05000400) gpio_free(P_IDENT(P_PPI0_FS3)); } -static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) +static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev, + unsigned ppi16) { + int ret; /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: * Drive PPI_FS3 Low */ @@ -342,7 +369,12 @@ static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); } - if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) { + if (ppi16) + ret = peripheral_request_list(ppi0_req_16, DRIVER_NAME); + else + ret = peripheral_request_list(ppi0_req_8, DRIVER_NAME); + + if (ret) { dev_err(&pdev->dev, "requesting peripherals failed\n"); return -EFAULT; } @@ -364,7 +396,7 @@ static int bfin_lq035q1_fb_open(struct fb_info *info, int user) bfin_lq035q1_config_dma(fbi); bfin_lq035q1_config_ppi(fbi); - bfin_lq035q1_init_timers(); + bfin_lq035q1_init_timers(fbi); /* start dma */ enable_dma(CH_PPI); @@ -402,12 +434,9 @@ static int bfin_lq035q1_fb_release(struct fb_info *info, int user) static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - switch (var->bits_per_pixel) { -#if (LCD_BPP == 24) - case 24:/* TRUECOLOUR, 16m */ -#else - case 16:/* DIRECTCOLOUR, 64k */ -#endif + struct bfin_lq035q1fb_info *fbi = info->par; + + if (var->bits_per_pixel == fbi->lcd_bpp) { var->red.offset = info->var.red.offset; var->green.offset = info->var.green.offset; var->blue.offset = info->var.blue.offset; @@ -420,8 +449,7 @@ static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, var->red.msb_right = 0; var->green.msb_right = 0; var->blue.msb_right = 0; - break; - default: + } else { pr_debug("%s: depth not supported: %u BPP\n", __func__, var->bits_per_pixel); return -EINVAL; @@ -528,6 +556,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) { struct bfin_lq035q1fb_info *info; struct fb_info *fbinfo; + u32 active_video_mem_offset; int ret; ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI"); @@ -550,6 +579,12 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fbinfo); + ret = bfin_lq035q1_calc_timing(info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed PPI Mode\n"); + goto out3; + } + strcpy(fbinfo->fix.id, DRIVER_NAME); fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; @@ -571,46 +606,48 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) fbinfo->var.xres_virtual = LCD_X_RES; fbinfo->var.yres = LCD_Y_RES; fbinfo->var.yres_virtual = LCD_Y_RES; - fbinfo->var.bits_per_pixel = LCD_BPP; + fbinfo->var.bits_per_pixel = info->lcd_bpp; if (info->disp_info->mode & LQ035_BGR) { -#if (LCD_BPP == 24) - fbinfo->var.red.offset = 0; - fbinfo->var.green.offset = 8; - fbinfo->var.blue.offset = 16; -#else - fbinfo->var.red.offset = 0; - fbinfo->var.green.offset = 5; - fbinfo->var.blue.offset = 11; -#endif + if (info->lcd_bpp == 24) { + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 16; + } else { + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 11; + } } else { -#if (LCD_BPP == 24) - fbinfo->var.red.offset = 16; - fbinfo->var.green.offset = 8; - fbinfo->var.blue.offset = 0; -#else - fbinfo->var.red.offset = 11; - fbinfo->var.green.offset = 5; - fbinfo->var.blue.offset = 0; -#endif + if (info->lcd_bpp == 24) { + fbinfo->var.red.offset = 16; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 0; + } else { + fbinfo->var.red.offset = 11; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 0; + } } fbinfo->var.transp.offset = 0; -#if (LCD_BPP == 24) - fbinfo->var.red.length = 8; - fbinfo->var.green.length = 8; - fbinfo->var.blue.length = 8; -#else - fbinfo->var.red.length = 5; - fbinfo->var.green.length = 6; - fbinfo->var.blue.length = 5; -#endif + if (info->lcd_bpp == 24) { + fbinfo->var.red.length = 8; + fbinfo->var.green.length = 8; + fbinfo->var.blue.length = 8; + } else { + fbinfo->var.red.length = 5; + fbinfo->var.green.length = 6; + fbinfo->var.blue.length = 5; + } fbinfo->var.transp.length = 0; - fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8 - + ACTIVE_VIDEO_MEM_OFFSET; + active_video_mem_offset = ((U_LINE / 2) * LCD_X_RES * (info->lcd_bpp / 8)); + + fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * info->lcd_bpp / 8 + + active_video_mem_offset; fbinfo->fix.line_length = fbinfo->var.xres_virtual * fbinfo->var.bits_per_pixel / 8; @@ -629,8 +666,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) goto out3; } - fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; - fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + fbinfo->screen_base = (void *)info->fb_buffer + active_video_mem_offset; + fbinfo->fix.smem_start = (int)info->fb_buffer + active_video_mem_offset; fbinfo->fbops = &bfin_lq035q1_fb_ops; @@ -643,7 +680,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) goto out4; } - ret = bfin_lq035q1_request_ports(pdev); + ret = bfin_lq035q1_request_ports(pdev, + info->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI); if (ret) { dev_err(&pdev->dev, "couldn't request gpio port\n"); goto out6; @@ -693,7 +731,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n", - LCD_X_RES, LCD_Y_RES, LCD_BPP); + LCD_X_RES, LCD_Y_RES, info->lcd_bpp); return 0; @@ -705,7 +743,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) out8: free_irq(info->irq, info); out7: - bfin_lq035q1_free_ports(); + bfin_lq035q1_free_ports(info->disp_info->ppi_mode == + USE_RGB565_16_BIT_PPI); out6: fb_dealloc_cmap(&fbinfo->cmap); out4: @@ -742,7 +781,8 @@ static int __devexit bfin_lq035q1_remove(struct platform_device *pdev) fb_dealloc_cmap(&fbinfo->cmap); - bfin_lq035q1_free_ports(); + bfin_lq035q1_free_ports(info->disp_info->ppi_mode == + USE_RGB565_16_BIT_PPI); platform_set_drvdata(pdev, NULL); framebuffer_release(fbinfo); @@ -781,7 +821,7 @@ static int bfin_lq035q1_resume(struct device *dev) bfin_lq035q1_config_dma(info); bfin_lq035q1_config_ppi(info); - bfin_lq035q1_init_timers(); + bfin_lq035q1_init_timers(info); /* start dma */ enable_dma(CH_PPI); -- cgit v1.2.2 From dbd536bf2f1b494240b56035ee16eba2e3d89b6a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 24 May 2010 14:33:53 -0700 Subject: sis: strcpy() => strlcpy() These are different size buffers (40 chars vs 16), we may as well be cautious. Signed-off-by: Dan Carpenter Cc: Thomas Winischhofer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/sis/sis_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index a531a0f7cdf2..559bf1727a2b 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -1845,7 +1845,7 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, ivideo->myid); + strlcpy(fix->id, ivideo->myid, sizeof(fix->id)); mutex_lock(&info->mm_lock); fix->smem_start = ivideo->video_base + ivideo->video_offset; -- cgit v1.2.2 From bd9b5caf8616501d2ab6f17210b11f81ea7546eb Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Mon, 24 May 2010 14:33:54 -0700 Subject: fbdev: section cleanup in arcfb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the sections in the arcfb driver, by moving: * the variables arcfb_fix and arcfb_var from .init.data to .devinit.data * arcfb_remove() from .text to .devexit.text This fixes the following warnings issued by modpost: WARNING: drivers/video/built-in.o(.devinit.text+0x543): Section mismatch in reference from the function arcfb_probe() to the variable .init.data:arcfb_var The function __devinit arcfb_probe() references a variable __initdata arcfb_var. If arcfb_var is only used by arcfb_probe then annotate arcfb_var with a matching annotation. WARNING: drivers/video/built-in.o(.devinit.text+0x558): Section mismatch in reference from the function arcfb_probe() to the variable .init.data:arcfb_fix The function __devinit arcfb_probe() references a variable __initdata arcfb_fix. If arcfb_fix is only used by arcfb_probe then annotate arcfb_fix with a matching annotation. Signed-off-by: Henrik Kretzschmar Acked-by: Uwe Kleine-König Cc: [if "platform-drivers: move probe to .devinit.text in drivers/video" was merged] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/arcfb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index 8d406fb689c1..f3d7440f0072 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c @@ -80,7 +80,7 @@ struct arcfb_par { spinlock_t lock; }; -static struct fb_fix_screeninfo arcfb_fix __initdata = { +static struct fb_fix_screeninfo arcfb_fix __devinitdata = { .id = "arcfb", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_MONO01, @@ -90,7 +90,7 @@ static struct fb_fix_screeninfo arcfb_fix __initdata = { .accel = FB_ACCEL_NONE, }; -static struct fb_var_screeninfo arcfb_var __initdata = { +static struct fb_var_screeninfo arcfb_var __devinitdata = { .xres = 128, .yres = 64, .xres_virtual = 128, @@ -588,7 +588,7 @@ err: return retval; } -static int arcfb_remove(struct platform_device *dev) +static int __devexit arcfb_remove(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); @@ -602,7 +602,7 @@ static int arcfb_remove(struct platform_device *dev) static struct platform_driver arcfb_driver = { .probe = arcfb_probe, - .remove = arcfb_remove, + .remove = __devexit_p(arcfb_remove), .driver = { .name = "arcfb", }, -- cgit v1.2.2 From e217e6e39f62e47f7e659b715235dbd57df480f8 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Mon, 24 May 2010 14:33:56 -0700 Subject: fbdev: section cleanup in hgafb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix up the sections in the hgafb driver, by * moving hga_default_var and hga_fix from .init.data to .devinit.data * moving hga_detect() from .init.text to .devinit.text * moving hga_fb_remove() from .text to .devexit.text This fixes the following warnings issued by modpost: WARNING: drivers/video/hgafb.o(.devinit.text+0x18): Section mismatch in referenc e from the function hgafb_probe() to the function .init.text:hga_card_detect() The function __devinit hgafb_probe() references a function __init hga_card_detect(). If hga_card_detect is only used by hgafb_probe then annotate hga_card_detect with a matching annotation. WARNING: drivers/video/hgafb.o(.devinit.text+0xfe): Section mismatch in referenc e from the function hgafb_probe() to the variable .init.data:hga_fix The function __devinit hgafb_probe() references a variable __initdata hga_fix. If hga_fix is only used by hgafb_probe then annotate hga_fix with a matching annotation. WARNING: drivers/video/hgafb.o(.devinit.text+0x105): Section mismatch in reference from the function hgafb_probe() to the variable .init.data:hga_default_var The function __devinit hgafb_probe() references a variable __initdata hga_default_var. If hga_default_var is only used by hgafb_probe then annotate hga_default_var with a matching annotation. Signed-off-by: Henrik Kretzschmar Acked-by: Uwe Kleine-König Cc: [if "platform-drivers: move probe to .devinit.text in drivers/video" was merged] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/hgafb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index 8bbf251f83d9..af8f0f2cc782 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -106,7 +106,7 @@ static DEFINE_SPINLOCK(hga_reg_lock); /* Framebuffer driver structures */ -static struct fb_var_screeninfo __initdata hga_default_var = { +static struct fb_var_screeninfo hga_default_var __devinitdata = { .xres = 720, .yres = 348, .xres_virtual = 720, @@ -120,7 +120,7 @@ static struct fb_var_screeninfo __initdata hga_default_var = { .width = -1, }; -static struct fb_fix_screeninfo __initdata hga_fix = { +static struct fb_fix_screeninfo hga_fix __devinitdata = { .id = "HGA", .type = FB_TYPE_PACKED_PIXELS, /* (not sure) */ .visual = FB_VISUAL_MONO10, @@ -276,7 +276,7 @@ static void hga_blank(int blank_mode) spin_unlock_irqrestore(&hga_reg_lock, flags); } -static int __init hga_card_detect(void) +static int __devinit hga_card_detect(void) { int count = 0; void __iomem *p, *q; @@ -596,7 +596,7 @@ static int __devinit hgafb_probe(struct platform_device *pdev) return 0; } -static int hgafb_remove(struct platform_device *pdev) +static int __devexit hgafb_remove(struct platform_device *pdev) { struct fb_info *info = platform_get_drvdata(pdev); @@ -621,7 +621,7 @@ static int hgafb_remove(struct platform_device *pdev) static struct platform_driver hgafb_driver = { .probe = hgafb_probe, - .remove = hgafb_remove, + .remove = __devexit_p(hgafb_remove), .driver = { .name = "hgafb", }, -- cgit v1.2.2 From 3cc04971661e37e7de6fbf9808ede554b5e1cb4e Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Mon, 24 May 2010 14:33:57 -0700 Subject: fbdev: section cleanup in vfb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix up the section in the vfb driver, by moving the variables vfb_default and vfb_fix from .init.data to .devinit.data This fixes the following warnings issued by modpost: WARNING: drivers/video/vfb.o(.devinit.text+0xf8): Section mismatch in reference from the function vfb_probe() to the variable .init.data:vfb_default The function __devinit vfb_probe() references a variable __initdata vfb_default. If vfb_default is only used by vfb_probe then annotate vfb_default with a matching annotation. WARNING: drivers/video/vfb.o(.devinit.text+0x114): Section mismatch in reference from the function vfb_probe() to the variable .init.data:vfb_fix The function __devinit vfb_probe() references a variable __initdata vfb_fix. If vfb_fix is only used by vfb_probe then annotate vfb_fix with a matching annotation. Signed-off-by: Henrik Kretzschmar Acked-by: Uwe Kleine-König Cc: [if "platform-drivers: move probe to .devinit.text in drivers/video" was merged] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/vfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 9b5532b4de35..bc67251f1a2f 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -78,7 +78,7 @@ static void rvfree(void *mem, unsigned long size) vfree(mem); } -static struct fb_var_screeninfo vfb_default __initdata = { +static struct fb_var_screeninfo vfb_default __devinitdata = { .xres = 640, .yres = 480, .xres_virtual = 640, @@ -100,7 +100,7 @@ static struct fb_var_screeninfo vfb_default __initdata = { .vmode = FB_VMODE_NONINTERLACED, }; -static struct fb_fix_screeninfo vfb_fix __initdata = { +static struct fb_fix_screeninfo vfb_fix __devinitdata = { .id = "Virtual FB", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, -- cgit v1.2.2 From ad1458464cbbe6935be6e20d70920301733158af Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Mon, 24 May 2010 14:33:59 -0700 Subject: fbdev: section cleanup in vga16fb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix up the sections in the vga16fb driver, by moving: * the variables vga16_defined and vga16fb from .init.data to .devinit.data * vga16fb_setup() from .text to .init.text * vga16fb_remove() from .text. to .devexit.text This fixes the following warnings issued by modpost: WARNING: drivers/video/built-in.o(.devinit.text+0x1a420): Section mismatch in re ference from the function vga16fb_probe() to the (unknown reference) .init.data: (unknown) The function __devinit vga16fb_probe() references a (unknown reference) __initdata (unknown). If (unknown) is only used by vga16fb_probe then annotate (unknown) with a matching annotation. WARNING: drivers/video/built-in.o(.devinit.text+0x1a437): Section mismatch in reference from the function vga16fb_probe() to the variable .init.data:vga16fb_defined The function __devinit vga16fb_probe() references a variable __initdata vga16fb_defined. If vga16fb_defined is only used by vga16fb_probe then annotate vga16fb_defined with a matching annotation. WARNING: drivers/video/built-in.o(.devinit.text+0x1a457): Section mismatch in reference from the function vga16fb_probe() to the variable .init.data:vga16fb_fix The function __devinit vga16fb_probe() references a variable __initdata vga16fb_fix. If vga16fb_fix is only used by vga16fb_probe then annotate vga16fb_fix with a matching annotation. Signed-off-by: Henrik Kretzschmar Acked-by: Uwe Kleine-König Cc: [if "platform-drivers: move probe to .devinit.text in drivers/video" was merged] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/vga16fb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index 149c47ac7e93..28ccab44a391 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -65,7 +65,7 @@ struct vga16fb_par { /* --------------------------------------------------------------------- */ -static struct fb_var_screeninfo vga16fb_defined __initdata = { +static struct fb_var_screeninfo vga16fb_defined __devinitdata = { .xres = 640, .yres = 480, .xres_virtual = 640, @@ -85,7 +85,7 @@ static struct fb_var_screeninfo vga16fb_defined __initdata = { }; /* name should not depend on EGA/VGA */ -static struct fb_fix_screeninfo vga16fb_fix __initdata = { +static struct fb_fix_screeninfo vga16fb_fix __devinitdata = { .id = "VGA16 VGA", .smem_start = VGA_FB_PHYS, .smem_len = VGA_FB_PHYS_LEN, @@ -1287,7 +1287,7 @@ static struct fb_ops vga16fb_ops = { }; #ifndef MODULE -static int vga16fb_setup(char *options) +static int __init vga16fb_setup(char *options) { char *this_opt; @@ -1393,7 +1393,7 @@ static int __devinit vga16fb_probe(struct platform_device *dev) return ret; } -static int vga16fb_remove(struct platform_device *dev) +static int __devexit vga16fb_remove(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); @@ -1405,7 +1405,7 @@ static int vga16fb_remove(struct platform_device *dev) static struct platform_driver vga16fb_driver = { .probe = vga16fb_probe, - .remove = vga16fb_remove, + .remove = __devexit_p(vga16fb_remove), .driver = { .name = "vga16fb", }, -- cgit v1.2.2 From fb6cb3270af8f2ad3dd556906a9c52aa85754849 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Mon, 24 May 2010 14:34:00 -0700 Subject: fbdev: section cleanup in w100fb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix up the section in the w100fb driver, by moving: * w100fb_remove() from .text to .devexit.text * w100_get_xtal_table() from .text to .devinit.text * w100fb_init() from .devinit.text to .init.text Signed-off-by: Henrik Kretzschmar Acked-by: Uwe Kleine-König Cc: [if "platform-drivers: move probe to .devinit.text in drivers/video" was merged] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/w100fb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 31b0e17ed090..e66b8b19ce5d 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -53,7 +53,7 @@ static void w100_update_enable(void); static void w100_update_disable(void); static void calc_hsync(struct w100fb_par *par); static void w100_init_graphic_engine(struct w100fb_par *par); -struct w100_pll_info *w100_get_xtal_table(unsigned int freq); +struct w100_pll_info *w100_get_xtal_table(unsigned int freq) __devinit; /* Pseudo palette size */ #define MAX_PALETTES 16 @@ -782,7 +782,7 @@ out: } -static int w100fb_remove(struct platform_device *pdev) +static int __devexit w100fb_remove(struct platform_device *pdev) { struct fb_info *info = platform_get_drvdata(pdev); struct w100fb_par *par=info->par; @@ -1020,7 +1020,7 @@ static struct pll_entries { { 0 }, }; -struct w100_pll_info *w100_get_xtal_table(unsigned int freq) +struct w100_pll_info __devinit *w100_get_xtal_table(unsigned int freq) { struct pll_entries *pll_entry = w100_pll_tables; @@ -1611,7 +1611,7 @@ static void w100_vsync(void) static struct platform_driver w100fb_driver = { .probe = w100fb_probe, - .remove = w100fb_remove, + .remove = __devexit_p(w100fb_remove), .suspend = w100fb_suspend, .resume = w100fb_resume, .driver = { @@ -1619,7 +1619,7 @@ static struct platform_driver w100fb_driver = { }, }; -int __devinit w100fb_init(void) +int __init w100fb_init(void) { return platform_driver_register(&w100fb_driver); } -- cgit v1.2.2 From 1f9c3e1f07e39c8af3bf42236fc553b5bb0f83f1 Mon Sep 17 00:00:00 2001 From: Martin Ambrose Date: Mon, 24 May 2010 14:34:01 -0700 Subject: fbdev: da8xx/omap-l1xx: implement double buffering This work includes the following: - Implement handler for FBIO_WAITFORVSYNC ioctl. - Allocate the data and palette buffers separately. A consequence of this is that the palette and data loading is now done in different phases. And that the LCD must be disabled temporarily after the palette is loaded but this will only happen once after init and each time the palette is changed. I think this is OK. - Allocate two (ping and pong) framebuffers from memory. - Add pan_display handler which toggles the LCDC DMA registers between the ping and pong buffers. Signed-off-by: Martin Ambrose Cc: Chaithrika U S Cc: Sudhakar Rajashekhara Cc: Krzysztof Helt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/da8xx-fb.c | 301 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 234 insertions(+), 67 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 8d244ba0f601..cad7d45c8bac 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -36,7 +36,9 @@ #define DRIVER_NAME "da8xx_lcdc" /* LCD Status Register */ +#define LCD_END_OF_FRAME1 BIT(9) #define LCD_END_OF_FRAME0 BIT(8) +#define LCD_PL_LOAD_DONE BIT(6) #define LCD_FIFO_UNDERFLOW BIT(5) #define LCD_SYNC_LOST BIT(2) @@ -58,11 +60,13 @@ #define LCD_PALETTE_LOAD_MODE(x) ((x) << 20) #define PALETTE_AND_DATA 0x00 #define PALETTE_ONLY 0x01 +#define DATA_ONLY 0x02 #define LCD_MONO_8BIT_MODE BIT(9) #define LCD_RASTER_ORDER BIT(8) #define LCD_TFT_MODE BIT(7) #define LCD_UNDERFLOW_INT_ENA BIT(6) +#define LCD_PL_ENABLE BIT(4) #define LCD_MONOCHROME_MODE BIT(1) #define LCD_RASTER_ENABLE BIT(0) #define LCD_TFT_ALT_ENABLE BIT(23) @@ -87,6 +91,10 @@ #define LCD_DMA_CTRL_REG 0x40 #define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44 #define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48 +#define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C +#define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50 + +#define LCD_NUM_BUFFERS 2 #define WSI_TIMEOUT 50 #define PALETTE_SIZE 256 @@ -111,13 +119,20 @@ static inline void lcdc_write(unsigned int val, unsigned int addr) struct da8xx_fb_par { resource_size_t p_palette_base; unsigned char *v_palette_base; + dma_addr_t vram_phys; + unsigned long vram_size; + void *vram_virt; + unsigned int dma_start; + unsigned int dma_end; struct clk *lcdc_clk; int irq; unsigned short pseudo_palette[16]; - unsigned int databuf_sz; unsigned int palette_sz; unsigned int pxl_clk; int blank; + wait_queue_head_t vsync_wait; + int vsync_flag; + int vsync_timeout; #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; #endif @@ -148,9 +163,9 @@ static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = { .type = FB_TYPE_PACKED_PIXELS, .type_aux = 0, .visual = FB_VISUAL_PSEUDOCOLOR, - .xpanstep = 1, + .xpanstep = 0, .ypanstep = 1, - .ywrapstep = 1, + .ywrapstep = 0, .accel = FB_ACCEL_NONE }; @@ -221,22 +236,48 @@ static inline void lcd_disable_raster(void) static void lcd_blit(int load_mode, struct da8xx_fb_par *par) { - u32 tmp = par->p_palette_base + par->databuf_sz - 4; - u32 reg; + u32 start; + u32 end; + u32 reg_ras; + u32 reg_dma; + + /* init reg to clear PLM (loading mode) fields */ + reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); + reg_ras &= ~(3 << 20); + + reg_dma = lcdc_read(LCD_DMA_CTRL_REG); + + if (load_mode == LOAD_DATA) { + start = par->dma_start; + end = par->dma_end; + + reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY); + reg_dma |= LCD_END_OF_FRAME_INT_ENA; + reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; + + lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); + lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); + } else if (load_mode == LOAD_PALETTE) { + start = par->p_palette_base; + end = start + par->palette_sz - 1; + + reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); + reg_ras |= LCD_PL_ENABLE; + + lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + } - /* Update the databuf in the hw. */ - lcdc_write(par->p_palette_base, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); - lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + lcdc_write(reg_dma, LCD_DMA_CTRL_REG); + lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); - /* Start the DMA. */ - reg = lcdc_read(LCD_RASTER_CTRL_REG); - reg &= ~(3 << 20); - if (load_mode == LOAD_DATA) - reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA); - else if (load_mode == LOAD_PALETTE) - reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); - - lcdc_write(reg, LCD_RASTER_CTRL_REG); + /* + * The Raster enable bit must be set after all other control fields are + * set. + */ + lcd_enable_raster(); } /* Configure the Burst Size of DMA */ @@ -368,12 +409,8 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, u32 bpp, u32 raster_order) { - u32 bpl, reg; + u32 reg; - /* Disable Dual Frame Buffer. */ - reg = lcdc_read(LCD_DMA_CTRL_REG); - lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE, - LCD_DMA_CTRL_REG); /* Set the Panel Width */ /* Pixels per line = (PPL + 1)*16 */ /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/ @@ -410,9 +447,6 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, return -EINVAL; } - bpl = width * bpp / 8; - par->databuf_sz = height * bpl + par->palette_sz; - return 0; } @@ -421,8 +455,9 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct da8xx_fb_par *par = info->par; - unsigned short *palette = (unsigned short *)par->v_palette_base; + unsigned short *palette = (unsigned short *) par->v_palette_base; u_short pal; + int update_hw = 0; if (regno > 255) return 1; @@ -439,8 +474,10 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, pal |= (green & 0x00f0); pal |= (blue & 0x000f); - palette[regno] = pal; - + if (palette[regno] != pal) { + update_hw = 1; + palette[regno] = pal; + } } else if ((info->var.bits_per_pixel == 16) && regno < 16) { red >>= (16 - info->var.red.length); red <<= info->var.red.offset; @@ -453,9 +490,16 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, par->pseudo_palette[regno] = red | green | blue; - palette[0] = 0x4000; + if (palette[0] != 0x4000) { + update_hw = 1; + palette[0] = 0x4000; + } } + /* Update the palette in the h/w as needed. */ + if (update_hw) + lcd_blit(LOAD_PALETTE, par); + return 0; } @@ -541,15 +585,54 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, static irqreturn_t lcdc_irq_handler(int irq, void *arg) { + struct da8xx_fb_par *par = arg; u32 stat = lcdc_read(LCD_STAT_REG); + u32 reg_ras; if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { lcd_disable_raster(); lcdc_write(stat, LCD_STAT_REG); lcd_enable_raster(); - } else + } else if (stat & LCD_PL_LOAD_DONE) { + /* + * Must disable raster before changing state of any control bit. + * And also must be disabled before clearing the PL loading + * interrupt via the following write to the status register. If + * this is done after then one gets multiple PL done interrupts. + */ + lcd_disable_raster(); + lcdc_write(stat, LCD_STAT_REG); + /* Disable PL completion inerrupt */ + reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); + reg_ras &= ~LCD_PL_ENABLE; + lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); + + /* Setup and start data loading mode */ + lcd_blit(LOAD_DATA, par); + } else { + lcdc_write(stat, LCD_STAT_REG); + + if (stat & LCD_END_OF_FRAME0) { + lcdc_write(par->dma_start, + LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(par->dma_end, + LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + par->vsync_flag = 1; + wake_up_interruptible(&par->vsync_wait); + } + + if (stat & LCD_END_OF_FRAME1) { + lcdc_write(par->dma_start, + LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); + lcdc_write(par->dma_end, + LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); + par->vsync_flag = 1; + wake_up_interruptible(&par->vsync_wait); + } + } + return IRQ_HANDLED; } @@ -654,9 +737,10 @@ static int __devexit fb_remove(struct platform_device *dev) unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); - dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, - info->screen_base - PAGE_SIZE, - info->fix.smem_start); + dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base, + par->p_palette_base); + dma_free_coherent(NULL, par->vram_size, par->vram_virt, + par->vram_phys); free_irq(par->irq, par); clk_disable(par->lcdc_clk); clk_put(par->lcdc_clk); @@ -668,6 +752,39 @@ static int __devexit fb_remove(struct platform_device *dev) return 0; } +/* + * Function to wait for vertical sync which for this LCD peripheral + * translates into waiting for the current raster frame to complete. + */ +static int fb_wait_for_vsync(struct fb_info *info) +{ + struct da8xx_fb_par *par = info->par; + int ret; + + /* + * Set flag to 0 and wait for isr to set to 1. It would seem there is a + * race condition here where the ISR could have occured just before or + * just after this set. But since we are just coarsely waiting for + * a frame to complete then that's OK. i.e. if the frame completed + * just before this code executed then we have to wait another full + * frame time but there is no way to avoid such a situation. On the + * other hand if the frame completed just after then we don't need + * to wait long at all. Either way we are guaranteed to return to the + * user immediately after a frame completion which is all that is + * required. + */ + par->vsync_flag = 0; + ret = wait_event_interruptible_timeout(par->vsync_wait, + par->vsync_flag != 0, + par->vsync_timeout); + if (ret < 0) + return ret; + if (ret == 0) + return -ETIMEDOUT; + + return 0; +} + static int fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { @@ -697,6 +814,8 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd, sync_arg.pulse_width, sync_arg.front_porch); break; + case FBIO_WAITFORVSYNC: + return fb_wait_for_vsync(info); default: return -EINVAL; } @@ -732,10 +851,47 @@ static int cfb_blank(int blank, struct fb_info *info) return ret; } +/* + * Set new x,y offsets in the virtual display for the visible area and switch + * to the new mode. + */ +static int da8xx_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fbi) +{ + int ret = 0; + struct fb_var_screeninfo new_var; + struct da8xx_fb_par *par = fbi->par; + struct fb_fix_screeninfo *fix = &fbi->fix; + unsigned int end; + unsigned int start; + + if (var->xoffset != fbi->var.xoffset || + var->yoffset != fbi->var.yoffset) { + memcpy(&new_var, &fbi->var, sizeof(new_var)); + new_var.xoffset = var->xoffset; + new_var.yoffset = var->yoffset; + if (fb_check_var(&new_var, fbi)) + ret = -EINVAL; + else { + memcpy(&fbi->var, &new_var, sizeof(new_var)); + + start = fix->smem_start + + new_var.yoffset * fix->line_length + + new_var.xoffset * var->bits_per_pixel / 8; + end = start + var->yres * fix->line_length - 1; + par->dma_start = start; + par->dma_end = end; + } + } + + return ret; +} + static struct fb_ops da8xx_fb_ops = { .owner = THIS_MODULE, .fb_check_var = fb_check_var, .fb_setcolreg = fb_setcolreg, + .fb_pan_display = da8xx_pan_display, .fb_ioctl = fb_ioctl, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, @@ -829,40 +985,53 @@ static int __init fb_probe(struct platform_device *device) } /* allocate frame buffer */ - da8xx_fb_info->screen_base = dma_alloc_coherent(NULL, - par->databuf_sz + PAGE_SIZE, - (resource_size_t *) - &da8xx_fb_info->fix.smem_start, - GFP_KERNEL | GFP_DMA); - - if (!da8xx_fb_info->screen_base) { + par->vram_size = lcdc_info->width * lcdc_info->height * lcd_cfg->bpp; + par->vram_size = PAGE_ALIGN(par->vram_size/8); + par->vram_size = par->vram_size * LCD_NUM_BUFFERS; + + par->vram_virt = dma_alloc_coherent(NULL, + par->vram_size, + (resource_size_t *) &par->vram_phys, + GFP_KERNEL | GFP_DMA); + if (!par->vram_virt) { dev_err(&device->dev, "GLCD: kmalloc for frame buffer failed\n"); ret = -EINVAL; goto err_release_fb; } - /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */ - par->v_palette_base = da8xx_fb_info->screen_base + - (PAGE_SIZE - par->palette_sz); - par->p_palette_base = da8xx_fb_info->fix.smem_start + - (PAGE_SIZE - par->palette_sz); - - /* the rest of the frame buffer is pixel data */ - da8xx_fb_info->screen_base = par->v_palette_base + par->palette_sz; - da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz; - da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz; - da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; + da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt; + da8xx_fb_fix.smem_start = par->vram_phys; + da8xx_fb_fix.smem_len = par->vram_size; + da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; + + par->dma_start = par->vram_phys; + par->dma_end = par->dma_start + lcdc_info->height * + da8xx_fb_fix.line_length - 1; + + /* allocate palette buffer */ + par->v_palette_base = dma_alloc_coherent(NULL, + PALETTE_SIZE, + (resource_size_t *) + &par->p_palette_base, + GFP_KERNEL | GFP_DMA); + if (!par->v_palette_base) { + dev_err(&device->dev, + "GLCD: kmalloc for palette buffer failed\n"); + ret = -EINVAL; + goto err_release_fb_mem; + } + memset(par->v_palette_base, 0, PALETTE_SIZE); par->irq = platform_get_irq(device, 0); if (par->irq < 0) { ret = -ENOENT; - goto err_release_fb_mem; + goto err_release_pl_mem; } ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); if (ret) - goto err_release_fb_mem; + goto err_release_pl_mem; /* Initialize par */ da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp; @@ -870,8 +1039,8 @@ static int __init fb_probe(struct platform_device *device) da8xx_fb_var.xres = lcdc_info->width; da8xx_fb_var.xres_virtual = lcdc_info->width; - da8xx_fb_var.yres = lcdc_info->height; - da8xx_fb_var.yres_virtual = lcdc_info->height; + da8xx_fb_var.yres = lcdc_info->height; + da8xx_fb_var.yres_virtual = lcdc_info->height * LCD_NUM_BUFFERS; da8xx_fb_var.grayscale = lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0; @@ -892,18 +1061,18 @@ static int __init fb_probe(struct platform_device *device) ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); if (ret) goto err_free_irq; - - /* First palette_sz byte of the frame buffer is the palette */ da8xx_fb_info->cmap.len = par->palette_sz; - /* Flush the buffer to the screen. */ - lcd_blit(LOAD_DATA, par); - /* initialize var_screeninfo */ da8xx_fb_var.activate = FB_ACTIVATE_FORCE; fb_set_var(da8xx_fb_info, &da8xx_fb_var); dev_set_drvdata(&device->dev, da8xx_fb_info); + + /* initialize the vsync wait queue */ + init_waitqueue_head(&par->vsync_wait); + par->vsync_timeout = HZ / 5; + /* Register the Frame Buffer */ if (register_framebuffer(da8xx_fb_info) < 0) { dev_err(&device->dev, @@ -919,10 +1088,6 @@ static int __init fb_probe(struct platform_device *device) goto err_cpu_freq; } #endif - - /* enable raster engine */ - lcd_enable_raster(); - return 0; #ifdef CONFIG_CPU_FREQ @@ -936,10 +1101,12 @@ err_dealloc_cmap: err_free_irq: free_irq(par->irq, par); +err_release_pl_mem: + dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base, + par->p_palette_base); + err_release_fb_mem: - dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, - da8xx_fb_info->screen_base - PAGE_SIZE, - da8xx_fb_info->fix.smem_start); + dma_free_coherent(NULL, par->vram_size, par->vram_virt, par->vram_phys); err_release_fb: framebuffer_release(da8xx_fb_info); -- cgit v1.2.2 From 49c39b4953e545ce3b5957cce22e1ade01c6e642 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Mon, 24 May 2010 14:34:02 -0700 Subject: fbdev: move FBIO_WAITFORVSYNC to linux/fb.h FBIO_WAITFORVSYNC is currently implemented by matroxfb, atyfb, intelfb and more. All of them keep redefining the same FBIO_WAITFORVSYNC macro over and over again, so move it to linux/fb.h and clean up those duplicate defines. Signed-off-by: Grazvydas Ignotas Cc: Ville Syrjala Cc: Grant Likely Cc: Maik Broemme Cc: Petr Vandrovec Cc: Benjamin Herrenschmidt Cc: Krzysztof Helt Cc: "Hiremath, Vaibhav" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/aty/atyfb_base.c | 4 ---- drivers/video/intelfb/intelfb.h | 4 ---- 2 files changed, 8 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 29d72851f85b..f8d69ad36830 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -1820,10 +1820,6 @@ struct atyclk { #define ATYIO_FEATW 0x41545903 /* ATY\03 */ #endif -#ifndef FBIO_WAITFORVSYNC -#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) -#endif - static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg) { struct atyfb_par *par = (struct atyfb_par *) info->par; diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 40984551c927..6b51175629c7 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -371,10 +371,6 @@ struct intelfb_info { ((dinfo)->chipset == INTEL_965G) || \ ((dinfo)->chipset == INTEL_965GM)) -#ifndef FBIO_WAITFORVSYNC -#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) -#endif - /*** function prototypes ***/ extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); -- cgit v1.2.2 From e88a0f461aeadfe309d36a2a4fac9ffb1b0ed651 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Mon, 24 May 2010 14:34:04 -0700 Subject: hitfb: fix sections Since the drivers probe call was changed from .init.text to .devinit.text in commit c2e13037e6794bd0d9de3f9ecabf5615f15c160b ("platform-drivers: move probe to .devinit.text in drivers/video") the fb_fix_screeninfo and fb_var_screeninfo structures must be changed from .init.data to .devinit.data, too. Also the drivers remove routine should be moved from .exit.text to .devexit.text Signed-off-by: Henrik Kretzschmar Cc: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/hitfb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index 393f3f3d3dfe..cfb8d6451014 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -30,14 +30,14 @@ #define WIDTH 640 -static struct fb_var_screeninfo hitfb_var __initdata = { +static struct fb_var_screeninfo hitfb_var __devinitdata = { .activate = FB_ACTIVATE_NOW, .height = -1, .width = -1, .vmode = FB_VMODE_NONINTERLACED, }; -static struct fb_fix_screeninfo hitfb_fix __initdata = { +static struct fb_fix_screeninfo hitfb_fix __devinitdata = { .id = "Hitachi HD64461", .type = FB_TYPE_PACKED_PIXELS, .accel = FB_ACCEL_NONE, @@ -417,7 +417,7 @@ err_fb: return ret; } -static int __exit hitfb_remove(struct platform_device *dev) +static int __devexit hitfb_remove(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); @@ -462,7 +462,7 @@ static const struct dev_pm_ops hitfb_dev_pm_ops = { static struct platform_driver hitfb_driver = { .probe = hitfb_probe, - .remove = __exit_p(hitfb_remove), + .remove = __devexit_p(hitfb_remove), .driver = { .name = "hitfb", .owner = THIS_MODULE, -- cgit v1.2.2 From a8ce4be7d5b99a6338e695b26358abca329735c1 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Mon, 24 May 2010 14:34:05 -0700 Subject: s3c2410fb: fix sections Since the drivers probe calls were changed from .init.text to .devinit.text in commit c2e13037e6794bd0d9de3f9ecabf5615f15c160b ("platform-drivers: move probe to .devinit.text in drivers/video") all the function from .init.text should be moved to .devinit.text, too. The drivers remove calls can also be move from .text to .devexit.text. Signed-off-by: Henrik Kretzschmar Cc: Vincent Sanders Acked-by: Arnaud Patard Tested-by: Arnaud Patard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/s3c2410fb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 2b094dec4a56..46b430978bcc 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -631,7 +631,7 @@ static struct fb_ops s3c2410fb_ops = { * cache. Once this area is remapped, all virtual memory * access to the video memory should occur at the new region. */ -static int __init s3c2410fb_map_video_memory(struct fb_info *info) +static int __devinit s3c2410fb_map_video_memory(struct fb_info *info) { struct s3c2410fb_info *fbi = info->par; dma_addr_t map_dma; @@ -814,7 +814,7 @@ static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info) static char driver_name[] = "s3c2410fb"; -static int __init s3c24xxfb_probe(struct platform_device *pdev, +static int __devinit s3c24xxfb_probe(struct platform_device *pdev, enum s3c_drv_type drv_type) { struct s3c2410fb_info *info; @@ -1018,7 +1018,7 @@ static int __devinit s3c2412fb_probe(struct platform_device *pdev) /* * Cleanup */ -static int s3c2410fb_remove(struct platform_device *pdev) +static int __devexit s3c2410fb_remove(struct platform_device *pdev) { struct fb_info *fbinfo = platform_get_drvdata(pdev); struct s3c2410fb_info *info = fbinfo->par; @@ -1096,7 +1096,7 @@ static int s3c2410fb_resume(struct platform_device *dev) static struct platform_driver s3c2410fb_driver = { .probe = s3c2410fb_probe, - .remove = s3c2410fb_remove, + .remove = __devexit_p(s3c2410fb_remove), .suspend = s3c2410fb_suspend, .resume = s3c2410fb_resume, .driver = { @@ -1107,7 +1107,7 @@ static struct platform_driver s3c2410fb_driver = { static struct platform_driver s3c2412fb_driver = { .probe = s3c2412fb_probe, - .remove = s3c2410fb_remove, + .remove = __devexit_p(s3c2410fb_remove), .suspend = s3c2410fb_suspend, .resume = s3c2410fb_resume, .driver = { -- cgit v1.2.2 From 0d5b02641faade3dfd376abdcffbd8ccb03c7a91 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Mon, 24 May 2010 14:34:07 -0700 Subject: sgivwfb: fix sections Since the drivers probe call was changed from .init.text to .devinit.text in commit c2e13037e6794bd0d9de3f9ecabf5615f15c160b ("platform-drivers: move probe to .devinit.text in drivers/video") the fb_fix_screeninfo and fb_var_screeninfo structures must be changed from .init.data to .devinit.data, too. Also the drivers remove routine should be moved from .text to .devexit.text It removes these 7 section mismatch warnings from modpost: WARNING: vmlinux.o(.devinit.text+0x1e28): Section mismatch in reference from the function sgivwfb_probe() to the variable .init.data:sgivwfb_fix The function __devinit sgivwfb_probe() references a variable __initdata sgivwfb_fix. If sgivwfb_fix is only used by sgivwfb_probe then annotate sgivwfb_fix with a matching annotation. WARNING: vmlinux.o(.devinit.text+0x1e50): Section mismatch in reference from the function sgivwfb_probe() to the (unknown reference) .init.data:(unknown) The function __devinit sgivwfb_probe() references a (unknown reference) __initdata (unknown). If (unknown) is only used by sgivwfb_probe then annotate (unknown) with a matching annotation. WARNING: vmlinux.o(.devinit.text+0x1e59): Section mismatch in reference from the function sgivwfb_probe() to the (unknown reference) .init.data:(unknown) The function __devinit sgivwfb_probe() references a (unknown reference) __initdata (unknown). If (unknown) is only used by sgivwfb_probe then annotate (unknown) with a matching annotation. WARNING: vmlinux.o(.devinit.text+0x1e60): Section mismatch in reference from the function sgivwfb_probe() to the variable .init.data:sgivwfb_fix The function __devinit sgivwfb_probe() references a variable __initdata sgivwfb_fix. If sgivwfb_fix is only used by sgivwfb_probe then annotate sgivwfb_fix with a matching annotation. WARNING: vmlinux.o(.devinit.text+0x1e6a): Section mismatch in reference from the function sgivwfb_probe() to the (unknown reference) .init.data:(unknown) The function __devinit sgivwfb_probe() references a (unknown reference) __initdata (unknown). If (unknown) is only used by sgivwfb_probe then annotate (unknown) with a matching annotation. WARNING: vmlinux.o(.devinit.text+0x1e7f): Section mismatch in reference from the function sgivwfb_probe() to the variable .init.data:sgivwfb_var1600sw The function __devinit sgivwfb_probe() references a variable __initdata sgivwfb_var1600sw. If sgivwfb_var1600sw is only used by sgivwfb_probe then annotate sgivwfb_var1600sw with a matching annotation. WARNING: vmlinux.o(.devinit.text+0x1e91): Section mismatch in reference from the function sgivwfb_probe() to the variable .init.data:sgivwfb_var The function __devinit sgivwfb_probe() references a variable __initdata sgivwfb_var. If sgivwfb_var is only used by sgivwfb_probe then annotate sgivwfb_var with a matching annotation. Signed-off-by: Henrik Kretzschmar Cc: Arnaud Patard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/sgivwfb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index 7a3a5e28eca1..53455f295510 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c @@ -47,7 +47,7 @@ static int ywrap = 0; static int flatpanel_id = -1; -static struct fb_fix_screeninfo sgivwfb_fix __initdata = { +static struct fb_fix_screeninfo sgivwfb_fix __devinitdata = { .id = "SGI Vis WS FB", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, @@ -57,7 +57,7 @@ static struct fb_fix_screeninfo sgivwfb_fix __initdata = { .line_length = 640, }; -static struct fb_var_screeninfo sgivwfb_var __initdata = { +static struct fb_var_screeninfo sgivwfb_var __devinitdata = { /* 640x480, 8 bpp */ .xres = 640, .yres = 480, @@ -79,7 +79,7 @@ static struct fb_var_screeninfo sgivwfb_var __initdata = { .vmode = FB_VMODE_NONINTERLACED }; -static struct fb_var_screeninfo sgivwfb_var1600sw __initdata = { +static struct fb_var_screeninfo sgivwfb_var1600sw __devinitdata = { /* 1600x1024, 8 bpp */ .xres = 1600, .yres = 1024, @@ -825,7 +825,7 @@ fail_ioremap_regs: return -ENXIO; } -static int sgivwfb_remove(struct platform_device *dev) +static int __devexit sgivwfb_remove(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); @@ -845,7 +845,7 @@ static int sgivwfb_remove(struct platform_device *dev) static struct platform_driver sgivwfb_driver = { .probe = sgivwfb_probe, - .remove = sgivwfb_remove, + .remove = __devexit_p(sgivwfb_remove), .driver = { .name = "sgivwfb", }, -- cgit v1.2.2 From 49bbd815fd8ba26d0354900b783b767c7f47c816 Mon Sep 17 00:00:00 2001 From: Albert Herranz Date: Mon, 24 May 2010 14:34:08 -0700 Subject: fb_defio: fix for non-dirty ptes Fix a problem observed while using fb_defio with a short delay on a PowerPC platform. It is possible that page_mkclean() is invoked in the deferred io work function _before_ a PTE has been marked dirty. In this case, the page is removed from the defio pagelist but page_mkclean() does not write-protect the page again. The end result is that defio ignores all subsequent writes to the page and the corresponding portions of the framebuffer never get updated. The fix consists in keeping track of the pages with non-dirty PTEs, re-checking them again on the next deferred io work iteration. Note that those pages are not passed to the defio callback as they are not written by userspace yet. Signed-off-by: Albert Herranz Acked-by: Jaya Kumar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/fb_defio.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 6113c47e095a..1105a591dcc1 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -155,25 +155,41 @@ static void fb_deferred_io_work(struct work_struct *work) { struct fb_info *info = container_of(work, struct fb_info, deferred_work.work); - struct list_head *node, *next; - struct page *cur; struct fb_deferred_io *fbdefio = info->fbdefio; + struct page *page, *tmp_page; + struct list_head *node, *tmp_node; + struct list_head non_dirty; + + INIT_LIST_HEAD(&non_dirty); /* here we mkclean the pages, then do all deferred IO */ mutex_lock(&fbdefio->lock); - list_for_each_entry(cur, &fbdefio->pagelist, lru) { - lock_page(cur); - page_mkclean(cur); - unlock_page(cur); + list_for_each_entry_safe(page, tmp_page, &fbdefio->pagelist, lru) { + lock_page(page); + /* + * The workqueue callback can be triggered after a + * ->page_mkwrite() call but before the PTE has been marked + * dirty. In this case page_mkclean() won't "rearm" the page. + * + * To avoid this, remove those "non-dirty" pages from the + * pagelist before calling the driver's callback, then add + * them back to get processed on the next work iteration. + * At that time, their PTEs will hopefully be dirty for real. + */ + if (!page_mkclean(page)) + list_move_tail(&page->lru, &non_dirty); + unlock_page(page); } /* driver's callback with pagelist */ fbdefio->deferred_io(info, &fbdefio->pagelist); - /* clear the list */ - list_for_each_safe(node, next, &fbdefio->pagelist) { + /* clear the list... */ + list_for_each_safe(node, tmp_node, &fbdefio->pagelist) { list_del(node); } + /* ... and add back the "non-dirty" pages to the list */ + list_splice_tail(&non_dirty, &fbdefio->pagelist); mutex_unlock(&fbdefio->lock); } @@ -202,6 +218,7 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_open); void fb_deferred_io_cleanup(struct fb_info *info) { struct fb_deferred_io *fbdefio = info->fbdefio; + struct list_head *node, *tmp_node; struct page *page; int i; @@ -209,6 +226,13 @@ void fb_deferred_io_cleanup(struct fb_info *info) cancel_delayed_work(&info->deferred_work); flush_scheduled_work(); + /* the list may have still some non-dirty pages at this point */ + mutex_lock(&fbdefio->lock); + list_for_each_safe(node, tmp_node, &fbdefio->pagelist) { + list_del(node); + } + mutex_unlock(&fbdefio->lock); + /* clear out the mapping that we setup */ for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) { page = fb_deferred_io_page(info, i); -- cgit v1.2.2 From a42dcb883d948a5f26c005f0e401e8297aa05f76 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 24 May 2010 14:34:09 -0700 Subject: nuc900fb: release correct mem region We should be releasing "res->start" here. Signed-off-by: Dan Carpenter Acked-by: Wan ZongShun Cc: Wang Qiang Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/nuc900fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index 6bf0d460a738..d4cde79ea15e 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c @@ -667,7 +667,7 @@ release_irq: release_regs: iounmap(fbi->io); release_mem_region: - release_mem_region((unsigned long)fbi->mem, size); + release_mem_region(res->start, size); free_fb: framebuffer_release(fbinfo); return ret; -- cgit v1.2.2 From 3e4a326df654d748d73600068fbdbdfed0b0db43 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Mar 2010 20:51:36 -0400 Subject: backlight: backlight_device_register() return ERR_PTR() backlight_device_register() returns a valid pointer or ERR_PTR() never NULL. Signed-off-by: Dan Carpenter Signed-off-by: Andrew Morton Signed-off-by: Richard Purdie --- drivers/video/backlight/adx_bl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c index 7f4a7c30a98b..fe9af129c5dd 100644 --- a/drivers/video/backlight/adx_bl.c +++ b/drivers/video/backlight/adx_bl.c @@ -107,8 +107,8 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev) props.max_brightness = 0xff; bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, bl, &adx_backlight_ops, &props); - if (!bldev) { - ret = -ENOMEM; + if (IS_ERR(bldev)) { + ret = PTR_ERR(bldev); goto out; } -- cgit v1.2.2 From 8fdd5767ebe5806f02e1c8d9ac67ac4da8836f53 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 30 Mar 2010 13:17:35 -0500 Subject: backlight: Kconfig cleanup Cleanup the "depends on" logic by wrapping the affected config options in appropriate if/endif blocks. Remove all the "default n" since that is the default default. Signed-off-by: H Hartley Sweeten Signed-off-by: Richard Purdie --- drivers/video/backlight/Kconfig | 79 ++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 44 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index c025c84601b0..4dfb5f44dffd 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -8,12 +8,13 @@ menuconfig BACKLIGHT_LCD_SUPPORT Enable this to be able to choose the drivers for controlling the backlight and the LCD panel on some platforms, for example on PDAs. +if BACKLIGHT_LCD_SUPPORT + # # LCD # config LCD_CLASS_DEVICE tristate "Lowlevel LCD controls" - depends on BACKLIGHT_LCD_SUPPORT default m help This framework adds support for low-level control of LCD. @@ -24,31 +25,32 @@ config LCD_CLASS_DEVICE To have support for your specific LCD panel you will have to select the proper drivers which depend on this option. +if LCD_CLASS_DEVICE + config LCD_CORGI tristate "LCD Panel support for SHARP corgi/spitz model" - depends on LCD_CLASS_DEVICE && SPI_MASTER && PXA_SHARPSL + depends on SPI_MASTER && PXA_SHARPSL help Say y here to support the LCD panels usually found on SHARP corgi (C7x0) and spitz (Cxx00) models. config LCD_L4F00242T03 tristate "Epson L4F00242T03 LCD" - depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO + depends on SPI_MASTER && GENERIC_GPIO help SPI driver for Epson L4F00242T03. This provides basic support for init and powering the LCD up/down through a sysfs interface. config LCD_LMS283GF05 tristate "Samsung LMS283GF05 LCD" - depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO + depends on SPI_MASTER && GENERIC_GPIO help SPI driver for Samsung LMS283GF05. This provides basic support for powering the LCD up/down through a sysfs interface. config LCD_LTV350QV tristate "Samsung LTV350QV LCD Panel" - depends on LCD_CLASS_DEVICE && SPI_MASTER - default n + depends on SPI_MASTER help If you have a Samsung LTV350QV LCD panel, say y to include a power control driver for it. The panel starts up in power @@ -59,60 +61,53 @@ config LCD_LTV350QV config LCD_ILI9320 tristate - depends on LCD_CLASS_DEVICE && BACKLIGHT_LCD_SUPPORT - default n help If you have a panel based on the ILI9320 controller chip then say y to include a power driver for it. config LCD_TDO24M tristate "Toppoly TDO24M and TDO35S LCD Panels support" - depends on LCD_CLASS_DEVICE && SPI_MASTER - default n + depends on SPI_MASTER help If you have a Toppoly TDO24M/TDO35S series LCD panel, say y here to include the support for it. config LCD_VGG2432A4 tristate "VGG2432A4 LCM device support" - depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER + depends on SPI_MASTER select LCD_ILI9320 - default n help If you have a VGG2432A4 panel based on the ILI9320 controller chip then say y to include a power driver for it. config LCD_PLATFORM tristate "Platform LCD controls" - depends on LCD_CLASS_DEVICE help This driver provides a platform-device registered LCD power control interface. config LCD_TOSA tristate "Sharp SL-6000 LCD Driver" - depends on LCD_CLASS_DEVICE && SPI - depends on MACH_TOSA - default n + depends on SPI && MACH_TOSA help If you have an Sharp SL-6000 Zaurus say Y to enable a driver for its LCD. config LCD_HP700 tristate "HP Jornada 700 series LCD Driver" - depends on LCD_CLASS_DEVICE depends on SA1100_JORNADA720_SSP && !PREEMPT default y help If you have an HP Jornada 700 series handheld (710/720/728) say Y to enable LCD control driver. +endif # LCD_CLASS_DEVICE + # # Backlight # config BACKLIGHT_CLASS_DEVICE tristate "Lowlevel Backlight controls" - depends on BACKLIGHT_LCD_SUPPORT default m help This framework adds support for low-level control of the LCD @@ -121,9 +116,11 @@ config BACKLIGHT_CLASS_DEVICE To have support for your specific LCD panel you will have to select the proper drivers which depend on this option. +if BACKLIGHT_CLASS_DEVICE + config BACKLIGHT_ATMEL_LCDC bool "Atmel LCDC Contrast-as-Backlight control" - depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL + depends on FB_ATMEL default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK help This provides a backlight control internal to the Atmel LCDC @@ -136,8 +133,7 @@ config BACKLIGHT_ATMEL_LCDC config BACKLIGHT_ATMEL_PWM tristate "Atmel PWM backlight control" - depends on BACKLIGHT_CLASS_DEVICE && ATMEL_PWM - default n + depends on ATMEL_PWM help Say Y here if you want to use the PWM peripheral in Atmel AT91 and AVR32 devices. This driver will need additional platform data to know @@ -148,7 +144,6 @@ config BACKLIGHT_ATMEL_PWM config BACKLIGHT_GENERIC tristate "Generic (aka Sharp Corgi) Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE default y help Say y to enable the generic platform backlight driver previously @@ -157,7 +152,7 @@ config BACKLIGHT_GENERIC config BACKLIGHT_LOCOMO tristate "Sharp LOCOMO LCD/Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && SHARP_LOCOMO + depends on SHARP_LOCOMO default y help If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to @@ -165,7 +160,7 @@ config BACKLIGHT_LOCOMO config BACKLIGHT_OMAP1 tristate "OMAP1 PWL-based LCD Backlight" - depends on BACKLIGHT_CLASS_DEVICE && ARCH_OMAP1 + depends on ARCH_OMAP1 default y help This driver controls the LCD backlight level and power for @@ -174,7 +169,7 @@ config BACKLIGHT_OMAP1 config BACKLIGHT_HP680 tristate "HP Jornada 680 Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && SH_HP6XX + depends on SH_HP6XX default y help If you have a HP Jornada 680, say y to enable the @@ -182,7 +177,6 @@ config BACKLIGHT_HP680 config BACKLIGHT_HP700 tristate "HP Jornada 700 series Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE depends on SA1100_JORNADA720_SSP && !PREEMPT default y help @@ -191,76 +185,70 @@ config BACKLIGHT_HP700 config BACKLIGHT_PROGEAR tristate "Frontpath ProGear Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && PCI && X86 - default n + depends on PCI && X86 help If you have a Frontpath ProGear say Y to enable the backlight driver. config BACKLIGHT_CARILLO_RANCH tristate "Intel Carillo Ranch Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 - default n + depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 help If you have a Intel LE80578 (Carillo Ranch) say Y to enable the backlight driver. config BACKLIGHT_PWM tristate "Generic PWM based Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && HAVE_PWM + depends on HAVE_PWM help If you have a LCD backlight adjustable by PWM, say Y to enable this driver. config BACKLIGHT_DA903X tristate "Backlight Driver for DA9030/DA9034 using WLED" - depends on BACKLIGHT_CLASS_DEVICE && PMIC_DA903X + depends on PMIC_DA903X help If you have a LCD backlight connected to the WLED output of DA9030 or DA9034 WLED output, say Y here to enable this driver. config BACKLIGHT_MAX8925 tristate "Backlight driver for MAX8925" - depends on BACKLIGHT_CLASS_DEVICE && MFD_MAX8925 + depends on MFD_MAX8925 help If you have a LCD backlight connected to the WLED output of MAX8925 WLED output, say Y here to enable this driver. config BACKLIGHT_MBP_NVIDIA tristate "MacBook Pro Nvidia Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && X86 - default n + depends on X86 help If you have an Apple Macbook Pro with Nvidia graphics hardware say Y to enable a driver for its backlight config BACKLIGHT_TOSA tristate "Sharp SL-6000 Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && I2C - depends on MACH_TOSA && LCD_TOSA - default n + depends on I2C && MACH_TOSA && LCD_TOSA help If you have an Sharp SL-6000 Zaurus say Y to enable a driver for its backlight config BACKLIGHT_SAHARA tristate "Tabletkiosk Sahara Touch-iT Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && X86 - default n + depends on X86 help If you have a Tabletkiosk Sahara Touch-iT, say y to enable the backlight driver. config BACKLIGHT_WM831X tristate "WM831x PMIC Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && MFD_WM831X + depends on MFD_WM831X help If you have a backlight driven by the ISINK and DCDC of a WM831x PMIC say y to enable the backlight driver for it. config BACKLIGHT_ADX tristate "Avionic Design Xanthos Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && ARCH_PXA_ADX + depends on ARCH_PXA_ADX default y help Say Y to enable the backlight driver on Avionic Design Xanthos-based @@ -268,7 +256,7 @@ config BACKLIGHT_ADX config BACKLIGHT_ADP5520 tristate "Backlight Driver for ADP5520/ADP5501 using WLED" - depends on BACKLIGHT_CLASS_DEVICE && PMIC_ADP5520 + depends on PMIC_ADP5520 help If you have a LCD backlight connected to the BST/BL_SNK output of ADP5520 or ADP5501, say Y here to enable this driver. @@ -278,7 +266,10 @@ config BACKLIGHT_ADP5520 config BACKLIGHT_88PM860X tristate "Backlight Driver for 88PM8606 using WLED" - depends on BACKLIGHT_CLASS_DEVICE && MFD_88PM860X + depends on MFD_88PM860X help Say Y to enable the backlight driver for Marvell 88PM8606. +endif # BACKLIGHT_CLASS_DEVICE + +endif # BACKLIGHT_LCD_SUPPORT -- cgit v1.2.2 From 8193db229101fa5e7e7070422a7471775140e7bd Mon Sep 17 00:00:00 2001 From: Mario Schwalbe Date: Mon, 19 Apr 2010 17:59:26 +0100 Subject: backlight: mbp_nvidia_bl - add support for older MacBookPro and MacBook 6,1. Add support for all remaining models not yet present in Linus'/Richard Purdie's tree nor Evan McClain's patch to finally complete the list. Signed-off-by: Mario Schwalbe Signed-off-by: Andrew Morton Signed-off-by: Richard Purdie --- drivers/video/backlight/mbp_nvidia_bl.c | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 1b5d3fe6bbbc..52c780f5db1b 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c @@ -182,6 +182,42 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { }, .driver_data = (void *)&intel_chipset_data, }, + { + .callback = mbp_dmi_match, + .ident = "MacBookPro 1,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"), + }, + .driver_data = (void *)&intel_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBookPro 1,2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,2"), + }, + .driver_data = (void *)&intel_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBookPro 2,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,1"), + }, + .driver_data = (void *)&intel_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBookPro 2,2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"), + }, + .driver_data = (void *)&intel_chipset_data, + }, { .callback = mbp_dmi_match, .ident = "MacBookPro 3,1", @@ -236,6 +272,15 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { }, .driver_data = (void *)&nvidia_chipset_data, }, + { + .callback = mbp_dmi_match, + .ident = "MacBook 6,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, { .callback = mbp_dmi_match, .ident = "MacBookAir 2,1", -- cgit v1.2.2 From 9844ce0501b03843c44156d6e36afb80e847c974 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 7 May 2010 11:06:21 +0200 Subject: backlight: 88pm860x_bl - potential memory leak I added a kfree() on the error path. I don't really expect it to affect anyone, but it's easy and makes the static checkers happy. Signed-off-by: Dan Carpenter Signed-off-by: Richard Purdie --- drivers/video/backlight/88pm860x_bl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/video') diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 68d2518fadaa..78d8fde9fe8f 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -222,6 +222,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) data->port = __check_device(pdata, name); if (data->port < 0) { dev_err(&pdev->dev, "wrong platform data is assigned"); + kfree(data); return -EINVAL; } -- cgit v1.2.2 From 82fd53b7f70af9855eda613450a7e4701ffdae20 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 30 Apr 2010 14:09:51 -0700 Subject: backlight: new driver for the ADP8860 backlight parts The ADP8860 combines a programmable backlight LED charge pump driver with automatic phototransistor control. Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Andrew Morton Signed-off-by: Richard Purdie --- drivers/video/backlight/Kconfig | 12 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/adp8860_bl.c | 809 +++++++++++++++++++++++++++++++++++ 3 files changed, 822 insertions(+) create mode 100644 drivers/video/backlight/adp8860_bl.c (limited to 'drivers/video') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 4dfb5f44dffd..0f7e795f27f8 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -264,6 +264,18 @@ config BACKLIGHT_ADP5520 To compile this driver as a module, choose M here: the module will be called adp5520_bl. +config BACKLIGHT_ADP8860 + tristate "Backlight Driver for ADP8860 using WLED" + depends on BACKLIGHT_CLASS_DEVICE && I2C + select NEW_LEDS + select LEDS_CLASS + help + If you have a LCD backlight connected to the ADP8860, + say Y here to enable this driver. + + To compile this driver as a module, choose M here: the module will + be called adp8860_bl. + config BACKLIGHT_88PM860X tristate "Backlight Driver for 88PM8606 using WLED" depends on MFD_88PM860X diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 09d1f14d6257..3cbaacae8f9c 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -30,5 +30,6 @@ obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o +obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c new file mode 100644 index 000000000000..3c449d2f68b9 --- /dev/null +++ b/drivers/video/backlight/adp8860_bl.c @@ -0,0 +1,809 @@ +/* + * Backlight driver for Analog Devices ADP8860 Backlight Devices + * + * Copyright 2009-2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#define ADP8860_EXT_FEATURES +#define ADP8860_USE_LEDS + +#define ADP8860_MFDVID 0x00 /* Manufacturer and device ID */ +#define ADP8860_MDCR 0x01 /* Device mode and status */ +#define ADP8860_MDCR2 0x02 /* Device mode and Status Register 2 */ +#define ADP8860_INTR_EN 0x03 /* Interrupts enable */ +#define ADP8860_CFGR 0x04 /* Configuration register */ +#define ADP8860_BLSEN 0x05 /* Sink enable backlight or independent */ +#define ADP8860_BLOFF 0x06 /* Backlight off timeout */ +#define ADP8860_BLDIM 0x07 /* Backlight dim timeout */ +#define ADP8860_BLFR 0x08 /* Backlight fade in and out rates */ +#define ADP8860_BLMX1 0x09 /* Backlight (Brightness Level 1-daylight) maximum current */ +#define ADP8860_BLDM1 0x0A /* Backlight (Brightness Level 1-daylight) dim current */ +#define ADP8860_BLMX2 0x0B /* Backlight (Brightness Level 2-office) maximum current */ +#define ADP8860_BLDM2 0x0C /* Backlight (Brightness Level 2-office) dim current */ +#define ADP8860_BLMX3 0x0D /* Backlight (Brightness Level 3-dark) maximum current */ +#define ADP8860_BLDM3 0x0E /* Backlight (Brightness Level 3-dark) dim current */ +#define ADP8860_ISCFR 0x0F /* Independent sink current fade control register */ +#define ADP8860_ISCC 0x10 /* Independent sink current control register */ +#define ADP8860_ISCT1 0x11 /* Independent Sink Current Timer Register LED[7:5] */ +#define ADP8860_ISCT2 0x12 /* Independent Sink Current Timer Register LED[4:1] */ +#define ADP8860_ISCF 0x13 /* Independent sink current fade register */ +#define ADP8860_ISC7 0x14 /* Independent Sink Current LED7 */ +#define ADP8860_ISC6 0x15 /* Independent Sink Current LED6 */ +#define ADP8860_ISC5 0x16 /* Independent Sink Current LED5 */ +#define ADP8860_ISC4 0x17 /* Independent Sink Current LED4 */ +#define ADP8860_ISC3 0x18 /* Independent Sink Current LED3 */ +#define ADP8860_ISC2 0x19 /* Independent Sink Current LED2 */ +#define ADP8860_ISC1 0x1A /* Independent Sink Current LED1 */ +#define ADP8860_CCFG 0x1B /* Comparator configuration */ +#define ADP8860_CCFG2 0x1C /* Second comparator configuration */ +#define ADP8860_L2_TRP 0x1D /* L2 comparator reference */ +#define ADP8860_L2_HYS 0x1E /* L2 hysteresis */ +#define ADP8860_L3_TRP 0x1F /* L3 comparator reference */ +#define ADP8860_L3_HYS 0x20 /* L3 hysteresis */ +#define ADP8860_PH1LEVL 0x21 /* First phototransistor ambient light level-low byte register */ +#define ADP8860_PH1LEVH 0x22 /* First phototransistor ambient light level-high byte register */ +#define ADP8860_PH2LEVL 0x23 /* Second phototransistor ambient light level-low byte register */ +#define ADP8860_PH2LEVH 0x24 /* Second phototransistor ambient light level-high byte register */ + +#define ADP8860_MANUFID 0x0 /* Analog Devices ADP8860 Manufacturer ID */ +#define ADP8860_DEVICEID 0x7 /* Analog Devices ADP8860 Device ID */ +#define ADP8860_DEVID(x) ((x) & 0xF) +#define ADP8860_MANID(x) ((x) >> 4) + +/* MDCR Device mode and status */ +#define INT_CFG (1 << 6) +#define NSTBY (1 << 5) +#define DIM_EN (1 << 4) +#define SIS_EN (1 << 2) +#define CMP_AUTOEN (1 << 1) +#define BLEN (1 << 0) + +/* ADP8860_CCFG Main ALS comparator level enable */ +#define L3_EN (1 << 1) +#define L2_EN (1 << 0) + +#define CFGR_BLV_SHIFT 3 +#define CFGR_BLV_MASK 0x3 +#define ADP8860_FLAG_LED_MASK 0xFF + +#define FADE_VAL(in, out) ((0xF & (in)) | ((0xF & (out)) << 4)) +#define BL_CFGR_VAL(law, blv) ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1)) +#define ALS_CCFG_VAL(filt) ((0x7 & filt) << 5) + +struct adp8860_led { + struct led_classdev cdev; + struct work_struct work; + struct i2c_client *client; + enum led_brightness new_brightness; + int id; + int flags; +}; + +struct adp8860_bl { + struct i2c_client *client; + struct backlight_device *bl; + struct adp8860_led *led; + struct adp8860_backlight_platform_data *pdata; + struct mutex lock; + unsigned long cached_daylight_max; + int id; + int revid; + int current_brightness; +}; + +static int adp8860_read(struct i2c_client *client, int reg, uint8_t *val) +{ + int ret; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "failed reading at 0x%02x\n", reg); + return ret; + } + + *val = (uint8_t)ret; + return 0; +} + + +static int adp8860_write(struct i2c_client *client, u8 reg, u8 val) +{ + return i2c_smbus_write_byte_data(client, reg, val); +} + +static int adp8860_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask) +{ + struct adp8860_bl *data = i2c_get_clientdata(client); + uint8_t reg_val; + int ret; + + mutex_lock(&data->lock); + + ret = adp8860_read(client, reg, ®_val); + + if (!ret && ((reg_val & bit_mask) == 0)) { + reg_val |= bit_mask; + ret = adp8860_write(client, reg, reg_val); + } + + mutex_unlock(&data->lock); + return ret; +} + +static int adp8860_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask) +{ + struct adp8860_bl *data = i2c_get_clientdata(client); + uint8_t reg_val; + int ret; + + mutex_lock(&data->lock); + + ret = adp8860_read(client, reg, ®_val); + + if (!ret && (reg_val & bit_mask)) { + reg_val &= ~bit_mask; + ret = adp8860_write(client, reg, reg_val); + } + + mutex_unlock(&data->lock); + return ret; +} + +/* + * Independent sink / LED + */ +#if defined(ADP8860_USE_LEDS) +static void adp8860_led_work(struct work_struct *work) +{ + struct adp8860_led *led = container_of(work, struct adp8860_led, work); + adp8860_write(led->client, ADP8860_ISC1 - led->id + 1, + led->new_brightness >> 1); +} + +static void adp8860_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct adp8860_led *led; + + led = container_of(led_cdev, struct adp8860_led, cdev); + led->new_brightness = value; + schedule_work(&led->work); +} + +static int adp8860_led_setup(struct adp8860_led *led) +{ + struct i2c_client *client = led->client; + int ret = 0; + + ret = adp8860_write(client, ADP8860_ISC1 - led->id + 1, 0); + ret |= adp8860_set_bits(client, ADP8860_ISCC, 1 << (led->id - 1)); + + if (led->id > 4) + ret |= adp8860_set_bits(client, ADP8860_ISCT1, + (led->flags & 0x3) << ((led->id - 5) * 2)); + else + ret |= adp8860_set_bits(client, ADP8860_ISCT2, + (led->flags & 0x3) << ((led->id - 1) * 2)); + + return ret; +} + +static int __devinit adp8860_led_probe(struct i2c_client *client) +{ + struct adp8860_backlight_platform_data *pdata = + client->dev.platform_data; + struct adp8860_bl *data = i2c_get_clientdata(client); + struct adp8860_led *led, *led_dat; + struct led_info *cur_led; + int ret, i; + + led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL); + if (led == NULL) { + dev_err(&client->dev, "failed to alloc memory\n"); + return -ENOMEM; + } + + ret = adp8860_write(client, ADP8860_ISCFR, pdata->led_fade_law); + ret = adp8860_write(client, ADP8860_ISCT1, + (pdata->led_on_time & 0x3) << 6); + ret |= adp8860_write(client, ADP8860_ISCF, + FADE_VAL(pdata->led_fade_in, pdata->led_fade_out)); + + if (ret) { + dev_err(&client->dev, "failed to write\n"); + goto err_free; + } + + for (i = 0; i < pdata->num_leds; ++i) { + cur_led = &pdata->leds[i]; + led_dat = &led[i]; + + led_dat->id = cur_led->flags & ADP8860_FLAG_LED_MASK; + + if (led_dat->id > 7 || led_dat->id < 1) { + dev_err(&client->dev, "Invalid LED ID %d\n", + led_dat->id); + goto err; + } + + if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) { + dev_err(&client->dev, "LED %d used by Backlight\n", + led_dat->id); + goto err; + } + + led_dat->cdev.name = cur_led->name; + led_dat->cdev.default_trigger = cur_led->default_trigger; + led_dat->cdev.brightness_set = adp8860_led_set; + led_dat->cdev.brightness = LED_OFF; + led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT; + led_dat->client = client; + led_dat->new_brightness = LED_OFF; + INIT_WORK(&led_dat->work, adp8860_led_work); + + ret = led_classdev_register(&client->dev, &led_dat->cdev); + if (ret) { + dev_err(&client->dev, "failed to register LED %d\n", + led_dat->id); + goto err; + } + + ret = adp8860_led_setup(led_dat); + if (ret) { + dev_err(&client->dev, "failed to write\n"); + i++; + goto err; + } + } + + data->led = led; + + return 0; + + err: + for (i = i - 1; i >= 0; --i) { + led_classdev_unregister(&led[i].cdev); + cancel_work_sync(&led[i].work); + } + + err_free: + kfree(led); + + return ret; +} + +static int __devexit adp8860_led_remove(struct i2c_client *client) +{ + struct adp8860_backlight_platform_data *pdata = + client->dev.platform_data; + struct adp8860_bl *data = i2c_get_clientdata(client); + int i; + + for (i = 0; i < pdata->num_leds; i++) { + led_classdev_unregister(&data->led[i].cdev); + cancel_work_sync(&data->led[i].work); + } + + kfree(data->led); + return 0; +} +#else +static int __devinit adp8860_led_probe(struct i2c_client *client) +{ + return 0; +} + +static int __devexit adp8860_led_remove(struct i2c_client *client) +{ + return 0; +} +#endif + +static int adp8860_bl_set(struct backlight_device *bl, int brightness) +{ + struct adp8860_bl *data = bl_get_data(bl); + struct i2c_client *client = data->client; + int ret = 0; + + if (data->pdata->en_ambl_sens) { + if ((brightness > 0) && (brightness < ADP8860_MAX_BRIGHTNESS)) { + /* Disable Ambient Light auto adjust */ + ret |= adp8860_clr_bits(client, ADP8860_MDCR, + CMP_AUTOEN); + ret |= adp8860_write(client, ADP8860_BLMX1, brightness); + } else { + /* + * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust + * restore daylight l1 sysfs brightness + */ + ret |= adp8860_write(client, ADP8860_BLMX1, + data->cached_daylight_max); + ret |= adp8860_set_bits(client, ADP8860_MDCR, + CMP_AUTOEN); + } + } else + ret |= adp8860_write(client, ADP8860_BLMX1, brightness); + + if (data->current_brightness && brightness == 0) + ret |= adp8860_set_bits(client, + ADP8860_MDCR, DIM_EN); + else if (data->current_brightness == 0 && brightness) + ret |= adp8860_clr_bits(client, + ADP8860_MDCR, DIM_EN); + + if (!ret) + data->current_brightness = brightness; + + return ret; +} + +static int adp8860_bl_update_status(struct backlight_device *bl) +{ + int brightness = bl->props.brightness; + if (bl->props.power != FB_BLANK_UNBLANK) + brightness = 0; + + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + brightness = 0; + + return adp8860_bl_set(bl, brightness); +} + +static int adp8860_bl_get_brightness(struct backlight_device *bl) +{ + struct adp8860_bl *data = bl_get_data(bl); + + return data->current_brightness; +} + +static const struct backlight_ops adp8860_bl_ops = { + .update_status = adp8860_bl_update_status, + .get_brightness = adp8860_bl_get_brightness, +}; + +static int adp8860_bl_setup(struct backlight_device *bl) +{ + struct adp8860_bl *data = bl_get_data(bl); + struct i2c_client *client = data->client; + struct adp8860_backlight_platform_data *pdata = data->pdata; + int ret = 0; + + ret |= adp8860_write(client, ADP8860_BLSEN, ~pdata->bl_led_assign); + ret |= adp8860_write(client, ADP8860_BLMX1, pdata->l1_daylight_max); + ret |= adp8860_write(client, ADP8860_BLDM1, pdata->l1_daylight_dim); + + if (pdata->en_ambl_sens) { + data->cached_daylight_max = pdata->l1_daylight_max; + ret |= adp8860_write(client, ADP8860_BLMX2, + pdata->l2_office_max); + ret |= adp8860_write(client, ADP8860_BLDM2, + pdata->l2_office_dim); + ret |= adp8860_write(client, ADP8860_BLMX3, + pdata->l3_dark_max); + ret |= adp8860_write(client, ADP8860_BLDM3, + pdata->l3_dark_dim); + + ret |= adp8860_write(client, ADP8860_L2_TRP, pdata->l2_trip); + ret |= adp8860_write(client, ADP8860_L2_HYS, pdata->l2_hyst); + ret |= adp8860_write(client, ADP8860_L3_TRP, pdata->l3_trip); + ret |= adp8860_write(client, ADP8860_L3_HYS, pdata->l3_hyst); + ret |= adp8860_write(client, ADP8860_CCFG, L2_EN | L3_EN | + ALS_CCFG_VAL(pdata->abml_filt)); + } + + ret |= adp8860_write(client, ADP8860_CFGR, + BL_CFGR_VAL(pdata->bl_fade_law, 0)); + + ret |= adp8860_write(client, ADP8860_BLFR, FADE_VAL(pdata->bl_fade_in, + pdata->bl_fade_out)); + + ret |= adp8860_set_bits(client, ADP8860_MDCR, BLEN | DIM_EN | NSTBY); + + return ret; +} + +static ssize_t adp8860_show(struct device *dev, char *buf, int reg) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + int error; + uint8_t reg_val; + + mutex_lock(&data->lock); + error = adp8860_read(data->client, reg, ®_val); + mutex_unlock(&data->lock); + + if (error < 0) + return error; + + return sprintf(buf, "%u\n", reg_val); +} + +static ssize_t adp8860_store(struct device *dev, const char *buf, + size_t count, int reg) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&data->lock); + adp8860_write(data->client, reg, val); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t adp8860_bl_l3_dark_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLMX3); +} + +static ssize_t adp8860_bl_l3_dark_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return adp8860_store(dev, buf, count, ADP8860_BLMX3); +} + +static DEVICE_ATTR(l3_dark_max, 0664, adp8860_bl_l3_dark_max_show, + adp8860_bl_l3_dark_max_store); + +static ssize_t adp8860_bl_l2_office_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLMX2); +} + +static ssize_t adp8860_bl_l2_office_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return adp8860_store(dev, buf, count, ADP8860_BLMX2); +} +static DEVICE_ATTR(l2_office_max, 0664, adp8860_bl_l2_office_max_show, + adp8860_bl_l2_office_max_store); + +static ssize_t adp8860_bl_l1_daylight_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLMX1); +} + +static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + + strict_strtoul(buf, 10, &data->cached_daylight_max); + return adp8860_store(dev, buf, count, ADP8860_BLMX1); +} +static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show, + adp8860_bl_l1_daylight_max_store); + +static ssize_t adp8860_bl_l3_dark_dim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLDM3); +} + +static ssize_t adp8860_bl_l3_dark_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return adp8860_store(dev, buf, count, ADP8860_BLDM3); +} +static DEVICE_ATTR(l3_dark_dim, 0664, adp8860_bl_l3_dark_dim_show, + adp8860_bl_l3_dark_dim_store); + +static ssize_t adp8860_bl_l2_office_dim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLDM2); +} + +static ssize_t adp8860_bl_l2_office_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return adp8860_store(dev, buf, count, ADP8860_BLDM2); +} +static DEVICE_ATTR(l2_office_dim, 0664, adp8860_bl_l2_office_dim_show, + adp8860_bl_l2_office_dim_store); + +static ssize_t adp8860_bl_l1_daylight_dim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLDM1); +} + +static ssize_t adp8860_bl_l1_daylight_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return adp8860_store(dev, buf, count, ADP8860_BLDM1); +} +static DEVICE_ATTR(l1_daylight_dim, 0664, adp8860_bl_l1_daylight_dim_show, + adp8860_bl_l1_daylight_dim_store); + +#ifdef ADP8860_EXT_FEATURES +static ssize_t adp8860_bl_ambient_light_level_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + int error; + uint8_t reg_val; + uint16_t ret_val; + + mutex_lock(&data->lock); + error = adp8860_read(data->client, ADP8860_PH1LEVL, ®_val); + ret_val = reg_val; + error |= adp8860_read(data->client, ADP8860_PH1LEVH, ®_val); + mutex_unlock(&data->lock); + + if (error < 0) + return error; + + /* Return 13-bit conversion value for the first light sensor */ + ret_val += (reg_val & 0x1F) << 8; + + return sprintf(buf, "%u\n", ret_val); +} +static DEVICE_ATTR(ambient_light_level, 0444, + adp8860_bl_ambient_light_level_show, NULL); + +static ssize_t adp8860_bl_ambient_light_zone_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + int error; + uint8_t reg_val; + + mutex_lock(&data->lock); + error = adp8860_read(data->client, ADP8860_CFGR, ®_val); + mutex_unlock(&data->lock); + + if (error < 0) + return error; + + return sprintf(buf, "%u\n", + ((reg_val >> CFGR_BLV_SHIFT) & CFGR_BLV_MASK) + 1); +} + +static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + unsigned long val; + uint8_t reg_val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + return ret; + + if (val == 0) { + /* Enable automatic ambient light sensing */ + adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); + } else if ((val > 0) && (val < 6)) { + /* Disable automatic ambient light sensing */ + adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); + + /* Set user supplied ambient light zone */ + mutex_lock(&data->lock); + adp8860_read(data->client, ADP8860_CFGR, ®_val); + reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT); + reg_val |= val << CFGR_BLV_SHIFT; + adp8860_write(data->client, ADP8860_CFGR, reg_val); + mutex_unlock(&data->lock); + } + + return count; +} +static DEVICE_ATTR(ambient_light_zone, 0664, + adp8860_bl_ambient_light_zone_show, + adp8860_bl_ambient_light_zone_store); +#endif + +static struct attribute *adp8860_bl_attributes[] = { + &dev_attr_l3_dark_max.attr, + &dev_attr_l3_dark_dim.attr, + &dev_attr_l2_office_max.attr, + &dev_attr_l2_office_dim.attr, + &dev_attr_l1_daylight_max.attr, + &dev_attr_l1_daylight_dim.attr, +#ifdef ADP8860_EXT_FEATURES + &dev_attr_ambient_light_level.attr, + &dev_attr_ambient_light_zone.attr, +#endif + NULL +}; + +static const struct attribute_group adp8860_bl_attr_group = { + .attrs = adp8860_bl_attributes, +}; + +static int __devinit adp8860_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct backlight_device *bl; + struct adp8860_bl *data; + struct adp8860_backlight_platform_data *pdata = + client->dev.platform_data; + uint8_t reg_val; + int ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); + return -EIO; + } + + if (!pdata) { + dev_err(&client->dev, "no platform data?\n"); + return -EINVAL; + } + + ret = adp8860_read(client, ADP8860_MFDVID, ®_val); + if (ret < 0) + return -EIO; + + if (ADP8860_MANID(reg_val) != ADP8860_MANUFID) { + dev_err(&client->dev, "failed to probe\n"); + return -ENODEV; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + /* It's confirmed that the DEVID field is actually a REVID */ + + data->revid = ADP8860_DEVID(reg_val); + data->client = client; + data->pdata = pdata; + data->id = id->driver_data; + data->current_brightness = 0; + i2c_set_clientdata(client, data); + + mutex_init(&data->lock); + + bl = backlight_device_register(dev_driver_string(&client->dev), + &client->dev, data, &adp8860_bl_ops); + if (IS_ERR(bl)) { + dev_err(&client->dev, "failed to register backlight\n"); + ret = PTR_ERR(bl); + goto out2; + } + + bl->props.max_brightness = + bl->props.brightness = ADP8860_MAX_BRIGHTNESS; + + data->bl = bl; + + if (pdata->en_ambl_sens) + ret = sysfs_create_group(&bl->dev.kobj, + &adp8860_bl_attr_group); + + if (ret) { + dev_err(&client->dev, "failed to register sysfs\n"); + goto out1; + } + + ret = adp8860_bl_setup(bl); + if (ret) { + ret = -EIO; + goto out; + } + + backlight_update_status(bl); + + dev_info(&client->dev, "Rev.%d Backlight\n", data->revid); + + if (pdata->num_leds) + adp8860_led_probe(client); + + return 0; + +out: + if (data->pdata->en_ambl_sens) + sysfs_remove_group(&data->bl->dev.kobj, + &adp8860_bl_attr_group); +out1: + backlight_device_unregister(bl); +out2: + i2c_set_clientdata(client, NULL); + kfree(data); + + return ret; +} + +static int __devexit adp8860_remove(struct i2c_client *client) +{ + struct adp8860_bl *data = i2c_get_clientdata(client); + + adp8860_clr_bits(client, ADP8860_MDCR, NSTBY); + + if (data->led) + adp8860_led_remove(client); + + if (data->pdata->en_ambl_sens) + sysfs_remove_group(&data->bl->dev.kobj, + &adp8860_bl_attr_group); + + backlight_device_unregister(data->bl); + i2c_set_clientdata(client, NULL); + kfree(data); + + return 0; +} + +#ifdef CONFIG_PM +static int adp8860_i2c_suspend(struct i2c_client *client, pm_message_t message) +{ + adp8860_clr_bits(client, ADP8860_MDCR, NSTBY); + + return 0; +} + +static int adp8860_i2c_resume(struct i2c_client *client) +{ + adp8860_set_bits(client, ADP8860_MDCR, NSTBY); + + return 0; +} +#else +#define adp8860_i2c_suspend NULL +#define adp8860_i2c_resume NULL +#endif + +static const struct i2c_device_id adp8860_id[] = { + { "adp8860", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adp8860_id); + +static struct i2c_driver adp8860_driver = { + .driver = { + .name = KBUILD_MODNAME, + }, + .probe = adp8860_probe, + .remove = __devexit_p(adp8860_remove), + .suspend = adp8860_i2c_suspend, + .resume = adp8860_i2c_resume, + .id_table = adp8860_id, +}; + +static int __init adp8860_init(void) +{ + return i2c_add_driver(&adp8860_driver); +} +module_init(adp8860_init); + +static void __exit adp8860_exit(void) +{ + i2c_del_driver(&adp8860_driver); +} +module_exit(adp8860_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("ADP8860 Backlight driver"); +MODULE_ALIAS("i2c:adp8860-backlight"); -- cgit v1.2.2 From 3f43f8b2ad9035c5440d65681079f4d80542d21f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 12 May 2010 13:49:12 -0700 Subject: backlight: fix adp8860_bl build errors Add slab.h to fix part of build. Add a parameter in backlight_device_register() call to fix part of build. drivers/video/backlight/adp8860_bl.c:215: error: implicit declaration of function 'kzalloc' drivers/video/backlight/adp8860_bl.c:215: warning: assignment makes pointer from integer without a cast drivers/video/backlight/adp8860_bl.c:285: error: implicit declaration of function 'kfree' drivers/video/backlight/adp8860_bl.c:673: warning: assignment makes pointer from integer without a cast drivers/video/backlight/adp8860_bl.c:689: error: too few arguments to function 'backlight_device_register' Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Richard Purdie --- drivers/video/backlight/adp8860_bl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 3c449d2f68b9..99d14ed88571 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -647,6 +648,7 @@ static int __devinit adp8860_probe(struct i2c_client *client, struct adp8860_bl *data; struct adp8860_backlight_platform_data *pdata = client->dev.platform_data; + struct backlight_properties props; uint8_t reg_val; int ret; @@ -683,10 +685,13 @@ static int __devinit adp8860_probe(struct i2c_client *client, data->current_brightness = 0; i2c_set_clientdata(client, data); + memset(&props, 0, sizeof(props)); + props.max_brightness = ADP8860_MAX_BRIGHTNESS; + mutex_init(&data->lock); bl = backlight_device_register(dev_driver_string(&client->dev), - &client->dev, data, &adp8860_bl_ops); + &client->dev, data, &adp8860_bl_ops, &props); if (IS_ERR(bl)) { dev_err(&client->dev, "failed to register backlight\n"); ret = PTR_ERR(bl); -- cgit v1.2.2 From 47306fc35ec39a5d0715e0a79344d02dffeaeeb2 Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Mon, 26 Apr 2010 22:51:08 +0200 Subject: backlight: l4f00242t03: Fix regulators handling code in remove function Simple swap of regulator free Signed-off-by: Alberto Panizzo Signed-off-by: Richard Purdie --- drivers/video/backlight/l4f00242t03.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index bcdb12c93efd..1dafec85ddc0 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -222,9 +222,9 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi) gpio_free(pdata->reset_gpio); if (priv->io_reg) - regulator_put(priv->core_reg); - if (priv->core_reg) regulator_put(priv->io_reg); + if (priv->core_reg) + regulator_put(priv->core_reg); kfree(priv); -- cgit v1.2.2 From 08b3924b24cdb1942393dc3009335a2153bd2eac Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 May 2010 12:13:23 -0500 Subject: backlight: Add Cirrus EP93xx backlight driver The EP9307, EP9312, and EP9315 processors include a framebuffer peripheral. This peripheral has a dedicated pwm output called BRIGHT that can be used to control the backlight on an LCD. Signed-off-by: H Hartley Sweeten Signed-off-by: Richard Purdie --- drivers/video/backlight/Kconfig | 10 +++ drivers/video/backlight/Makefile | 1 + drivers/video/backlight/ep93xx_bl.c | 160 ++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 drivers/video/backlight/ep93xx_bl.c (limited to 'drivers/video') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 0f7e795f27f8..2d8052182960 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -142,6 +142,16 @@ config BACKLIGHT_ATMEL_PWM To compile this driver as a module, choose M here: the module will be called atmel-pwm-bl. +config BACKLIGHT_EP93XX + tristate "Cirrus EP93xx Backlight Driver" + depends on FB_EP93XX + help + If you have a LCD backlight connected to the BRIGHT output of + the EP93xx, say Y here to enable this driver. + + To compile this driver as a module, choose M here: the module will + be called ep93xx_bl. + config BACKLIGHT_GENERIC tristate "Generic (aka Sharp Corgi) Backlight Driver" default y diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 3cbaacae8f9c..ef610b15fdc6 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o +obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c new file mode 100644 index 000000000000..b0cc49184803 --- /dev/null +++ b/drivers/video/backlight/ep93xx_bl.c @@ -0,0 +1,160 @@ +/* + * Driver for the Cirrus EP93xx lcd backlight + * + * Copyright (c) 2010 H Hartley Sweeten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This driver controls the pulse width modulated brightness control output, + * BRIGHT, on the Cirrus EP9307, EP9312, and EP9315 processors. + */ + + +#include +#include +#include +#include + +#include + +#define EP93XX_RASTER_REG(x) (EP93XX_RASTER_BASE + (x)) +#define EP93XX_RASTER_BRIGHTNESS EP93XX_RASTER_REG(0x20) + +#define EP93XX_MAX_COUNT 255 +#define EP93XX_MAX_BRIGHT 255 +#define EP93XX_DEF_BRIGHT 128 + +struct ep93xxbl { + void __iomem *mmio; + int brightness; +}; + +static int ep93xxbl_set(struct backlight_device *bl, int brightness) +{ + struct ep93xxbl *ep93xxbl = bl_get_data(bl); + + __raw_writel((brightness << 8) | EP93XX_MAX_COUNT, ep93xxbl->mmio); + + ep93xxbl->brightness = brightness; + + return 0; +} + +static int ep93xxbl_update_status(struct backlight_device *bl) +{ + int brightness = bl->props.brightness; + + if (bl->props.power != FB_BLANK_UNBLANK || + bl->props.fb_blank != FB_BLANK_UNBLANK) + brightness = 0; + + return ep93xxbl_set(bl, brightness); +} + +static int ep93xxbl_get_brightness(struct backlight_device *bl) +{ + struct ep93xxbl *ep93xxbl = bl_get_data(bl); + + return ep93xxbl->brightness; +} + +static const struct backlight_ops ep93xxbl_ops = { + .update_status = ep93xxbl_update_status, + .get_brightness = ep93xxbl_get_brightness, +}; + +static int __init ep93xxbl_probe(struct platform_device *dev) +{ + struct ep93xxbl *ep93xxbl; + struct backlight_device *bl; + struct backlight_properties props; + + ep93xxbl = devm_kzalloc(&dev->dev, sizeof(*ep93xxbl), GFP_KERNEL); + if (!ep93xxbl) + return -ENOMEM; + + /* + * This register is located in the range already ioremap'ed by + * the framebuffer driver. A MFD driver seems a bit of overkill + * to handle this so use the static I/O mapping; this address + * is already virtual. + * + * NOTE: No locking is required; the framebuffer does not touch + * this register. + */ + ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = EP93XX_MAX_BRIGHT; + bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl, + &ep93xxbl_ops, &props); + if (IS_ERR(bl)) + return PTR_ERR(bl); + + bl->props.brightness = EP93XX_DEF_BRIGHT; + + platform_set_drvdata(dev, bl); + + ep93xxbl_update_status(bl); + + return 0; +} + +static int ep93xxbl_remove(struct platform_device *dev) +{ + struct backlight_device *bl = platform_get_drvdata(dev); + + backlight_device_unregister(bl); + platform_set_drvdata(dev, NULL); + return 0; +} + +#ifdef CONFIG_PM +static int ep93xxbl_suspend(struct platform_device *dev, pm_message_t state) +{ + struct backlight_device *bl = platform_get_drvdata(dev); + + return ep93xxbl_set(bl, 0); +} + +static int ep93xxbl_resume(struct platform_device *dev) +{ + struct backlight_device *bl = platform_get_drvdata(dev); + + backlight_update_status(bl); + return 0; +} +#else +#define ep93xxbl_suspend NULL +#define ep93xxbl_resume NULL +#endif + +static struct platform_driver ep93xxbl_driver = { + .driver = { + .name = "ep93xx-bl", + .owner = THIS_MODULE, + }, + .probe = ep93xxbl_probe, + .remove = __devexit_p(ep93xxbl_remove), + .suspend = ep93xxbl_suspend, + .resume = ep93xxbl_resume, +}; + +static int __init ep93xxbl_init(void) +{ + return platform_driver_register(&ep93xxbl_driver); +} +module_init(ep93xxbl_init); + +static void __exit ep93xxbl_exit(void) +{ + platform_driver_unregister(&ep93xxbl_driver); +} +module_exit(ep93xxbl_exit); + +MODULE_DESCRIPTION("EP93xx Backlight Driver"); +MODULE_AUTHOR("H Hartley Sweeten "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ep93xx-bl"); -- cgit v1.2.2 From ed601fa46777cb529bda0dbec80c4aec704dd063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffen=20R=C3=B6cker?= Date: Tue, 23 Mar 2010 23:12:33 +0100 Subject: backlight: mbp_nvidia_bl - Fix DMI_SYS_VENDOR for MacBook1,1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix DMI_SYS_VENDOR for MacBook1,1. When the MacBook1,1 came out Apple was still named Apple Computer, I am not sure if this applies to older MacBook2,1 versions aswell. Signed-off-by: Steffen Röcker Signed-off-by: Richard Purdie --- drivers/video/backlight/mbp_nvidia_bl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 52c780f5db1b..9fb533f6373e 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c @@ -141,7 +141,7 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { .callback = mbp_dmi_match, .ident = "MacBook 1,1", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), }, .driver_data = (void *)&intel_chipset_data, -- cgit v1.2.2 From c7c06d8a95fd6b83d9f71a0cfecd3f91945d17e5 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 26 May 2010 03:00:59 -0400 Subject: backlight: adp8860: add support for ADP8861 & ADP8863 Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Richard Purdie --- drivers/video/backlight/Kconfig | 6 ++-- drivers/video/backlight/adp8860_bl.c | 58 +++++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 20 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 2d8052182960..39ecaf71c1f9 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -275,13 +275,13 @@ config BACKLIGHT_ADP5520 be called adp5520_bl. config BACKLIGHT_ADP8860 - tristate "Backlight Driver for ADP8860 using WLED" + tristate "Backlight Driver for ADP8860/ADP8861/ADP8863 using WLED" depends on BACKLIGHT_CLASS_DEVICE && I2C select NEW_LEDS select LEDS_CLASS help - If you have a LCD backlight connected to the ADP8860, - say Y here to enable this driver. + If you have a LCD backlight connected to the ADP8860, ADP8861 or + ADP8863 say Y here to enable this driver. To compile this driver as a module, choose M here: the module will be called adp8860_bl. diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 99d14ed88571..921ca37398f3 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -62,7 +62,9 @@ #define ADP8860_PH2LEVH 0x24 /* Second phototransistor ambient light level-high byte register */ #define ADP8860_MANUFID 0x0 /* Analog Devices ADP8860 Manufacturer ID */ -#define ADP8860_DEVICEID 0x7 /* Analog Devices ADP8860 Device ID */ +#define ADP8861_MANUFID 0x4 /* Analog Devices ADP8861 Manufacturer ID */ +#define ADP8863_MANUFID 0x2 /* Analog Devices ADP8863 Manufacturer ID */ + #define ADP8860_DEVID(x) ((x) & 0xF) #define ADP8860_MANID(x) ((x) >> 4) @@ -70,6 +72,7 @@ #define INT_CFG (1 << 6) #define NSTBY (1 << 5) #define DIM_EN (1 << 4) +#define GDWN_DIS (1 << 3) #define SIS_EN (1 << 2) #define CMP_AUTOEN (1 << 1) #define BLEN (1 << 0) @@ -86,6 +89,12 @@ #define BL_CFGR_VAL(law, blv) ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1)) #define ALS_CCFG_VAL(filt) ((0x7 & filt) << 5) +enum { + adp8860, + adp8861, + adp8863 +}; + struct adp8860_led { struct led_classdev cdev; struct work_struct work; @@ -105,6 +114,8 @@ struct adp8860_bl { int id; int revid; int current_brightness; + unsigned en_ambl_sens:1; + unsigned gdwn_dis:1; }; static int adp8860_read(struct i2c_client *client, int reg, uint8_t *val) @@ -121,7 +132,6 @@ static int adp8860_read(struct i2c_client *client, int reg, uint8_t *val) return 0; } - static int adp8860_write(struct i2c_client *client, u8 reg, u8 val) { return i2c_smbus_write_byte_data(client, reg, val); @@ -321,7 +331,7 @@ static int adp8860_bl_set(struct backlight_device *bl, int brightness) struct i2c_client *client = data->client; int ret = 0; - if (data->pdata->en_ambl_sens) { + if (data->en_ambl_sens) { if ((brightness > 0) && (brightness < ADP8860_MAX_BRIGHTNESS)) { /* Disable Ambient Light auto adjust */ ret |= adp8860_clr_bits(client, ADP8860_MDCR, @@ -388,7 +398,7 @@ static int adp8860_bl_setup(struct backlight_device *bl) ret |= adp8860_write(client, ADP8860_BLMX1, pdata->l1_daylight_max); ret |= adp8860_write(client, ADP8860_BLDM1, pdata->l1_daylight_dim); - if (pdata->en_ambl_sens) { + if (data->en_ambl_sens) { data->cached_daylight_max = pdata->l1_daylight_max; ret |= adp8860_write(client, ADP8860_BLMX2, pdata->l2_office_max); @@ -413,7 +423,8 @@ static int adp8860_bl_setup(struct backlight_device *bl) ret |= adp8860_write(client, ADP8860_BLFR, FADE_VAL(pdata->bl_fade_in, pdata->bl_fade_out)); - ret |= adp8860_set_bits(client, ADP8860_MDCR, BLEN | DIM_EN | NSTBY); + ret |= adp8860_set_bits(client, ADP8860_MDCR, BLEN | DIM_EN | NSTBY | + (data->gdwn_dis ? GDWN_DIS : 0)); return ret; } @@ -663,19 +674,29 @@ static int __devinit adp8860_probe(struct i2c_client *client, return -EINVAL; } + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + ret = adp8860_read(client, ADP8860_MFDVID, ®_val); if (ret < 0) - return -EIO; + goto out2; - if (ADP8860_MANID(reg_val) != ADP8860_MANUFID) { + switch (ADP8860_MANID(reg_val)) { + case ADP8863_MANUFID: + data->gdwn_dis = !!pdata->gdwn_dis; + case ADP8860_MANUFID: + data->en_ambl_sens = !!pdata->en_ambl_sens; + break; + case ADP8861_MANUFID: + data->gdwn_dis = !!pdata->gdwn_dis; + break; + default: dev_err(&client->dev, "failed to probe\n"); - return -ENODEV; + ret = -ENODEV; + goto out2; } - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - /* It's confirmed that the DEVID field is actually a REVID */ data->revid = ADP8860_DEVID(reg_val); @@ -703,7 +724,7 @@ static int __devinit adp8860_probe(struct i2c_client *client, data->bl = bl; - if (pdata->en_ambl_sens) + if (data->en_ambl_sens) ret = sysfs_create_group(&bl->dev.kobj, &adp8860_bl_attr_group); @@ -720,7 +741,8 @@ static int __devinit adp8860_probe(struct i2c_client *client, backlight_update_status(bl); - dev_info(&client->dev, "Rev.%d Backlight\n", data->revid); + dev_info(&client->dev, "%s Rev.%d Backlight\n", + client->name, data->revid); if (pdata->num_leds) adp8860_led_probe(client); @@ -728,7 +750,7 @@ static int __devinit adp8860_probe(struct i2c_client *client, return 0; out: - if (data->pdata->en_ambl_sens) + if (data->en_ambl_sens) sysfs_remove_group(&data->bl->dev.kobj, &adp8860_bl_attr_group); out1: @@ -749,7 +771,7 @@ static int __devexit adp8860_remove(struct i2c_client *client) if (data->led) adp8860_led_remove(client); - if (data->pdata->en_ambl_sens) + if (data->en_ambl_sens) sysfs_remove_group(&data->bl->dev.kobj, &adp8860_bl_attr_group); @@ -780,7 +802,9 @@ static int adp8860_i2c_resume(struct i2c_client *client) #endif static const struct i2c_device_id adp8860_id[] = { - { "adp8860", 0 }, + { "adp8860", adp8860 }, + { "adp8861", adp8861 }, + { "adp8863", adp8863 }, { } }; MODULE_DEVICE_TABLE(i2c, adp8860_id); -- cgit v1.2.2 From ee378a5c6550dcbfe6fa9c71b84ca2eb19cb288e Mon Sep 17 00:00:00 2001 From: InKi Dae Date: Mon, 24 May 2010 12:21:36 -0700 Subject: backlight: add S6E63M0 AMOLED LCD Panel driver This is S6E63M0 AMOLED LCD Panel(480x800) driver using 3-wired SPI interface also almost features for lcd panel driver has been implemented in here. and I added new structure common for all the lcd panel drivers to include/linux/lcd.h file. LCD Panel driver needs interfaces for controlling device power such as power on/off and reset. these interfaces are device specific so it should be implemented to machine code at this time, we should create new structure for registering these functions as callbacks and also a header file for that structure and finally registered callback functions would be called by lcd panel driver. such header file(including new structure for lcd panel) would be added for all the lcd panel drivers. If anyone provides common structure for registering such callback functions then we could reduce unnecessary header files for lcd panel. I thought that suitable anyone could be include/linux/lcd.h so a new lcd_platform_data structure was added there. [akpm@linux-foundation.org: coding-style fixes] [randy.dunlap@oracle.com: fix s6e63m0 kconfig] [randy.dunlap@oracle.com: fix device attribute functions return types] Signed-off-by: InKi Dae Reviewed-by: KyungMin Park Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Richard Purdie --- drivers/video/backlight/Kconfig | 8 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/s6e63m0.c | 920 ++++++++++++++++++++++++++++++++ drivers/video/backlight/s6e63m0_gamma.h | 266 +++++++++ 4 files changed, 1195 insertions(+) create mode 100644 drivers/video/backlight/s6e63m0.c create mode 100644 drivers/video/backlight/s6e63m0_gamma.h (limited to 'drivers/video') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 39ecaf71c1f9..cbd80978460e 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -101,6 +101,14 @@ config LCD_HP700 If you have an HP Jornada 700 series handheld (710/720/728) say Y to enable LCD control driver. +config LCD_S6E63M0 + tristate "S6E63M0 AMOLED LCD Driver" + depends on SPI && BACKLIGHT_CLASS_DEVICE + default n + help + If you have an S6E63M0 LCD Panel, say Y to enable its + LCD control driver. + endif # LCD_CLASS_DEVICE # diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index ef610b15fdc6..f8978c0a2319 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o obj-$(CONFIG_LCD_TDO24M) += tdo24m.o obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o +obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c new file mode 100644 index 000000000000..a3128c9cb7ad --- /dev/null +++ b/drivers/video/backlight/s6e63m0.c @@ -0,0 +1,920 @@ +/* + * S6E63M0 AMOLED LCD panel driver. + * + * Author: InKi Dae + * + * Derived from drivers/video/omap/lcd-apollon.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "s6e63m0_gamma.h" + +#define SLEEPMSEC 0x1000 +#define ENDDEF 0x2000 +#define DEFMASK 0xFF00 +#define COMMAND_ONLY 0xFE +#define DATA_ONLY 0xFF + +#define MIN_BRIGHTNESS 0 +#define MAX_BRIGHTNESS 10 + +#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) + +struct s6e63m0 { + struct device *dev; + struct spi_device *spi; + unsigned int power; + unsigned int current_brightness; + unsigned int gamma_mode; + unsigned int gamma_table_count; + struct lcd_device *ld; + struct backlight_device *bd; + struct lcd_platform_data *lcd_pd; +}; + +static const unsigned short SEQ_PANEL_CONDITION_SET[] = { + 0xF8, 0x01, + DATA_ONLY, 0x27, + DATA_ONLY, 0x27, + DATA_ONLY, 0x07, + DATA_ONLY, 0x07, + DATA_ONLY, 0x54, + DATA_ONLY, 0x9f, + DATA_ONLY, 0x63, + DATA_ONLY, 0x86, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x33, + DATA_ONLY, 0x0d, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = { + 0xf2, 0x02, + DATA_ONLY, 0x03, + DATA_ONLY, 0x1c, + DATA_ONLY, 0x10, + DATA_ONLY, 0x10, + + 0xf7, 0x03, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_GAMMA_SETTING[] = { + 0xfa, 0x00, + DATA_ONLY, 0x18, + DATA_ONLY, 0x08, + DATA_ONLY, 0x24, + DATA_ONLY, 0x64, + DATA_ONLY, 0x56, + DATA_ONLY, 0x33, + DATA_ONLY, 0xb6, + DATA_ONLY, 0xba, + DATA_ONLY, 0xa8, + DATA_ONLY, 0xac, + DATA_ONLY, 0xb1, + DATA_ONLY, 0x9d, + DATA_ONLY, 0xc1, + DATA_ONLY, 0xc1, + DATA_ONLY, 0xb7, + DATA_ONLY, 0x00, + DATA_ONLY, 0x9c, + DATA_ONLY, 0x00, + DATA_ONLY, 0x9f, + DATA_ONLY, 0x00, + DATA_ONLY, 0xd6, + + 0xfa, 0x01, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_ETC_CONDITION_SET[] = { + 0xf6, 0x00, + DATA_ONLY, 0x8c, + DATA_ONLY, 0x07, + + 0xb3, 0xc, + + 0xb5, 0x2c, + DATA_ONLY, 0x12, + DATA_ONLY, 0x0c, + DATA_ONLY, 0x0a, + DATA_ONLY, 0x10, + DATA_ONLY, 0x0e, + DATA_ONLY, 0x17, + DATA_ONLY, 0x13, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x2a, + DATA_ONLY, 0x24, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1b, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x17, + + DATA_ONLY, 0x2b, + DATA_ONLY, 0x26, + DATA_ONLY, 0x22, + DATA_ONLY, 0x20, + DATA_ONLY, 0x3a, + DATA_ONLY, 0x34, + DATA_ONLY, 0x30, + DATA_ONLY, 0x2c, + DATA_ONLY, 0x29, + DATA_ONLY, 0x26, + DATA_ONLY, 0x25, + DATA_ONLY, 0x23, + DATA_ONLY, 0x21, + DATA_ONLY, 0x20, + DATA_ONLY, 0x1e, + DATA_ONLY, 0x1e, + + 0xb6, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x11, + DATA_ONLY, 0x22, + DATA_ONLY, 0x33, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + + DATA_ONLY, 0x55, + DATA_ONLY, 0x55, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + + 0xb7, 0x2c, + DATA_ONLY, 0x12, + DATA_ONLY, 0x0c, + DATA_ONLY, 0x0a, + DATA_ONLY, 0x10, + DATA_ONLY, 0x0e, + DATA_ONLY, 0x17, + DATA_ONLY, 0x13, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x2a, + DATA_ONLY, 0x24, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1b, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x17, + + DATA_ONLY, 0x2b, + DATA_ONLY, 0x26, + DATA_ONLY, 0x22, + DATA_ONLY, 0x20, + DATA_ONLY, 0x3a, + DATA_ONLY, 0x34, + DATA_ONLY, 0x30, + DATA_ONLY, 0x2c, + DATA_ONLY, 0x29, + DATA_ONLY, 0x26, + DATA_ONLY, 0x25, + DATA_ONLY, 0x23, + DATA_ONLY, 0x21, + DATA_ONLY, 0x20, + DATA_ONLY, 0x1e, + DATA_ONLY, 0x1e, + + 0xb8, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x11, + DATA_ONLY, 0x22, + DATA_ONLY, 0x33, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + + DATA_ONLY, 0x55, + DATA_ONLY, 0x55, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + + 0xb9, 0x2c, + DATA_ONLY, 0x12, + DATA_ONLY, 0x0c, + DATA_ONLY, 0x0a, + DATA_ONLY, 0x10, + DATA_ONLY, 0x0e, + DATA_ONLY, 0x17, + DATA_ONLY, 0x13, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x2a, + DATA_ONLY, 0x24, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1b, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x17, + + DATA_ONLY, 0x2b, + DATA_ONLY, 0x26, + DATA_ONLY, 0x22, + DATA_ONLY, 0x20, + DATA_ONLY, 0x3a, + DATA_ONLY, 0x34, + DATA_ONLY, 0x30, + DATA_ONLY, 0x2c, + DATA_ONLY, 0x29, + DATA_ONLY, 0x26, + DATA_ONLY, 0x25, + DATA_ONLY, 0x23, + DATA_ONLY, 0x21, + DATA_ONLY, 0x20, + DATA_ONLY, 0x1e, + DATA_ONLY, 0x1e, + + 0xba, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x11, + DATA_ONLY, 0x22, + DATA_ONLY, 0x33, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + + DATA_ONLY, 0x55, + DATA_ONLY, 0x55, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + + 0xc1, 0x4d, + DATA_ONLY, 0x96, + DATA_ONLY, 0x1d, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x01, + DATA_ONLY, 0xdf, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + DATA_ONLY, 0x06, + DATA_ONLY, 0x09, + DATA_ONLY, 0x0d, + DATA_ONLY, 0x0f, + DATA_ONLY, 0x12, + DATA_ONLY, 0x15, + DATA_ONLY, 0x18, + + 0xb2, 0x10, + DATA_ONLY, 0x10, + DATA_ONLY, 0x0b, + DATA_ONLY, 0x05, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_ACL_ON[] = { + /* ACL on */ + 0xc0, 0x01, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_ACL_OFF[] = { + /* ACL off */ + 0xc0, 0x00, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_ELVSS_ON[] = { + /* ELVSS on */ + 0xb1, 0x0b, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_ELVSS_OFF[] = { + /* ELVSS off */ + 0xb1, 0x0a, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_STAND_BY_OFF[] = { + 0x11, COMMAND_ONLY, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_STAND_BY_ON[] = { + 0x10, COMMAND_ONLY, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_DISPLAY_ON[] = { + 0x29, COMMAND_ONLY, + + ENDDEF, 0x0000 +}; + + +static int s6e63m0_spi_write_byte(struct s6e63m0 *lcd, int addr, int data) +{ + u16 buf[1]; + struct spi_message msg; + + struct spi_transfer xfer = { + .len = 2, + .tx_buf = buf, + }; + + buf[0] = (addr << 8) | data; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + return spi_sync(lcd->spi, &msg); +} + +static int s6e63m0_spi_write(struct s6e63m0 *lcd, unsigned char address, + unsigned char command) +{ + int ret = 0; + + if (address != DATA_ONLY) + ret = s6e63m0_spi_write_byte(lcd, 0x0, address); + if (command != COMMAND_ONLY) + ret = s6e63m0_spi_write_byte(lcd, 0x1, command); + + return ret; +} + +static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd, + const unsigned short *wbuf) +{ + int ret = 0, i = 0; + + while ((wbuf[i] & DEFMASK) != ENDDEF) { + if ((wbuf[i] & DEFMASK) != SLEEPMSEC) { + ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]); + if (ret) + break; + } else + udelay(wbuf[i+1]*1000); + i += 2; + } + + return ret; +} + +static int _s6e63m0_gamma_ctl(struct s6e63m0 *lcd, const unsigned int *gamma) +{ + unsigned int i = 0; + int ret = 0; + + /* disable gamma table updating. */ + ret = s6e63m0_spi_write(lcd, 0xfa, 0x00); + if (ret) { + dev_err(lcd->dev, "failed to disable gamma table updating.\n"); + goto gamma_err; + } + + for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) { + ret = s6e63m0_spi_write(lcd, DATA_ONLY, gamma[i]); + if (ret) { + dev_err(lcd->dev, "failed to set gamma table.\n"); + goto gamma_err; + } + } + + /* update gamma table. */ + ret = s6e63m0_spi_write(lcd, 0xfa, 0x01); + if (ret) + dev_err(lcd->dev, "failed to update gamma table.\n"); + +gamma_err: + return ret; +} + +static int s6e63m0_gamma_ctl(struct s6e63m0 *lcd, int gamma) +{ + int ret = 0; + + ret = _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); + + return ret; +} + + +static int s6e63m0_ldi_init(struct s6e63m0 *lcd) +{ + int ret, i; + const unsigned short *init_seq[] = { + SEQ_PANEL_CONDITION_SET, + SEQ_DISPLAY_CONDITION_SET, + SEQ_GAMMA_SETTING, + SEQ_ETC_CONDITION_SET, + SEQ_ACL_ON, + SEQ_ELVSS_ON, + }; + + for (i = 0; i < ARRAY_SIZE(init_seq); i++) { + ret = s6e63m0_panel_send_sequence(lcd, init_seq[i]); + if (ret) + break; + } + + return ret; +} + +static int s6e63m0_ldi_enable(struct s6e63m0 *lcd) +{ + int ret = 0, i; + const unsigned short *enable_seq[] = { + SEQ_STAND_BY_OFF, + SEQ_DISPLAY_ON, + }; + + for (i = 0; i < ARRAY_SIZE(enable_seq); i++) { + ret = s6e63m0_panel_send_sequence(lcd, enable_seq[i]); + if (ret) + break; + } + + return ret; +} + +static int s6e63m0_ldi_disable(struct s6e63m0 *lcd) +{ + int ret; + + ret = s6e63m0_panel_send_sequence(lcd, SEQ_STAND_BY_ON); + + return ret; +} + +static int s6e63m0_power_on(struct s6e63m0 *lcd) +{ + int ret = 0; + struct lcd_platform_data *pd = NULL; + struct backlight_device *bd = NULL; + + pd = lcd->lcd_pd; + if (!pd) { + dev_err(lcd->dev, "platform data is NULL.\n"); + return -EFAULT; + } + + bd = lcd->bd; + if (!bd) { + dev_err(lcd->dev, "backlight device is NULL.\n"); + return -EFAULT; + } + + if (!pd->power_on) { + dev_err(lcd->dev, "power_on is NULL.\n"); + return -EFAULT; + } else { + pd->power_on(lcd->ld, 1); + mdelay(pd->power_on_delay); + } + + if (!pd->reset) { + dev_err(lcd->dev, "reset is NULL.\n"); + return -EFAULT; + } else { + pd->reset(lcd->ld); + mdelay(pd->reset_delay); + } + + ret = s6e63m0_ldi_init(lcd); + if (ret) { + dev_err(lcd->dev, "failed to initialize ldi.\n"); + return ret; + } + + ret = s6e63m0_ldi_enable(lcd); + if (ret) { + dev_err(lcd->dev, "failed to enable ldi.\n"); + return ret; + } + + /* set brightness to current value after power on or resume. */ + ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness); + if (ret) { + dev_err(lcd->dev, "lcd gamma setting failed.\n"); + return ret; + } + + return 0; +} + +static int s6e63m0_power_off(struct s6e63m0 *lcd) +{ + int ret = 0; + struct lcd_platform_data *pd = NULL; + + pd = lcd->lcd_pd; + if (!pd) { + dev_err(lcd->dev, "platform data is NULL.\n"); + return -EFAULT; + } + + ret = s6e63m0_ldi_disable(lcd); + if (ret) { + dev_err(lcd->dev, "lcd setting failed.\n"); + return -EIO; + } + + mdelay(pd->power_off_delay); + + if (!pd->power_on) { + dev_err(lcd->dev, "power_on is NULL.\n"); + return -EFAULT; + } else + pd->power_on(lcd->ld, 0); + + return 0; +} + +static int s6e63m0_power(struct s6e63m0 *lcd, int power) +{ + int ret = 0; + + if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) + ret = s6e63m0_power_on(lcd); + else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) + ret = s6e63m0_power_off(lcd); + + if (!ret) + lcd->power = power; + + return ret; +} + +static int s6e63m0_set_power(struct lcd_device *ld, int power) +{ + struct s6e63m0 *lcd = lcd_get_data(ld); + + if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && + power != FB_BLANK_NORMAL) { + dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); + return -EINVAL; + } + + return s6e63m0_power(lcd, power); +} + +static int s6e63m0_get_power(struct lcd_device *ld) +{ + struct s6e63m0 *lcd = lcd_get_data(ld); + + return lcd->power; +} + +static int s6e63m0_get_brightness(struct backlight_device *bd) +{ + return bd->props.brightness; +} + +static int s6e63m0_set_brightness(struct backlight_device *bd) +{ + int ret = 0, brightness = bd->props.brightness; + struct s6e63m0 *lcd = bl_get_data(bd); + + if (brightness < MIN_BRIGHTNESS || + brightness > bd->props.max_brightness) { + dev_err(&bd->dev, "lcd brightness should be %d to %d.\n", + MIN_BRIGHTNESS, MAX_BRIGHTNESS); + return -EINVAL; + } + + ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness); + if (ret) { + dev_err(&bd->dev, "lcd brightness setting failed.\n"); + return -EIO; + } + + return ret; +} + +static struct lcd_ops s6e63m0_lcd_ops = { + .set_power = s6e63m0_set_power, + .get_power = s6e63m0_get_power, +}; + +static const struct backlight_ops s6e63m0_backlight_ops = { + .get_brightness = s6e63m0_get_brightness, + .update_status = s6e63m0_set_brightness, +}; + +static ssize_t s6e63m0_sysfs_show_gamma_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct s6e63m0 *lcd = dev_get_drvdata(dev); + char temp[10]; + + switch (lcd->gamma_mode) { + case 0: + sprintf(temp, "2.2 mode\n"); + strcat(buf, temp); + break; + case 1: + sprintf(temp, "1.9 mode\n"); + strcat(buf, temp); + break; + case 2: + sprintf(temp, "1.7 mode\n"); + strcat(buf, temp); + break; + default: + dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7)n"); + break; + } + + return strlen(buf); +} + +static ssize_t s6e63m0_sysfs_store_gamma_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct s6e63m0 *lcd = dev_get_drvdata(dev); + struct backlight_device *bd = NULL; + int brightness, rc; + + rc = strict_strtoul(buf, 0, (unsigned long *)&lcd->gamma_mode); + if (rc < 0) + return rc; + + bd = lcd->bd; + + brightness = bd->props.brightness; + + switch (lcd->gamma_mode) { + case 0: + _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]); + break; + case 1: + _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_19_table[brightness]); + break; + case 2: + _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_17_table[brightness]); + break; + default: + dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7\n"); + _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]); + break; + } + return len; +} + +static DEVICE_ATTR(gamma_mode, 0644, + s6e63m0_sysfs_show_gamma_mode, s6e63m0_sysfs_store_gamma_mode); + +static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct s6e63m0 *lcd = dev_get_drvdata(dev); + char temp[3]; + + sprintf(temp, "%d\n", lcd->gamma_table_count); + strcpy(buf, temp); + + return strlen(buf); +} +static DEVICE_ATTR(gamma_table, 0644, + s6e63m0_sysfs_show_gamma_table, NULL); + +static int __init s6e63m0_probe(struct spi_device *spi) +{ + int ret = 0; + struct s6e63m0 *lcd = NULL; + struct lcd_device *ld = NULL; + struct backlight_device *bd = NULL; + + lcd = kzalloc(sizeof(struct s6e63m0), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + /* s6e63m0 lcd panel uses 3-wire 9bits SPI Mode. */ + spi->bits_per_word = 9; + + ret = spi_setup(spi); + if (ret < 0) { + dev_err(&spi->dev, "spi setup failed.\n"); + goto out_free_lcd; + } + + lcd->spi = spi; + lcd->dev = &spi->dev; + + lcd->lcd_pd = (struct lcd_platform_data *)spi->dev.platform_data; + if (!lcd->lcd_pd) { + dev_err(&spi->dev, "platform data is NULL.\n"); + goto out_free_lcd; + } + + ld = lcd_device_register("s6e63m0", &spi->dev, lcd, &s6e63m0_lcd_ops); + if (IS_ERR(ld)) { + ret = PTR_ERR(ld); + goto out_free_lcd; + } + + lcd->ld = ld; + + bd = backlight_device_register("s6e63m0bl-bl", &spi->dev, lcd, + &s6e63m0_backlight_ops, NULL); + if (IS_ERR(bd)) { + ret = PTR_ERR(bd); + goto out_lcd_unregister; + } + + bd->props.max_brightness = MAX_BRIGHTNESS; + bd->props.brightness = MAX_BRIGHTNESS; + lcd->bd = bd; + + /* + * it gets gamma table count available so it gets user + * know that. + */ + lcd->gamma_table_count = + sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int)); + + ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode); + if (ret < 0) + dev_err(&(spi->dev), "failed to add sysfs entries\n"); + + ret = device_create_file(&(spi->dev), &dev_attr_gamma_table); + if (ret < 0) + dev_err(&(spi->dev), "failed to add sysfs entries\n"); + + /* + * if lcd panel was on from bootloader like u-boot then + * do not lcd on. + */ + if (!lcd->lcd_pd->lcd_enabled) { + /* + * if lcd panel was off from bootloader then + * current lcd status is powerdown and then + * it enables lcd panel. + */ + lcd->power = FB_BLANK_POWERDOWN; + + s6e63m0_power(lcd, FB_BLANK_UNBLANK); + } else + lcd->power = FB_BLANK_UNBLANK; + + dev_set_drvdata(&spi->dev, lcd); + + dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n"); + + return 0; + +out_lcd_unregister: + lcd_device_unregister(ld); +out_free_lcd: + kfree(lcd); + return ret; +} + +static int __devexit s6e63m0_remove(struct spi_device *spi) +{ + struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); + + s6e63m0_power(lcd, FB_BLANK_POWERDOWN); + lcd_device_unregister(lcd->ld); + kfree(lcd); + + return 0; +} + +#if defined(CONFIG_PM) +unsigned int before_power; + +static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg) +{ + int ret = 0; + struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); + + dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); + + before_power = lcd->power; + + /* + * when lcd panel is suspend, lcd panel becomes off + * regardless of status. + */ + ret = s6e63m0_power(lcd, FB_BLANK_POWERDOWN); + + return ret; +} + +static int s6e63m0_resume(struct spi_device *spi) +{ + int ret = 0; + struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); + + /* + * after suspended, if lcd panel status is FB_BLANK_UNBLANK + * (at that time, before_power is FB_BLANK_UNBLANK) then + * it changes that status to FB_BLANK_POWERDOWN to get lcd on. + */ + if (before_power == FB_BLANK_UNBLANK) + lcd->power = FB_BLANK_POWERDOWN; + + dev_dbg(&spi->dev, "before_power = %d\n", before_power); + + ret = s6e63m0_power(lcd, before_power); + + return ret; +} +#else +#define s6e63m0_suspend NULL +#define s6e63m0_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt. */ +static void s6e63m0_shutdown(struct spi_device *spi) +{ + struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); + + s6e63m0_power(lcd, FB_BLANK_POWERDOWN); +} + +static struct spi_driver s6e63m0_driver = { + .driver = { + .name = "s6e63m0", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = s6e63m0_probe, + .remove = __devexit_p(s6e63m0_remove), + .shutdown = s6e63m0_shutdown, + .suspend = s6e63m0_suspend, + .resume = s6e63m0_resume, +}; + +static int __init s6e63m0_init(void) +{ + return spi_register_driver(&s6e63m0_driver); +} + +static void __exit s6e63m0_exit(void) +{ + spi_unregister_driver(&s6e63m0_driver); +} + +module_init(s6e63m0_init); +module_exit(s6e63m0_exit); + +MODULE_AUTHOR("InKi Dae "); +MODULE_DESCRIPTION("S6E63M0 LCD Driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/backlight/s6e63m0_gamma.h b/drivers/video/backlight/s6e63m0_gamma.h new file mode 100644 index 000000000000..2c44bdb0696b --- /dev/null +++ b/drivers/video/backlight/s6e63m0_gamma.h @@ -0,0 +1,266 @@ +/* linux/drivers/video/samsung/s6e63m0_brightness.h + * + * Gamma level definitions. + * + * Copyright (c) 2009 Samsung Electronics + * InKi Dae + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef _S6E63M0_BRIGHTNESS_H +#define _S6E63M0_BRIGHTNESS_H + +#define MAX_GAMMA_LEVEL 11 +#define GAMMA_TABLE_COUNT 21 + +/* gamma value: 2.2 */ +static const unsigned int s6e63m0_22_300[] = { + 0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6, + 0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0, + 0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb +}; + +static const unsigned int s6e63m0_22_280[] = { + 0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6, + 0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1, + 0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 +}; + +static const unsigned int s6e63m0_22_260[] = { + 0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6, + 0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2, + 0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 + +}; + +static const unsigned int s6e63m0_22_240[] = { + 0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9, + 0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3, + 0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA + +}; +static const unsigned int s6e63m0_22_220[] = { + 0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8, + 0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4, + 0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 +}; + +static const unsigned int s6e63m0_22_200[] = { + 0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA, + 0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6, + 0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA +}; + +static const unsigned int s6e63m0_22_170[] = { + 0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB, + 0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8, + 0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB +}; + +static const unsigned int s6e63m0_22_140[] = { + 0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC, + 0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9, + 0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E +}; + +static const unsigned int s6e63m0_22_110[] = { + 0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF, + 0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC, + 0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D +}; + +static const unsigned int s6e63m0_22_90[] = { + 0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0, + 0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF, + 0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 +}; + +static const unsigned int s6e63m0_22_30[] = { + 0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8, + 0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7, + 0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 +}; + +/* gamma value: 1.9 */ +static const unsigned int s6e63m0_19_300[] = { + 0x18, 0x08, 0x24, 0x61, 0x5F, 0x39, 0xBA, + 0xBD, 0xAD, 0xB1, 0xB6, 0xA5, 0xC4, 0xC5, + 0xBC, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB +}; + +static const unsigned int s6e63m0_19_280[] = { + 0x18, 0x08, 0x24, 0x61, 0x60, 0x39, 0xBB, + 0xBE, 0xAD, 0xB2, 0xB6, 0xA6, 0xC5, 0xC7, + 0xBD, 0x00, 0x9B, 0x00, 0x9E, 0x00, 0xD5 +}; + +static const unsigned int s6e63m0_19_260[] = { + 0x18, 0x08, 0x24, 0x63, 0x61, 0x3B, 0xBA, + 0xBE, 0xAC, 0xB3, 0xB8, 0xA7, 0xC6, 0xC8, + 0xBD, 0x00, 0x96, 0x00, 0x98, 0x00, 0xCF +}; + +static const unsigned int s6e63m0_19_240[] = { + 0x18, 0x08, 0x24, 0x67, 0x64, 0x3F, 0xBB, + 0xBE, 0xAD, 0xB3, 0xB9, 0xA7, 0xC8, 0xC9, + 0xBE, 0x00, 0x90, 0x00, 0x92, 0x00, 0xC8 +}; + +static const unsigned int s6e63m0_19_220[] = { + 0x18, 0x08, 0x24, 0x68, 0x64, 0x40, 0xBC, + 0xBF, 0xAF, 0xB4, 0xBA, 0xA9, 0xC8, 0xCA, + 0xBE, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0xC0 +}; + +static const unsigned int s6e63m0_19_200[] = { + 0x18, 0x08, 0x24, 0x68, 0x64, 0x3F, 0xBE, + 0xC0, 0xB0, 0xB6, 0xBB, 0xAB, 0xC8, 0xCB, + 0xBF, 0x00, 0x85, 0x00, 0x86, 0x00, 0xB8 +}; + +static const unsigned int s6e63m0_19_170[] = { + 0x18, 0x08, 0x24, 0x69, 0x64, 0x40, 0xBF, + 0xC1, 0xB0, 0xB9, 0xBE, 0xAD, 0xCB, 0xCD, + 0xC2, 0x00, 0x7A, 0x00, 0x7B, 0x00, 0xAA +}; + +static const unsigned int s6e63m0_19_140[] = { + 0x18, 0x08, 0x24, 0x6E, 0x65, 0x45, 0xC0, + 0xC3, 0xB2, 0xBA, 0xBE, 0xAE, 0xCD, 0xD0, + 0xC4, 0x00, 0x70, 0x00, 0x70, 0x00, 0x9C +}; + +static const unsigned int s6e63m0_19_110[] = { + 0x18, 0x08, 0x24, 0x6F, 0x65, 0x46, 0xC2, + 0xC4, 0xB3, 0xBF, 0xC2, 0xB2, 0xCF, 0xD1, + 0xC6, 0x00, 0x64, 0x00, 0x64, 0x00, 0x8D +}; + +static const unsigned int s6e63m0_19_90[] = { + 0x18, 0x08, 0x24, 0x74, 0x60, 0x4A, 0xC3, + 0xC6, 0xB5, 0xBF, 0xC3, 0xB2, 0xD2, 0xD3, + 0xC8, 0x00, 0x5B, 0x00, 0x5B, 0x00, 0x81 +}; + +static const unsigned int s6e63m0_19_30[] = { + 0x18, 0x08, 0x24, 0x84, 0x45, 0x4F, 0xCA, + 0xCB, 0xBC, 0xC9, 0xCB, 0xBC, 0xDA, 0xDA, + 0xD0, 0x00, 0x35, 0x00, 0x34, 0x00, 0x4E +}; + +/* gamma value: 1.7 */ +static const unsigned int s6e63m0_17_300[] = { + 0x18, 0x08, 0x24, 0x70, 0x70, 0x4F, 0xBF, + 0xC2, 0xB2, 0xB8, 0xBC, 0xAC, 0xCB, 0xCD, + 0xC3, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB +}; + +static const unsigned int s6e63m0_17_280[] = { + 0x18, 0x08, 0x24, 0x71, 0x71, 0x50, 0xBF, + 0xC2, 0xB2, 0xBA, 0xBE, 0xAE, 0xCB, 0xCD, + 0xC3, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 +}; + +static const unsigned int s6e63m0_17_260[] = { + 0x18, 0x08, 0x24, 0x72, 0x72, 0x50, 0xC0, + 0xC3, 0xB4, 0xB9, 0xBE, 0xAE, 0xCC, 0xCF, + 0xC4, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 +}; + +static const unsigned int s6e63m0_17_240[] = { + 0x18, 0x08, 0x24, 0x71, 0x72, 0x4F, 0xC2, + 0xC4, 0xB5, 0xBB, 0xBF, 0xB0, 0xCC, 0xCF, + 0xC3, 0x00, 0x91, 0x00, 0x95, 0x00, 0xCA +}; + +static const unsigned int s6e63m0_17_220[] = { + 0x18, 0x08, 0x24, 0x71, 0x73, 0x4F, 0xC2, + 0xC5, 0xB5, 0xBD, 0xC0, 0xB2, 0xCD, 0xD1, + 0xC5, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 +}; + +static const unsigned int s6e63m0_17_200[] = { + 0x18, 0x08, 0x24, 0x72, 0x75, 0x51, 0xC2, + 0xC6, 0xB5, 0xBF, 0xC1, 0xB3, 0xCE, 0xD1, + 0xC6, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA +}; + +static const unsigned int s6e63m0_17_170[] = { + 0x18, 0x08, 0x24, 0x75, 0x77, 0x54, 0xC3, + 0xC7, 0xB7, 0xC0, 0xC3, 0xB4, 0xD1, 0xD3, + 0xC9, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB +}; + +static const unsigned int s6e63m0_17_140[] = { + 0x18, 0x08, 0x24, 0x7B, 0x77, 0x58, 0xC3, + 0xC8, 0xB8, 0xC2, 0xC6, 0xB6, 0xD3, 0xD4, + 0xCA, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E +}; + +static const unsigned int s6e63m0_17_110[] = { + 0x18, 0x08, 0x24, 0x81, 0x7B, 0x5D, 0xC6, + 0xCA, 0xBB, 0xC3, 0xC7, 0xB8, 0xD6, 0xD8, + 0xCD, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D +}; + +static const unsigned int s6e63m0_17_90[] = { + 0x18, 0x08, 0x24, 0x82, 0x7A, 0x5B, 0xC8, + 0xCB, 0xBD, 0xC5, 0xCA, 0xBA, 0xD6, 0xD8, + 0xCE, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 +}; + +static const unsigned int s6e63m0_17_30[] = { + 0x18, 0x08, 0x24, 0x8F, 0x73, 0x63, 0xD1, + 0xD0, 0xC5, 0xCC, 0xD1, 0xC2, 0xDE, 0xE0, + 0xD6, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 +}; + +struct s6e63m0_gamma { + unsigned int *gamma_22_table[MAX_GAMMA_LEVEL]; + unsigned int *gamma_19_table[MAX_GAMMA_LEVEL]; + unsigned int *gamma_17_table[MAX_GAMMA_LEVEL]; +}; + +static struct s6e63m0_gamma gamma_table = { + .gamma_22_table[0] = (unsigned int *)&s6e63m0_22_30, + .gamma_22_table[1] = (unsigned int *)&s6e63m0_22_90, + .gamma_22_table[2] = (unsigned int *)&s6e63m0_22_110, + .gamma_22_table[3] = (unsigned int *)&s6e63m0_22_140, + .gamma_22_table[4] = (unsigned int *)&s6e63m0_22_170, + .gamma_22_table[5] = (unsigned int *)&s6e63m0_22_200, + .gamma_22_table[6] = (unsigned int *)&s6e63m0_22_220, + .gamma_22_table[7] = (unsigned int *)&s6e63m0_22_240, + .gamma_22_table[8] = (unsigned int *)&s6e63m0_22_260, + .gamma_22_table[9] = (unsigned int *)&s6e63m0_22_280, + .gamma_22_table[10] = (unsigned int *)&s6e63m0_22_300, + + .gamma_19_table[0] = (unsigned int *)&s6e63m0_19_30, + .gamma_19_table[1] = (unsigned int *)&s6e63m0_19_90, + .gamma_19_table[2] = (unsigned int *)&s6e63m0_19_110, + .gamma_19_table[3] = (unsigned int *)&s6e63m0_19_140, + .gamma_19_table[4] = (unsigned int *)&s6e63m0_19_170, + .gamma_19_table[5] = (unsigned int *)&s6e63m0_19_200, + .gamma_19_table[6] = (unsigned int *)&s6e63m0_19_220, + .gamma_19_table[7] = (unsigned int *)&s6e63m0_19_240, + .gamma_19_table[8] = (unsigned int *)&s6e63m0_19_260, + .gamma_19_table[9] = (unsigned int *)&s6e63m0_19_280, + .gamma_19_table[10] = (unsigned int *)&s6e63m0_19_300, + + .gamma_17_table[0] = (unsigned int *)&s6e63m0_17_30, + .gamma_17_table[1] = (unsigned int *)&s6e63m0_17_90, + .gamma_17_table[2] = (unsigned int *)&s6e63m0_17_110, + .gamma_17_table[3] = (unsigned int *)&s6e63m0_17_140, + .gamma_17_table[4] = (unsigned int *)&s6e63m0_17_170, + .gamma_17_table[5] = (unsigned int *)&s6e63m0_17_200, + .gamma_17_table[6] = (unsigned int *)&s6e63m0_17_220, + .gamma_17_table[7] = (unsigned int *)&s6e63m0_17_240, + .gamma_17_table[8] = (unsigned int *)&s6e63m0_17_260, + .gamma_17_table[9] = (unsigned int *)&s6e63m0_17_280, + .gamma_17_table[10] = (unsigned int *)&s6e63m0_17_300, +}; + +#endif + -- cgit v1.2.2 From beb0a43f398efac87a3b9c2c6a5c5a163df50413 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 3 May 2010 14:42:44 +0800 Subject: backlight: l4f00242t03: fix error handling in l4f00242t03_probe Error handling fixes: 1. In the case of kzalloc failure, simple return -ENOMEM instead of goto err. ( priv is NULL in this case ) 2. In the case of gpio_request fail for reset_gpio and data_enable_gpio, properly release resources by goto err and err2 respectively. Signed-off-by: Axel Lin Acked-by: Alberto Panizzo Signed-off-by: Richard Purdie --- drivers/video/backlight/l4f00242t03.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 1dafec85ddc0..9093ef0fa869 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -125,8 +125,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) if (priv == NULL) { dev_err(&spi->dev, "No memory for this device.\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } dev_set_drvdata(&spi->dev, priv); @@ -139,7 +138,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) if (ret) { dev_err(&spi->dev, "Unable to get the lcd l4f00242t03 reset gpio.\n"); - return ret; + goto err; } ret = gpio_direction_output(pdata->reset_gpio, 1); @@ -151,7 +150,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) if (ret) { dev_err(&spi->dev, "Unable to get the lcd l4f00242t03 data en gpio.\n"); - return ret; + goto err2; } ret = gpio_direction_output(pdata->data_enable_gpio, 0); -- cgit v1.2.2 From 146e10a8c457236e017355ed9ba0ef78fbb3d12b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 10 May 2010 09:27:34 +0800 Subject: backlight: max8925_bl: Fix error handling path Properly unregister a previously registered backlight device object in error handling of max8925_backlight_probe. Signed-off-by: Axel Lin Signed-off-by: Richard Purdie --- drivers/video/backlight/max8925_bl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/video') diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index b5accc957ad3..b2b2c7ba1f63 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -162,6 +162,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) backlight_update_status(bl); return 0; out: + backlight_device_unregister(bl); kfree(data); return ret; } -- cgit v1.2.2 From 1f976996c7413b5b48d35b195cc2d7adcd3f68d7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 10 May 2010 09:29:58 +0800 Subject: backlight: 88pm860x_bl: fix error handling in pm860x_backlight_probe This patch properly unregisters a previously registered backlight device object in error handling Signed-off-by: Axel Lin Signed-off-by: Richard Purdie --- drivers/video/backlight/88pm860x_bl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/video') diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 78d8fde9fe8f..38ffc3fbcbe4 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -267,6 +267,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) backlight_update_status(bl); return 0; out: + backlight_device_unregister(bl); kfree(data); return ret; } -- cgit v1.2.2 From 2ddfd12f3584840f5190897214423061d8a0602f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 12 May 2010 02:44:32 +0200 Subject: backlight: Add pcf50633 backlight driver This patch adds a backlight driver for controlling the pcf50633 LED module. Signed-off-by: Lars-Peter Clausen Acked-by: Samuel Ortiz Signed-off-by: Richard Purdie --- drivers/video/backlight/Kconfig | 7 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/pcf50633-backlight.c | 190 +++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 drivers/video/backlight/pcf50633-backlight.c (limited to 'drivers/video') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index cbd80978460e..e54a337227ea 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -300,6 +300,13 @@ config BACKLIGHT_88PM860X help Say Y to enable the backlight driver for Marvell 88PM8606. +config BACKLIGHT_PCF50633 + tristate "Backlight driver for NXP PCF50633 MFD" + depends on BACKLIGHT_CLASS_DEVICE && MFD_PCF50633 + help + If you have a backlight driven by a NXP PCF50633 MFD, say Y here to + enable its driver. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index f8978c0a2319..44c0f81ad85d 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -34,4 +34,5 @@ obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o +obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c new file mode 100644 index 000000000000..3c424f7efdcc --- /dev/null +++ b/drivers/video/backlight/pcf50633-backlight.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * PCF50633 backlight device driver + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +struct pcf50633_bl { + struct pcf50633 *pcf; + struct backlight_device *bl; + + unsigned int brightness; + unsigned int brightness_limit; +}; + +/* + * pcf50633_bl_set_brightness_limit + * + * Update the brightness limit for the pc50633 backlight. The actual brightness + * will not go above the limit. This is useful to limit power drain for example + * on low battery. + * + * @dev: Pointer to a pcf50633 device + * @limit: The brightness limit. Valid values are 0-63 + */ +int pcf50633_bl_set_brightness_limit(struct pcf50633 *pcf, unsigned int limit) +{ + struct pcf50633_bl *pcf_bl = platform_get_drvdata(pcf->bl_pdev); + + if (!pcf_bl) + return -ENODEV; + + pcf_bl->brightness_limit = limit & 0x3f; + backlight_update_status(pcf_bl->bl); + + return 0; +} + +static int pcf50633_bl_update_status(struct backlight_device *bl) +{ + struct pcf50633_bl *pcf_bl = bl_get_data(bl); + unsigned int new_brightness; + + + if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK) || + bl->props.power != FB_BLANK_UNBLANK) + new_brightness = 0; + else if (bl->props.brightness < pcf_bl->brightness_limit) + new_brightness = bl->props.brightness; + else + new_brightness = pcf_bl->brightness_limit; + + + if (pcf_bl->brightness == new_brightness) + return 0; + + if (new_brightness) { + pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDOUT, + new_brightness); + if (!pcf_bl->brightness) + pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 1); + } else { + pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 0); + } + + pcf_bl->brightness = new_brightness; + + return 0; +} + +static int pcf50633_bl_get_brightness(struct backlight_device *bl) +{ + struct pcf50633_bl *pcf_bl = bl_get_data(bl); + return pcf_bl->brightness; +} + +static const struct backlight_ops pcf50633_bl_ops = { + .get_brightness = pcf50633_bl_get_brightness, + .update_status = pcf50633_bl_update_status, + .options = BL_CORE_SUSPENDRESUME, +}; + +static int __devinit pcf50633_bl_probe(struct platform_device *pdev) +{ + int ret; + struct pcf50633_bl *pcf_bl; + struct device *parent = pdev->dev.parent; + struct pcf50633_platform_data *pcf50633_data = parent->platform_data; + struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data; + struct backlight_properties bl_props; + + pcf_bl = kzalloc(sizeof(*pcf_bl), GFP_KERNEL); + if (!pcf_bl) + return -ENOMEM; + + bl_props.max_brightness = 0x3f; + bl_props.power = FB_BLANK_UNBLANK; + + if (pdata) { + bl_props.brightness = pdata->default_brightness; + pcf_bl->brightness_limit = pdata->default_brightness_limit; + } else { + bl_props.brightness = 0x3f; + pcf_bl->brightness_limit = 0x3f; + } + + pcf_bl->pcf = dev_to_pcf50633(pdev->dev.parent); + + pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl, + &pcf50633_bl_ops, &bl_props); + + if (IS_ERR(pcf_bl->bl)) { + ret = PTR_ERR(pcf_bl->bl); + goto err_free; + } + + platform_set_drvdata(pdev, pcf_bl); + + pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDDIM, pdata->ramp_time); + + /* Should be different from bl_props.brightness, so we do not exit + * update_status early the first time it's called */ + pcf_bl->brightness = pcf_bl->bl->props.brightness + 1; + + backlight_update_status(pcf_bl->bl); + + return 0; + +err_free: + kfree(pcf_bl); + + return ret; +} + +static int __devexit pcf50633_bl_remove(struct platform_device *pdev) +{ + struct pcf50633_bl *pcf_bl = platform_get_drvdata(pdev); + + backlight_device_unregister(pcf_bl->bl); + + platform_set_drvdata(pdev, NULL); + + kfree(pcf_bl); + + return 0; +} + +static struct platform_driver pcf50633_bl_driver = { + .probe = pcf50633_bl_probe, + .remove = __devexit_p(pcf50633_bl_remove), + .driver = { + .name = "pcf50633-backlight", + }, +}; + +static int __init pcf50633_bl_init(void) +{ + return platform_driver_register(&pcf50633_bl_driver); +} +module_init(pcf50633_bl_init); + +static void __exit pcf50633_bl_exit(void) +{ + platform_driver_unregister(&pcf50633_bl_driver); +} +module_exit(pcf50633_bl_exit); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("PCF50633 backlight driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pcf50633-backlight"); -- cgit v1.2.2 From 9966c4fea578bcf356c35cdf184cdacde495bc2c Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Wed, 26 May 2010 14:42:27 -0700 Subject: add support for S3 Trio3D/1X/2X Add support for S3 Trio3D/1X (86C360) and S3 Trio3D/2X (86C362 and 86C368) cards to s3fb driver. Tested with 86C362 AGP and 86C368 PCI&AGP. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Ondrej Zary Acked-by: Ondrej Zajicek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/s3fb.c | 101 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 20 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index d4471b4c0374..dce8c97b4333 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -71,7 +71,8 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", "S3 Trio64UV+", "S3 Trio64V2/DX", "S3 Trio64V2/GX", "S3 Plato/PX", "S3 Aurora64VP", "S3 Virge", "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX", - "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P"}; + "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P", + "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X"}; #define CHIP_UNKNOWN 0x00 #define CHIP_732_TRIO32 0x01 @@ -89,10 +90,14 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", #define CHIP_356_VIRGE_GX2 0x0D #define CHIP_357_VIRGE_GX2P 0x0E #define CHIP_359_VIRGE_GX2P 0x0F +#define CHIP_360_TRIO3D_1X 0x10 +#define CHIP_362_TRIO3D_2X 0x11 +#define CHIP_368_TRIO3D_2X 0x12 #define CHIP_XXX_TRIO 0x80 #define CHIP_XXX_TRIO64V2_DXGX 0x81 #define CHIP_XXX_VIRGE_DXGX 0x82 +#define CHIP_36X_TRIO3D_1X_2X 0x83 #define CHIP_UNDECIDED_FLAG 0x80 #define CHIP_MASK 0xFF @@ -324,6 +329,7 @@ static void s3fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) static void s3_set_pixclock(struct fb_info *info, u32 pixclock) { + struct s3fb_info *par = info->par; u16 m, n, r; u8 regval; int rv; @@ -339,7 +345,13 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock) vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); /* Set S3 clock registers */ - vga_wseq(NULL, 0x12, ((n - 2) | (r << 5))); + if (par->chip == CHIP_360_TRIO3D_1X || + par->chip == CHIP_362_TRIO3D_2X || + par->chip == CHIP_368_TRIO3D_2X) { + vga_wseq(NULL, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */ + vga_wseq(NULL, 0x29, r >> 2); /* remaining highest bit of r */ + } else + vga_wseq(NULL, 0x12, (n - 2) | (r << 5)); vga_wseq(NULL, 0x13, m - 2); udelay(1000); @@ -456,7 +468,7 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) static int s3fb_set_par(struct fb_info *info) { struct s3fb_info *par = info->par; - u32 value, mode, hmul, offset_value, screen_size, multiplex; + u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes; u32 bpp = info->var.bits_per_pixel; if (bpp != 0) { @@ -518,7 +530,7 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ? */ svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ? */ - svga_wcrt_mask(0x5D, 0x00, 0x28); // Clear strange HSlen bits + svga_wcrt_mask(0x5D, 0x00, 0x28); /* Clear strange HSlen bits */ /* svga_wcrt_mask(0x58, 0x03, 0x03); */ @@ -530,10 +542,14 @@ static int s3fb_set_par(struct fb_info *info) pr_debug("fb%d: offset register : %d\n", info->node, offset_value); svga_wcrt_multi(s3_offset_regs, offset_value); - vga_wcrt(NULL, 0x54, 0x18); /* M parameter */ - vga_wcrt(NULL, 0x60, 0xff); /* N parameter */ - vga_wcrt(NULL, 0x61, 0xff); /* L parameter */ - vga_wcrt(NULL, 0x62, 0xff); /* L parameter */ + if (par->chip != CHIP_360_TRIO3D_1X && + par->chip != CHIP_362_TRIO3D_2X && + par->chip != CHIP_368_TRIO3D_2X) { + vga_wcrt(NULL, 0x54, 0x18); /* M parameter */ + vga_wcrt(NULL, 0x60, 0xff); /* N parameter */ + vga_wcrt(NULL, 0x61, 0xff); /* L parameter */ + vga_wcrt(NULL, 0x62, 0xff); /* L parameter */ + } vga_wcrt(NULL, 0x3A, 0x35); svga_wattr(0x33, 0x00); @@ -570,6 +586,16 @@ static int s3fb_set_par(struct fb_info *info) vga_wcrt(NULL, 0x66, 0x90); } + if (par->chip == CHIP_360_TRIO3D_1X || + par->chip == CHIP_362_TRIO3D_2X || + par->chip == CHIP_368_TRIO3D_2X) { + dbytes = info->var.xres * ((bpp+7)/8); + vga_wcrt(NULL, 0x91, (dbytes + 7) / 8); + vga_wcrt(NULL, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80); + + vga_wcrt(NULL, 0x66, 0x81); + } + svga_wcrt_mask(0x31, 0x00, 0x40); multiplex = 0; hmul = 1; @@ -615,11 +641,13 @@ static int s3fb_set_par(struct fb_info *info) break; case 3: pr_debug("fb%d: 8 bit pseudocolor\n", info->node); - if (info->var.pixclock > 20000) { - svga_wcrt_mask(0x50, 0x00, 0x30); + svga_wcrt_mask(0x50, 0x00, 0x30); + if (info->var.pixclock > 20000 || + par->chip == CHIP_360_TRIO3D_1X || + par->chip == CHIP_362_TRIO3D_2X || + par->chip == CHIP_368_TRIO3D_2X) svga_wcrt_mask(0x67, 0x00, 0xF0); - } else { - svga_wcrt_mask(0x50, 0x00, 0x30); + else { svga_wcrt_mask(0x67, 0x10, 0xF0); multiplex = 1; } @@ -634,7 +662,10 @@ static int s3fb_set_par(struct fb_info *info) } else { svga_wcrt_mask(0x50, 0x10, 0x30); svga_wcrt_mask(0x67, 0x30, 0xF0); - hmul = 2; + if (par->chip != CHIP_360_TRIO3D_1X && + par->chip != CHIP_362_TRIO3D_2X && + par->chip != CHIP_368_TRIO3D_2X) + hmul = 2; } break; case 5: @@ -647,7 +678,10 @@ static int s3fb_set_par(struct fb_info *info) } else { svga_wcrt_mask(0x50, 0x10, 0x30); svga_wcrt_mask(0x67, 0x50, 0xF0); - hmul = 2; + if (par->chip != CHIP_360_TRIO3D_1X && + par->chip != CHIP_362_TRIO3D_2X && + par->chip != CHIP_368_TRIO3D_2X) + hmul = 2; } break; case 6: @@ -866,6 +900,17 @@ static int __devinit s3_identification(int chip) return CHIP_385_VIRGE_GX; } + if (chip == CHIP_36X_TRIO3D_1X_2X) { + switch (vga_rcrt(NULL, 0x2f)) { + case 0x00: + return CHIP_360_TRIO3D_1X; + case 0x01: + return CHIP_362_TRIO3D_2X; + case 0x02: + return CHIP_368_TRIO3D_2X; + } + } + return CHIP_UNKNOWN; } @@ -930,17 +975,32 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i vga_wcrt(NULL, 0x38, 0x48); vga_wcrt(NULL, 0x39, 0xA5); - /* Find how many physical memory there is on card */ - /* 0x36 register is accessible even if other registers are locked */ - regval = vga_rcrt(NULL, 0x36); - info->screen_size = s3_memsizes[regval >> 5] << 10; - info->fix.smem_len = info->screen_size; - + /* Identify chip type */ par->chip = id->driver_data & CHIP_MASK; par->rev = vga_rcrt(NULL, 0x2f); if (par->chip & CHIP_UNDECIDED_FLAG) par->chip = s3_identification(par->chip); + /* Find how many physical memory there is on card */ + /* 0x36 register is accessible even if other registers are locked */ + regval = vga_rcrt(NULL, 0x36); + if (par->chip == CHIP_360_TRIO3D_1X || + par->chip == CHIP_362_TRIO3D_2X || + par->chip == CHIP_368_TRIO3D_2X) { + switch ((regval & 0xE0) >> 5) { + case 0: /* 8MB -- only 4MB usable for display */ + case 1: /* 4MB with 32-bit bus */ + case 2: /* 4MB */ + info->screen_size = 4 << 20; + break; + case 6: /* 2MB */ + info->screen_size = 2 << 20; + break; + } + } else + info->screen_size = s3_memsizes[regval >> 5] << 10; + info->fix.smem_len = info->screen_size; + /* Find MCLK frequency */ regval = vga_rseq(NULL, 0x10); par->mclk_freq = ((vga_rseq(NULL, 0x11) + 2) * 14318) / ((regval & 0x1F) + 2); @@ -1131,6 +1191,7 @@ static struct pci_device_id s3_devices[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_356_VIRGE_GX2}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X}, {0, 0, 0, 0, 0, 0, 0} }; -- cgit v1.2.2 From a51faabc666c054cb2d983fcd5152aa6d0b80604 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 26 May 2010 14:42:29 -0700 Subject: drivers/video/via: use memdup_user Use memdup_user when user data is immediately copied into the allocated region. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression from,to,size,flag; position p; identifier l1,l2; @@ - to = \(kmalloc@p\|kzalloc@p\)(size,flag); + to = memdup_user(from,size); if ( - to==NULL + IS_ERR(to) || ...) { <+... when != goto l1; - -ENOMEM + PTR_ERR(to) ...+> } - if (copy_from_user(to, from, size) != 0) { - <+... when != goto l2; - -EFAULT - ...+> - } // Signed-off-by: Julia Lawall Cc: Joseph Chan Cc: Scott Fang Cc: Florian Tobias Schandinat Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/via/viafbdev.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 2bc40e682f95..1082541358f0 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -578,14 +578,9 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) break; case VIAFB_SET_GAMMA_LUT: - viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL); - if (!viafb_gamma_table) - return -ENOMEM; - if (copy_from_user(viafb_gamma_table, argp, - 256 * sizeof(u32))) { - kfree(viafb_gamma_table); - return -EFAULT; - } + viafb_gamma_table = memdup_user(argp, 256 * sizeof(u32)); + if (IS_ERR(viafb_gamma_table)) + return PTR_ERR(viafb_gamma_table); viafb_set_gamma_table(viafb_bpp, viafb_gamma_table); kfree(viafb_gamma_table); break; -- cgit v1.2.2 From d11991cbacaa9283de2b6e362e7ec5f21bc40044 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 26 May 2010 14:42:30 -0700 Subject: fbdev: bfin-t350mcqb-fb: avoid unused warnings in backlight code The current backlight code is stubbed out, so the new props changes added some warnings about unused label/prop. Signed-off-by: Mike Frysinger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/bfin-t350mcqb-fb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index c2ec3dcd4e91..7a50272eaab9 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -420,7 +420,9 @@ static irqreturn_t bfin_t350mcqb_irq_error(int irq, void *dev_id) static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) { +#ifndef NO_BL_SUPPORT struct backlight_properties props; +#endif struct bfin_t350mcqbfb_info *info; struct fb_info *fbinfo; int ret; @@ -550,7 +552,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) printk(KERN_ERR DRIVER_NAME ": unable to register backlight.\n"); ret = -EINVAL; - goto out9; + unregister_framebuffer(fbinfo); + goto out8; } lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops); @@ -559,8 +562,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) return 0; -out9: - unregister_framebuffer(fbinfo); out8: free_irq(info->irq, info); out7: -- cgit v1.2.2 From 8fc809d17984f18fbad7ae23e47a62b195969c19 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 26 May 2010 14:42:31 -0700 Subject: fbdev: bf54x-lq043fb: fix unused warnings with backlight code The current backlight code is stubbed out, so the new props changes added some warnings: drivers/video/bf54x-lq043fb.c: In function 'bfin_bf54x_probe': drivers/video/bf54x-lq043fb.c:666: warning: label 'out9' defined but not used drivers/video/bf54x-lq043fb.c:504: warning: unused variable 'props' Fix em ! Signed-off-by: Mike Frysinger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/bf54x-lq043fb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 23b2a8c0dbfc..b020ba7f1cf2 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -501,7 +501,9 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id) static int __devinit bfin_bf54x_probe(struct platform_device *pdev) { +#ifndef NO_BL_SUPPORT struct backlight_properties props; +#endif struct bfin_bf54xfb_info *info; struct fb_info *fbinfo; int ret; @@ -654,7 +656,8 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) printk(KERN_ERR DRIVER_NAME ": unable to register backlight.\n"); ret = -EINVAL; - goto out9; + unregister_framebuffer(fbinfo); + goto out8; } lcd_dev = lcd_device_register(DRIVER_NAME, &pdev->dev, NULL, &bfin_lcd_ops); @@ -663,8 +666,6 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) return 0; -out9: - unregister_framebuffer(fbinfo); out8: free_irq(info->irq, info); out7: -- cgit v1.2.2 From 7ea8085910ef3dd4f3cad6845aaa2b580d39b115 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 26 May 2010 17:53:25 +0200 Subject: drop unused dentry argument to ->fsync Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- drivers/video/fb_defio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 1105a591dcc1..073c9b408cf7 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -66,7 +66,7 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma, return 0; } -int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync) +int fb_deferred_io_fsync(struct file *file, int datasync) { struct fb_info *info = file->private_data; -- cgit v1.2.2