Merge branch 'next-spi' of git://git.secretlab.ca/git/linux-2.6
[pandora-kernel.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                 if (regno > 255)
362                         return 1;
363                 rgb = ((red & 0xff00) << 8) | (green & 0xff00) |
364                         ((blue & 0xff00) >> 8);
365
366                 pal[regno] = rgb;
367                 ep93xxfb_writel(fbi, rgb, (EP93XXFB_COLOR_LUT + (regno << 2)));
368                 ctrl = ep93xxfb_readl(fbi, EP93XXFB_LUT_SW_CONTROL);
369                 lut_stat = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SSTAT);
370                 lut_current = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SWTCH);
371
372                 if (lut_stat == lut_current) {
373                         for (i = 0; i < 256; i++) {
374                                 ep93xxfb_writel(fbi, pal[i],
375                                         EP93XXFB_COLOR_LUT + (i << 2));
376                         }
377
378                         ep93xxfb_writel(fbi,
379                                         ctrl ^ EP93XXFB_LUT_SW_CONTROL_SWTCH,
380                                         EP93XXFB_LUT_SW_CONTROL);
381                 }
382                 break;
383
384         case FB_VISUAL_TRUECOLOR:
385                 if (regno > 16)
386                         return 1;
387
388                 red = ep93xxfb_convert_color(red, info->var.red.length);
389                 green = ep93xxfb_convert_color(green, info->var.green.length);
390                 blue = ep93xxfb_convert_color(blue, info->var.blue.length);
391                 transp = ep93xxfb_convert_color(transp,
392                                                 info->var.transp.length);
393
394                 pal[regno] = (red << info->var.red.offset) |
395                         (green << info->var.green.offset) |
396                         (blue << info->var.blue.offset) |
397                         (transp << info->var.transp.offset);
398                 break;
399
400         default:
401                 return 1;
402         }
403
404         return 0;
405 }
406
407 static struct fb_ops ep93xxfb_ops = {
408         .owner          = THIS_MODULE,
409         .fb_check_var   = ep93xxfb_check_var,
410         .fb_set_par     = ep93xxfb_set_par,
411         .fb_blank       = ep93xxfb_blank,
412         .fb_fillrect    = cfb_fillrect,
413         .fb_copyarea    = cfb_copyarea,
414         .fb_imageblit   = cfb_imageblit,
415         .fb_setcolreg   = ep93xxfb_setcolreg,
416         .fb_mmap        = ep93xxfb_mmap,
417 };
418
419 static int __init ep93xxfb_calc_fbsize(struct ep93xxfb_mach_info *mach_info)
420 {
421         int i, fb_size = 0;
422
423         if (mach_info->num_modes == EP93XXFB_USE_MODEDB) {
424                 fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES *
425                         mach_info->bpp / 8;
426         } else {
427                 for (i = 0; i < mach_info->num_modes; i++) {
428                         const struct fb_videomode *mode;
429                         int size;
430
431                         mode = &mach_info->modes[i];
432                         size = mode->xres * mode->yres * mach_info->bpp / 8;
433                         if (size > fb_size)
434                                 fb_size = size;
435                 }
436         }
437
438         return fb_size;
439 }
440
441 static int __init ep93xxfb_alloc_videomem(struct fb_info *info)
442 {
443         struct ep93xx_fbi *fbi = info->par;
444         char __iomem *virt_addr;
445         dma_addr_t phys_addr;
446         unsigned int fb_size;
447
448         fb_size = ep93xxfb_calc_fbsize(fbi->mach_info);
449         virt_addr = dma_alloc_writecombine(info->dev, fb_size,
450                                            &phys_addr, GFP_KERNEL);
451         if (!virt_addr)
452                 return -ENOMEM;
453
454         /*
455          * There is a bug in the ep93xx framebuffer which causes problems
456          * if bit 27 of the physical address is set.
457          * See: http://marc.info/?l=linux-arm-kernel&m=110061245502000&w=2
458          * There does not seem to be any offical errata for this, but I
459          * have confirmed the problem exists on my hardware (ep9315) at
460          * least.
461          */
462         if (check_screenpage_bug && phys_addr & (1 << 27)) {
463                 dev_err(info->dev, "ep93xx framebuffer bug. phys addr (0x%x) "
464                         "has bit 27 set: cannot init framebuffer\n",
465                         phys_addr);
466
467                 dma_free_coherent(info->dev, fb_size, virt_addr, phys_addr);
468                 return -ENOMEM;
469         }
470
471         info->fix.smem_start = phys_addr;
472         info->fix.smem_len = fb_size;
473         info->screen_base = virt_addr;
474
475         return 0;
476 }
477
478 static void ep93xxfb_dealloc_videomem(struct fb_info *info)
479 {
480         if (info->screen_base)
481                 dma_free_coherent(info->dev, info->fix.smem_len,
482                                   info->screen_base, info->fix.smem_start);
483 }
484
485 static int __init ep93xxfb_probe(struct platform_device *pdev)
486 {
487         struct ep93xxfb_mach_info *mach_info = pdev->dev.platform_data;
488         struct fb_info *info;
489         struct ep93xx_fbi *fbi;
490         struct resource *res;
491         char *video_mode;
492         int err;
493
494         if (!mach_info)
495                 return -EINVAL;
496
497         info = framebuffer_alloc(sizeof(struct ep93xx_fbi), &pdev->dev);
498         if (!info)
499                 return -ENOMEM;
500
501         info->dev = &pdev->dev;
502         platform_set_drvdata(pdev, info);
503         fbi = info->par;
504         fbi->mach_info = mach_info;
505
506         err = fb_alloc_cmap(&info->cmap, 256, 0);
507         if (err)
508                 goto failed;
509
510         err = ep93xxfb_alloc_videomem(info);
511         if (err)
512                 goto failed;
513
514         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
515         if (!res) {
516                 err = -ENXIO;
517                 goto failed;
518         }
519
520         res = request_mem_region(res->start, resource_size(res), pdev->name);
521         if (!res) {
522                 err = -EBUSY;
523                 goto failed;
524         }
525
526         fbi->res = res;
527         fbi->mmio_base = ioremap(res->start, resource_size(res));
528         if (!fbi->mmio_base) {
529                 err = -ENXIO;
530                 goto failed;
531         }
532
533         strcpy(info->fix.id, pdev->name);
534         info->fbops             = &ep93xxfb_ops;
535         info->fix.type          = FB_TYPE_PACKED_PIXELS;
536         info->fix.accel         = FB_ACCEL_NONE;
537         info->var.activate      = FB_ACTIVATE_NOW;
538         info->var.vmode         = FB_VMODE_NONINTERLACED;
539         info->flags             = FBINFO_DEFAULT;
540         info->node              = -1;
541         info->state             = FBINFO_STATE_RUNNING;
542         info->pseudo_palette    = &fbi->pseudo_palette;
543
544         fb_get_options("ep93xx-fb", &video_mode);
545         err = fb_find_mode(&info->var, info, video_mode,
546                            fbi->mach_info->modes, fbi->mach_info->num_modes,
547                            fbi->mach_info->default_mode, fbi->mach_info->bpp);
548         if (err == 0) {
549                 dev_err(info->dev, "No suitable video mode found\n");
550                 err = -EINVAL;
551                 goto failed;
552         }
553
554         if (mach_info->setup) {
555                 err = mach_info->setup(pdev);
556                 if (err)
557                         return err;
558         }
559
560         err = ep93xxfb_check_var(&info->var, info);
561         if (err)
562                 goto failed;
563
564         fbi->clk = clk_get(info->dev, NULL);
565         if (IS_ERR(fbi->clk)) {
566                 err = PTR_ERR(fbi->clk);
567                 fbi->clk = NULL;
568                 goto failed;
569         }
570
571         ep93xxfb_set_par(info);
572         clk_enable(fbi->clk);
573
574         err = register_framebuffer(info);
575         if (err)
576                 goto failed;
577
578         dev_info(info->dev, "registered. Mode = %dx%d-%d\n",
579                  info->var.xres, info->var.yres, info->var.bits_per_pixel);
580         return 0;
581
582 failed:
583         if (fbi->clk)
584                 clk_put(fbi->clk);
585         if (fbi->mmio_base)
586                 iounmap(fbi->mmio_base);
587         if (fbi->res)
588                 release_mem_region(fbi->res->start, resource_size(fbi->res));
589         ep93xxfb_dealloc_videomem(info);
590         if (&info->cmap)
591                 fb_dealloc_cmap(&info->cmap);
592         if (fbi->mach_info->teardown)
593                 fbi->mach_info->teardown(pdev);
594         kfree(info);
595         platform_set_drvdata(pdev, NULL);
596
597         return err;
598 }
599
600 static int ep93xxfb_remove(struct platform_device *pdev)
601 {
602         struct fb_info *info = platform_get_drvdata(pdev);
603         struct ep93xx_fbi *fbi = info->par;
604
605         unregister_framebuffer(info);
606         clk_disable(fbi->clk);
607         clk_put(fbi->clk);
608         iounmap(fbi->mmio_base);
609         release_mem_region(fbi->res->start, resource_size(fbi->res));
610         ep93xxfb_dealloc_videomem(info);
611         fb_dealloc_cmap(&info->cmap);
612
613         if (fbi->mach_info->teardown)
614                 fbi->mach_info->teardown(pdev);
615
616         kfree(info);
617         platform_set_drvdata(pdev, NULL);
618
619         return 0;
620 }
621
622 static struct platform_driver ep93xxfb_driver = {
623         .probe          = ep93xxfb_probe,
624         .remove         = ep93xxfb_remove,
625         .driver = {
626                 .name   = "ep93xx-fb",
627                 .owner  = THIS_MODULE,
628         },
629 };
630
631 static int __devinit ep93xxfb_init(void)
632 {
633         return platform_driver_register(&ep93xxfb_driver);
634 }
635
636 static void __exit ep93xxfb_exit(void)
637 {
638         platform_driver_unregister(&ep93xxfb_driver);
639 }
640
641 module_init(ep93xxfb_init);
642 module_exit(ep93xxfb_exit);
643
644 MODULE_DESCRIPTION("EP93XX Framebuffer Driver");
645 MODULE_ALIAS("platform:ep93xx-fb");
646 MODULE_AUTHOR("Ryan Mallon <ryan&bluewatersys.com>, "
647               "H Hartley Sweeten <hsweeten@visionengravers.com");
648 MODULE_LICENSE("GPL");