fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / video / pxafb.c
index 0c86ff9..b4947c8 100644 (file)
@@ -22,7 +22,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/cpufreq.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/mach-types.h>
 #include <asm/uaccess.h>
+#include <asm/div64.h>
+#include <asm/arch/pxa-regs.h>
 #include <asm/arch/bitfield.h>
 #include <asm/arch/pxafb.h>
 
@@ -59,7 +59,7 @@
 #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);
+static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
 
 static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
 static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
@@ -109,10 +109,13 @@ pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
        u_int val, ret = 1;
 
        if (regno < fbi->palette_size) {
-               val  = ((red   >>  0) & 0xf800);
-               val |= ((green >>  5) & 0x07e0);
-               val |= ((blue  >> 11) & 0x001f);
-
+               if (fbi->fb.var.grayscale) {
+                       val = ((blue >> 8) & 0x00ff);
+               } else {
+                       val  = ((red   >>  0) & 0xf800);
+                       val |= ((green >>  5) & 0x07e0);
+                       val |= ((blue  >> 11) & 0x001f);
+               }
                fbi->palette_cpu[regno] = val;
                ret = 0;
        }
@@ -150,7 +153,7 @@ pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        switch (fbi->fb.fix.visual) {
        case FB_VISUAL_TRUECOLOR:
                /*
-                * 12 or 16-bit True Colour.  We encode the RGB value
+                * 16-bit True Colour.  We encode the RGB value
                 * according to the RGB bitfield information.
                 */
                if (regno < 16) {
@@ -210,6 +213,48 @@ static unsigned int pxafb_display_dma_period(struct fb_var_screeninfo *var)
 extern unsigned int get_clk_frequency_khz(int info);
 #endif
 
+/*
+ * Select the smallest mode that allows the desired resolution to be
+ * displayed. If desired parameters can be rounded up.
+ */
+static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, struct fb_var_screeninfo *var)
+{
+       struct pxafb_mode_info *mode = NULL;
+       struct pxafb_mode_info *modelist = mach->modes;
+       unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
+       unsigned int i;
+
+       for (i = 0 ; i < mach->num_modes ; i++) {
+               if (modelist[i].xres >= var->xres && modelist[i].yres >= var->yres &&
+                               modelist[i].xres < best_x && modelist[i].yres < best_y &&
+                               modelist[i].bpp >= var->bits_per_pixel ) {
+                       best_x = modelist[i].xres;
+                       best_y = modelist[i].yres;
+                       mode = &modelist[i];
+               }
+       }
+
+       return mode;
+}
+
+static void pxafb_setmode(struct fb_var_screeninfo *var, struct pxafb_mode_info *mode)
+{
+       var->xres               = mode->xres;
+       var->yres               = mode->yres;
+       var->bits_per_pixel     = mode->bpp;
+       var->pixclock           = mode->pixclock;
+       var->hsync_len          = mode->hsync_len;
+       var->left_margin        = mode->left_margin;
+       var->right_margin       = mode->right_margin;
+       var->vsync_len          = mode->vsync_len;
+       var->upper_margin       = mode->upper_margin;
+       var->lower_margin       = mode->lower_margin;
+       var->sync               = mode->sync;
+       var->grayscale          = mode->cmap_greyscale;
+       var->xres_virtual       = var->xres;
+       var->yres_virtual       = var->yres;
+}
+
 /*
  *  pxafb_check_var():
  *    Get the video params out of 'var'. If a value doesn't fit, round it up,
@@ -222,15 +267,29 @@ extern unsigned int get_clk_frequency_khz(int info);
 static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
        struct pxafb_info *fbi = (struct pxafb_info *)info;
+       struct pxafb_mach_info *inf = fbi->dev->platform_data;
 
        if (var->xres < MIN_XRES)
                var->xres = MIN_XRES;
        if (var->yres < MIN_YRES)
                var->yres = MIN_YRES;
-       if (var->xres > fbi->max_xres)
-               var->xres = fbi->max_xres;
-       if (var->yres > fbi->max_yres)
-               var->yres = fbi->max_yres;
+
+       if (inf->fixed_modes) {
+               struct pxafb_mode_info *mode;
+
+               mode = pxafb_getmode(inf, var);
+               if (!mode)
+                       return -EINVAL;
+               pxafb_setmode(var, mode);
+       } else {
+               if (var->xres > inf->modes->xres)
+                       return -EINVAL;
+               if (var->yres > inf->modes->yres)
+                       return -EINVAL;
+               if (var->bits_per_pixel > inf->modes->bpp)
+                       return -EINVAL;
+       }
+
        var->xres_virtual =
                max(var->xres_virtual, var->xres);
        var->yres_virtual =
@@ -242,7 +301,7 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
         * The pixel packing format is described on page 7-11 of the
         * PXA2XX Developer's Manual.
          */
-       if ( var->bits_per_pixel == 16 ) {
+       if (var->bits_per_pixel == 16) {
                var->red.offset   = 11; var->red.length   = 5;
                var->green.offset = 5;  var->green.length = 6;
                var->blue.offset  = 0;  var->blue.length  = 5;
@@ -256,9 +315,9 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        }
 
 #ifdef CONFIG_CPU_FREQ
-       DPRINTK("dma period = %d ps, clock = %d kHz\n",
-               pxafb_display_dma_period(var),
-               get_clk_frequency_khz(0));
+       pr_debug("pxafb: dma period = %d ps, clock = %d kHz\n",
+                pxafb_display_dma_period(var),
+                get_clk_frequency_khz(0));
 #endif
 
        return 0;
@@ -266,7 +325,7 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 
 static inline void pxafb_set_truecolor(u_int is_true_color)
 {
-       DPRINTK("true_color = %d\n", is_true_color);
+       pr_debug("pxafb: true_color = %d\n", is_true_color);
        // do your machine-specific setup if needed
 }
 
@@ -280,7 +339,7 @@ static int pxafb_set_par(struct fb_info *info)
        struct fb_var_screeninfo *var = &info->var;
        unsigned long palette_mem_size;
 
-       DPRINTK("set_par\n");
+       pr_debug("pxafb: set_par\n");
 
        if (var->bits_per_pixel == 16)
                fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
@@ -297,11 +356,14 @@ static int pxafb_set_par(struct fb_info *info)
 
        fbi->fb.fix.line_length = var->xres_virtual *
                                  var->bits_per_pixel / 8;
-       fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
+       if (var->bits_per_pixel == 16)
+               fbi->palette_size = 0;
+       else
+               fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
 
        palette_mem_size = fbi->palette_size * sizeof(u16);
 
-       DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+       pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
 
        fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
        fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
@@ -311,6 +373,11 @@ static int pxafb_set_par(struct fb_info *info)
         */
        pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
 
+       if (fbi->fb.var.bits_per_pixel == 16)
+               fb_dealloc_cmap(&fbi->fb.cmap);
+       else
+               fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0);
+
        pxafb_activate_var(var, fbi);
 
        return 0;
@@ -349,7 +416,7 @@ static int pxafb_set_par(struct fb_info *info)
 /*
  * pxafb_blank():
  *     Blank the display by setting all palette values to zero.  Note, the
- *     12 and 16 bpp modes don't really use the palette, so this will not
+ *     16 bpp mode does not really use the palette, so this will not
  *      blank the display in all modes.
  */
 static int pxafb_blank(int blank, struct fb_info *info)
@@ -357,12 +424,13 @@ static int pxafb_blank(int blank, struct fb_info *info)
        struct pxafb_info *fbi = (struct pxafb_info *)info;
        int i;
 
-       DPRINTK("pxafb_blank: blank=%d\n", blank);
+       pr_debug("pxafb: blank=%d\n", blank);
 
        switch (blank) {
-       case VESA_POWERDOWN:
-       case VESA_VSYNC_SUSPEND:
-       case VESA_HSYNC_SUSPEND:
+       case FB_BLANK_POWERDOWN:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       case FB_BLANK_NORMAL:
                if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
                    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
                        for (i = 0; i < fbi->palette_size; i++)
@@ -372,16 +440,30 @@ static int pxafb_blank(int blank, struct fb_info *info)
                //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
                break;
 
-       case VESA_NO_BLANKING:
+       case FB_BLANK_UNBLANK:
                //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
                if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
                    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
-                       fb_set_cmap(&fbi->fb.cmap, 1, info);
+                       fb_set_cmap(&fbi->fb.cmap, info);
                pxafb_schedule_work(fbi, C_ENABLE);
        }
        return 0;
 }
 
