From: Anatolij G. <ag...@de...> - 2009-11-09 11:13:31
|
To activate this driver select CONFIG_BACKLIGHT_LCD_SUPPORT in the kernel configuration. Backlight control interface will be available under /sys/class/backlight/mx3fb/. Signed-off-by: Anatolij Gustschin <ag...@de...> --- drivers/video/mx3fb.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 99 insertions(+), 1 deletions(-) diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 86312dd..f8f9338 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -30,6 +30,7 @@ #include <mach/hardware.h> #include <mach/ipu.h> #include <mach/mx3fb.h> +#include <linux/backlight.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -60,6 +61,12 @@ #define SDC_COM_BG_EN 0x00000200UL #define SDC_COM_SHARP 0x00001000UL +#define SDC_PWM_SRC_HSYNC_CLK 0x00000000UL +#define SDC_PWM_SRC_PXL_CLK 0x02000000UL +#define SDC_PWM_SRC_HSP_CLK 0x04000000UL +#define SDC_PWM_CC_EN 0x01000000UL +#define SDC_PWM_PWM_MSK 0x00FF0000UL + #define SDC_V_SYNC_WIDTH_L 0x00000001UL /* Display Interface registers */ @@ -238,6 +245,7 @@ static const struct fb_videomode mx3fb_modedb[] = { struct mx3fb_data { struct fb_info *fbi; int backlight_level; + int pwm_clk_src; /* clock source for PWM */ void __iomem *reg_base; spinlock_t lock; struct device *dev; @@ -268,6 +276,7 @@ struct mx3fb_info { struct scatterlist sg[2]; u32 sync; /* preserve var->sync flags */ + struct backlight_device *backlight; }; static void mx3fb_dma_done(void *); @@ -647,7 +656,9 @@ static int sdc_set_global_alpha(struct mx3fb_data *mx3fb, bool enable, uint8_t a static void sdc_set_brightness(struct mx3fb_data *mx3fb, uint8_t value) { /* This might be board-specific */ - mx3fb_write_reg(mx3fb, 0x03000000UL | value << 16, SDC_PWM_CTRL); + u32 reg = mx3fb->pwm_clk_src | SDC_PWM_CC_EN | value << 16; + + mx3fb_write_reg(mx3fb, reg, SDC_PWM_CTRL); return; } @@ -1207,6 +1218,88 @@ static int mx3fb_resume(struct platform_device *pdev) #define mx3fb_resume NULL #endif +#ifdef CONFIG_BACKLIGHT_LCD_SUPPORT +/* + * Backlight device + */ +static int mx3fb_bl_update_status(struct backlight_device *bl) +{ + struct mx3fb_info *fbi = bl_get_data(bl); + struct mx3fb_data *mx3fb = fbi->mx3fb; + int brightness; + + if (bl->props.power != FB_BLANK_UNBLANK || + bl->props.fb_blank != FB_BLANK_UNBLANK) + brightness = 0; + else + brightness = bl->props.brightness; + + mx3fb->backlight_level = brightness; + sdc_set_brightness(mx3fb, mx3fb->backlight_level); + return 0; +} + +static int mx3fb_bl_get_brightness(struct backlight_device *bl) +{ + struct mx3fb_info *fbi = bl_get_data(bl); + struct mx3fb_data *mx3fb = fbi->mx3fb; + uint32_t reg; + + reg = mx3fb_read_reg(mx3fb, SDC_PWM_CTRL); + + return (reg & SDC_PWM_PWM_MSK) >> 16; +} + +static struct backlight_ops mx3fb_bl_ops = { + .update_status = mx3fb_bl_update_status, + .get_brightness = mx3fb_bl_get_brightness, +}; + +static void mx3fb_init_backlight(struct mx3fb_info *fbi) +{ + struct backlight_device *bl; + struct mx3fb_data *mx3fb = fbi->mx3fb; + + /* + * COM57H5M10XRC supports max. 300Hz for PDM, so + * we use HSYNC as clock source. + */ + if (fb_mode && !strncmp(fb_mode, "COM57H5M10XRC", 13)) + mx3fb->pwm_clk_src = SDC_PWM_SRC_HSYNC_CLK; + + if (fbi->backlight) + return; + + bl = backlight_device_register("mx3fb", mx3fb->dev, + fbi, &mx3fb_bl_ops); + if (IS_ERR(bl)) { + dev_err(mx3fb->dev, "register backlight failed: %ld\n", + PTR_ERR(bl)); + return; + } + fbi->backlight = bl; + + bl->props.power = FB_BLANK_UNBLANK; + bl->props.fb_blank = FB_BLANK_UNBLANK; + bl->props.max_brightness = 0xff; + bl->props.brightness = 0xff; +} + +static void mx3fb_exit_backlight(struct mx3fb_info *fbi) +{ + if (fbi->backlight) + backlight_device_unregister(fbi->backlight); +} +#else +static inline void mx3fb_init_backlight(struct mx3fb_info *fbi) +{ +} + +static inline void mx3fb_exit_backlight(struct mx3fb_info *fbi) +{ +} +#endif + /* * Main framebuffer functions */ @@ -1390,6 +1483,8 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan) if (ret < 0) goto esetpar; + mx3fb_init_backlight(mx3fbi); + __blank(FB_BLANK_UNBLANK, fbi); dev_info(dev, "registered, using mode %s\n", fb_mode); @@ -1401,6 +1496,7 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan) return 0; erfb: + mx3fb_exit_backlight(mx3fbi); esetpar: emode: fb_dealloc_cmap(&fbi->cmap); @@ -1487,6 +1583,7 @@ static int mx3fb_probe(struct platform_device *pdev) } mx3fb->backlight_level = 255; + mx3fb->pwm_clk_src = SDC_PWM_SRC_PXL_CLK; ret = init_fb_chan(mx3fb, to_idmac_chan(chan)); if (ret < 0) @@ -1513,6 +1610,7 @@ static int mx3fb_remove(struct platform_device *dev) struct dma_chan *chan; chan = &mx3_fbi->idmac_channel->dma_chan; + mx3fb_exit_backlight(mx3_fbi); release_fbi(fbi); dma_release_channel(chan); -- 1.5.6.3 |