ep93xx video driver
[linux-2.6.git] / drivers / video / ep93xx-fb.c
1 /*
2  * linux/drivers/video/ep93xx-fb.c
3  *
4  * Framebuffer support for the EP93xx series.
5  *
6  * Copyright (C) 2007 Bluewater Systems Ltd
7  * Author: Ryan Mallon <ryan@bluewatersys.com>
8  *
9  * Copyright (c) 2009 H Hartley Sweeten <hsweeten@visionengravers.com>
10  *
11  * Based on the Cirrus Logic ep93xxfb driver, and various other ep93xxfb
12  * drivers.
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License version 2 as
16  * published by the Free Software Foundation.
17  *
18  */
19
20 #include <linux/platform_device.h>
21 #include <linux/dma-mapping.h>
22 #include <linux/clk.h>
23 #include <linux/fb.h>
24
25 #include <mach/fb.h>
26
27 /* Vertical Frame Timing Registers */
28 #define EP93XXFB_VLINES_TOTAL                   0x0000  /* SW locked */
29 #define EP93XXFB_VSYNC                          0x0004  /* SW locked */
30 #define EP93XXFB_VACTIVE                        0x0008  /* SW locked */
31 #define EP93XXFB_VBLANK                         0x0228  /* SW locked */
32 #define EP93XXFB_VCLK                           0x000c  /* SW locked */
33
34 /* Horizontal Frame Timing Registers */
35 #define EP93XXFB_HCLKS_TOTAL                    0x0010  /* SW locked */
36 #define EP93XXFB_HSYNC                          0x0014  /* SW locked */
37 #define EP93XXFB_HACTIVE                        0x0018  /* SW locked */
38 #define EP93XXFB_HBLANK                         0x022c  /* SW locked */
39 #define EP93XXFB_HCLK                           0x001c  /* SW locked */
40
41 /* Frame Buffer Memory Configuration Registers */
42 #define EP93XXFB_SCREEN_PAGE                    0x0028
43 #define EP93XXFB_SCREEN_HPAGE                   0x002c
44 #define EP93XXFB_SCREEN_LINES                   0x0030
45 #define EP93XXFB_LINE_LENGTH                    0x0034
46 #define EP93XXFB_VLINE_STEP                     0x0038
47 #define EP93XXFB_LINE_CARRY                     0x003c  /* SW locked */
48 #define EP93XXFB_EOL_OFFSET                     0x0230
49
50 /* Other Video Registers */
51 #define EP93XXFB_BRIGHTNESS                     0x0020
52 #define EP93XXFB_ATTRIBS                        0x0024  /* SW locked */
53 #define EP93XXFB_SWLOCK                         0x007c  /* SW locked */
54 #define EP93XXFB_AC_RATE                        0x0214
55 #define EP93XXFB_FIFO_LEVEL                     0x0234
56 #define EP93XXFB_PIXELMODE                      0x0054
57 #define EP93XXFB_PIXELMODE_32BPP                (0x7 << 0)
58 #define EP93XXFB_PIXELMODE_24BPP                (0x6 << 0)
59 #define EP93XXFB_PIXELMODE_16BPP                (0x4 << 0)
60 #define EP93XXFB_PIXELMODE_8BPP                 (0x2 << 0)
61 #define EP93XXFB_PIXELMODE_SHIFT_1P_24B         (0x0 << 3)
62 #define EP93XXFB_PIXELMODE_SHIFT_1P_18B         (0x1 << 3)
63 #define EP93XXFB_PIXELMODE_COLOR_LUT            (0x0 << 10)
64 #define EP93XXFB_PIXELMODE_COLOR_888            (0x4 << 10)
65 #define EP93XXFB_PIXELMODE_COLOR_555            (0x5 << 10)
66 #define EP93XXFB_PARL_IF_OUT                    0x0058
67 #define EP93XXFB_PARL_IF_IN                     0x005c
68
69 /* Blink Control Registers */
70 #define EP93XXFB_BLINK_RATE                     0x0040
71 #define EP93XXFB_BLINK_MASK                     0x0044
72 #define EP93XXFB_BLINK_PATTRN                   0x0048
73 #define EP93XXFB_PATTRN_MASK                    0x004c
74 #define EP93XXFB_BKGRND_OFFSET                  0x0050
75
76 /* Hardware Cursor Registers */
77 #define EP93XXFB_CURSOR_ADR_START               0x0060
78 #define EP93XXFB_CURSOR_ADR_RESET               0x0064
79 #define EP93XXFB_CURSOR_SIZE                    0x0068
80 #define EP93XXFB_CURSOR_COLOR1                  0x006c
81 #define EP93XXFB_CURSOR_COLOR2                  0x0070
82 #define EP93XXFB_CURSOR_BLINK_COLOR1            0x021c
83 #define EP93XXFB_CURSOR_BLINK_COLOR2            0x0220
84 #define EP93XXFB_CURSOR_XY_LOC                  0x0074
85 #define EP93XXFB_CURSOR_DSCAN_HY_LOC            0x0078
86 #define EP93XXFB_CURSOR_BLINK_RATE_CTRL         0x0224
87
88 /* LUT Registers */
89 #define EP93XXFB_GRY_SCL_LUTR                   0x0080
90 #define EP93XXFB_GRY_SCL_LUTG                   0x0280
91 #define EP93XXFB_GRY_SCL_LUTB                   0x0300
92 #define EP93XXFB_LUT_SW_CONTROL                 0x0218
93 #define EP93XXFB_LUT_SW_CONTROL_SWTCH           (1 << 0)
94 #define EP93XXFB_LUT_SW_CONTROL_SSTAT           (1 << 1)
95 #define EP93XXFB_COLOR_LUT                      0x0400
96
97 /* Video Signature Registers */
98 #define EP93XXFB_VID_SIG_RSLT_VAL               0x0200
99 #define EP93XXFB_VID_SIG_CTRL                   0x0204
100 #define EP93XXFB_VSIG                           0x0208
101 #define EP93XXFB_HSIG                           0x020c
102 #define EP93XXFB_SIG_CLR_STR                    0x0210
103
104 /* Minimum / Maximum resolutions supported */
105 #define EP93XXFB_MIN_XRES                       64
106 #define EP93XXFB_MIN_YRES                       64
107 #define EP93XXFB_MAX_XRES                       1024
108 #define EP93XXFB_MAX_YRES                       768
109
110 struct ep93xx_fbi {
111         struct ep93xxfb_mach_info       *mach_info;
112         struct clk                      *clk;
113         struct resource                 *res;
114         void __iomem                    *mmio_base;
115         unsigned int                    pseudo_palette[256];
116 };
117
118 static int check_screenpage_bug = 1;
119 module_param(check_screenpage_bug, int, 0644);
120 MODULE_PARM_DESC(check_screenpage_bug,
121                  "Check for bit 27 screen page bug. Default = 1");
122
123 static inline unsigned int ep93xxfb_readl(struct ep93xx_fbi *fbi,
124                                           unsigned int off)
125 {
126         return __raw_readl(fbi->mmio_base + off);
127 }
128
129 static inline void ep93xxfb_writel(struct ep93xx_fbi *fbi,
130                                    unsigned int val, unsigned int off)
131 {
132         __raw_writel(val, fbi->mmio_base + off);
133 }
134
135 /*
136  * Write to one of the locked raster registers.
137  */
138 static inline void ep93xxfb_out_locked(struct ep93xx_fbi *fbi,
139                                        unsigned int val, unsigned int reg)
140 {
141         /*
142          * We don't need a lock or delay here since the raster register
143          * block will remain unlocked until the next access.
144          */
145         ep93xxfb_writel(fbi, 0xaa, EP93XXFB_SWLOCK);
146         ep93xxfb_writel(fbi, val, reg);
147 }
148
149 static void ep93xxfb_set_video_attribs(struct fb_info *info)
150 {
151         struct ep93xx_fbi *fbi = info->par;
152         unsigned int attribs;
153
154         attribs = EP93XXFB_ENABLE;
155         attribs |= fbi->mach_info->flags;
156         ep93xxfb_out_locked(fbi, attribs, EP93XXFB_ATTRIBS);
157 }
158
159 static int ep93xxfb_set_pixelmode(struct fb_info *info)
160 {
161         struct ep93xx_fbi *fbi = info->par;
162         unsigned int val;
163
164         info->var.transp.offset = 0;
165         info->var.transp.length = 0;
166
167         switch (info->var.bits_per_pixel) {
168         case 8:
169                 val = EP93XXFB_PIXELMODE_8BPP | EP93XXFB_PIXELMODE_COLOR_LUT |
170                         EP93XXFB_PIXELMODE_SHIFT_1P_18B;
171
172                 info->var.red.offset    = 0;
173                 info->var.red.length    = 8;
174                 info->var.green.offset  = 0;
175                 info->var.green.length  = 8;
176                 info->var.blue.offset   = 0;
177                 info->var.blue.length   = 8;
178                 info->fix.visual        = FB_VISUAL_PSEUDOCOLOR;
179                 break;
180
181         case 16:
182                 val = EP93XXFB_PIXELMODE_16BPP | EP93XXFB_PIXELMODE_COLOR_555 |
183                         EP93XXFB_PIXELMODE_SHIFT_1P_18B;
184
185                 info->var.red.offset    = 11;
186                 info->var.red.length    = 5;
187                 info->var.green.offset  = 5;
188                 info->var.green.length  = 6;
189                 info->var.blue.offset   = 0;
190                 info->var.blue.length   = 5;
191                 info->fix.visual        = FB_VISUAL_TRUECOLOR;
192                 break;
193
194         case 24:
195                 val = EP93XXFB_PIXELMODE_24BPP | EP93XXFB_PIXELMODE_COLOR_888 |
196                         EP93XXFB_PIXELMODE_SHIFT_1P_24B;
197
198                 info->var.red.offset    = 16;
199                 info->var.red.length    = 8;
200                 info->var.green.offset  = 8;
201                 info->var.green.length  = 8;
202                 info->var.blue.offset   = 0;
203                 info->var.blue.length   = 8;
204                 info->fix.visual        = FB_VISUAL_TRUECOLOR;
205                 break;
206
207         case 32:
208                 val = EP93XXFB_PIXELMODE_32BPP | EP93XXFB_PIXELMODE_COLOR_888 |
209                         EP93XXFB_PIXELMODE_SHIFT_1P_24B;
210
211                 info->var.red.offset    = 16;
212                 info->var.red.length    = 8;
213                 info->var.green.offset  = 8;
214                 info->var.green.length  = 8;
215                 info->var.blue.offset   = 0;
216                 info->var.blue.length   = 8;
217                 info->fix.visual        = FB_VISUAL_TRUECOLOR;
218                 break;
219
220         default:
221                 return -EINVAL;
222         }
223
224         ep93xxfb_writel(fbi, val, EP93XXFB_PIXELMODE);
225         return 0;
226 }
227
228 static void ep93xxfb_set_timing(struct fb_info *info)
229 {
230         struct ep93xx_fbi *fbi = info->par;
231         unsigned int vlines_total, hclks_total, start, stop;
232
233         vlines_total = info->var.yres + info->var.upper_margin +
234                 info->var.lower_margin + info->var.vsync_len - 1;
235
236         hclks_total = info->var.xres + info->var.left_margin +
237                 info->var.right_margin + info->var.hsync_len - 1;
238
239         ep93xxfb_out_locked(fbi, vlines_total, EP93XXFB_VLINES_TOTAL);
240         ep93xxfb_out_locked(fbi, hclks_total, EP93XXFB_HCLKS_TOTAL);
241
242         start = vlines_total;
243         stop = vlines_total - info->var.vsync_len;
244         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VSYNC);
245
246         start = vlines_total - info->var.vsync_len - info->var.upper_margin;
247         stop = info->var.lower_margin - 1;
248         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VBLANK);
249         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VACTIVE);
250
251         start = vlines_total;
252         stop = vlines_total + 1;
253         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VCLK);
254
255         start = hclks_total;
256         stop = hclks_total - info->var.hsync_len;
257         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HSYNC);
258
259         start = hclks_total - info->var.hsync_len - info->var.left_margin;
260         stop = info->var.right_margin - 1;
261         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HBLANK);
262         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HACTIVE);
263
264         start = hclks_total;
265         stop = hclks_total;
266         ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HCLK);
267
268         ep93xxfb_out_locked(fbi, 0x0, EP93XXFB_LINE_CARRY);
269 }
270
271 static int ep93xxfb_set_par(struct fb_info *info)
272 {
273         struct ep93xx_fbi *fbi = info->par;
274
275         clk_set_rate(fbi->clk, 1000 * PICOS2KHZ(info->var.pixclock));
276
277         ep93xxfb_set_timing(info);
278
279         info->fix.line_length = info->var.xres_virtual *
280                 info->var.bits_per_pixel / 8;
281
282         ep93xxfb_writel(fbi, info->fix.smem_start, EP93XXFB_SCREEN_PAGE);
283         ep93xxfb_writel(fbi, info->var.yres - 1, EP93XXFB_SCREEN_LINES);
284         ep93xxfb_writel(fbi, ((info->var.xres * info->var.bits_per_pixel)
285                               / 32) - 1, EP93XXFB_LINE_LENGTH);
286         ep93xxfb_writel(fbi, info->fix.line_length / 4, EP93XXFB_VLINE_STEP);
287         ep93xxfb_set_video_attribs(info);
288         return 0;
289 }
290
291 static int ep93xxfb_check_var(struct fb_var_screeninfo *var,
292                               struct fb_info *info)
293 {
294         int err;
295
296         err = ep93xxfb_set_pixelmode(info);
297         if (err)
298                 return err;
299
300         var->xres = max_t(unsigned int, var->xres, EP93XXFB_MIN_XRES);
301         var->xres = min_t(unsigned int, var->xres, EP93XXFB_MAX_XRES);
302         var->xres_virtual = max(var->xres_virtual, var->xres);
303
304         var->yres = max_t(unsigned int, var->yres, EP93XXFB_MIN_YRES);
305         var->yres = min_t(unsigned int, var->yres, EP93XXFB_MAX_YRES);
306         var->yres_virtual = max(var->yres_virtual, var->yres);
307
308         return 0;
309 }
310
311 static int ep93xxfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
312 {
313         unsigned int offset = vma->vm_pgoff << PAGE_SHIFT;
314
315         if (offset < info->fix.smem_len) {
316                 return dma_mmap_writecombine(info->dev, vma, info->screen_base,
317                                              info->fix.smem_start,
318                                              info->fix.smem_len);
319         }
320
321         return -EINVAL;
322 }
323
324 static int ep93xxfb_blank(int blank_mode, struct fb_info *info)
325 {
326         struct ep93xx_fbi *fbi = info->par;
327         unsigned int attribs = ep93xxfb_readl(fbi, EP93XXFB_ATTRIBS);
328
329         if (blank_mode) {
330                 if (fbi->mach_info->blank)
331                         fbi->mach_info->blank(blank_mode, info);
332                 ep93xxfb_out_locked(fbi, attribs & ~EP93XXFB_ENABLE,
333                                     EP93XXFB_ATTRIBS);
334                 clk_disable(fbi->clk);
335         } else {
336                 clk_enable(fbi->clk);
337                 ep93xxfb_out_locked(fbi, attribs | EP93XXFB_ENABLE,
338                                     EP93XXFB_ATTRIBS);
339                 if (fbi->mach_info->blank)
340                         fbi->mach_info->blank(blank_mode, info);
341         }
342
343         return 0;
344 }
345
346 static inline int ep93xxfb_convert_color(int val, int width)
347 {
348         return ((val << width) + 0x7fff - val) >> 16;
349 }
350
351 static int ep93xxfb_setcolreg(unsigned int regno, unsigned int red,
352                               unsigned int green, unsigned int blue,
353                               unsigned int transp, struct fb_info *info)
354 {
355         struct ep93xx_fbi *fbi = info->par;
356         unsigned int *pal = info->pseudo_palette;
357         unsigned int ctrl, i, rgb, lut_current, lut_stat;
358
359         switch (info->fix.visual) {
360         case FB_VISUAL_PSEUDOCOLOR:
361                 rgb = ((red & 0xff00) << 8) | (green & 0xff00) |
362                         ((blue & 0xff00) >> 8);
363
364                 pal[regno] = rgb;
365                 ep93xxfb_writel(fbi, rgb, (EP93XXFB_COLOR_LUT + (regno << 2)));
366                 ctrl = ep93xxfb_readl(fbi, EP93XXFB_LUT_SW_CONTROL);
367                 lut_stat = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SSTAT);
368                 lut_current = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SWTCH);
369
370                 if (lut_stat == lut_current) {
371                         for (i = 0; i < 256; i++) {
372                                 ep93xxfb_writel(fbi, pal[i],
373                                         EP93XXFB_COLOR_LUT + (i << 2));
374                         }
375
376                         ep93xxfb_writel(fbi,
377                                         ctrl ^ EP93XXFB_LUT_SW_CONTROL_SWTCH,
378                                         EP93XXFB_LUT_SW_CONTROL);
379                 }
380                 break;
381
382         case FB_VISUAL_TRUECOLOR:
383                 if (regno > 16)
384                         return 1;
385
386                 red = ep93xxfb_convert_color(red, info->var.red.length);
387                 green = ep93xxfb_convert_color(green, info->var.green.length);
388                 blue = ep93xxfb_convert_color(blue, info->var.blue.length);
389                 transp = ep93xxfb_convert_color(transp,
390                                                 info->var.transp.length);
391
392                 pal[regno] = (red << info->var.red.offset) |
393                         (green << info->var.green.offset) |
394                         (blue << info->var.blue.offset) |
395                         (transp << info->var.transp.offset);
396                 break;
397
398         default:
399                 return 1;
400         }
401
402         return 0;
403 }
404
405 static struct fb_ops ep93xxfb_ops = {
406         .owner          = THIS_MODULE,
407         .fb_check_var   = ep93xxfb_check_var,
408         .fb_set_par     = ep93xxfb_set_par,
409         .fb_blank       = ep93xxfb_blank,
410         .fb_fillrect    = cfb_fillrect,
411         .fb_copyarea    = cfb_copyarea,
412         .fb_imageblit   = cfb_imageblit,
413         .fb_setcolreg   = ep93xxfb_setcolreg,
414         .fb_mmap        = ep93xxfb_mmap,
415 };
416
417 static int __init ep93xxfb_calc_fbsize(struct ep93xxfb_mach_info *mach_info)
418 {
419         int i, fb_size = 0;
420
421         if (mach_info->num_modes == EP93XXFB_USE_MODEDB) {
422                 fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES *
423                         mach_info->bpp / 8;
424         } else {
425                 for (i = 0; i < mach_info->num_modes; i++) {
426                         const struct fb_videomode *mode;
427                         int size;
428
429                         mode = &mach_info->modes[i];
430                         size = mode->xres * mode->yres * mach_info->bpp / 8;
431                         if (size > fb_size)
432                                 fb_size = size;
433                 }
434         }
435
436         return fb_size;
437 }
438
439 static int __init ep93xxfb_alloc_videomem(struct fb_info *info)
440 {
441         struct ep93xx_fbi *fbi = info->par;
442         char __iomem *virt_addr;
443         dma_addr_t phys_addr;
444         unsigned int fb_size;
445
446         fb_size = ep93xxfb_calc_fbsize(fbi->mach_info);
447         virt_addr = dma_alloc_writecombine(info->dev, fb_size,
448                                            &phys_addr, GFP_KERNEL);
449         if (!virt_addr)
450                 return -ENOMEM;
451
452         /*
453          * There is a bug in the ep93xx framebuffer which causes problems
454          * if bit 27 of the physical address is set.
455          * See: http://marc.info/?l=linux-arm-kernel&m=110061245502000&w=2
456          * There does not seem to be any offical errata for this, but I
457          * have confirmed the problem exists on my hardware (ep9315) at
458          * least.
459          */
460         if (check_screenpage_bug && phys_addr & (1 << 27)) {
461                 dev_err(info->dev, "ep93xx framebuffer bug. phys addr (0x%x) "
462                         "has bit 27 set: cannot init framebuffer\n",
463                         phys_addr);
464
465                 dma_free_coherent(info->dev, fb_size, virt_addr, phys_addr);
466                 return -ENOMEM;
467         }
468
469         info->fix.smem_start = phys_addr;
470         info->fix.smem_len = fb_size;
471         info->screen_base = virt_addr;
472
473         return 0;
474 }
475
476 static void ep93xxfb_dealloc_videomem(struct fb_info *info)
477 {
478         if (info->screen_base)
479                 dma_free_coherent(info->dev, info->fix.smem_len,
480                                   info->screen_base, info->fix.smem_start);
481 }
482
483 static int __init ep93xxfb_probe(struct platform_device *pdev)
484 {
485         struct ep93xxfb_mach_info *mach_info = pdev->dev.platform_data;
486         struct fb_info *info;
487         struct ep93xx_fbi *fbi;
488         struct resource *res;
489         char *video_mode;
490         int err;
491
492         if (!mach_info)
493                 return -EINVAL;
494
495         info = framebuffer_alloc(sizeof(struct ep93xx_fbi), &pdev->dev);
496         if (!info)
497                 return -ENOMEM;
498
499         info->dev = &pdev->dev;
500         platform_set_drvdata(pdev, info);
501         fbi = info->par;
502         fbi->mach_info = mach_info;
503
504         err = fb_alloc_cmap(&info->cmap, 256, 0);
505         if (err)
506                 goto failed;
507
508         err = ep93xxfb_alloc_videomem(info);
509         if (err)
510                 goto failed;
511
512         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
513         if (!res) {
514                 err = -ENXIO;
515                 goto failed;
516         }
517
518         res = request_mem_region(res->start, resource_size(res), pdev->name);
519         if (!res) {
520                 err = -EBUSY;
521                 goto failed;
522         }
523
524         fbi->res = res;
525         fbi->mmio_base = ioremap(res->start, resource_size(res));
526         if (!fbi->mmio_base) {
527                 err = -ENXIO;
528                 goto failed;
529         }
530
531         strcpy(info->fix.id, pdev->name);
532         info->fbops             = &ep93xxfb_ops;
533         info->fix.type          = FB_TYPE_PACKED_PIXELS;
534         info->fix.accel         = FB_ACCEL_NONE;
535         info->var.activate      = FB_ACTIVATE_NOW;
536         info->var.vmode         = FB_VMODE_NONINTERLACED;
537         info->flags             = FBINFO_DEFAULT;
538         info->node              = -1;
539         info->state             = FBINFO_STATE_RUNNING;
540         info->pseudo_palette    = &fbi->pseudo_palette;
541
542         fb_get_options("ep93xx-fb", &video_mode);
543         err = fb_find_mode(&info->var, info, video_mode,
544                            fbi->mach_info->modes, fbi->mach_info->num_modes,
545                            fbi->mach_info->default_mode, fbi->mach_info->bpp);
546         if (err == 0) {
547                 dev_err(info->dev, "No suitable video mode found\n");
548                 err = -EINVAL;
549                 goto failed;
550         }
551
552         if (mach_info->setup) {
553                 err = mach_info->setup(pdev);
554                 if (err)
555                         return err;
556         }
557
558         err = ep93xxfb_check_var(&info->var, info);
559         if (err)
560                 goto failed;
561
562         fbi->clk = clk_get(info->dev, NULL);
563         if (IS_ERR(fbi->clk)) {
564                 err = PTR_ERR(fbi->clk);
565                 fbi->clk = NULL;
566                 goto failed;
567         }
568
569         ep93xxfb_set_par(info);
570         clk_enable(fbi->clk);
571
572         err = register_framebuffer(info);
573         if (err)
574                 goto failed;
575
576         dev_info(info->dev, "registered. Mode = %dx%d-%d\n",
577                  info->var.xres, info->var.yres, info->var.bits_per_pixel);
578         return 0;
579
580 failed:
581         if (fbi->clk)
582                 clk_put(fbi->clk);
583         if (fbi->mmio_base)
584                 iounmap(fbi->mmio_base);
585         if (fbi->res)
586                 release_mem_region(fbi->res->start, resource_size(fbi->res));
587         ep93xxfb_dealloc_videomem(info);
588         if (&info->cmap)
589                 fb_dealloc_cmap(&info->cmap);
590         if (fbi->mach_info->teardown)
591                 fbi->mach_info->teardown(pdev);
592         kfree(info);
593         platform_set_drvdata(pdev, NULL);
594
595         return err;
596 }
597
598 static int ep93xxfb_remove(struct platform_device *pdev)
599 {
600         struct fb_info *info = platform_get_drvdata(pdev);
601         struct ep93xx_fbi *fbi = info->par;
602
603         unregister_framebuffer(info);
604         clk_disable(fbi->clk);
605         clk_put(fbi->clk);
606         iounmap(fbi->mmio_base);
607         release_mem_region(fbi->res->start, resource_size(fbi->res));
608         ep93xxfb_dealloc_videomem(info);
609         fb_dealloc_cmap(&info->cmap);
610
611         if (fbi->mach_info->teardown)
612                 fbi->mach_info->teardown(pdev);
613
614         kfree(info);
615         platform_set_drvdata(pdev, NULL);
616
617         return 0;
618 }
619
620 static struct platform_driver ep93xxfb_driver = {
621         .probe          = ep93xxfb_probe,
622         .remove         = ep93xxfb_remove,
623         .driver = {
624                 .name   = "ep93xx-fb",
625                 .owner  = THIS_MODULE,
626         },
627 };
628
629 static int __devinit ep93xxfb_init(void)
630 {
631         return platform_driver_register(&ep93xxfb_driver);
632 }
633
634 static void __exit ep93xxfb_exit(void)
635 {
636         platform_driver_unregister(&ep93xxfb_driver);
637 }
638
639 module_init(ep93xxfb_init);
640 module_exit(ep93xxfb_exit);
641
642 MODULE_DESCRIPTION("EP93XX Framebuffer Driver");
643 MODULE_ALIAS("platform:ep93xx-fb");
644 MODULE_AUTHOR("Ryan Mallon <ryan&bluewatersys.com>, "
645               "H Hartley Sweeten <hsweeten@visionengravers.com");
646 MODULE_LICENSE("GPL");