+static int pxafb_mmap(struct fb_info *info,
+                     struct vm_area_struct *vma)
+{
+       struct pxafb_info *fbi = (struct pxafb_info *)info;
+       unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+
+       if (off < info->fix.smem_len) {
+               vma->vm_pgoff += 1;
+               return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
+                                            fbi->map_dma, fbi->map_size);
+       }
+       return -EINVAL;
+}
+
 static struct fb_ops pxafb_ops = {
        .owner          = THIS_MODULE,
        .fb_check_var   = pxafb_check_var,
@@ -391,7 +473,7 @@ static struct fb_ops pxafb_ops = {
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit   = cfb_imageblit,
        .fb_blank       = pxafb_blank,
-       .fb_cursor      = soft_cursor,
+       .fb_mmap        = pxafb_mmap,
 };
 
 /*
@@ -432,13 +514,43 @@ static inline unsigned int get_pcd(unsigned int pixclock)
          * (DPC) bit? or perhaps set it based on the various clock
          * speeds */
 
-       pcd = (unsigned long long)get_lclk_frequency_10khz() * (unsigned long long)pixclock;
-       pcd /= 100000000 * 2;
+       pcd = (unsigned long long)get_lcdclk_frequency_10khz() * pixclock;
+       do_div(pcd, 100000000 * 2);
        /* no need for this, since we should subtract 1 anyway. they cancel */
        /* pcd += 1; */ /* make up for integer math truncations */
        return (unsigned int)pcd;
 }
 
