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