fbdev: platforming metronomefb and am200epd
[GitHub/LineageOS/android_kernel_samsung_universal7580.git] / drivers / video / metronomefb.c
CommitLineData
de7c6d15
JK
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.
03c33a4f
JK
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
de7c6d15 19 *
de7c6d15
JK
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
03c33a4f
JK
39#include <video/metronomefb.h>
40
de7c6d15
JK
41#include <asm/unaligned.h>
42
03c33a4f 43
de7c6d15
JK
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
de7c6d15
JK
56/* frame differs from image. frame includes non-visible pixels */
57struct epd_frame {
58 int fw; /* frame width */
59 int fh; /* frame height */
60};
61
62static struct epd_frame epd_frame_table[] = {
63 {
64 .fw = 832,
65 .fh = 622
66 },
67};
68
69static 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
80static 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
03c33a4f 94/* the waveform structure that is coming from userspace firmware */
de7c6d15
JK
95struct 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 */
115static 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
126static 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
138static 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
de7c6d15
JK
274static 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
03c33a4f 307 return par->board->met_wait_event_intr(par);
de7c6d15
JK
308}
309
310static 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);
03c33a4f 331 par->board->set_rst(par, 1);
de7c6d15
JK
332
333 msleep(1);
03c33a4f 334 par->board->set_stdby(par, 1);
de7c6d15 335
03c33a4f 336 return par->board->met_wait_event(par);
de7c6d15
JK
337}
338
339static 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
03c33a4f 381 return par->board->met_wait_event(par);
de7c6d15
JK
382}
383
384static 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
03c33a4f 407 return par->board->met_wait_event(par);
de7c6d15
JK
408}
409
410static int __devinit metronome_init_regs(struct metronomefb_par *par)
411{
412 int res;
413
03c33a4f
JK
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);
de7c6d15
JK
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);
de7c6d15
JK
430
431 return res;
432}
433
434static 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);
03c33a4f 444 *((u16 *)(par->metromem_img) +
de7c6d15
JK
445 (epd_frame_table[0].fw * DPY_H)/2) = cksum;
446 metronome_display_cmd(par);
447}
448
449static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index)
450{
451 int i;
452 u16 csum = 0;
03c33a4f
JK
453 u16 *buf = (u16 __force *)(par->info->screen_base + index);
454 u16 *img = (u16 *)(par->metromem_img + index);
de7c6d15
JK
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 */
465static 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
485static void metronomefb_fillrect(struct fb_info *info,
486 const struct fb_fillrect *rect)
487{
488 struct metronomefb_par *par = info->par;
489
555514fa 490 sys_fillrect(info, rect);
de7c6d15
JK
491 metronomefb_dpy_update(par);
492}
493
494static void metronomefb_copyarea(struct fb_info *info,
495 const struct fb_copyarea *area)
496{
497 struct metronomefb_par *par = info->par;
498
555514fa 499 sys_copyarea(info, area);
de7c6d15
JK
500 metronomefb_dpy_update(par);
501}
502
503static void metronomefb_imageblit(struct fb_info *info,
504 const struct fb_image *image)
505{
506 struct metronomefb_par *par = info->par;
507
555514fa 508 sys_imageblit(info, image);
de7c6d15
JK
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 */
516static 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
03c33a4f 545 dst = (void __force *)(info->screen_base + p);
de7c6d15
JK
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
558static 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
566static struct fb_deferred_io metronomefb_defio = {
567 .delay = HZ,
568 .deferred_io = metronomefb_dpy_deferred_io,
569};
570
de7c6d15
JK
571static int __devinit metronomefb_probe(struct platform_device *dev)
572{
573 struct fb_info *info;
03c33a4f 574 struct metronome_board *board;
de7c6d15
JK
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
03c33a4f
JK
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
de7c6d15
JK
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
03c33a4f 597 by the device's LCD controller and pushed to Metronome */
de7c6d15
JK
598
599 videomemorysize = (DPY_W*DPY_H);
600 videomemory = vmalloc(videomemorysize);
601 if (!videomemory)
03c33a4f 602 return -ENOMEM;
de7c6d15
JK
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
03c33a4f 610 info->screen_base = (char __force __iomem *)videomemory;
de7c6d15
JK
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;
03c33a4f 618 par->board = board;
de7c6d15
JK
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
03c33a4f
JK
663 /* load the waveform in. assume mode 3, temp 31 for now
664 a) request the waveform file from userspace
de7c6d15 665 b) process waveform and decode into metromem */
03c33a4f 666 retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
de7c6d15
JK
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
03c33a4f 680 if (board->setup_irq(info))
de7c6d15 681 goto err_ld_wfm;
de7c6d15
JK
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
716err_cmap:
717 fb_dealloc_cmap(&info->cmap);
718err_fb_rel:
719 framebuffer_release(info);
720err_free_irq:
03c33a4f 721 board->free_irq(info);
de7c6d15
JK
722err_ld_wfm:
723 release_firmware(fw_entry);
724err_dma_free:
725 dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem,
726 par->metromem_dma);
727err_csum_table:
728 vfree(par->csum_table);
729err_vfree:
730 vfree(videomemory);
03c33a4f 731 module_put(board->owner);
de7c6d15
JK
732 return retval;
733}
734
735static 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);
03c33a4f
JK
748 par->board->free_irq(info);
749 module_put(par->board->owner);
de7c6d15
JK
750 framebuffer_release(info);
751 }
752 return 0;
753}
754
755static struct platform_driver metronomefb_driver = {
756 .probe = metronomefb_probe,
757 .remove = metronomefb_remove,
758 .driver = {
03c33a4f 759 .owner = THIS_MODULE,
de7c6d15
JK
760 .name = "metronomefb",
761 },
762};
763
de7c6d15
JK
764static int __init metronomefb_init(void)
765{
03c33a4f 766 return platform_driver_register(&metronomefb_driver);
de7c6d15
JK
767}
768
769static void __exit metronomefb_exit(void)
770{
de7c6d15
JK
771 platform_driver_unregister(&metronomefb_driver);
772}
773
de7c6d15
JK
774module_init(metronomefb_init);
775module_exit(metronomefb_exit);
776
777MODULE_DESCRIPTION("fbdev driver for Metronome controller");
778MODULE_AUTHOR("Jaya Kumar");
779MODULE_LICENSE("GPL");