+/*
+ * Some touchscreens need hsync information from the video driver to
+ * function correctly. We export it here.
+ */
+static inline void set_hsync_time(struct pxafb_info *fbi, unsigned int pcd)
+{
+       unsigned long long htime;
+
+       if ((pcd == 0) || (fbi->fb.var.hsync_len == 0)) {
+               fbi->hsync_time=0;
+               return;
+       }
+
+       htime = (unsigned long long)get_lcdclk_frequency_10khz() * 10000;
+       do_div(htime, pcd * fbi->fb.var.hsync_len);
+       fbi->hsync_time = htime;
+}
+
+unsigned long pxafb_get_hsync_time(struct device *dev)
+{
+       struct pxafb_info *fbi = dev_get_drvdata(dev);
+
+       /* If display is blanked/suspended, hsync isn't active */
+       if (!fbi || (fbi->state != C_ENABLE))
+               return 0;
+
+       return fbi->hsync_time;
+}
+EXPORT_SYMBOL(pxafb_get_hsync_time);
+
 /*
  * pxafb_activate_var():
  *     Configures LCD Controller based on entries in var parameter.  Settings are
@@ -450,15 +562,15 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
        u_long flags;
        u_int lines_per_panel, pcd = get_pcd(var->pixclock);
 
-       DPRINTK("Configuring PXA LCD\n");
+       pr_debug("pxafb: Configuring PXA LCD\n");
 
-       DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
-               var->xres, var->hsync_len,
-               var->left_margin, var->right_margin);
-       DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
-               var->yres, var->vsync_len,
-               var->upper_margin, var->lower_margin);
-       DPRINTK("var: pixclock=%d pcd=%d\n", var->pixclock, pcd);
+       pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
+                var->xres, var->hsync_len,
+                var->left_margin, var->right_margin);
+       pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n",
+                var->yres, var->vsync_len,
+                var->upper_margin, var->lower_margin);
+       pr_debug("var: pixclock=%d pcd=%d\n", var->pixclock, pcd);
 
 #if DEBUG_VAR
        if (var->xres < 16        || var->xres > 1024)
@@ -514,7 +626,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
         * the YRES parameter.
         */
        lines_per_panel = var->yres;
-       if (fbi->lccr0 & LCCR0_SDS)
+       if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual)
                lines_per_panel /= 2;
 
        new_regs.lccr2 =
@@ -531,10 +643,10 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
        if (pcd)
                new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
 
-       DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
-       DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
-       DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2);
-       DPRINTK("nlccr3 = 0x%08x\n", new_regs.lccr3);
+       pr_debug("nlccr0 = 0x%08x\n", new_regs.lccr0);
+       pr_debug("nlccr1 = 0x%08x\n", new_regs.lccr1);
+       pr_debug("nlccr2 = 0x%08x\n", new_regs.lccr2);
+       pr_debug("nlccr3 = 0x%08x\n", new_regs.lccr3);
 
        /* Update shadow copy atomically */
        local_irq_save(flags);
@@ -566,47 +678,44 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
        fbi->dmadesc_palette_cpu->fidr  = 0;
        fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL;
 
