fbcon: fix scrolling after logo is cleared
[linux-2.6] / drivers / video / metronomefb.c
1 /*
2  * linux/drivers/video/metronomefb.c -- FB driver for Metronome controller
3  *
4  * Copyright (C) 2008, Jaya Kumar
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License. See the file COPYING in the main directory of this archive for
8  * more details.
9  *
10  * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
11  *
12  * This work was made possible by help and equipment support from E-Ink
13  * Corporation. http://support.eink.com/community
14  *
15  * This driver is written to be used with the Metronome display controller.
16  * It is intended to be architecture independent. A board specific driver
17  * must be used to perform all the physical IO interactions. An example
18  * is provided as am200epd.c
19  *
20  */
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/errno.h>
24 #include <linux/string.h>
25 #include <linux/mm.h>
26 #include <linux/slab.h>
27 #include <linux/vmalloc.h>
28 #include <linux/delay.h>
29 #include <linux/interrupt.h>
30 #include <linux/fb.h>
31 #include <linux/init.h>
32 #include <linux/platform_device.h>
33 #include <linux/list.h>
34 #include <linux/firmware.h>
35 #include <linux/dma-mapping.h>
36 #include <linux/uaccess.h>
37 #include <linux/irq.h>
38
39 #include <video/metronomefb.h>
40
41 #include <asm/unaligned.h>
42
43
44 #define DEBUG 1
45 #ifdef DEBUG
46 #define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
47 #else
48 #define DPRINTK(f, a...)
49 #endif
50
51
52 /* Display specific information */
53 #define DPY_W 832
54 #define DPY_H 622
55
56 /* frame differs from image. frame includes non-visible pixels */
57 struct epd_frame {
58         int fw; /* frame width */
59         int fh; /* frame height */
60 };
61
62 static struct epd_frame epd_frame_table[] = {
63         {
64         .fw = 832,
65         .fh = 622
66         },
67 };
68
69 static struct fb_fix_screeninfo metronomefb_fix __devinitdata = {
70         .id =           "metronomefb",
71         .type =         FB_TYPE_PACKED_PIXELS,
72         .visual =       FB_VISUAL_STATIC_PSEUDOCOLOR,
73         .xpanstep =     0,
74         .ypanstep =     0,
75         .ywrapstep =    0,
76         .line_length =  DPY_W,
77         .accel =        FB_ACCEL_NONE,
78 };
79
80 static struct fb_var_screeninfo metronomefb_var __devinitdata = {
81         .xres           = DPY_W,
82         .yres           = DPY_H,
83         .xres_virtual   = DPY_W,
84         .yres_virtual   = DPY_H,
85         .bits_per_pixel = 8,
86         .grayscale      = 1,
87         .nonstd         = 1,
88         .red =          { 4, 3, 0 },
89         .green =        { 0, 0, 0 },
90         .blue =         { 0, 0, 0 },
91         .transp =       { 0, 0, 0 },
92 };
93
94 /* the waveform structure that is coming from userspace firmware */
95 struct waveform_hdr {
96         u8 stuff[32];
97
98         u8 wmta[3];
99         u8 fvsn;
100
101         u8 luts;
102         u8 mc;
103         u8 trc;
104         u8 stuff3;
105
106         u8 endb;
107         u8 swtb;
108         u8 stuff2a[2];
109
110         u8 stuff2b[3];
111         u8 wfm_cs;
112 } __attribute__ ((packed));
113
114 /* main metronomefb functions */
115 static u8 calc_cksum(int start, int end, u8 *mem)
116 {
117         u8 tmp = 0;
118         int i;
119
120         for (i = start; i < end; i++)
121                 tmp += mem[i];
122
123         return tmp;
124 }
125
126 static u16 calc_img_cksum(u16 *start, int length)
127 {
128         u16 tmp = 0;
129
130         while (length--)
131                 tmp += *start++;
132
133         return tmp;
134 }
135
136 /* here we decode the incoming waveform file and populate metromem */
137 #define EXP_WFORM_SIZE 47001
138 static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
139                                 u8 *frame_count)
140 {
141         int tta;
142         int wmta;
143         int trn = 0;
144         int i;
145         unsigned char v;
146         u8 cksum;
147         int cksum_idx;
148         int wfm_idx, owfm_idx;
149         int mem_idx = 0;
150         struct waveform_hdr *wfm_hdr;
151
152         if (size != EXP_WFORM_SIZE) {
153                 printk(KERN_ERR "Error: unexpected size %d != %d\n", size,
154                                         EXP_WFORM_SIZE);
155                 return -EINVAL;
156         }
157
158         wfm_hdr = (struct waveform_hdr *) mem;
159
160         if (wfm_hdr->fvsn != 1) {
161                 printk(KERN_ERR "Error: bad fvsn %x\n", wfm_hdr->fvsn);
162                 return -EINVAL;
163         }
164         if (wfm_hdr->luts != 0) {
165                 printk(KERN_ERR "Error: bad luts %x\n", wfm_hdr->luts);
166                 return -EINVAL;
167         }
168         cksum = calc_cksum(32, 47, mem);
169         if (cksum != wfm_hdr->wfm_cs) {
170                 printk(KERN_ERR "Error: bad cksum %x != %x\n", cksum,
171                                         wfm_hdr->wfm_cs);
172                 return -EINVAL;
173         }
174         wfm_hdr->mc += 1;
175         wfm_hdr->trc += 1;
176         for (i = 0; i < 5; i++) {
177                 if (*(wfm_hdr->stuff2a + i) != 0) {
178                         printk(KERN_ERR "Error: unexpected value in padding\n");
179                         return -EINVAL;
180                 }
181         }
182
183         /* calculating trn. trn is something used to index into
184         the waveform. presumably selecting the right one for the
185         desired temperature. it works out the offset of the first
186         v that exceeds the specified temperature */
187         if ((sizeof(*wfm_hdr) + wfm_hdr->trc) > size)
188                 return -EINVAL;
189
190         for (i = sizeof(*wfm_hdr); i <= sizeof(*wfm_hdr) + wfm_hdr->trc; i++) {
191                 if (mem[i] > t) {
192                         trn = i - sizeof(*wfm_hdr) - 1;
193                         break;
194                 }
195         }
196
197         /* check temperature range table checksum */
198         cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1;
199         if (cksum_idx > size)
200                 return -EINVAL;
201         cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem);
202         if (cksum != mem[cksum_idx]) {
203                 printk(KERN_ERR "Error: bad temperature range table cksum"
204                                 " %x != %x\n", cksum, mem[cksum_idx]);
205                 return -EINVAL;
206         }
207
208         /* check waveform mode table address checksum */
209         wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF;
210         cksum_idx = wmta + m*4 + 3;
211         if (cksum_idx > size)
212                 return -EINVAL;
213         cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
214         if (cksum != mem[cksum_idx]) {
215                 printk(KERN_ERR "Error: bad mode table address cksum"
216                                 " %x != %x\n", cksum, mem[cksum_idx]);
217                 return -EINVAL;
218         }
219
220         /* check waveform temperature table address checksum */
221         tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF;
222         cksum_idx = tta + trn*4 + 3;
223         if (cksum_idx > size)
224                 return -EINVAL;
225         cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
226         if (cksum != mem[cksum_idx]) {
227                 printk(KERN_ERR "Error: bad temperature table address cksum"
228                         " %x != %x\n", cksum, mem[cksum_idx]);
229                 return -EINVAL;
230         }
231
232         /* here we do the real work of putting the waveform into the
233         metromem buffer. this does runlength decoding of the waveform */
234         wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF;
235         owfm_idx = wfm_idx;
236         if (wfm_idx > size)
237                 return -EINVAL;
238         while (wfm_idx < size) {
239                 unsigned char rl;
240                 v = mem[wfm_idx++];
241                 if (v == wfm_hdr->swtb) {
242                         while (((v = mem[wfm_idx++]) != wfm_hdr->swtb) &&
243                                 wfm_idx < size)
244                                 metromem[mem_idx++] = v;
245
246                         continue;
247                 }
248
249                 if (v == wfm_hdr->endb)
250                         break;
251
252                 rl = mem[wfm_idx++];
253                 for (i = 0; i <= rl; i++)
254                         metromem[mem_idx++] = v;
255         }
256
257         cksum_idx = wfm_idx;
258         if (cksum_idx > size)
259                 return -EINVAL;
260         cksum = calc_cksum(owfm_idx, cksum_idx, mem);
261         if (cksum != mem[cksum_idx]) {
262                 printk(KERN_ERR "Error: bad waveform data cksum"
263                                 " %x != %x\n", cksum, mem[cksum_idx]);
264                 return -EINVAL;
265         }
266         *frame_count = (mem_idx/64);
267
268         return 0;
269 }
270
271 static int metronome_display_cmd(struct metronomefb_par *par)
272 {
273         int i;
274         u16 cs;
275         u16 opcode;
276         static u8 borderval;
277         u8 *ptr;
278
279         /* setup display command
280         we can't immediately set the opcode since the controller
281         will try parse the command before we've set it all up
282         so we just set cs here and set the opcode at the end */
283
284         ptr = par->metromem;
285
286         if (par->metromem_cmd->opcode == 0xCC40)
287                 opcode = cs = 0xCC41;
288         else
289                 opcode = cs = 0xCC40;
290
291         /* set the args ( 2 bytes ) for display */
292         i = 0;
293         par->metromem_cmd->args[i] =    1 << 3 /* border update */
294                                         | ((borderval++ % 4) & 0x0F) << 4
295                                         | (par->frame_count - 1) << 8;
296         cs += par->metromem_cmd->args[i++];
297
298         /* the rest are 0 */
299         memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
300
301         par->metromem_cmd->csum = cs;
302         par->metromem_cmd->opcode = opcode; /* display cmd */
303
304         return par->board->met_wait_event_intr(par);
305 }
306
307 static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
308 {
309         int i;
310         u16 cs;
311
312         /* setup power up command */
313         par->metromem_cmd->opcode = 0x1234; /* pwr up pseudo cmd */
314         cs = par->metromem_cmd->opcode;
315
316         /* set pwr1,2,3 to 1024 */
317         for (i = 0; i < 3; i++) {
318                 par->metromem_cmd->args[i] = 1024;
319                 cs += par->metromem_cmd->args[i];
320         }
321
322         /* the rest are 0 */
323         memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
324
325         par->metromem_cmd->csum = cs;
326
327         msleep(1);
328         par->board->set_rst(par, 1);
329
330         msleep(1);
331         par->board->set_stdby(par, 1);
332
333         return par->board->met_wait_event(par);
334 }
335
336 static int __devinit metronome_config_cmd(struct metronomefb_par *par)
337 {
338         int i;
339         u16 cs;
340
341         /* setup config command
342         we can't immediately set the opcode since the controller
343         will try parse the command before we've set it all up
344         so we just set cs here and set the opcode at the end */
345
346         cs = 0xCC10;
347
348         /* set the 12 args ( 8 bytes ) for config. see spec for meanings */
349         i = 0;
350         par->metromem_cmd->args[i] =    15 /* sdlew */
351                                         | 2 << 8 /* sdosz */
352                                         | 0 << 11 /* sdor */
353                                         | 0 << 12 /* sdces */
354                                         | 0 << 15; /* sdcer */
355         cs += par->metromem_cmd->args[i++];
356
357         par->metromem_cmd->args[i] =    42 /* gdspl */
358                                         | 1 << 8 /* gdr1 */
359                                         | 1 << 9 /* sdshr */
360                                         | 0 << 15; /* gdspp */
361         cs += par->metromem_cmd->args[i++];
362
363         par->metromem_cmd->args[i] =    18 /* gdspw */
364                                         | 0 << 15; /* dispc */
365         cs += par->metromem_cmd->args[i++];
366
367         par->metromem_cmd->args[i] =    599 /* vdlc */
368                                         | 0 << 11 /* dsi */
369                                         | 0 << 12; /* dsic */
370         cs += par->metromem_cmd->args[i++];
371
372         /* the rest are 0 */
373         memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
374
375         par->metromem_cmd->csum = cs;
376         par->metromem_cmd->opcode = 0xCC10; /* config cmd */
377
378         return par->board->met_wait_event(par);
379 }
380
381 static int __devinit metronome_init_cmd(struct metronomefb_par *par)
382 {
383         int i;
384         u16 cs;
385
386         /* setup init command
387         we can't immediately set the opcode since the controller
388         will try parse the command before we've set it all up
389         so we just set cs here and set the opcode at the end */
390
391         cs = 0xCC20;
392
393         /* set the args ( 2 bytes ) for init */
394         i = 0;
395         par->metromem_cmd->args[i] = 0;
396         cs += par->metromem_cmd->args[i++];
397
398         /* the rest are 0 */
399         memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
400
401         par->metromem_cmd->csum = cs;
402         par->metromem_cmd->opcode = 0xCC20; /* init cmd */
403
404         return par->board->met_wait_event(par);
405 }
406
407 static int __devinit metronome_init_regs(struct metronomefb_par *par)
408 {
409         int res;
410
411         par->board->init_gpio_regs(par);
412
413         par->board->init_lcdc_regs(par);
414
415         /* now that lcd is setup, setup dma descriptor */
416         par->board->post_dma_setup(par);
417
418         res = metronome_powerup_cmd(par);
419         if (res)
420                 return res;
421
422         res = metronome_config_cmd(par);
423         if (res)
424                 return res;
425
426         res = metronome_init_cmd(par);
427
428         return res;
429 }
430
431 static void metronomefb_dpy_update(struct metronomefb_par *par)
432 {
433         u16 cksum;
434         unsigned char *buf = (unsigned char __force *)par->info->screen_base;
435
436         /* copy from vm to metromem */
437         memcpy(par->metromem_img, buf, DPY_W*DPY_H);
438
439         cksum = calc_img_cksum((u16 *) par->metromem_img,
440                                 (epd_frame_table[0].fw * DPY_H)/2);
441         *((u16 *)(par->metromem_img) +
442                         (epd_frame_table[0].fw * DPY_H)/2) = cksum;
443         metronome_display_cmd(par);
444 }
445
446 static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index)
447 {
448         int i;
449         u16 csum = 0;
450         u16 *buf = (u16 __force *)(par->info->screen_base + index);
451         u16 *img = (u16 *)(par->metromem_img + index);
452
453         /* swizzle from vm to metromem and recalc cksum at the same time*/
454         for (i = 0; i < PAGE_SIZE/2; i++) {
455                 *(img + i) = (buf[i] << 5) & 0xE0E0;
456                 csum += *(img + i);
457         }
458         return csum;
459 }
460
461 /* this is called back from the deferred io workqueue */
462 static void metronomefb_dpy_deferred_io(struct fb_info *info,
463                                 struct list_head *pagelist)
464 {
465         u16 cksum;
466         struct page *cur;
467         struct fb_deferred_io *fbdefio = info->fbdefio;
468         struct metronomefb_par *par = info->par;
469
470         /* walk the written page list and swizzle the data */
471         list_for_each_entry(cur, &fbdefio->pagelist, lru) {
472                 cksum = metronomefb_dpy_update_page(par,
473                                         (cur->index << PAGE_SHIFT));
474                 par->metromem_img_csum -= par->csum_table[cur->index];
475                 par->csum_table[cur->index] = cksum;
476                 par->metromem_img_csum += cksum;
477         }
478
479         metronome_display_cmd(par);
480 }
481
482 static void metronomefb_fillrect(struct fb_info *info,
483                                    const struct fb_fillrect *rect)
484 {
485         struct metronomefb_par *par = info->par;
486
487         sys_fillrect(info, rect);
488         metronomefb_dpy_update(par);
489 }
490
491 static void metronomefb_copyarea(struct fb_info *info,
492                                    const struct fb_copyarea *area)
493 {
494         struct metronomefb_par *par = info->par;
495
496         sys_copyarea(info, area);
497         metronomefb_dpy_update(par);
498 }
499
500 static void metronomefb_imageblit(struct fb_info *info,
501                                 const struct fb_image *image)
502 {
503         struct metronomefb_par *par = info->par;
504
505         sys_imageblit(info, image);
506         metronomefb_dpy_update(par);
507 }
508
509 /*
510  * this is the slow path from userspace. they can seek and write to
511  * the fb. it is based on fb_sys_write
512  */
513 static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf,
514                                 size_t count, loff_t *ppos)
515 {
516         struct metronomefb_par *par = info->par;
517         unsigned long p = *ppos;
518         void *dst;
519         int err = 0;
520         unsigned long total_size;
521
522         if (info->state != FBINFO_STATE_RUNNING)
523                 return -EPERM;
524
525         total_size = info->fix.smem_len;
526
527         if (p > total_size)
528                 return -EFBIG;
529
530         if (count > total_size) {
531                 err = -EFBIG;
532                 count = total_size;
533         }
534
535         if (count + p > total_size) {
536                 if (!err)
537                         err = -ENOSPC;
538
539                 count = total_size - p;
540         }
541
542         dst = (void __force *)(info->screen_base + p);
543
544         if (copy_from_user(dst, buf, count))
545                 err = -EFAULT;
546
547         if  (!err)
548                 *ppos += count;
549
550         metronomefb_dpy_update(par);
551
552         return (err) ? err : count;
553 }
554
555 static struct fb_ops metronomefb_ops = {
556         .owner          = THIS_MODULE,
557         .fb_write       = metronomefb_write,
558         .fb_fillrect    = metronomefb_fillrect,
559         .fb_copyarea    = metronomefb_copyarea,
560         .fb_imageblit   = metronomefb_imageblit,
561 };
562
563 static struct fb_deferred_io metronomefb_defio = {
564         .delay          = HZ,
565         .deferred_io    = metronomefb_dpy_deferred_io,
566 };
567
568 static int __devinit metronomefb_probe(struct platform_device *dev)
569 {
570         struct fb_info *info;
571         struct metronome_board *board;
572         int retval = -ENOMEM;
573         int videomemorysize;
574         unsigned char *videomemory;
575         struct metronomefb_par *par;
576         const struct firmware *fw_entry;
577         int cmd_size, wfm_size, img_size, padding_size, totalsize;
578         int i;
579
580         /* pick up board specific routines */
581         board = dev->dev.platform_data;
582         if (!board)
583                 return -EINVAL;
584
585         /* try to count device specific driver, if can't, platform recalls */
586         if (!try_module_get(board->owner))
587                 return -ENODEV;
588
589         /* we have two blocks of memory.
590         info->screen_base which is vm, and is the fb used by apps.
591         par->metromem which is physically contiguous memory and
592         contains the display controller commands, waveform,
593         processed image data and padding. this is the data pulled
594         by the device's LCD controller and pushed to Metronome */
595
596         videomemorysize = (DPY_W*DPY_H);
597         videomemory = vmalloc(videomemorysize);
598         if (!videomemory)
599                 return -ENOMEM;
600
601         memset(videomemory, 0, videomemorysize);
602
603         info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
604         if (!info)
605                 goto err_vfree;
606
607         info->screen_base = (char __force __iomem *)videomemory;
608         info->fbops = &metronomefb_ops;
609
610         info->var = metronomefb_var;
611         info->fix = metronomefb_fix;
612         info->fix.smem_len = videomemorysize;
613         par = info->par;
614         par->info = info;
615         par->board = board;
616         init_waitqueue_head(&par->waitq);
617
618         /* this table caches per page csum values. */
619         par->csum_table = vmalloc(videomemorysize/PAGE_SIZE);
620         if (!par->csum_table)
621                 goto err_csum_table;
622
623         /* the metromem buffer is divided as follows:
624         command | CRC | padding
625         16kb waveform data | CRC | padding
626         image data | CRC
627         and an extra 256 bytes for dma descriptors
628         eg: IW=832 IH=622 WS=128
629         */
630
631         cmd_size = 1 * epd_frame_table[0].fw;
632         wfm_size = ((16*1024 + 2 + epd_frame_table[0].fw - 1)
633                         / epd_frame_table[0].fw) * epd_frame_table[0].fw;
634         img_size = epd_frame_table[0].fh * epd_frame_table[0].fw;
635         padding_size = 4 * epd_frame_table[0].fw;
636         totalsize = cmd_size + wfm_size + img_size + padding_size;
637         par->metromemsize = PAGE_ALIGN(totalsize + 256);
638         DPRINTK("desired memory size = %d\n", par->metromemsize);
639         dev->dev.coherent_dma_mask = 0xffffffffull;
640         par->metromem = dma_alloc_writecombine(&dev->dev, par->metromemsize,
641                                                 &par->metromem_dma, GFP_KERNEL);
642         if (!par->metromem) {
643                 printk(KERN_ERR
644                         "metronomefb: unable to allocate dma buffer\n");
645                 goto err_vfree;
646         }
647
648         info->fix.smem_start = par->metromem_dma;
649         par->metromem_cmd = (struct metromem_cmd *) par->metromem;
650         par->metromem_wfm = par->metromem + cmd_size;
651         par->metromem_img = par->metromem + cmd_size + wfm_size;
652         par->metromem_img_csum = (u16 *) (par->metromem_img +
653                                         (epd_frame_table[0].fw * DPY_H));
654         DPRINTK("img offset=0x%x\n", cmd_size + wfm_size);
655         par->metromem_desc = (struct metromem_desc *) (par->metromem + cmd_size
656                                         + wfm_size + img_size + padding_size);
657         par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size
658                                  + img_size + padding_size;
659
660         /* load the waveform in. assume mode 3, temp 31 for now
661                 a) request the waveform file from userspace
662                 b) process waveform and decode into metromem */
663         retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
664         if (retval < 0) {
665                 printk(KERN_ERR "metronomefb: couldn't get waveform\n");
666                 goto err_dma_free;
667         }
668
669         retval = load_waveform((u8 *) fw_entry->data, fw_entry->size,
670                                 par->metromem_wfm, 3, 31, &par->frame_count);
671         release_firmware(fw_entry);
672         if (retval < 0) {
673                 printk(KERN_ERR "metronomefb: couldn't process waveform\n");
674                 goto err_dma_free;
675         }
676
677         if (board->setup_irq(info))
678                 goto err_dma_free;
679
680         retval = metronome_init_regs(par);
681         if (retval < 0)
682                 goto err_free_irq;
683
684         info->flags = FBINFO_FLAG_DEFAULT;
685
686         info->fbdefio = &metronomefb_defio;
687         fb_deferred_io_init(info);
688
689         retval = fb_alloc_cmap(&info->cmap, 8, 0);
690         if (retval < 0) {
691                 printk(KERN_ERR "Failed to allocate colormap\n");
692                 goto err_fb_rel;
693         }
694
695         /* set cmap */
696         for (i = 0; i < 8; i++)
697                 info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/16;
698         memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*8);
699         memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*8);
700
701         retval = register_framebuffer(info);
702         if (retval < 0)
703                 goto err_cmap;
704
705         platform_set_drvdata(dev, info);
706
707         printk(KERN_INFO
708                 "fb%d: Metronome frame buffer device, using %dK of video"
709                 " memory\n", info->node, videomemorysize >> 10);
710
711         return 0;
712
713 err_cmap:
714         fb_dealloc_cmap(&info->cmap);
715 err_fb_rel:
716         framebuffer_release(info);
717 err_free_irq:
718         board->free_irq(info);
719 err_dma_free:
720         dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem,
721                                 par->metromem_dma);
722 err_csum_table:
723         vfree(par->csum_table);
724 err_vfree:
725         vfree(videomemory);
726         module_put(board->owner);
727         return retval;
728 }
729
730 static int __devexit metronomefb_remove(struct platform_device *dev)
731 {
732         struct fb_info *info = platform_get_drvdata(dev);
733
734         if (info) {
735                 struct metronomefb_par *par = info->par;
736                 fb_deferred_io_cleanup(info);
737                 dma_free_writecombine(&dev->dev, par->metromemsize,
738                                         par->metromem, par->metromem_dma);
739                 fb_dealloc_cmap(&info->cmap);
740                 vfree(par->csum_table);
741                 unregister_framebuffer(info);
742                 vfree((void __force *)info->screen_base);
743                 par->board->free_irq(info);
744                 module_put(par->board->owner);
745                 framebuffer_release(info);
746         }
747         return 0;
748 }
749
750 static struct platform_driver metronomefb_driver = {
751         .probe  = metronomefb_probe,
752         .remove = metronomefb_remove,
753         .driver = {
754                 .owner  = THIS_MODULE,
755                 .name   = "metronomefb",
756         },
757 };
758
759 static int __init metronomefb_init(void)
760 {
761         return platform_driver_register(&metronomefb_driver);
762 }
763
764 static void __exit metronomefb_exit(void)
765 {
766         platform_driver_unregister(&metronomefb_driver);
767 }
768
769 module_init(metronomefb_init);
770 module_exit(metronomefb_exit);
771
772 MODULE_DESCRIPTION("fbdev driver for Metronome controller");
773 MODULE_AUTHOR("Jaya Kumar");
774 MODULE_LICENSE("GPL");