diff options
-rw-r--r-- | drivers/video/Kconfig | 18 | ||||
-rw-r--r-- | drivers/video/metronomefb.c | 241 | ||||
-rw-r--r-- | include/video/metronomefb.h | 31 |
3 files changed, 160 insertions, 130 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 70d135e0cc47..6fd4a2f63cf8 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -172,11 +172,6 @@ config FB_DEFERRED_IO | |||
172 | bool | 172 | bool |
173 | depends on FB | 173 | depends on FB |
174 | 174 | ||
175 | config FB_METRONOME | ||
176 | tristate | ||
177 | depends on FB | ||
178 | depends on FB_DEFERRED_IO | ||
179 | |||
180 | config FB_HECUBA | 175 | config FB_HECUBA |
181 | tristate | 176 | tristate |
182 | depends on FB | 177 | depends on FB |
@@ -2041,6 +2036,19 @@ config XEN_FBDEV_FRONTEND | |||
2041 | frame buffer driver. It communicates with a back-end | 2036 | frame buffer driver. It communicates with a back-end |
2042 | in another domain. | 2037 | in another domain. |
2043 | 2038 | ||
2039 | config FB_METRONOME | ||
2040 | tristate "E-Ink Metronome/8track controller support" | ||
2041 | depends on FB | ||
2042 | select FB_SYS_FILLRECT | ||
2043 | select FB_SYS_COPYAREA | ||
2044 | select FB_SYS_IMAGEBLIT | ||
2045 | select FB_SYS_FOPS | ||
2046 | select FB_DEFERRED_IO | ||
2047 | help | ||
2048 | This driver implements support for the E-Ink Metronome | ||
2049 | controller. The pre-release name for this device was 8track | ||
2050 | and could also have been called by some vendors as PVI-nnnn. | ||
2051 | |||
2044 | source "drivers/video/omap/Kconfig" | 2052 | source "drivers/video/omap/Kconfig" |
2045 | 2053 | ||
2046 | source "drivers/video/backlight/Kconfig" | 2054 | source "drivers/video/backlight/Kconfig" |
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c index 7cda4f80af52..afeed0611e3e 100644 --- a/drivers/video/metronomefb.c +++ b/drivers/video/metronomefb.c | |||
@@ -44,16 +44,59 @@ | |||
44 | #define DPY_W 832 | 44 | #define DPY_W 832 |
45 | #define DPY_H 622 | 45 | #define DPY_H 622 |
46 | 46 | ||
47 | static int user_wfm_size; | ||
48 | |||
47 | /* frame differs from image. frame includes non-visible pixels */ | 49 | /* frame differs from image. frame includes non-visible pixels */ |
48 | struct epd_frame { | 50 | struct epd_frame { |
49 | int fw; /* frame width */ | 51 | int fw; /* frame width */ |
50 | int fh; /* frame height */ | 52 | int fh; /* frame height */ |
53 | u16 config[4]; | ||
54 | int wfm_size; | ||
51 | }; | 55 | }; |
52 | 56 | ||
53 | static struct epd_frame epd_frame_table[] = { | 57 | static struct epd_frame epd_frame_table[] = { |
54 | { | 58 | { |
55 | .fw = 832, | 59 | .fw = 832, |
56 | .fh = 622 | 60 | .fh = 622, |
61 | .config = { | ||
62 | 15 /* sdlew */ | ||
63 | | 2 << 8 /* sdosz */ | ||
64 | | 0 << 11 /* sdor */ | ||
65 | | 0 << 12 /* sdces */ | ||
66 | | 0 << 15, /* sdcer */ | ||
67 | 42 /* gdspl */ | ||
68 | | 1 << 8 /* gdr1 */ | ||
69 | | 1 << 9 /* sdshr */ | ||
70 | | 0 << 15, /* gdspp */ | ||
71 | 18 /* gdspw */ | ||
72 | | 0 << 15, /* dispc */ | ||
73 | 599 /* vdlc */ | ||
74 | | 0 << 11 /* dsi */ | ||
75 | | 0 << 12, /* dsic */ | ||
76 | }, | ||
77 | .wfm_size = 47001, | ||
78 | }, | ||
79 | { | ||
80 | .fw = 1088, | ||
81 | .fh = 791, | ||
82 | .config = { | ||
83 | 0x0104, | ||
84 | 0x031f, | ||
85 | 0x0088, | ||
86 | 0x02ff, | ||
87 | }, | ||
88 | .wfm_size = 46770, | ||
89 | }, | ||
90 | { | ||
91 | .fw = 1200, | ||
92 | .fh = 842, | ||
93 | .config = { | ||
94 | 0x0101, | ||
95 | 0x030e, | ||
96 | 0x0012, | ||
97 | 0x0280, | ||
98 | }, | ||
99 | .wfm_size = 46770, | ||
57 | }, | 100 | }, |
58 | }; | 101 | }; |
59 | 102 | ||
@@ -125,7 +168,6 @@ static u16 calc_img_cksum(u16 *start, int length) | |||
125 | } | 168 | } |
126 | 169 | ||
127 | /* here we decode the incoming waveform file and populate metromem */ | 170 | /* here we decode the incoming waveform file and populate metromem */ |
128 | #define EXP_WFORM_SIZE 47001 | ||
129 | static int __devinit load_waveform(u8 *mem, size_t size, int m, int t, | 171 | static int __devinit load_waveform(u8 *mem, size_t size, int m, int t, |
130 | struct metronomefb_par *par) | 172 | struct metronomefb_par *par) |
131 | { | 173 | { |
@@ -142,9 +184,12 @@ static int __devinit load_waveform(u8 *mem, size_t size, int m, int t, | |||
142 | u8 *metromem = par->metromem_wfm; | 184 | u8 *metromem = par->metromem_wfm; |
143 | struct device *dev = par->info->dev; | 185 | struct device *dev = par->info->dev; |
144 | 186 | ||
145 | if (size != EXP_WFORM_SIZE) { | 187 | if (user_wfm_size) |
188 | epd_frame_table[par->dt].wfm_size = user_wfm_size; | ||
189 | |||
190 | if (size != epd_frame_table[par->dt].wfm_size) { | ||
146 | dev_err(dev, "Error: unexpected size %d != %d\n", size, | 191 | dev_err(dev, "Error: unexpected size %d != %d\n", size, |
147 | EXP_WFORM_SIZE); | 192 | epd_frame_table[par->dt].wfm_size); |
148 | return -EINVAL; | 193 | return -EINVAL; |
149 | } | 194 | } |
150 | 195 | ||
@@ -267,15 +312,12 @@ static int metronome_display_cmd(struct metronomefb_par *par) | |||
267 | u16 cs; | 312 | u16 cs; |
268 | u16 opcode; | 313 | u16 opcode; |
269 | static u8 borderval; | 314 | static u8 borderval; |
270 | u8 *ptr; | ||
271 | 315 | ||
272 | /* setup display command | 316 | /* setup display command |
273 | we can't immediately set the opcode since the controller | 317 | we can't immediately set the opcode since the controller |
274 | will try parse the command before we've set it all up | 318 | will try parse the command before we've set it all up |
275 | so we just set cs here and set the opcode at the end */ | 319 | so we just set cs here and set the opcode at the end */ |
276 | 320 | ||
277 | ptr = par->metromem; | ||
278 | |||
279 | if (par->metromem_cmd->opcode == 0xCC40) | 321 | if (par->metromem_cmd->opcode == 0xCC40) |
280 | opcode = cs = 0xCC41; | 322 | opcode = cs = 0xCC41; |
281 | else | 323 | else |
@@ -328,44 +370,17 @@ static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) | |||
328 | 370 | ||
329 | static int __devinit metronome_config_cmd(struct metronomefb_par *par) | 371 | static int __devinit metronome_config_cmd(struct metronomefb_par *par) |
330 | { | 372 | { |
331 | int i; | ||
332 | u16 cs; | ||
333 | |||
334 | /* setup config command | 373 | /* setup config command |
335 | we can't immediately set the opcode since the controller | 374 | we can't immediately set the opcode since the controller |
336 | will try parse the command before we've set it all up | 375 | will try parse the command before we've set it all up */ |
337 | so we just set cs here and set the opcode at the end */ | ||
338 | |||
339 | cs = 0xCC10; | ||
340 | |||
341 | /* set the 12 args ( 8 bytes ) for config. see spec for meanings */ | ||
342 | i = 0; | ||
343 | par->metromem_cmd->args[i] = 15 /* sdlew */ | ||
344 | | 2 << 8 /* sdosz */ | ||
345 | | 0 << 11 /* sdor */ | ||
346 | | 0 << 12 /* sdces */ | ||
347 | | 0 << 15; /* sdcer */ | ||
348 | cs += par->metromem_cmd->args[i++]; | ||
349 | |||
350 | par->metromem_cmd->args[i] = 42 /* gdspl */ | ||
351 | | 1 << 8 /* gdr1 */ | ||
352 | | 1 << 9 /* sdshr */ | ||
353 | | 0 << 15; /* gdspp */ | ||
354 | cs += par->metromem_cmd->args[i++]; | ||
355 | |||
356 | par->metromem_cmd->args[i] = 18 /* gdspw */ | ||
357 | | 0 << 15; /* dispc */ | ||
358 | cs += par->metromem_cmd->args[i++]; | ||
359 | |||
360 | par->metromem_cmd->args[i] = 599 /* vdlc */ | ||
361 | | 0 << 11 /* dsi */ | ||
362 | | 0 << 12; /* dsic */ | ||
363 | cs += par->metromem_cmd->args[i++]; | ||
364 | 376 | ||
377 | memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config, | ||
378 | sizeof(epd_frame_table[par->dt].config)); | ||
365 | /* the rest are 0 */ | 379 | /* the rest are 0 */ |
366 | memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2); | 380 | memset((u8 *) (par->metromem_cmd->args + 4), 0, (32-4)*2); |
367 | 381 | ||
368 | par->metromem_cmd->csum = cs; | 382 | par->metromem_cmd->csum = 0xCC10; |
383 | par->metromem_cmd->csum += calc_img_cksum(par->metromem_cmd->args, 4); | ||
369 | par->metromem_cmd->opcode = 0xCC10; /* config cmd */ | 384 | par->metromem_cmd->opcode = 0xCC10; /* config cmd */ |
370 | 385 | ||
371 | return par->board->met_wait_event(par); | 386 | return par->board->met_wait_event(par); |
@@ -401,12 +416,9 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par) | |||
401 | { | 416 | { |
402 | int res; | 417 | int res; |
403 | 418 | ||
404 | par->board->init_gpio_regs(par); | 419 | res = par->board->setup_io(par); |
405 | 420 | if (res) | |
406 | par->board->init_lcdc_regs(par); | 421 | return res; |
407 | |||
408 | /* now that lcd is setup, setup dma descriptor */ | ||
409 | par->board->post_dma_setup(par); | ||
410 | 422 | ||
411 | res = metronome_powerup_cmd(par); | 423 | res = metronome_powerup_cmd(par); |
412 | if (res) | 424 | if (res) |
@@ -423,16 +435,16 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par) | |||
423 | 435 | ||
424 | static void metronomefb_dpy_update(struct metronomefb_par *par) | 436 | static void metronomefb_dpy_update(struct metronomefb_par *par) |
425 | { | 437 | { |
438 | int fbsize; | ||
426 | u16 cksum; | 439 | u16 cksum; |
427 | unsigned char *buf = (unsigned char __force *)par->info->screen_base; | 440 | unsigned char *buf = (unsigned char __force *)par->info->screen_base; |
428 | 441 | ||
442 | fbsize = par->info->fix.smem_len; | ||
429 | /* copy from vm to metromem */ | 443 | /* copy from vm to metromem */ |
430 | memcpy(par->metromem_img, buf, DPY_W*DPY_H); | 444 | memcpy(par->metromem_img, buf, fbsize); |
431 | 445 | ||
432 | cksum = calc_img_cksum((u16 *) par->metromem_img, | 446 | cksum = calc_img_cksum((u16 *) par->metromem_img, fbsize/2); |
433 | (epd_frame_table[0].fw * DPY_H)/2); | 447 | *((u16 *)(par->metromem_img) + fbsize/2) = cksum; |
434 | *((u16 *)(par->metromem_img) + | ||
435 | (epd_frame_table[0].fw * DPY_H)/2) = cksum; | ||
436 | metronome_display_cmd(par); | 448 | metronome_display_cmd(par); |
437 | } | 449 | } |
438 | 450 | ||
@@ -567,8 +579,10 @@ static int __devinit metronomefb_probe(struct platform_device *dev) | |||
567 | unsigned char *videomemory; | 579 | unsigned char *videomemory; |
568 | struct metronomefb_par *par; | 580 | struct metronomefb_par *par; |
569 | const struct firmware *fw_entry; | 581 | const struct firmware *fw_entry; |
570 | int cmd_size, wfm_size, img_size, padding_size, totalsize; | ||
571 | int i; | 582 | int i; |
583 | int panel_type; | ||
584 | int fw, fh; | ||
585 | int epd_dt_index; | ||
572 | 586 | ||
573 | /* pick up board specific routines */ | 587 | /* pick up board specific routines */ |
574 | board = dev->dev.platform_data; | 588 | board = dev->dev.platform_data; |
@@ -579,76 +593,88 @@ static int __devinit metronomefb_probe(struct platform_device *dev) | |||
579 | if (!try_module_get(board->owner)) | 593 | if (!try_module_get(board->owner)) |
580 | return -ENODEV; | 594 | return -ENODEV; |
581 | 595 | ||
596 | info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev); | ||
597 | if (!info) | ||
598 | goto err; | ||
599 | |||
582 | /* we have two blocks of memory. | 600 | /* we have two blocks of memory. |
583 | info->screen_base which is vm, and is the fb used by apps. | 601 | info->screen_base which is vm, and is the fb used by apps. |
584 | par->metromem which is physically contiguous memory and | 602 | par->metromem which is physically contiguous memory and |
585 | contains the display controller commands, waveform, | 603 | contains the display controller commands, waveform, |
586 | processed image data and padding. this is the data pulled | 604 | processed image data and padding. this is the data pulled |
587 | by the device's LCD controller and pushed to Metronome */ | 605 | by the device's LCD controller and pushed to Metronome. |
606 | the metromem memory is allocated by the board driver and | ||
607 | is provided to us */ | ||
608 | |||
609 | panel_type = board->get_panel_type(); | ||
610 | switch (panel_type) { | ||
611 | case 6: | ||
612 | epd_dt_index = 0; | ||
613 | break; | ||
614 | case 8: | ||
615 | epd_dt_index = 1; | ||
616 | break; | ||
617 | case 97: | ||
618 | epd_dt_index = 2; | ||
619 | break; | ||
620 | default: | ||
621 | dev_err(&dev->dev, "Unexpected panel type. Defaulting to 6\n"); | ||
622 | epd_dt_index = 0; | ||
623 | break; | ||
624 | } | ||
588 | 625 | ||
589 | videomemorysize = (DPY_W*DPY_H); | 626 | fw = epd_frame_table[epd_dt_index].fw; |
627 | fh = epd_frame_table[epd_dt_index].fh; | ||
628 | |||
629 | /* we need to add a spare page because our csum caching scheme walks | ||
630 | * to the end of the page */ | ||
631 | videomemorysize = PAGE_SIZE + (fw * fh); | ||
590 | videomemory = vmalloc(videomemorysize); | 632 | videomemory = vmalloc(videomemorysize); |
591 | if (!videomemory) | 633 | if (!videomemory) |
592 | return -ENOMEM; | 634 | goto err_fb_rel; |
593 | 635 | ||
594 | memset(videomemory, 0, videomemorysize); | 636 | memset(videomemory, 0, videomemorysize); |
595 | 637 | ||
596 | info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev); | ||
597 | if (!info) | ||
598 | goto err_vfree; | ||
599 | |||
600 | info->screen_base = (char __force __iomem *)videomemory; | 638 | info->screen_base = (char __force __iomem *)videomemory; |
601 | info->fbops = &metronomefb_ops; | 639 | info->fbops = &metronomefb_ops; |
602 | 640 | ||
641 | metronomefb_fix.line_length = fw; | ||
642 | metronomefb_var.xres = fw; | ||
643 | metronomefb_var.yres = fh; | ||
644 | metronomefb_var.xres_virtual = fw; | ||
645 | metronomefb_var.yres_virtual = fh; | ||
603 | info->var = metronomefb_var; | 646 | info->var = metronomefb_var; |
604 | info->fix = metronomefb_fix; | 647 | info->fix = metronomefb_fix; |
605 | info->fix.smem_len = videomemorysize; | 648 | info->fix.smem_len = videomemorysize; |
606 | par = info->par; | 649 | par = info->par; |
607 | par->info = info; | 650 | par->info = info; |
608 | par->board = board; | 651 | par->board = board; |
652 | par->dt = epd_dt_index; | ||
609 | init_waitqueue_head(&par->waitq); | 653 | init_waitqueue_head(&par->waitq); |
610 | 654 | ||
611 | /* this table caches per page csum values. */ | 655 | /* this table caches per page csum values. */ |
612 | par->csum_table = vmalloc(videomemorysize/PAGE_SIZE); | 656 | par->csum_table = vmalloc(videomemorysize/PAGE_SIZE); |
613 | if (!par->csum_table) | 657 | if (!par->csum_table) |
658 | goto err_vfree; | ||
659 | |||
660 | /* the physical framebuffer that we use is setup by | ||
661 | * the platform device driver. It will provide us | ||
662 | * with cmd, wfm and image memory in a contiguous area. */ | ||
663 | retval = board->setup_fb(par); | ||
664 | if (retval) { | ||
665 | dev_err(&dev->dev, "Failed to setup fb\n"); | ||
614 | goto err_csum_table; | 666 | goto err_csum_table; |
667 | } | ||
615 | 668 | ||
616 | /* the metromem buffer is divided as follows: | 669 | /* after this point we should have a framebuffer */ |
617 | command | CRC | padding | 670 | if ((!par->metromem_wfm) || (!par->metromem_img) || |
618 | 16kb waveform data | CRC | padding | 671 | (!par->metromem_dma)) { |
619 | image data | CRC | 672 | dev_err(&dev->dev, "fb access failure\n"); |
620 | and an extra 256 bytes for dma descriptors | 673 | retval = -EINVAL; |
621 | eg: IW=832 IH=622 WS=128 | 674 | goto err_csum_table; |
622 | */ | ||
623 | |||
624 | cmd_size = 1 * epd_frame_table[0].fw; | ||
625 | wfm_size = ((16*1024 + 2 + epd_frame_table[0].fw - 1) | ||
626 | / epd_frame_table[0].fw) * epd_frame_table[0].fw; | ||
627 | img_size = epd_frame_table[0].fh * epd_frame_table[0].fw; | ||
628 | padding_size = 4 * epd_frame_table[0].fw; | ||
629 | totalsize = cmd_size + wfm_size + img_size + padding_size; | ||
630 | par->metromemsize = PAGE_ALIGN(totalsize + 256); | ||
631 | DPRINTK("desired memory size = %d\n", par->metromemsize); | ||
632 | dev->dev.coherent_dma_mask = 0xffffffffull; | ||
633 | par->metromem = dma_alloc_writecombine(&dev->dev, par->metromemsize, | ||
634 | &par->metromem_dma, GFP_KERNEL); | ||
635 | if (!par->metromem) { | ||
636 | printk(KERN_ERR | ||
637 | "metronomefb: unable to allocate dma buffer\n"); | ||
638 | goto err_vfree; | ||
639 | } | 675 | } |
640 | 676 | ||
641 | info->fix.smem_start = par->metromem_dma; | 677 | info->fix.smem_start = par->metromem_dma; |
642 | par->metromem_cmd = (struct metromem_cmd *) par->metromem; | ||
643 | par->metromem_wfm = par->metromem + cmd_size; | ||
644 | par->metromem_img = par->metromem + cmd_size + wfm_size; | ||
645 | par->metromem_img_csum = (u16 *) (par->metromem_img + | ||
646 | (epd_frame_table[0].fw * DPY_H)); | ||
647 | DPRINTK("img offset=0x%x\n", cmd_size + wfm_size); | ||
648 | par->metromem_desc = (struct metromem_desc *) (par->metromem + cmd_size | ||
649 | + wfm_size + img_size + padding_size); | ||
650 | par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size | ||
651 | + img_size + padding_size; | ||
652 | 678 | ||
653 | /* load the waveform in. assume mode 3, temp 31 for now | 679 | /* load the waveform in. assume mode 3, temp 31 for now |
654 | a) request the waveform file from userspace | 680 | a) request the waveform file from userspace |
@@ -656,7 +682,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev) | |||
656 | retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev); | 682 | retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev); |
657 | if (retval < 0) { | 683 | if (retval < 0) { |
658 | dev_err(&dev->dev, "Failed to get waveform\n"); | 684 | dev_err(&dev->dev, "Failed to get waveform\n"); |
659 | goto err_dma_free; | 685 | goto err_csum_table; |
660 | } | 686 | } |
661 | 687 | ||
662 | retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31, | 688 | retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31, |
@@ -664,11 +690,11 @@ static int __devinit metronomefb_probe(struct platform_device *dev) | |||
664 | release_firmware(fw_entry); | 690 | release_firmware(fw_entry); |
665 | if (retval < 0) { | 691 | if (retval < 0) { |
666 | dev_err(&dev->dev, "Failed processing waveform\n"); | 692 | dev_err(&dev->dev, "Failed processing waveform\n"); |
667 | goto err_dma_free; | 693 | goto err_csum_table; |
668 | } | 694 | } |
669 | 695 | ||
670 | if (board->setup_irq(info)) | 696 | if (board->setup_irq(info)) |
671 | goto err_dma_free; | 697 | goto err_csum_table; |
672 | 698 | ||
673 | retval = metronome_init_regs(par); | 699 | retval = metronome_init_regs(par); |
674 | if (retval < 0) | 700 | if (retval < 0) |
@@ -682,7 +708,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev) | |||
682 | retval = fb_alloc_cmap(&info->cmap, 8, 0); | 708 | retval = fb_alloc_cmap(&info->cmap, 8, 0); |
683 | if (retval < 0) { | 709 | if (retval < 0) { |
684 | dev_err(&dev->dev, "Failed to allocate colormap\n"); | 710 | dev_err(&dev->dev, "Failed to allocate colormap\n"); |
685 | goto err_fb_rel; | 711 | goto err_free_irq; |
686 | } | 712 | } |
687 | 713 | ||
688 | /* set cmap */ | 714 | /* set cmap */ |
@@ -705,17 +731,15 @@ static int __devinit metronomefb_probe(struct platform_device *dev) | |||
705 | 731 | ||
706 | err_cmap: | 732 | err_cmap: |
707 | fb_dealloc_cmap(&info->cmap); | 733 | fb_dealloc_cmap(&info->cmap); |
708 | err_fb_rel: | ||
709 | framebuffer_release(info); | ||
710 | err_free_irq: | 734 | err_free_irq: |
711 | board->free_irq(info); | 735 | board->cleanup(par); |
712 | err_dma_free: | ||
713 | dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem, | ||
714 | par->metromem_dma); | ||
715 | err_csum_table: | 736 | err_csum_table: |
716 | vfree(par->csum_table); | 737 | vfree(par->csum_table); |
717 | err_vfree: | 738 | err_vfree: |
718 | vfree(videomemory); | 739 | vfree(videomemory); |
740 | err_fb_rel: | ||
741 | framebuffer_release(info); | ||
742 | err: | ||
719 | module_put(board->owner); | 743 | module_put(board->owner); |
720 | return retval; | 744 | return retval; |
721 | } | 745 | } |
@@ -726,15 +750,15 @@ static int __devexit metronomefb_remove(struct platform_device *dev) | |||
726 | 750 | ||
727 | if (info) { | 751 | if (info) { |
728 | struct metronomefb_par *par = info->par; | 752 | struct metronomefb_par *par = info->par; |
753 | |||
754 | unregister_framebuffer(info); | ||
729 | fb_deferred_io_cleanup(info); | 755 | fb_deferred_io_cleanup(info); |
730 | dma_free_writecombine(&dev->dev, par->metromemsize, | ||
731 | par->metromem, par->metromem_dma); | ||
732 | fb_dealloc_cmap(&info->cmap); | 756 | fb_dealloc_cmap(&info->cmap); |
757 | par->board->cleanup(par); | ||
733 | vfree(par->csum_table); | 758 | vfree(par->csum_table); |
734 | unregister_framebuffer(info); | ||
735 | vfree((void __force *)info->screen_base); | 759 | vfree((void __force *)info->screen_base); |
736 | par->board->free_irq(info); | ||
737 | module_put(par->board->owner); | 760 | module_put(par->board->owner); |
761 | dev_dbg(&dev->dev, "calling release\n"); | ||
738 | framebuffer_release(info); | 762 | framebuffer_release(info); |
739 | } | 763 | } |
740 | return 0; | 764 | return 0; |
@@ -759,6 +783,9 @@ static void __exit metronomefb_exit(void) | |||
759 | platform_driver_unregister(&metronomefb_driver); | 783 | platform_driver_unregister(&metronomefb_driver); |
760 | } | 784 | } |
761 | 785 | ||
786 | module_param(user_wfm_size, uint, 0); | ||
787 | MODULE_PARM_DESC(user_wfm_size, "Set custom waveform size"); | ||
788 | |||
762 | module_init(metronomefb_init); | 789 | module_init(metronomefb_init); |
763 | module_exit(metronomefb_exit); | 790 | module_exit(metronomefb_exit); |
764 | 791 | ||
diff --git a/include/video/metronomefb.h b/include/video/metronomefb.h index dab04b4fad7f..9863f4b6d418 100644 --- a/include/video/metronomefb.h +++ b/include/video/metronomefb.h | |||
@@ -12,14 +12,6 @@ | |||
12 | #ifndef _LINUX_METRONOMEFB_H_ | 12 | #ifndef _LINUX_METRONOMEFB_H_ |
13 | #define _LINUX_METRONOMEFB_H_ | 13 | #define _LINUX_METRONOMEFB_H_ |
14 | 14 | ||
15 | /* address and control descriptors used by metronome controller */ | ||
16 | struct metromem_desc { | ||
17 | u32 mFDADR0; | ||
18 | u32 mFSADR0; | ||
19 | u32 mFIDR0; | ||
20 | u32 mLDCMD0; | ||
21 | }; | ||
22 | |||
23 | /* command structure used by metronome controller */ | 15 | /* command structure used by metronome controller */ |
24 | struct metromem_cmd { | 16 | struct metromem_cmd { |
25 | u16 opcode; | 17 | u16 opcode; |
@@ -29,34 +21,37 @@ struct metromem_cmd { | |||
29 | 21 | ||
30 | /* struct used by metronome. board specific stuff comes from *board */ | 22 | /* struct used by metronome. board specific stuff comes from *board */ |
31 | struct metronomefb_par { | 23 | struct metronomefb_par { |
32 | unsigned char *metromem; | ||
33 | struct metromem_desc *metromem_desc; | ||
34 | struct metromem_cmd *metromem_cmd; | 24 | struct metromem_cmd *metromem_cmd; |
35 | unsigned char *metromem_wfm; | 25 | unsigned char *metromem_wfm; |
36 | unsigned char *metromem_img; | 26 | unsigned char *metromem_img; |
37 | u16 *metromem_img_csum; | 27 | u16 *metromem_img_csum; |
38 | u16 *csum_table; | 28 | u16 *csum_table; |
39 | int metromemsize; | ||
40 | dma_addr_t metromem_dma; | 29 | dma_addr_t metromem_dma; |
41 | dma_addr_t metromem_desc_dma; | ||
42 | struct fb_info *info; | 30 | struct fb_info *info; |
43 | struct metronome_board *board; | 31 | struct metronome_board *board; |
44 | wait_queue_head_t waitq; | 32 | wait_queue_head_t waitq; |
45 | u8 frame_count; | 33 | u8 frame_count; |
34 | int extra_size; | ||
35 | int dt; | ||
46 | }; | 36 | }; |
47 | 37 | ||
48 | /* board specific routines */ | 38 | /* board specific routines and data */ |
49 | struct metronome_board { | 39 | struct metronome_board { |
50 | struct module *owner; | 40 | struct module *owner; /* the platform device */ |
51 | void (*free_irq)(struct fb_info *); | ||
52 | void (*init_gpio_regs)(struct metronomefb_par *); | ||
53 | void (*init_lcdc_regs)(struct metronomefb_par *); | ||
54 | void (*post_dma_setup)(struct metronomefb_par *); | ||
55 | void (*set_rst)(struct metronomefb_par *, int); | 41 | void (*set_rst)(struct metronomefb_par *, int); |
56 | void (*set_stdby)(struct metronomefb_par *, int); | 42 | void (*set_stdby)(struct metronomefb_par *, int); |
43 | void (*cleanup)(struct metronomefb_par *); | ||
57 | int (*met_wait_event)(struct metronomefb_par *); | 44 | int (*met_wait_event)(struct metronomefb_par *); |
58 | int (*met_wait_event_intr)(struct metronomefb_par *); | 45 | int (*met_wait_event_intr)(struct metronomefb_par *); |
59 | int (*setup_irq)(struct fb_info *); | 46 | int (*setup_irq)(struct fb_info *); |
47 | int (*setup_fb)(struct metronomefb_par *); | ||
48 | int (*setup_io)(struct metronomefb_par *); | ||
49 | int (*get_panel_type)(void); | ||
50 | unsigned char *metromem; | ||
51 | int fw; | ||
52 | int fh; | ||
53 | int wfm_size; | ||
54 | struct fb_info *host_fbinfo; /* the host LCD controller's fbi */ | ||
60 | }; | 55 | }; |
61 | 56 | ||
62 | #endif | 57 | #endif |