fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / arm / mach-integrator / impd1.c
index e776e8a..92d79fb 100644 (file)
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
 
 #include <asm/io.h>
 #include <asm/hardware/icst525.h>
-#include <asm/hardware/amba.h>
 #include <asm/arch/lm.h>
 #include <asm/arch/impd1.h>
 #include <asm/sizes.h>
@@ -33,7 +35,7 @@ module_param_named(lmid, module_id, int, 0444);
 MODULE_PARM_DESC(lmid, "logic module stack position");
 
 struct impd1_module {
-       void            *base;
+       void __iomem    *base;
        struct clk      vcos[2];
 };
 
@@ -65,7 +67,7 @@ static void impd1_setvco(struct clk *clk, struct icst525_vco vco)
        }
        writel(0, impd1->base + IMPD1_LOCK);
 
-#if DEBUG
+#ifdef DEBUG
        vco.v = val & 0x1ff;
        vco.r = (val >> 9) & 0x7f;
        vco.s = (val >> 16) & 7;
@@ -87,10 +89,210 @@ void impd1_tweak_control(struct device *dev, u32 mask, u32 val)
 
 EXPORT_SYMBOL(impd1_tweak_control);
 
+/*
+ * CLCD support
+ */
+#define PANEL          PROSPECTOR
+
+#define LTM10C209              1
+#define PROSPECTOR             2
+#define SVGA                   3
+#define VGA                    4
+
+#if PANEL == VGA
+#define PANELTYPE      vga
+static struct clcd_panel vga = {
+       .mode           = {
+               .name           = "VGA",
+               .refresh        = 60,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = 39721,
+               .left_margin    = 40,
+               .right_margin   = 24,
+               .upper_margin   = 32,
+               .lower_margin   = 11,
+               .hsync_len      = 96,
+               .vsync_len      = 2,
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+       .width          = -1,
+       .height         = -1,
+       .tim2           = TIM2_BCD | TIM2_IPC,
+       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+       .connector      = IMPD1_CTRL_DISP_VGA,
+       .bpp            = 16,
+       .grayscale      = 0,
+};
+
+#elif PANEL == SVGA
+#define PANELTYPE      svga
+static struct clcd_panel svga = {
+       .mode           = {
+               .name           = "SVGA",
+               .refresh        = 0,
+               .xres           = 800,
+               .yres           = 600,
+               .pixclock       = 27778,
+               .left_margin    = 20,
+               .right_margin   = 20,
+               .upper_margin   = 5,
+               .lower_margin   = 5,
+               .hsync_len      = 164,
+               .vsync_len      = 62,
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+       .width          = -1,
+       .height         = -1,
+       .tim2           = TIM2_BCD,
+       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+       .connector      = IMPD1_CTRL_DISP_VGA,
+       .bpp            = 16,
+       .grayscale      = 0,
+};
+
+#elif PANEL == PROSPECTOR
+#define PANELTYPE      prospector
+static struct clcd_panel prospector = {
+       .mode           = {
+               .name           = "PROSPECTOR",
+               .refresh        = 0,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = 40000,
+               .left_margin    = 33,
+               .right_margin   = 64,
+               .upper_margin   = 36,
+               .lower_margin   = 7,
+               .hsync_len      = 64,
+               .vsync_len      = 25,
+               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+       .width          = -1,
+       .height         = -1,
+       .tim2           = TIM2_BCD,
+       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+       .fixedtimings   = 1,
+       .connector      = IMPD1_CTRL_DISP_LCD,
+       .bpp            = 16,
+       .grayscale      = 0,
+};
+
+#elif PANEL == LTM10C209
+#define PANELTYPE      ltm10c209
+/*
+ * Untested.
+ */
+static struct clcd_panel ltm10c209 = {
+       .mode           = {
+               .name           = "LTM10C209",
+               .refresh        = 0,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = 40000,
+               .left_margin    = 20,
+               .right_margin   = 20,
+               .upper_margin   = 19,
+               .lower_margin   = 19,
+               .hsync_len      = 20,
+               .vsync_len      = 10,
+               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+       .width          = -1,
+       .height         = -1,
+       .tim2           = TIM2_BCD,
+       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+       .fixedtimings   = 1,
+       .connector      = IMPD1_CTRL_DISP_LCD,
+       .bpp            = 16,
+       .grayscale      = 0,
+};
+#endif
+
+/*
+ * Disable all display connectors on the interface module.
+ */
+static void impd1fb_clcd_disable(struct clcd_fb *fb)
+{
+       impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK, 0);
+}
+
+/*
+ * Enable the relevant connector on the interface module.
+ */
+static void impd1fb_clcd_enable(struct clcd_fb *fb)
+{
+       impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK,
+                       fb->panel->connector | IMPD1_CTRL_DISP_ENABLE);
+}
+
+static int impd1fb_clcd_setup(struct clcd_fb *fb)
+{
+       unsigned long framebase = fb->dev->res.start + 0x01000000;
+       unsigned long framesize = SZ_1M;
+       int ret = 0;
+
+       fb->panel = &PANELTYPE;
+
+       if (!request_mem_region(framebase, framesize, "clcd framebuffer")) {
+               printk(KERN_ERR "IM-PD1: unable to reserve framebuffer\n");
+               return -EBUSY;
+       }
+
+       fb->fb.screen_base = ioremap(framebase, framesize);
+       if (!fb->fb.screen_base) {
+               printk(KERN_ERR "IM-PD1: unable to map framebuffer\n");
+               ret = -ENOMEM;
+               goto free_buffer;
+       }
+
+       fb->fb.fix.smem_start   = framebase;
+       fb->fb.fix.smem_len     = framesize;
+
+       return 0;
+
+ free_buffer:
+       release_mem_region(framebase, framesize);
+       return ret;
+}
+
+static int impd1fb_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+       unsigned long start, size;
+
+       start = vma->vm_pgoff + (fb->fb.fix.smem_start >> PAGE_SHIFT);
+       size = vma->vm_end - vma->vm_start;
+
+       return remap_pfn_range(vma, vma->vm_start, start, size,
+                              vma->vm_page_prot);
+}
+
+static void impd1fb_clcd_remove(struct clcd_fb *fb)
+{
+       iounmap(fb->fb.screen_base);
+       release_mem_region(fb->fb.fix.smem_start, fb->fb.fix.smem_len);
+}
+
+static struct clcd_board impd1_clcd_data = {
+       .name           = "IM-PD/1",
+       .check          = clcdfb_check,
+       .decode         = clcdfb_decode,
+       .disable        = impd1fb_clcd_disable,
+       .enable         = impd1fb_clcd_enable,
+       .setup          = impd1fb_clcd_setup,
+       .mmap           = impd1fb_clcd_mmap,
+       .remove         = impd1fb_clcd_remove,
+};
+
 struct impd1_device {
        unsigned long   offset;
        unsigned int    irq[2];
        unsigned int    id;
+       void            *platform_data;
 };
 
 static struct impd1_device impd1_devs[] = {
@@ -133,6 +335,7 @@ static struct impd1_device impd1_devs[] = {
                .offset = 0x01000000,
                .irq    = { 11 },
                .id     = 0x00041110,
+               .platform_data = &impd1_clcd_data,
        }
 };
 
@@ -152,12 +355,11 @@ static int impd1_probe(struct lm_device *dev)
        if (!request_mem_region(dev->resource.start, SZ_4K, "LM registers"))
                return -EBUSY;
 
-       impd1 = kmalloc(sizeof(struct impd1_module), GFP_KERNEL);
+       impd1 = kzalloc(sizeof(struct impd1_module), GFP_KERNEL);
        if (!impd1) {
                ret = -ENOMEM;
                goto release_lm;
        }
-       memset(impd1, 0, sizeof(struct impd1_module));
 
        impd1->base = ioremap(dev->resource.start, SZ_4K);
        if (!impd1->base) {
@@ -186,12 +388,10 @@ static int impd1_probe(struct lm_device *dev)
 
                pc_base = dev->resource.start + idev->offset;
 
-               d = kmalloc(sizeof(struct amba_device), GFP_KERNEL);
+               d = kzalloc(sizeof(struct amba_device), GFP_KERNEL);
                if (!d)
                        continue;
 
-               memset(d, 0, sizeof(struct amba_device));
-
                snprintf(d->dev.bus_id, sizeof(d->dev.bus_id),
                         "lm%x:%5.5lx", dev->id, idev->offset >> 12);
 
@@ -202,6 +402,7 @@ static int impd1_probe(struct lm_device *dev)
                d->irq[0]       = dev->irq;
                d->irq[1]       = dev->irq;
                d->periphid     = idev->id;
+               d->dev.platform_data = idev->platform_data;
 
                ret = amba_device_register(d, &dev->resource);
                if (ret) {
@@ -216,24 +417,24 @@ static int impd1_probe(struct lm_device *dev)
  free_impd1:
        if (impd1 && impd1->base)
                iounmap(impd1->base);
-       if (impd1)
-               kfree(impd1);
+       kfree(impd1);
  release_lm:
        release_mem_region(dev->resource.start, SZ_4K);
        return ret;
 }
 
+static int impd1_remove_one(struct device *dev, void *data)
+{
+       device_unregister(dev);
+       return 0;
+}
+
 static void impd1_remove(struct lm_device *dev)
 {
        struct impd1_module *impd1 = lm_get_drvdata(dev);
-       struct list_head *l, *n;
        int i;
 
-       list_for_each_safe(l, n, &dev->dev.children) {
-               struct device *d = list_to_dev(l);
-
-               device_unregister(d);
-       }
+       device_for_each_child(&dev->dev, NULL, impd1_remove_one);
 
        for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++)
                clk_unregister(&impd1->vcos[i]);