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