X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fmach-integrator%2Fimpd1.c;h=92d79fb39311f73ee755abd6c67f6b8df6c5b3ed;hb=refs%2Fheads%2Fvserver;hp=e776e8a8d06181b9c7c0a6ab34ae9cdca477c64f;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index e776e8a8d..92d79fb39 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -17,10 +17,12 @@ #include #include #include +#include +#include +#include #include #include -#include #include #include #include @@ -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]);