V4L/DVB: tm6000: README - add vbi
[safe/jmp/linux-2.6] / drivers / video / atmel_lcdfb.c
index 75dac57..8dce251 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/backlight.h>
+#include <linux/gfp.h>
 
 #include <mach/board.h>
 #include <mach/cpu.h>
 
 /* configurable parameters */
 #define ATMEL_LCDC_CVAL_DEFAULT                0xc8
-#define ATMEL_LCDC_DMA_BURST_LEN       8
-
-#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) || \
-       defined(CONFIG_ARCH_AT91SAM9RL)
-#define ATMEL_LCDC_FIFO_SIZE           2048
-#else
-#define ATMEL_LCDC_FIFO_SIZE           512
-#endif
+#define ATMEL_LCDC_DMA_BURST_LEN       8       /* words */
+#define ATMEL_LCDC_FIFO_SIZE           512     /* words */
 
 #if defined(CONFIG_ARCH_AT91)
 #define        ATMEL_LCDFB_FBINFO_DEFAULT      (FBINFO_DEFAULT \
@@ -123,6 +118,7 @@ static struct backlight_ops atmel_lcdc_bl_ops = {
 
 static void init_backlight(struct atmel_lcdfb_info *sinfo)
 {
+       struct backlight_properties props;
        struct backlight_device *bl;
 
        sinfo->bl_power = FB_BLANK_UNBLANK;
@@ -130,9 +126,11 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
        if (sinfo->backlight)
                return;
 
-       bl = backlight_device_register("backlight", &sinfo->pdev->dev,
-                       sinfo, &atmel_lcdc_bl_ops);
-       if (IS_ERR(sinfo->backlight)) {
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 0xff;
+       bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
+                                      &atmel_lcdc_bl_ops, &props);
+       if (IS_ERR(bl)) {
                dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
                                PTR_ERR(bl));
                return;
@@ -141,7 +139,6 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
 
        bl->props.power = FB_BLANK_UNBLANK;
        bl->props.fb_blank = FB_BLANK_UNBLANK;
-       bl->props.max_brightness = 0xff;
        bl->props.brightness = atmel_bl_get_brightness(bl);
 }
 
@@ -188,7 +185,8 @@ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
 {
        unsigned long value;
 
-       if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000()))
+       if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
+               || cpu_is_at32ap7000()))
                return xres;
 
        value = xres;
@@ -267,6 +265,9 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
 /**
  *     atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
  *     @sinfo: the frame buffer to allocate memory for
+ *     
+ *     This function is called only from the atmel_lcdfb_probe()
+ *     so no locking by fb_info->mm_lock around smem_len setting is needed.
  */
 static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
 {
@@ -351,7 +352,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
        dev_dbg(dev, "  bpp:        %u\n", var->bits_per_pixel);
        dev_dbg(dev, "  clk:        %lu KHz\n", clk_value_khz);
 
-       if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) {
+       if (PICOS2KHZ(var->pixclock) > clk_value_khz) {
                dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
                return -EINVAL;
        }
@@ -372,6 +373,13 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
        var->transp.offset = var->transp.length = 0;
        var->xoffset = var->yoffset = 0;
 
+       if (info->fix.smem_len) {
+               unsigned int smem_len = (var->xres_virtual * var->yres_virtual
+                                        * ((var->bits_per_pixel + 7) / 8));
+               if (smem_len > info->fix.smem_len)
+                       return -EINVAL;
+       }
+
        /* Saturate vertical and horizontal timings at maximum values */
        var->vsync_len = min_t(u32, var->vsync_len,
                        (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
@@ -408,6 +416,10 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
                        var->red.offset = 11;
                        var->blue.offset = 0;
                        var->green.length = 6;
+               } else if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB555) {
+                       var->red.offset = 10;
+                       var->blue.offset = 0;
+                       var->green.length = 5;
                } else {
                        /* BGR:555 mode */
                        var->red.offset = 0;
@@ -475,6 +487,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
        unsigned long value;
        unsigned long clk_value_khz;
        unsigned long bits_per_line;
+       unsigned long pix_factor = 2;
 
        might_sleep();
 
@@ -507,20 +520,24 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
        /* Now, the LCDC core... */
 
        /* Set pixel clock */
+       if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
+               pix_factor = 1;
+
        clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
 
        value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
 
-       if (value < 2) {
+       if (value < pix_factor) {
                dev_notice(info->device, "Bypassing pixel clock divider\n");
                lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
        } else {
-               value = (value / 2) - 1;
+               value = (value / pix_factor) - 1;
                dev_dbg(info->device, "  * programming CLKVAL = 0x%08lx\n",
                                value);
                lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
                                value << ATMEL_LCDC_CLKVAL_OFFSET);
-               info->var.pixclock = KHZ2PICOS(clk_value_khz / (2 * (value + 1)));
+               info->var.pixclock =
+                       KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
                dev_dbg(info->device, "  updated pixclk:     %lu KHz\n",
                                        PICOS2KHZ(info->var.pixclock));
        }
@@ -816,7 +833,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
        info->fix = atmel_lcdfb_fix;
 
        /* Enable LCDC Clocks */
-       if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) {
+       if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()
+        || cpu_is_at32ap7000()) {
                sinfo->bus_clk = clk_get(dev, "hck1");
                if (IS_ERR(sinfo->bus_clk)) {
                        ret = PTR_ERR(sinfo->bus_clk);
@@ -949,7 +967,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
        if (sinfo->atmel_lcdfb_power_control)
                sinfo->atmel_lcdfb_power_control(1);
 
-       dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n",
+       dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
                       info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
 
        return 0;