diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index c1536d7..1ee589e 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1514,6 +1514,14 @@ config FB_PXA_PARAMETERS describes the available parameters. +config FB_PXA_BACKLIGHT + bool "Support for backlight control" + default y + depends on FB_PXA + select FB_BACKLIGHT + help + Say Y here if you want to control the backlight of your display. + config FB_MBX tristate "2700G LCD framebuffer support" depends on FB && ARCH_PXA diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index b4947c8..489174a 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -9,6 +9,8 @@ * which in turn is * Based on acornfb.c Copyright (C) Russell King. * + * Backlight support by Rodolfo Giometti + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. @@ -37,6 +39,7 @@ #include #include #include +#include #include #include @@ -58,7 +61,6 @@ #define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM|LCCR0_BM|LCCR0_QDM|LCCR0_DIS|LCCR0_EFM|LCCR0_IUM|LCCR0_SFM|LCCR0_LDM|LCCR0_ENB) #define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP) -static void (*pxafb_backlight_power)(int); static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *); static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *); @@ -69,6 +71,71 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); static char g_options[PXAFB_OPTIONS_SIZE] __initdata = ""; #endif + +/* + * Backlight control + */ +#ifdef CONFIG_FB_BACKLIGHT +static void pxafb_bl_suspend(struct pxafb_info *fbi) +{ + struct backlight_device *bl_dev = fbi->fb.bl_dev; + + if (bl_dev) { + down(&bl_dev->sem); + bl_dev->props->fb_blank = FB_BLANK_POWERDOWN; + bl_dev->props->update_status(bl_dev); + up(&bl_dev->sem); + } +} + +static void pxafb_bl_resume(struct pxafb_info *fbi) +{ + struct backlight_device *bl_dev = fbi->fb.bl_dev; + + if (bl_dev) { + down(&bl_dev->sem); + bl_dev->props->fb_blank = FB_BLANK_UNBLANK; + bl_dev->props->update_status(bl_dev); + up(&bl_dev->sem); + } +} + +static void pxafb_bl_init(struct fb_info *info, struct backlight_properties *bl_props) +{ + struct backlight_device *bl_dev; + char name[16]; + + snprintf(name, sizeof(name), "pxabl%d", info->node); + + bl_dev = backlight_device_register(name, info->dev, info, bl_props); + if (IS_ERR(bl_dev)) { + info->bl_dev = NULL; + printk(KERN_WARNING "pxafb: backlight registration failed\n"); + return; + } + + mutex_lock(&info->bl_mutex); + info->bl_dev = bl_dev; + fb_bl_default_curve(info, 0, 0, 100); /* level: 0 - 100 */ + mutex_unlock(&info->bl_mutex); + + down(&bl_dev->sem); + bl_dev->props->brightness = bl_props->max_brightness; + bl_dev->props->power = FB_BLANK_UNBLANK; + bl_dev->props->update_status(bl_dev); + up(&bl_dev->sem); + + printk("pxafb: backlight initialized (%s)\n", name); +} +#else +static inline void pxafb_bl_init(struct fb_info *info, struct backlight_properties *bl_props) {} +static inline void pxafb_bl_suspend(struct pxafb_info *fbi) {} +static inline void pxafb_bl_resume(struct pxafb_info *fbi) {} +#endif /* CONFIG_FB_BACKLIGHT */ + +/* + * + */ static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state) { unsigned long flags; @@ -736,14 +803,6 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info * * to ensure that things happen in the right way 100% of time time. * -- rmk */ -static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on) -{ - pr_debug("pxafb: backlight o%s\n", on ? "n" : "ff"); - - if (pxafb_backlight_power) - pxafb_backlight_power(on); -} - static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on) { pr_debug("pxafb: LCD power o%s\n", on ? "n" : "ff"); @@ -899,7 +958,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state) */ if (old_state != C_DISABLE) { fbi->state = state; - __pxafb_backlight_power(fbi, 0); + pxafb_bl_suspend(fbi); __pxafb_lcd_power(fbi, 0); if (old_state != C_DISABLE_CLKCHANGE) pxafb_disable_controller(fbi); @@ -953,7 +1012,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state) pxafb_setup_gpio(fbi); pxafb_enable_controller(fbi); __pxafb_lcd_power(fbi, 1); - __pxafb_backlight_power(fbi, 1); + pxafb_bl_resume(fbi); } break; } @@ -1112,11 +1171,10 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev) int i, smemlen; /* Alloc the pxafb_info and pseudo_palette in one step */ - fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL); + fbi = (struct pxafb_info *) framebuffer_alloc(sizeof(u32) * 16, dev); if (!fbi) return NULL; - memset(fbi, 0, sizeof(struct pxafb_info)); fbi->dev = dev; strcpy(fbi->fb.fix.id, PXA_NAME); @@ -1368,7 +1426,6 @@ int __init pxafb_probe(struct platform_device *dev) ret = -EINVAL; goto failed; } - pxafb_backlight_power = inf->pxafb_backlight_power; pxafb_lcd_power = inf->pxafb_lcd_power; fbi = pxafb_init_fbinfo(&dev->dev); if (!fbi) { @@ -1407,6 +1464,9 @@ int __init pxafb_probe(struct platform_device *dev) goto failed; } + /* Register the backlight support */ + pxafb_bl_init(&fbi->fb, inf->bl_props); + #ifdef CONFIG_PM // TODO #endif diff --git a/include/asm-arm/arch-pxa/pxafb.h b/include/asm-arm/arch-pxa/pxafb.h index 81c3928..5c89664 100644 --- a/include/asm-arm/arch-pxa/pxafb.h +++ b/include/asm-arm/arch-pxa/pxafb.h @@ -71,7 +71,7 @@ struct pxafb_mach_info { */ u_int lccr3; - void (*pxafb_backlight_power)(int); + struct backlight_properties *bl_props; void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *); };