From 0839d687f35b2f1a5e15fe5ee03bc4918457798d Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 16 Feb 2011 03:49:02 +0000 Subject: [PATCH 1/4] sh: mach-ecovec24: support for main lcd backlight Add support for the main LCD backlight that is controlled through the PTR1 GPIO. Signed-off-by: Alexandre Courbot Signed-off-by: Paul Mundt --- arch/sh/boards/mach-ecovec24/setup.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 701667acfd89..a2c06220bbab 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -261,6 +261,18 @@ const static struct fb_videomode ecovec_dvi_modes[] = { }, }; +static int ecovec24_set_brightness(void *board_data, int brightness) +{ + gpio_set_value(GPIO_PTR1, brightness); + + return 0; +} + +static int ecovec24_get_brightness(void *board_data) +{ + return gpio_get_value(GPIO_PTR1); +} + static struct sh_mobile_lcdc_info lcdc_info = { .ch[0] = { .interface_type = RGB18, @@ -271,6 +283,12 @@ static struct sh_mobile_lcdc_info lcdc_info = { .height = 91, }, .board_cfg = { + .set_brightness = ecovec24_set_brightness, + .get_brightness = ecovec24_get_brightness, + }, + .bl_info = { + .name = "sh_mobile_lcdc_bl", + .max_brightness = 1, }, } }; From bacbe55b63d434b7a33f01a03628b6302c75417b Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 16 Feb 2011 03:49:03 +0000 Subject: [PATCH 2/4] sh: mach-ap325rxa: move backlight control code Move the backlight control code into the appropriate hooks for the LCDC driver. Signed-off-by: Alexandre Courbot Signed-off-by: Paul Mundt --- arch/sh/boards/mach-ap325rxa/setup.c | 32 +++++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 3e5fc3bbf3ed..d695e43d3c6b 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -156,24 +156,34 @@ static struct platform_device nand_flash_device = { #define PORT_DRVCRA 0xA405018A #define PORT_DRVCRB 0xA405018C +static int ap320_wvga_set_brightness(void *board_data, int brightness) +{ + if (brightness) { + gpio_set_value(GPIO_PTS3, 0); + __raw_writew(0x100, FPGA_BKLREG); + } else { + __raw_writew(0, FPGA_BKLREG); + gpio_set_value(GPIO_PTS3, 1); + } + + return 0; +} + +static int ap320_wvga_get_brightness(void *board_data) +{ + return gpio_get_value(GPIO_PTS3); +} + static void ap320_wvga_power_on(void *board_data, struct fb_info *info) { msleep(100); /* ASD AP-320/325 LCD ON */ __raw_writew(FPGA_LCDREG_VAL, FPGA_LCDREG); - - /* backlight */ - gpio_set_value(GPIO_PTS3, 0); - __raw_writew(0x100, FPGA_BKLREG); } static void ap320_wvga_power_off(void *board_data) { - /* backlight */ - __raw_writew(0, FPGA_BKLREG); - gpio_set_value(GPIO_PTS3, 1); - /* ASD AP-320/325 LCD OFF */ __raw_writew(0, FPGA_LCDREG); } @@ -209,6 +219,12 @@ static struct sh_mobile_lcdc_info lcdc_info = { .board_cfg = { .display_on = ap320_wvga_power_on, .display_off = ap320_wvga_power_off, + .set_brightness = ap320_wvga_set_brightness, + .get_brightness = ap320_wvga_get_brightness, + }, + .bl_info = { + .name = "sh_mobile_lcdc_bl", + .max_brightness = 1, }, } }; From 8857b9aa7e64a70852545ee01fa638481cb08a76 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 23 Feb 2011 08:36:30 +0000 Subject: [PATCH 3/4] fbdev: sh_mobile_lcdcfb: add blanking support Add a blanking callback to the LCDC driver in order to support both FBIOBLANK and TIOCLINUX blanking ioctls. LCDC clocks are also released if the requested blanking level is superior to FB_BLANK_NORMAL, to allow runtime PM to disable the clocks if possible. Signed-off-by: Alexandre Courbot Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 44 ++++++++++++++++++++++++++++++++ drivers/video/sh_mobile_lcdcfb.h | 1 + 2 files changed, 45 insertions(+) diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index e040e46d7d91..65c4ee3628c4 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -977,6 +977,49 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in return 0; } +/* + * Screen blanking. Behavior is as follows: + * FB_BLANK_UNBLANK: screen unblanked, clocks enabled + * FB_BLANK_NORMAL: screen blanked, clocks enabled + * FB_BLANK_VSYNC, + * FB_BLANK_HSYNC, + * FB_BLANK_POWEROFF: screen blanked, clocks disabled + */ +static int sh_mobile_lcdc_blank(int blank, struct fb_info *info) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + struct sh_mobile_lcdc_priv *p = ch->lcdc; + + /* blank the screen? */ + if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) { + struct fb_fillrect rect = { + .width = info->var.xres, + .height = info->var.yres, + }; + sh_mobile_lcdc_fillrect(info, &rect); + } + /* turn clocks on? */ + if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) { + sh_mobile_lcdc_clk_on(p); + } + /* turn clocks off? */ + if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) { + /* make sure the screen is updated with the black fill before + * switching the clocks off. one vsync is not enough since + * blanking may occur in the middle of a refresh. deferred io + * mode will reenable the clocks and update the screen in time, + * so it does not need this. */ + if (!info->fbdefio) { + sh_mobile_wait_for_vsync(info); + sh_mobile_wait_for_vsync(info); + } + sh_mobile_lcdc_clk_off(p); + } + + ch->blank_status = blank; + return 0; +} + static struct fb_ops sh_mobile_lcdc_ops = { .owner = THIS_MODULE, .fb_setcolreg = sh_mobile_lcdc_setcolreg, @@ -985,6 +1028,7 @@ static struct fb_ops sh_mobile_lcdc_ops = { .fb_fillrect = sh_mobile_lcdc_fillrect, .fb_copyarea = sh_mobile_lcdc_copyarea, .fb_imageblit = sh_mobile_lcdc_imageblit, + .fb_blank = sh_mobile_lcdc_blank, .fb_pan_display = sh_mobile_fb_pan_display, .fb_ioctl = sh_mobile_ioctl, .fb_open = sh_mobile_open, diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index 03a22dcbcc59..fad353a7e44c 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h @@ -37,6 +37,7 @@ struct sh_mobile_lcdc_chan { struct completion vsync_completion; struct fb_var_screeninfo display_var; int use_count; + int blank_status; struct mutex open_lock; /* protects the use counter */ }; From 247f99386100d1d1c369ba98120d2edebf5426fc Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 23 Feb 2011 08:41:50 +0000 Subject: [PATCH 4/4] fbdev: sh_mobile_lcdcfb: fix module lock acquisition Whenever the LCDC is to be started or stopped, a board callback is checked for existence and invoked. Prior to the invokation, the callback's module lock is also acquired, to be released once the callback returns. However, the order of testing makes it possible for the lock to be acquired and not released in case the callback does not exist. This patch reorders the tests to prevent this particular case. Signed-off-by: Alexandre Courbot Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 65c4ee3628c4..69e2833bd460 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -616,7 +616,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) continue; board_cfg = &ch->cfg.board_cfg; - if (try_module_get(board_cfg->owner) && board_cfg->display_on) { + if (board_cfg->display_on && try_module_get(board_cfg->owner)) { board_cfg->display_on(board_cfg->board_data, ch->info); module_put(board_cfg->owner); } @@ -661,7 +661,7 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) } board_cfg = &ch->cfg.board_cfg; - if (try_module_get(board_cfg->owner) && board_cfg->display_off) { + if (board_cfg->display_off && try_module_get(board_cfg->owner)) { board_cfg->display_off(board_cfg->board_data); module_put(board_cfg->owner); } @@ -1228,7 +1228,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, switch(action) { case FB_EVENT_SUSPEND: - if (try_module_get(board_cfg->owner) && board_cfg->display_off) { + if (board_cfg->display_off && try_module_get(board_cfg->owner)) { board_cfg->display_off(board_cfg->board_data); module_put(board_cfg->owner); } @@ -1241,7 +1241,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, mutex_unlock(&ch->open_lock); /* HDMI must be enabled before LCDC configuration */ - if (try_module_get(board_cfg->owner) && board_cfg->display_on) { + if (board_cfg->display_on && try_module_get(board_cfg->owner)) { board_cfg->display_on(board_cfg->board_data, info); module_put(board_cfg->owner); }