fbdev: platforming metronomefb and am200epd
[safe/jmp/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 = le32_to_cpu(get_unaligned((__le32 *) wfm_hdr->wmta));
210         wmta &= 0x00FFFFFF;
211         cksum_idx = wmta + m*4 + 3;
212         if (cksum_idx > size)
213                 return -EINVAL;
214         cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
215         if (cksum != mem[cksum_idx]) {
216                 printk(KERN_ERR "Error: bad mode table address cksum"
217                                 " %x != %x\n", cksum, mem[cksum_idx]);
218                 return -EINVAL;
219         }
220
221         /* check waveform temperature table address checksum */
222         tta = le32_to_cpu(get_unaligned((int *) (mem + wmta + m*4)));
223         tta &= 0x00FFFFFF;
224         cksum_idx = tta + trn*4 + 3;
225         if (cksum_idx > size)
226                 return -EINVAL;
227         cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
228         if (cksum != mem[cksum_idx]) {
229                 printk(KERN_ERR "Error: bad temperature table address cksum"
230                         " %x != %x\n", cksum, mem[cksum_idx]);
231                 return -EINVAL;
232         }
233
234         /* here we do the real work of putting the waveform into the
235         metromem buffer. this does runlength decoding of the waveform */
236         wfm_idx = le32_to_cpu(get_unaligned((__le32 *) (mem + tta + trn*4)));
237         wfm_idx &= 0x00FFFFFF;
238         owfm_idx = wfm_idx;
239         if (wfm_idx > size)
240                 return -EINVAL;
241         while (wfm_idx < size) {
242                 unsigned char rl;
243                 v = mem[wfm_idx++];
244                 if (v == wfm_hdr->swtb) {
245                         while (((v = mem[wfm_idx++]) != wfm_hdr->swtb) &&
246                                 wfm_idx < size)
247                                 metromem[mem_idx++] = v;
248
249                         continue;
250                 }
251
252                 if (v == wfm_hdr->endb)
253                         break;
254
255                 rl = mem[wfm_idx++];
256                 for (i = 0; i <= rl; i++)
257                         metromem[mem_idx++] = v;
258         }
259
260         cksum_idx = wfm_idx;
261         if (cksum_idx > size)
262                 return -EINVAL;
263         cksum = calc_cksum(owfm_idx, cksum_idx, mem);
264         if (cksum != mem[cksum_idx]) {
265                 printk(KERN_ERR "Error: bad waveform data cksum"
266                                 " %x != %x\n", cksum, mem[cksum_idx]);
267                 return -EINVAL;
268         }
269         *frame_count = (mem_idx/64);
270
271         return 0;
272 }
273
274 static int metronome_display_cmd(struct metronomefb_par *par)
275 {
276         int i;
277         u16 cs;
278         u16 opcode;
279         static u8 borderval;
280         u8 *ptr;
281
282         /* setup display command
283         we can't immediately set the opcode since the controller
284         will try parse the command before we've set it all up
285         so we just set cs here and set the opcode at the end */
286
287         ptr = par->metromem;
288
289         if (par->metromem_cmd->opcode == 0xCC40)
290                 opcode = cs = 0xCC41;
291         else
292                 opcode = cs = 0xCC40;
293
294         /* set the args ( 2 bytes ) for display */
295         i = 0;
296         par->metromem_cmd->args[i] =    1 << 3 /* border update */
297                                         | ((borderval++ % 4) & 0x0F) << 4
298                                         | (par->frame_count - 1) << 8;
299         cs += par->metromem_cmd->args[i++];
300
301         /* the rest are 0 */
302         memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
303
304         par->metromem_cmd->csum = cs;
305         par->metromem_cmd->opcode = opcode; /* display cmd */
306
307         return par->board->met_wait_event_intr(par);
308 }
309
310 static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
311 {
312         int i;
313         u16 cs;
314
315         /* setup power up command */
316         par->metromem_cmd->opcode = 0x1234; /* pwr up pseudo cmd */
317         cs = par->metromem_cmd->opcode;
318
319         /* set pwr1,2,3 to 1024 */
320         for (i = 0; i < 3; i++) {
321                 par->metromem_cmd->args[i] = 1024;
322                 cs += par->metromem_cmd->args[i];
323         }
324
325         /* the rest are 0 */
326         memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
327
328         par->metromem_cmd->csum = cs;
329
330         msleep(1);
331         par->board->set_rst(par, 1);
332
333         msleep(1);
334         par->board->set_stdby(par, 1);
335
336         return par->board->met_wait_event(par);
337 }
338
339 static int __devinit metronome_config_cmd(struct metronomefb_par *par)
340 {
341         int i;
342         u16 cs;
343
344         /* setup config command
345         we can't immediately set the opcode since the controller
346         will try parse the command before we've set it all up
347         so we just set cs here and set the opcode at the end */
348
349         cs = 0xCC10;
350
351         /* set the 12 args ( 8 bytes ) for config. see spec for meanings */
352         i = 0;
353         par->metromem_cmd->args[i] =    15 /* sdlew */
354                                         | 2 << 8 /* sdosz */
355                                         | 0 << 11 /* sdor */
356                                         | 0 << 12 /* sdces */
357                                         | 0 << 15; /* sdcer */
358         cs += par->metromem_cmd->args[i++];
359
360         par->metromem_cmd->args[i] =    42 /* gdspl */
361                                         | 1 << 8 /* gdr1 */
362                                         | 1 << 9 /* sdshr */
363                                         | 0 << 15; /* gdspp */
364         cs += par->metromem_cmd->args[i++];
365
366         par->metromem_cmd->args[i] =    18 /* gdspw */
367                                         | 0 << 15; /* dispc */
368         cs += par->metromem_cmd->args[i++];
369
370         par->metromem_cmd->args[i] =    599 /* vdlc */
371                                         | 0 << 11 /* dsi */
372                                         | 0 << 12; /* dsic */
373         cs += par->metromem_cmd->args[i++];
374
375         /* the rest are 0 */
376         memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
377
378         par->metromem_cmd->csum = cs;
379         par->metromem_cmd->opcode = 0xCC10; /* config cmd */
380
381         return par->board->met_wait_event(par);
382 }
383
384 static int __devinit metronome_init_cmd(struct metronomefb_par *par)
385 {
386         int i;
387         u16 cs;
388
389         /* setup init command
390         we can't immediately set the opcode since the controller
391         will try parse the command before we've set it all up
392         so we just set cs here and set the opcode at the end */
393
394         cs = 0xCC20;
395
396         /* set the args ( 2 bytes ) for init */
397         i = 0;
398         par->metromem_cmd->args[i] = 0;
399         cs += par->metromem_cmd->args[i++];
400
401         /* the rest are 0 */
402         memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
403
404         par->metromem_cmd->csum = cs;
405         par->metromem_cmd->opcode = 0xCC20; /* init cmd */
406
407         return par->board->met_wait_event(par);
408 }
409
410 static int __devinit metronome_init_regs(struct metronomefb_par *par)
411 {
412         int res;
413
414         par->board->init_gpio_regs(par);
415
416         par->board->init_lcdc_regs(par);
417
418         /* now that lcd is setup, setup dma descriptor */
419         par->board->post_dma_setup(par);
420
421         res = metronome_powerup_cmd(par);
422         if (res)
423                 return res;
424
425         res = metronome_config_cmd(par);
426         if (res)
427                 return res;
428
429         res = metronome_init_cmd(par);
430
431         return res;
432 }
433
434 static void metronomefb_dpy_update(struct metronomefb_par *par)
435 {
436         u16 cksum;
437         unsigned char *buf = (unsigned char __force *)par->info->screen_base;
438
439         /* copy from vm to metromem */
440         memcpy(par->metromem_img, buf, DPY_W*DPY_H);
441
442         cksum = calc_img_cksum((u16 *) par->metromem_img,
443                                 (epd_frame_table[0].fw * DPY_H)/2);
444         *((u16 *)(par->metromem_img) +
445                         (epd_frame_table[0].fw * DPY_H)/2) = cksum;
446         metronome_display_cmd(par);
447 }
448
449 static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index)
450 {
451         int i;
452         u16 csum = 0;
453         u16 *buf = (u16 __force *)(par->info->screen_base + index);
454         u16 *img = (u16 *)(par->metromem_img + index);
455
456         /* swizzle from vm to metromem and recalc cksum at the same time*/
457         for (i = 0; i < PAGE_SIZE/2; i++) {
458                 *(img + i) = (buf[i] << 5) & 0xE0E0;
459                 csum += *(img + i);
460         }
461         return csum;
462 }
463
464 /* this is called back from the deferred io workqueue */
465 static void metronomefb_dpy_deferred_io(struct fb_info *info,
466                                 struct list_head *pagelist)
467 {
468         u16 cksum;
469         struct page *cur;
470         struct fb_deferred_io *fbdefio = info->fbdefio;
471         struct metronomefb_par *par = info->par;
472
473         /* walk the written page list and swizzle the data */
474         list_for_each_entry(cur, &fbdefio->pagelist, lru) {
475                 cksum = metronomefb_dpy_update_page(par,
476                                         (cur->index << PAGE_SHIFT));
477                 par->metromem_img_csum -= par->csum_table[cur->index];
478                 par->csum_table[cur->index] = cksum;
479                 par->metromem_img_csum += cksum;
480         }
481
482         metronome_display_cmd(par);
483 }
484
485 static void metronomefb_fillrect(struct fb_info *info,
486                                    const struct fb_fillrect *rect)
487 {
488         struct metronomefb_par *par = info->par;
489
490         sys_fillrect(info, rect);
491         metronomefb_dpy_update(par);
492 }
493
494 static void metronomefb_copyarea(struct fb_info *info,
495                                    const struct fb_copyarea *area)
496 {
497         struct metronomefb_par *par = info->par;
498
499         sys_copyarea(info, area);
500         metronomefb_dpy_update(par);
501 }
502
503 static void metronomefb_imageblit(struct fb_info *info,
504                                 const struct fb_image *image)
505 {
506         struct metronomefb_par *par = info->par;
507
508         sys_imageblit(info, image);
509         metronomefb_dpy_update(par);
510 }
511
512 /*
513  * this is the slow path from userspace. they can seek and write to
514  * the fb. it is based on fb_sys_write
515  */
516 static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf,
517                                 size_t count, loff_t *ppos)
518 {
519         struct metronomefb_par *par = info->par;
520         unsigned long p = *ppos;
521         void *dst;
522         int err = 0;
523         unsigned long total_size;
524
525         if (info->state != FBINFO_STATE_RUNNING)
526                 return -EPERM;
527
528         total_size = info->fix.smem_len;
529
530         if (p > total_size)
531                 return -EFBIG;
532
533         if (count > total_size) {
534                 err = -EFBIG;
535                 count = total_size;
536         }
537
538         if (count + p > total_size) {
539                 if (!err)
540                         err = -ENOSPC;
541
542                 count = total_size - p;
543         }
544
545         dst = (void __force *)(info->screen_base + p);
546
547         if (copy_from_user(dst, buf, count))
548                 err = -EFAULT;
549
550         if  (!err)
551                 *ppos += count;
552
553         metronomefb_dpy_update(par);
554
555         return (err) ? err : count;
556 }
557
558 static struct fb_ops metronomefb_ops = {
559         .owner          = THIS_MODULE,
560         .fb_write       = metronomefb_write,
561         .fb_fillrect    = metronomefb_fillrect,
562         .fb_copyarea    = metronomefb_copyarea,
563         .fb_imageblit   = metronomefb_imageblit,
564 };
565
566 static struct fb_deferred_io metronomefb_defio = {
567         .delay          = HZ,
568         .deferred_io    = metronomefb_dpy_deferred_io,
569 };
570
571 static int __devinit metronomefb_probe(struct platform_device *dev)
572 {
573         struct fb_info *info;
574         struct metronome_board *board;
575         int retval = -ENOMEM;
576         int videomemorysize;
577         unsigned char *videomemory;
578         struct metronomefb_par *par;
579         const struct firmware *fw_entry;
580         int cmd_size, wfm_size, img_size, padding_size, totalsize;
581         int i;
582
583         /* pick up board specific routines */
584         board = dev->dev.platform_data;
585         if (!board)
586                 return -EINVAL;
587
588         /* try to count device specific driver, if can't, platform recalls */
589         if (!try_module_get(board->owner))
590                 return -ENODEV;
591
592         /* we have two blocks of memory.
593         info->screen_base which is vm, and is the fb used by apps.
594         par->metromem which is physically contiguous memory and
595         contains the display controller commands, waveform,
596         processed image data and padding. this is the data pulled
597         by the device's LCD controller and pushed to Metronome */
598
599         videomemorysize = (DPY_W*DPY_H);
600         videomemory = vmalloc(videomemorysize);
601         if (!videomemory)
602                 return -ENOMEM;
603
604         memset(videomemory, 0, videomemorysize);
605
606         info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
607         if (!info)
608                 goto err_vfree;
609
610         info->screen_base = (char __force __iomem *)videomemory;
611         info->fbops = &metronomefb_ops;
612
613         info->var = metronomefb_var;
614         info->fix = metronomefb_fix;
615         info->fix.smem_len = videomemorysize;
616         par = info->par;
617         par->info = info;
618         par->board = board;
619         init_waitqueue_head(&par->waitq);
620
621         /* this table caches per page csum values. */
622         par->csum_table = vmalloc(videomemorysize/PAGE_SIZE);
623         if (!par->csum_table)
624                 goto err_csum_table;
625
626         /* the metromem buffer is divided as follows:
627         command | CRC | padding
628         16kb waveform data | CRC | padding
629         image data | CRC
630         and an extra 256 bytes for dma descriptors
631         eg: IW=832 IH=622 WS=128
632         */
633
634         cmd_size = 1 * epd_frame_table[0].fw;
635         wfm_size = ((16*1024 + 2 + epd_frame_table[0].fw - 1)
636                         / epd_frame_table[0].fw) * epd_frame_table[0].fw;
637         img_size = epd_frame_table[0].fh * epd_frame_table[0].fw;
638         padding_size = 4 * epd_frame_table[0].fw;
639         totalsize = cmd_size + wfm_size + img_size + padding_size;
640         par->metromemsize = PAGE_ALIGN(totalsize + 256);
641         DPRINTK("desired memory size = %d\n", par->metromemsize);
642         dev->dev.coherent_dma_mask = 0xffffffffull;
643         par->metromem = dma_alloc_writecombine(&dev->dev, par->metromemsize,
644                                                 &par->metromem_dma, GFP_KERNEL);
645         if (!par->metromem) {
646                 printk(KERN_ERR
647                         "metronomefb: unable to allocate dma buffer\n");
648                 goto err_vfree;
649         }
650
651         info->fix.smem_start = par->metromem_dma;
652         par->metromem_cmd = (struct metromem_cmd *) par->metromem;
653         par->metromem_wfm = par->metromem + cmd_size;
654         par->metromem_img = par->metromem + cmd_size + wfm_size;
655         par->metromem_img_csum = (u16 *) (par->metromem_img +
656                                         (epd_frame_table[0].fw * DPY_H));
657         DPRINTK("img offset=0x%x\n", cmd_size + wfm_size);
658         par->metromem_desc = (struct metromem_desc *) (par->metromem + cmd_size
659                                         + wfm_size + img_size + padding_size);
660         par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size
661                                  + img_size + padding_size;
662
663         /* load the waveform in. assume mode 3, temp 31 for now
664                 a) request the waveform file from userspace
665                 b) process waveform and decode into metromem */
666         retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
667         if (retval < 0) {
668                 printk(KERN_ERR "metronomefb: couldn't get waveform\n");
669                 goto err_dma_free;
670         }
671
672         retval = load_waveform((u8 *) fw_entry->data, fw_entry->size,
673                                 par->metromem_wfm, 3, 31, &par->frame_count);
674         if (retval < 0) {
675                 printk(KERN_ERR "metronomefb: couldn't process waveform\n");
676                 goto err_ld_wfm;
677         }
678         release_firmware(fw_entry);
679
680         if (board->setup_irq(info))
681                 goto err_ld_wfm;
682
683         retval = metronome_init_regs(par);
684         if (retval < 0)
685                 goto err_free_irq;
686
687         info->flags = FBINFO_FLAG_DEFAULT;
688
689         info->fbdefio = &metronomefb_defio;
690         fb_deferred_io_init(info);
691
692         retval = fb_alloc_cmap(&info->cmap, 8, 0);
693         if (retval < 0) {
694                 printk(KERN_ERR "Failed to allocate colormap\n");
695                 goto err_fb_rel;
696         }
697
698         /* set cmap */
699         for (i = 0; i < 8; i++)
700                 info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/16;
701         memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*8);
702         memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*8);
703
704         retval = register_framebuffer(info);
705         if (retval < 0)
706                 goto err_cmap;
707
708         platform_set_drvdata(dev, info);
709
710         printk(KERN_INFO
711                 "fb%d: Metronome frame buffer device, using %dK of video"
712                 " memory\n", info->node, videomemorysize >> 10);
713
714         return 0;
715
716 err_cmap:
717         fb_dealloc_cmap(&info->cmap);
718 err_fb_rel:
719         framebuffer_release(info);
720 err_free_irq:
721         board->free_irq(info);
722 err_ld_wfm:
723         release_firmware(fw_entry);
724 err_dma_free:
725         dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem,
726                                 par->metromem_dma);
727 err_csum_table:
728         vfree(par->csum_table);
729 err_vfree:
730         vfree(videomemory);
731         module_put(board->owner);
732         return retval;
733 }
734
735 static int __devexit metronomefb_remove(struct platform_device *dev)
736 {
737         struct fb_info *info = platform_get_drvdata(dev);
738
739         if (info) {
740                 struct metronomefb_par *par = info->par;
741                 fb_deferred_io_cleanup(info);
742                 dma_free_writecombine(&dev->dev, par->metromemsize,
743                                         par->metromem, par->metromem_dma);
744                 fb_dealloc_cmap(&info->cmap);
745                 vfree(par->csum_table);
746                 unregister_framebuffer(info);
747                 vfree((void __force *)info->screen_base);
748                 par->board->free_irq(info);
749                 module_put(par->board->owner);
750                 framebuffer_release(info);
751         }
752         return 0;
753 }
754
755 static struct platform_driver metronomefb_driver = {
756         .probe  = metronomefb_probe,
757         .remove = metronomefb_remove,
758         .driver = {
759                 .owner  = THIS_MODULE,
760                 .name   = "metronomefb",
761         },
762 };
763
764 static int __init metronomefb_init(void)
765 {
766         return platform_driver_register(&metronomefb_driver);
767 }
768
769 static void __exit metronomefb_exit(void)
770 {
771         platform_driver_unregister(&metronomefb_driver);
772 }
773
774 module_init(metronomefb_init);
775 module_exit(metronomefb_exit);
776
777 MODULE_DESCRIPTION("fbdev driver for Metronome controller");
778 MODULE_AUTHOR("Jaya Kumar");
779 MODULE_LICENSE("GPL");