-       if( var->bits_per_pixel < 12)
-       {
-               /* assume any mode with <12 bpp is palette driven */
-               fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
-               fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma;
-               fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */
-       }
-       else
-       {
+       if (var->bits_per_pixel == 16) {
                /* palette shouldn't be loaded in true-color mode */
                fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
                fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
                /* init it to something, even though we won't be using it */
                fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_palette_dma;
+       } else {
+               fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
+               fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma;
+               fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */
        }
 
 #if 0
-       DPRINTK("fbi->dmadesc_fblow_cpu = 0x%p\n", fbi->dmadesc_fblow_cpu);
-       DPRINTK("fbi->dmadesc_fbhigh_cpu = 0x%p\n", fbi->dmadesc_fbhigh_cpu);
-       DPRINTK("fbi->dmadesc_palette_cpu = 0x%p\n", fbi->dmadesc_palette_cpu);
-       DPRINTK("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma);
-       DPRINTK("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma);
-       DPRINTK("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma);
-
-       DPRINTK("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr);
-       DPRINTK("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr);
-       DPRINTK("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr);
-
-       DPRINTK("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr);
-       DPRINTK("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr);
-       DPRINTK("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr);
-
-       DPRINTK("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd);
-       DPRINTK("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd);
-       DPRINTK("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd);
+       pr_debug("fbi->dmadesc_fblow_cpu = 0x%p\n", fbi->dmadesc_fblow_cpu);
+       pr_debug("fbi->dmadesc_fbhigh_cpu = 0x%p\n", fbi->dmadesc_fbhigh_cpu);
+       pr_debug("fbi->dmadesc_palette_cpu = 0x%p\n", fbi->dmadesc_palette_cpu);
+       pr_debug("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma);
+       pr_debug("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma);
+       pr_debug("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma);
+
+       pr_debug("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr);
+       pr_debug("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr);
+       pr_debug("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr);
+
+       pr_debug("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr);
+       pr_debug("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr);
+       pr_debug("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr);
+
+       pr_debug("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd);
+       pr_debug("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd);
+       pr_debug("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd);
 #endif
 
        fbi->reg_lccr0 = new_regs.lccr0;
        fbi->reg_lccr1 = new_regs.lccr1;
        fbi->reg_lccr2 = new_regs.lccr2;
        fbi->reg_lccr3 = new_regs.lccr3;
+       set_hsync_time(fbi, pcd);
        local_irq_restore(flags);
 
        /*
@@ -629,7 +738,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
  */
 static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on)
 {
-       DPRINTK("backlight o%s\n", on ? "n" : "ff");
+       pr_debug("pxafb: backlight o%s\n", on ? "n" : "ff");
 
        if (pxafb_backlight_power)
                pxafb_backlight_power(on);
@@ -637,14 +746,15 @@ static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on)
 
 static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
 {
-       DPRINTK("LCD power o%s\n", on ? "n" : "ff");
+       pr_debug("pxafb: LCD power o%s\n", on ? "n" : "ff");
 
        if (pxafb_lcd_power)
-               pxafb_lcd_power(on);
+               pxafb_lcd_power(on, &fbi->fb.var);
 }
 
 static void pxafb_setup_gpio(struct pxafb_info *fbi)
 {
+       int gpio, ldd_bits;
         unsigned int lccr0 = fbi->lccr0;
 
        /*
@@ -655,60 +765,45 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi)
        if ((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
            (lccr0 & LCCR0_SDS) == LCCR0_Sngl &&
            (lccr0 & LCCR0_DPD) == LCCR0_4PixMono)
-       {
-               // bits 58-61
-               GPDR1 |= (0xf << 26);
-               GAFR1_U = (GAFR1_U & ~(0xff << 20)) | (0xaa << 20);
-
-               // bits 74-77
-               GPDR2 |= (0xf << 10);
-               GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
-       }
+               ldd_bits = 4;
 
        /* 8 bit interface */
         else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
                  ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
                  ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
                  (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
-       {
-               // bits 58-65
-               GPDR1 |= (0x3f << 26);
-               GPDR2 |= (0x3);
-
-               GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
-               GAFR2_L = (GAFR2_L & ~0xf) | (0xa);
-
-               // bits 74-77
-               GPDR2 |= (0xf << 10);
-               GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
-       }
+               ldd_bits = 8;
 
        /* 16 bit interface */
        else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
                 ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act))
-       {
-               // bits 58-77
-               GPDR1 |= (0x3f << 26);
-               GPDR2 |= 0x00003fff;
-
-               GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
-               GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
-       }
+               ldd_bits = 16;
 
        else {
-               printk( KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
+               printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
+               return;
         }
+
+       for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
+               pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
+       pxa_gpio_mode(GPIO74_LCD_FCLK_MD);
+       pxa_gpio_mode(GPIO75_LCD_LCLK_MD);
+       pxa_gpio_mode(GPIO76_LCD_PCLK_MD);
+       pxa_gpio_mode(GPIO77_LCD_ACBIAS_MD);
 }
 
 static void pxafb_enable_controller(struct pxafb_info *fbi)
 {
-       DPRINTK("Enabling LCD controller\n");
-       DPRINTK("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr0);
-       DPRINTK("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr1);
-       DPRINTK("reg_lccr0 0x%08x\n", (unsigned int) fbi->reg_lccr0);
-       DPRINTK("reg_lccr1 0x%08x\n", (unsigned int) fbi->reg_lccr1);
-       DPRINTK("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2);
-       DPRINTK("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
+       pr_debug("pxafb: Enabling LCD controller\n");
+       pr_debug("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr0);
+       pr_debug("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr1);
+       pr_debug("reg_lccr0 0x%08x\n", (unsigned int) fbi->reg_lccr0);
+       pr_debug("reg_lccr1 0x%08x\n", (unsigned int) fbi->reg_lccr1);
+       pr_debug("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2);
+       pr_debug("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
+
+       /* enable LCD controller clock */
+       pxa_set_cken(CKEN16_LCD, 1);
 
        /* Sequence from 11.7.10 */
        LCCR3 = fbi->reg_lccr3;
@@ -720,35 +815,38 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
        FDADR1 = fbi->fdadr1;
        LCCR0 |= LCCR0_ENB;
 
-       DPRINTK("FDADR0 0x%08x\n", (unsigned int) FDADR0);
-       DPRINTK("FDADR1 0x%08x\n", (unsigned int) FDADR1);
-       DPRINTK("LCCR0 0x%08x\n", (unsigned int) LCCR0);
-       DPRINTK("LCCR1 0x%08x\n", (unsigned int) LCCR1);
-       DPRINTK("LCCR2 0x%08x\n", (unsigned int) LCCR2);
-       DPRINTK("LCCR3 0x%08x\n", (unsigned int) LCCR3);
+       pr_debug("FDADR0 0x%08x\n", (unsigned int) FDADR0);
+       pr_debug("FDADR1 0x%08x\n", (unsigned int) FDADR1);
+       pr_debug("LCCR0 0x%08x\n", (unsigned int) LCCR0);
+       pr_debug("LCCR1 0x%08x\n", (unsigned int) LCCR1);
+       pr_debug("LCCR2 0x%08x\n", (unsigned int) LCCR2);
+       pr_debug("LCCR3 0x%08x\n", (unsigned int) LCCR3);
 }
 
 static void pxafb_disable_controller(struct pxafb_info *fbi)
 {
        DECLARE_WAITQUEUE(wait, current);
 
-       DPRINTK("Disabling LCD controller\n");
+       pr_debug("pxafb: disabling LCD controller\n");
 
-       add_wait_queue(&fbi->ctrlr_wait, &wait);
        set_current_state(TASK_UNINTERRUPTIBLE);
+       add_wait_queue(&fbi->ctrlr_wait, &wait);
 
        LCSR = 0xffffffff;      /* Clear LCD Status Register */
        LCCR0 &= ~LCCR0_LDM;    /* Enable LCD Disable Done Interrupt */
        LCCR0 |= LCCR0_DIS;     /* Disable LCD Controller */
 
-       schedule_timeout(20 * HZ / 1000);
+       schedule_timeout(200 * HZ / 1000);
        remove_wait_queue(&fbi->ctrlr_wait, &wait);
+
+       /* disable LCD controller clock */
+       pxa_set_cken(CKEN16_LCD, 0);
 }
 
 /*
  *  pxafb_handle_irq: Handle 'LCD DONE' interrupts.
  */
-static irqreturn_t pxafb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pxafb_handle_irq(int irq, void *dev_id)
 {
        struct pxafb_info *fbi = dev_id;
        unsigned int lcsr = LCSR;
@@ -827,9 +925,11 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
                 * registers.
                 */
                if (old_state == C_ENABLE) {
+                       __pxafb_lcd_power(fbi, 0);
                        pxafb_disable_controller(fbi);
                        pxafb_setup_gpio(fbi);
                        pxafb_enable_controller(fbi);
+                       __pxafb_lcd_power(fbi, 1);
                }
                break;
 
@@ -864,9 +964,10 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
  * Our LCD controller task (which is called when we blank or unblank)
  * via keventd.
  */
-static void pxafb_task(void *dummy)
+static void pxafb_task(struct work_struct *work)
 {
-       struct pxafb_info *fbi = dummy;
+       struct pxafb_info *fbi =
+               container_of(work, struct pxafb_info, task);
        u_int state = xchg(&fbi->task_state, -1);
 
        set_ctrlr_state(fbi, state);
@@ -894,6 +995,7 @@ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
 
        case CPUFREQ_POSTCHANGE:
                pcd = get_pcd(fbi->fb.var.pixclock);
+               set_hsync_time(fbi, pcd);
                fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
                set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
                break;
@@ -936,21 +1038,19 @@ pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data)
  * Power management hooks.  Note that we won't be called from IRQ context,
  * unlike the blank functions above, so we may sleep.
  */
-static int pxafb_suspend(struct device *dev, u32 state, u32 level)
+static int pxafb_suspend(struct platform_device *dev, pm_message_t state)
 {
-       struct pxafb_info *fbi = dev_get_drvdata(dev);
+       struct pxafb_info *fbi = platform_get_drvdata(dev);
 
-       if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN)
-               set_ctrlr_state(fbi, C_DISABLE_PM);
+       set_ctrlr_state(fbi, C_DISABLE_PM);
        return 0;
 }
 
-static int pxafb_resume(struct device *dev, u32 level)
+static int pxafb_resume(struct platform_device *dev)
 {
-       struct pxafb_info *fbi = dev_get_drvdata(dev);
+       struct pxafb_info *fbi = platform_get_drvdata(dev);
 
-       if (level == RESUME_ENABLE)
-               set_ctrlr_state(fbi, C_ENABLE_PM);
+       set_ctrlr_state(fbi, C_ENABLE_PM);
        return 0;
 }
 #else
@@ -994,7 +1094,7 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
                fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
 
                palette_mem_size = fbi->palette_size * sizeof(u16);
-               DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+               pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
 
                fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
                fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
@@ -1008,9 +1108,11 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
        struct pxafb_info *fbi;
        void *addr;
        struct pxafb_mach_info *inf = dev->platform_data;
+       struct pxafb_mode_info *mode = inf->modes;
+       int i, smemlen;
 
        /* Alloc the pxafb_info and pseudo_palette in one step */
-       fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 17, GFP_KERNEL);
+       fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
        if (!fbi)
                return NULL;
 
@@ -1034,42 +1136,31 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
        fbi->fb.var.vmode       = FB_VMODE_NONINTERLACED;
 
        fbi->fb.fbops           = &pxafb_ops;
-       fbi->fb.flags           = FBINFO_FLAG_DEFAULT;
+       fbi->fb.flags           = FBINFO_DEFAULT;
        fbi->fb.node            = -1;
-       fbi->fb.currcon         = -1;
 
        addr = fbi;
        addr = addr + sizeof(struct pxafb_info);
        fbi->fb.pseudo_palette  = addr;
 
-       fbi->max_xres                   = inf->xres;
-       fbi->fb.var.xres                = inf->xres;
-       fbi->fb.var.xres_virtual        = inf->xres;
-       fbi->max_yres                   = inf->yres;
-       fbi->fb.var.yres                = inf->yres;
-       fbi->fb.var.yres_virtual        = inf->yres;
-       fbi->max_bpp                    = inf->bpp;
-       fbi->fb.var.bits_per_pixel      = inf->bpp;
-       fbi->fb.var.pixclock            = inf->pixclock;
-       fbi->fb.var.hsync_len           = inf->hsync_len;
-       fbi->fb.var.left_margin         = inf->left_margin;
-       fbi->fb.var.right_margin        = inf->right_margin;
-       fbi->fb.var.vsync_len           = inf->vsync_len;
-       fbi->fb.var.upper_margin        = inf->upper_margin;
-       fbi->fb.var.lower_margin        = inf->lower_margin;
-       fbi->fb.var.sync                = inf->sync;
-       fbi->fb.var.grayscale           = inf->cmap_greyscale;
+       pxafb_setmode(&fbi->fb.var, mode);
+
        fbi->cmap_inverse               = inf->cmap_inverse;
        fbi->cmap_static                = inf->cmap_static;
+
        fbi->lccr0                      = inf->lccr0;
        fbi->lccr3                      = inf->lccr3;
        fbi->state                      = C_STARTUP;
        fbi->task_state                 = (u_char)-1;
-       fbi->fb.fix.smem_len            = fbi->max_xres * fbi->max_yres *
-                                         fbi->max_bpp / 8;
+
+       for (i = 0; i < inf->num_modes; i++) {
+               smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
+               if (smemlen > fbi->fb.fix.smem_len)
+                       fbi->fb.fix.smem_len = smemlen;
+       }
 
        init_waitqueue_head(&fbi->ctrlr_wait);
-       INIT_WORK(&fbi->task, pxafb_task, fbi);
+       INIT_WORK(&fbi->task, pxafb_task);
        init_MUTEX(&fbi->ctrlr_sem);
 
        return fbi;
@@ -1123,62 +1214,62 @@ static int __init pxafb_parse_options(struct device *dev, char *options)
                                res_specified = 1;
                        }
                done:
-                       if ( res_specified ) {
-                               dev_info(dev, "overriding resolution: %dx%x\n", xres, yres);
-                               inf->xres = xres; inf->yres = yres;
+                       if (res_specified) {
+                               dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
+                               inf->modes[0].xres = xres; inf->modes[0].yres = yres;
                        }
-                       if ( bpp_specified )
+                       if (bpp_specified)
                                switch (bpp) {
                                case 1:
                                case 2:
                                case 4:
                                case 8:
                                case 16:
-                                       inf->bpp = bpp;
+                                       inf->modes[0].bpp = bpp;
                                        dev_info(dev, "overriding bit depth: %d\n", bpp);
                                        break;
                                default:
                                        dev_err(dev, "Depth %d is not valid\n", bpp);
                                }
                 } else if (!strncmp(this_opt, "pixclock:", 9)) {
-                        inf->pixclock = simple_strtoul(this_opt+9, NULL, 0);
-                       dev_info(dev, "override pixclock: %u\n", inf->pixclock);
+                        inf->modes[0].pixclock = simple_strtoul(this_opt+9, NULL, 0);
+                       dev_info(dev, "override pixclock: %ld\n", inf->modes[0].pixclock);
                 } else if (!strncmp(this_opt, "left:", 5)) {
-                        inf->left_margin = simple_strtoul(this_opt+5, NULL, 0);
-                       dev_info(dev, "override left: %u\n", inf->left_margin);
+                        inf->modes[0].left_margin = simple_strtoul(this_opt+5, NULL, 0);
+                       dev_info(dev, "override left: %u\n", inf->modes[0].left_margin);
                 } else if (!strncmp(this_opt, "right:", 6)) {
-                        inf->right_margin = simple_strtoul(this_opt+6, NULL, 0);
-                       dev_info(dev, "override right: %u\n", inf->right_margin);
+                        inf->modes[0].right_margin = simple_strtoul(this_opt+6, NULL, 0);
+                       dev_info(dev, "override right: %u\n", inf->modes[0].right_margin);
                 } else if (!strncmp(this_opt, "upper:", 6)) {
-                        inf->upper_margin = simple_strtoul(this_opt+6, NULL, 0);
-                       dev_info(dev, "override upper: %u\n", inf->upper_margin);
+                        inf->modes[0].upper_margin = simple_strtoul(this_opt+6, NULL, 0);
+                       dev_info(dev, "override upper: %u\n", inf->modes[0].upper_margin);
                 } else if (!strncmp(this_opt, "lower:", 6)) {
-                        inf->lower_margin = simple_strtoul(this_opt+6, NULL, 0);
-                       dev_info(dev, "override lower: %u\n", inf->lower_margin);
+                        inf->modes[0].lower_margin = simple_strtoul(this_opt+6, NULL, 0);
+                       dev_info(dev, "override lower: %u\n", inf->modes[0].lower_margin);
                 } else if (!strncmp(this_opt, "hsynclen:", 9)) {
-                        inf->hsync_len = simple_strtoul(this_opt+9, NULL, 0);
-                       dev_info(dev, "override hsynclen: %u\n", inf->hsync_len);
+                        inf->modes[0].hsync_len = simple_strtoul(this_opt+9, NULL, 0);
+                       dev_info(dev, "override hsynclen: %u\n", inf->modes[0].hsync_len);
                 } else if (!strncmp(this_opt, "vsynclen:", 9)) {
-                        inf->vsync_len = simple_strtoul(this_opt+9, NULL, 0);
-                       dev_info(dev, "override vsynclen: %u\n", inf->vsync_len);
+                        inf->modes[0].vsync_len = simple_strtoul(this_opt+9, NULL, 0);
+                       dev_info(dev, "override vsynclen: %u\n", inf->modes[0].vsync_len);
                 } else if (!strncmp(this_opt, "hsync:", 6)) {
-                        if ( simple_strtoul(this_opt+6, NULL, 0) == 0 ) {
+                        if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
                                dev_info(dev, "override hsync: Active Low\n");
-                               inf->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+                               inf->modes[0].sync &= ~FB_SYNC_HOR_HIGH_ACT;
                        } else {
                                dev_info(dev, "override hsync: Active High\n");
-                               inf->sync |= FB_SYNC_HOR_HIGH_ACT;
+                               inf->modes[0].sync |= FB_SYNC_HOR_HIGH_ACT;
                        }
                 } else if (!strncmp(this_opt, "vsync:", 6)) {
-                        if ( simple_strtoul(this_opt+6, NULL, 0) == 0 ) {
+                        if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
                                dev_info(dev, "override vsync: Active Low\n");
-                               inf->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+                               inf->modes[0].sync &= ~FB_SYNC_VERT_HIGH_ACT;
                        } else {
                                dev_info(dev, "override vsync: Active High\n");
-                               inf->sync |= FB_SYNC_VERT_HIGH_ACT;
+                               inf->modes[0].sync |= FB_SYNC_VERT_HIGH_ACT;
                        }
                 } else if (!strncmp(this_opt, "dpc:", 4)) {
-                        if ( simple_strtoul(this_opt+4, NULL, 0) == 0 ) {
+                        if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
                                dev_info(dev, "override double pixel clock: false\n");
                                inf->lccr3 &= ~LCCR3_DPC;
                        } else {
@@ -1186,20 +1277,20 @@ static int __init pxafb_parse_options(struct device *dev, char *options)
                                inf->lccr3 |= LCCR3_DPC;
                        }
                 } else if (!strncmp(this_opt, "outputen:", 9)) {
-                        if ( simple_strtoul(this_opt+9, NULL, 0) == 0 ) {
+                        if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
                                dev_info(dev, "override output enable: active low\n");
-                               inf->lccr3 = ( inf->lccr3 & ~LCCR3_OEP ) | LCCR3_OutEnL;
+                               inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
                        } else {
                                dev_info(dev, "override output enable: active high\n");
-                               inf->lccr3 = ( inf->lccr3 & ~LCCR3_OEP ) | LCCR3_OutEnH;
+                               inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
                        }
                 } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
-                        if ( simple_strtoul(this_opt+12, NULL, 0) == 0 ) {
+                        if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
                                dev_info(dev, "override pixel clock polarity: falling edge\n");
-                               inf->lccr3 = ( inf->lccr3 & ~LCCR3_PCP ) | LCCR3_PixFlEdg;
+                               inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
                        } else {
                                dev_info(dev, "override pixel clock polarity: rising edge\n");
-                               inf->lccr3 = ( inf->lccr3 & ~LCCR3_PCP ) | LCCR3_PixRsEdg;
+                               inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
                        }
                 } else if (!strncmp(this_opt, "color", 5)) {
                        inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
@@ -1227,24 +1318,23 @@ static int __init pxafb_parse_options(struct device *dev, char *options)
 }
 #endif
 
-int __init pxafb_probe(struct device *dev)
+int __init pxafb_probe(struct platform_device *dev)
 {
        struct pxafb_info *fbi;
        struct pxafb_mach_info *inf;
-       unsigned long flags;
        int ret;
 
-       dev_dbg(dev, "pxafb_probe\n");
+       dev_dbg(&dev->dev, "pxafb_probe\n");
 
-       inf = dev->platform_data;
+       inf = dev->dev.platform_data;
        ret = -ENOMEM;
        fbi = NULL;
        if (!inf)
                goto failed;
 
 #ifdef CONFIG_FB_PXA_PARAMETERS
-       ret = pxafb_parse_options(dev, g_options);
-       if ( ret < 0 )
+       ret = pxafb_parse_options(&dev->dev, g_options);
+       if (ret < 0)
                goto failed;
 #endif
 
@@ -1252,37 +1342,37 @@ int __init pxafb_probe(struct device *dev)
         /* Check for various illegal bit-combinations. Currently only
         * a warning is given. */
 
-        if ( inf->lccr0 & LCCR0_INVALID_CONFIG_MASK )
-                dev_warn(dev, "machine LCCR0 setting contains illegal bits: %08x\n",
+        if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
+                dev_warn(&dev->dev, "machine LCCR0 setting contains illegal bits: %08x\n",
                         inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
-        if ( inf->lccr3 & LCCR3_INVALID_CONFIG_MASK )
-                dev_warn(dev, "machine LCCR3 setting contains illegal bits: %08x\n",
+        if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
+                dev_warn(&dev->dev, "machine LCCR3 setting contains illegal bits: %08x\n",
                         inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
-        if ( inf->lccr0 & LCCR0_DPD &&
-             ( ( inf->lccr0 & LCCR0_PAS ) != LCCR0_Pas ||
-               ( inf->lccr0 & LCCR0_SDS ) != LCCR0_Sngl ||
-               ( inf->lccr0 & LCCR0_CMS ) != LCCR0_Mono ) )
-                dev_warn(dev, "Double Pixel Data (DPD) mode is only valid in passive mono"
+        if (inf->lccr0 & LCCR0_DPD &&
+           ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
+            (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
+            (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono))
+                dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is only valid in passive mono"
                         " single panel mode\n");
-        if ( (inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
-             ( inf->lccr0 & LCCR0_SDS ) == LCCR0_Dual )
-                dev_warn(dev, "Dual panel only valid in passive mode\n");
-        if ( (inf->lccr0 & LCCR0_PAS ) == LCCR0_Pas &&
-             (inf->upper_margin || inf->lower_margin) )
-                dev_warn(dev, "Upper and lower margins must be 0 in passive mode\n");
+        if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
+           (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
+                dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
+        if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
+             (inf->modes->upper_margin || inf->modes->lower_margin))
+                dev_warn(&dev->dev, "Upper and lower margins must be 0 in passive mode\n");
 #endif
 
-       dev_dbg(dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp);
-       if (inf->xres == 0 || inf->yres == 0 || inf->bpp == 0) {
-               dev_err(dev, "Invalid resolution or bit depth\n");
+       dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->modes->xres, inf->modes->yres, inf->modes->bpp);
+       if (inf->modes->xres == 0 || inf->modes->yres == 0 || inf->modes->bpp == 0) {
+               dev_err(&dev->dev, "Invalid resolution or bit depth\n");
                ret = -EINVAL;
                goto failed;
        }
        pxafb_backlight_power = inf->pxafb_backlight_power;
        pxafb_lcd_power = inf->pxafb_lcd_power;
-       fbi = pxafb_init_fbinfo(dev);
+       fbi = pxafb_init_fbinfo(&dev->dev);
        if (!fbi) {
-               dev_err(dev, "Failed to initialize framebuffer device\n");
+               dev_err(&dev->dev, "Failed to initialize framebuffer device\n");
                ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
                goto failed;
        }
@@ -1290,18 +1380,14 @@ int __init pxafb_probe(struct device *dev)
        /* Initialize video memory */
        ret = pxafb_map_video_memory(fbi);
        if (ret) {
-               dev_err(dev, "Failed to allocate video RAM: %d\n", ret);
+               dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret);
                ret = -ENOMEM;
                goto failed;
        }
-       /* enable LCD controller clock */
-       local_irq_save(flags);
-       CKEN |= CKEN16_LCD;
-       local_irq_restore(flags);
 
-       ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, "LCD", fbi);
+       ret = request_irq(IRQ_LCD, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi);
        if (ret) {
-               dev_err(dev, "request_irq failed: %d\n", ret);
+               dev_err(&dev->dev, "request_irq failed: %d\n", ret);
                ret = -EBUSY;
                goto failed;
        }
@@ -1313,11 +1399,11 @@ int __init pxafb_probe(struct device *dev)
        pxafb_check_var(&fbi->fb.var, &fbi->fb);
        pxafb_set_par(&fbi->fb);
 
-       dev_set_drvdata(dev, fbi);
+       platform_set_drvdata(dev, fbi);
 
        ret = register_framebuffer(&fbi->fb);
        if (ret < 0) {
-               dev_err(dev, "Failed to register framebuffer device: %d\n", ret);
+               dev_err(&dev->dev, "Failed to register framebuffer device: %d\n", ret);
                goto failed;
        }
 
@@ -1340,42 +1426,51 @@ int __init pxafb_probe(struct device *dev)
        return 0;
 
 failed:
-       dev_set_drvdata(dev, NULL);
-       if (fbi)
-               kfree(fbi);
+       platform_set_drvdata(dev, NULL);
+       kfree(fbi);
        return ret;
 }
 
-static struct device_driver pxafb_driver = {
-       .name           = "pxafb",
-       .bus            = &platform_bus_type,
+static struct platform_driver pxafb_driver = {
        .probe          = pxafb_probe,
 #ifdef CONFIG_PM
        .suspend        = pxafb_suspend,
        .resume         = pxafb_resume,
 #endif
+       .driver         = {
+               .name   = "pxa2xx-fb",
+       },
 };
 
-int __devinit pxafb_init(void)
-{
-       return driver_register(&pxafb_driver);
-}
-
 #ifndef MODULE
 int __devinit pxafb_setup(char *options)
 {
 # ifdef CONFIG_FB_PXA_PARAMETERS
-       strlcpy(g_options, options, sizeof(g_options));
+       if (options)
+               strlcpy(g_options, options, sizeof(g_options));
 # endif
        return 0;
 }
 #else
-module_init(pxafb_init);
 # ifdef CONFIG_FB_PXA_PARAMETERS
 module_param_string(options, g_options, sizeof(g_options), 0);
 MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
 # endif
 #endif
 
+int __devinit pxafb_init(void)
+{
+#ifndef MODULE
+       char *option = NULL;
+
+       if (fb_get_options("pxafb", &option))
+               return -ENODEV;
+       pxafb_setup(option);
+#endif
+       return platform_driver_register(&pxafb_driver);
+}
+
+module_init(pxafb_init);
+
 MODULE_DESCRIPTION("loadable framebuffer driver for PXA");
 MODULE_LICENSE("GPL");