aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/metronomefb.c
diff options
context:
space:
mode:
authorJaya Kumar <jayakumar.lkml@gmail.com>2008-04-28 05:15:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-28 11:58:41 -0400
commit03c33a4f002b2521debf1efc269cade983b6e86a (patch)
treee4ed669161ba7d029497fe6917854bea0ae83aec /drivers/video/metronomefb.c
parent963654a9c919d18f8b9137f8ffd9d2d30a139269 (diff)
fbdev: platforming metronomefb and am200epd
This patch splits metronomefb into the platform independent metronomefb and the platform dependent am200epd. Signed-off-by: Jaya Kumar <jayakumar.lkml@gmail.com> Cc: "Antonino A. Daplas" <adaplas@pol.net> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/metronomefb.c')
-rw-r--r--drivers/video/metronomefb.c314
1 files changed, 47 insertions, 267 deletions
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c
index 5602f3e3f919..17066dd5a190 100644
--- a/drivers/video/metronomefb.c
+++ b/drivers/video/metronomefb.c
@@ -13,12 +13,10 @@
13 * Corporation. http://support.eink.com/community 13 * Corporation. http://support.eink.com/community
14 * 14 *
15 * This driver is written to be used with the Metronome display controller. 15 * This driver is written to be used with the Metronome display controller.
16 * It was tested with an E-Ink 800x600 Vizplex EPD on a Gumstix Connex board 16 * It is intended to be architecture independent. A board specific driver
17 * using the Lyre interface board. 17 * must be used to perform all the physical IO interactions. An example
18 * is provided as am200epd.c
18 * 19 *
19 * General notes:
20 * - User must set metronomefb_enable=1 to enable it.
21 * - See Documentation/fb/metronomefb.txt for how metronome works.
22 */ 20 */
23#include <linux/module.h> 21#include <linux/module.h>
24#include <linux/kernel.h> 22#include <linux/kernel.h>
@@ -38,9 +36,11 @@
38#include <linux/uaccess.h> 36#include <linux/uaccess.h>
39#include <linux/irq.h> 37#include <linux/irq.h>
40 38
41#include <asm/arch/pxa-regs.h> 39#include <video/metronomefb.h>
40
42#include <asm/unaligned.h> 41#include <asm/unaligned.h>
43 42
43
44#define DEBUG 1 44#define DEBUG 1
45#ifdef DEBUG 45#ifdef DEBUG
46#define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a) 46#define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
@@ -53,35 +53,6 @@
53#define DPY_W 832 53#define DPY_W 832
54#define DPY_H 622 54#define DPY_H 622
55 55
56struct metromem_desc {
57 u32 mFDADR0;
58 u32 mFSADR0;
59 u32 mFIDR0;
60 u32 mLDCMD0;
61};
62
63struct metromem_cmd {
64 u16 opcode;
65 u16 args[((64-2)/2)];
66 u16 csum;
67};
68
69struct metronomefb_par {
70 unsigned char *metromem;
71 struct metromem_desc *metromem_desc;
72 struct metromem_cmd *metromem_cmd;
73 unsigned char *metromem_wfm;
74 unsigned char *metromem_img;
75 u16 *metromem_img_csum;
76 u16 *csum_table;
77 int metromemsize;
78 dma_addr_t metromem_dma;
79 dma_addr_t metromem_desc_dma;
80 struct fb_info *info;
81 wait_queue_head_t waitq;
82 u8 frame_count;
83};
84
85/* frame differs from image. frame includes non-visible pixels */ 56/* frame differs from image. frame includes non-visible pixels */
86struct epd_frame { 57struct epd_frame {
87 int fw; /* frame width */ 58 int fw; /* frame width */
@@ -120,8 +91,7 @@ static struct fb_var_screeninfo metronomefb_var __devinitdata = {
120 .transp = { 0, 0, 0 }, 91 .transp = { 0, 0, 0 },
121}; 92};
122 93
123static unsigned int metronomefb_enable; 94/* the waveform structure that is coming from userspace firmware */
124
125struct waveform_hdr { 95struct waveform_hdr {
126 u8 stuff[32]; 96 u8 stuff[32];
127 97
@@ -301,165 +271,6 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
301 return 0; 271 return 0;
302} 272}
303 273
304/* register offsets for gpio control */
305#define LED_GPIO_PIN 51
306#define STDBY_GPIO_PIN 48
307#define RST_GPIO_PIN 49
308#define RDY_GPIO_PIN 32
309#define ERR_GPIO_PIN 17
310#define PCBPWR_GPIO_PIN 16
311
312#define AF_SEL_GPIO_N 0x3
313#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2)
314#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2)
315#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2)
316#define GPDR1_OFFSET(pin) (pin - 32)
317#define GPCR1_OFFSET(pin) (pin - 32)
318#define GPSR1_OFFSET(pin) (pin - 32)
319#define GPCR0_OFFSET(pin) (pin)
320#define GPSR0_OFFSET(pin) (pin)
321
322static void metronome_set_gpio_output(int pin, int val)
323{
324 u8 index;
325
326 index = pin >> 4;
327
328 switch (index) {
329 case 1:
330 if (val)
331 GPSR0 |= (1 << GPSR0_OFFSET(pin));
332 else
333 GPCR0 |= (1 << GPCR0_OFFSET(pin));
334 break;
335 case 2:
336 break;
337 case 3:
338 if (val)
339 GPSR1 |= (1 << GPSR1_OFFSET(pin));
340 else
341 GPCR1 |= (1 << GPCR1_OFFSET(pin));
342 break;
343 default:
344 printk(KERN_ERR "unimplemented\n");
345 }
346}
347
348static void __devinit metronome_init_gpio_pin(int pin, int dir)
349{
350 u8 index;
351 /* dir 0 is output, 1 is input
352 - do 2 things here:
353 - set gpio alternate function to standard gpio
354 - set gpio direction to input or output */
355
356 index = pin >> 4;
357 switch (index) {
358 case 1:
359 GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin));
360
361 if (dir)
362 GPDR0 &= ~(1 << pin);
363 else
364 GPDR0 |= (1 << pin);
365 break;
366 case 2:
367 GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin));
368
369 if (dir)
370 GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
371 else
372 GPDR1 |= (1 << GPDR1_OFFSET(pin));
373 break;
374 case 3:
375 GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin));
376
377 if (dir)
378 GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
379 else
380 GPDR1 |= (1 << GPDR1_OFFSET(pin));
381 break;
382 default:
383 printk(KERN_ERR "unimplemented\n");
384 }
385}
386
387static void __devinit metronome_init_gpio_regs(void)
388{
389 metronome_init_gpio_pin(LED_GPIO_PIN, 0);
390 metronome_set_gpio_output(LED_GPIO_PIN, 0);
391
392 metronome_init_gpio_pin(STDBY_GPIO_PIN, 0);
393 metronome_set_gpio_output(STDBY_GPIO_PIN, 0);
394
395 metronome_init_gpio_pin(RST_GPIO_PIN, 0);
396 metronome_set_gpio_output(RST_GPIO_PIN, 0);
397
398 metronome_init_gpio_pin(RDY_GPIO_PIN, 1);
399
400 metronome_init_gpio_pin(ERR_GPIO_PIN, 1);
401
402 metronome_init_gpio_pin(PCBPWR_GPIO_PIN, 0);
403 metronome_set_gpio_output(PCBPWR_GPIO_PIN, 0);
404}
405
406static void metronome_disable_lcd_controller(struct metronomefb_par *par)
407{
408 LCSR = 0xffffffff; /* Clear LCD Status Register */
409 LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */
410
411 /* we reset and just wait for things to settle */
412 msleep(200);
413}
414
415static void metronome_enable_lcd_controller(struct metronomefb_par *par)
416{
417 LCSR = 0xffffffff;
418 FDADR0 = par->metromem_desc_dma;
419 LCCR0 |= LCCR0_ENB;
420}
421
422static void __devinit metronome_init_lcdc_regs(struct metronomefb_par *par)
423{
424 /* here we do:
425 - disable the lcd controller
426 - setup lcd control registers
427 - setup dma descriptor
428 - reenable lcd controller
429 */
430
431 /* disable the lcd controller */
432 metronome_disable_lcd_controller(par);
433
434 /* setup lcd control registers */
435 LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS
436 | LCCR0_QDM | LCCR0_BM | LCCR0_OUM;
437
438 LCCR1 = (epd_frame_table[0].fw/2 - 1) /* pixels per line */
439 | (27 << 10) /* hsync pulse width - 1 */
440 | (33 << 16) /* eol pixel count */
441 | (33 << 24); /* bol pixel count */
442
443 LCCR2 = (epd_frame_table[0].fh - 1) /* lines per panel */
444 | (24 << 10) /* vsync pulse width - 1 */
445 | (2 << 16) /* eof pixel count */
446 | (0 << 24); /* bof pixel count */
447
448 LCCR3 = 2 /* pixel clock divisor */
449 | (24 << 8) /* AC Bias pin freq */
450 | LCCR3_16BPP /* BPP */
451 | LCCR3_PCP; /* PCP falling edge */
452
453 /* setup dma descriptor */
454 par->metromem_desc->mFDADR0 = par->metromem_desc_dma;
455 par->metromem_desc->mFSADR0 = par->metromem_dma;
456 par->metromem_desc->mFIDR0 = 0;
457 par->metromem_desc->mLDCMD0 = epd_frame_table[0].fw
458 * epd_frame_table[0].fh;
459 /* reenable lcd controller */
460 metronome_enable_lcd_controller(par);
461}
462
463static int metronome_display_cmd(struct metronomefb_par *par) 274static int metronome_display_cmd(struct metronomefb_par *par)
464{ 275{
465 int i; 276 int i;
@@ -493,8 +304,7 @@ static int metronome_display_cmd(struct metronomefb_par *par)
493 par->metromem_cmd->csum = cs; 304 par->metromem_cmd->csum = cs;
494 par->metromem_cmd->opcode = opcode; /* display cmd */ 305 par->metromem_cmd->opcode = opcode; /* display cmd */
495 306
496 i = wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ); 307 return par->board->met_wait_event_intr(par);
497 return i;
498} 308}
499 309
500static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) 310static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
@@ -518,13 +328,12 @@ static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
518 par->metromem_cmd->csum = cs; 328 par->metromem_cmd->csum = cs;
519 329
520 msleep(1); 330 msleep(1);
521 metronome_set_gpio_output(RST_GPIO_PIN, 1); 331 par->board->set_rst(par, 1);
522 332
523 msleep(1); 333 msleep(1);
524 metronome_set_gpio_output(STDBY_GPIO_PIN, 1); 334 par->board->set_stdby(par, 1);
525 335
526 i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); 336 return par->board->met_wait_event(par);
527 return i;
528} 337}
529 338
530static int __devinit metronome_config_cmd(struct metronomefb_par *par) 339static int __devinit metronome_config_cmd(struct metronomefb_par *par)
@@ -569,8 +378,7 @@ static int __devinit metronome_config_cmd(struct metronomefb_par *par)
569 par->metromem_cmd->csum = cs; 378 par->metromem_cmd->csum = cs;
570 par->metromem_cmd->opcode = 0xCC10; /* config cmd */ 379 par->metromem_cmd->opcode = 0xCC10; /* config cmd */
571 380
572 i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); 381 return par->board->met_wait_event(par);
573 return i;
574} 382}
575 383
576static int __devinit metronome_init_cmd(struct metronomefb_par *par) 384static int __devinit metronome_init_cmd(struct metronomefb_par *par)
@@ -596,16 +404,19 @@ static int __devinit metronome_init_cmd(struct metronomefb_par *par)
596 par->metromem_cmd->csum = cs; 404 par->metromem_cmd->csum = cs;
597 par->metromem_cmd->opcode = 0xCC20; /* init cmd */ 405 par->metromem_cmd->opcode = 0xCC20; /* init cmd */
598 406
599 i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); 407 return par->board->met_wait_event(par);
600 return i;
601} 408}
602 409
603static int __devinit metronome_init_regs(struct metronomefb_par *par) 410static int __devinit metronome_init_regs(struct metronomefb_par *par)
604{ 411{
605 int res; 412 int res;
606 413
607 metronome_init_gpio_regs(); 414 par->board->init_gpio_regs(par);
608 metronome_init_lcdc_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);
609 420
610 res = metronome_powerup_cmd(par); 421 res = metronome_powerup_cmd(par);
611 if (res) 422 if (res)
@@ -616,8 +427,6 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par)
616 return res; 427 return res;
617 428
618 res = metronome_init_cmd(par); 429 res = metronome_init_cmd(par);
619 if (res)
620 return res;
621 430
622 return res; 431 return res;
623} 432}
@@ -632,7 +441,7 @@ static void metronomefb_dpy_update(struct metronomefb_par *par)
632 441
633 cksum = calc_img_cksum((u16 *) par->metromem_img, 442 cksum = calc_img_cksum((u16 *) par->metromem_img,
634 (epd_frame_table[0].fw * DPY_H)/2); 443 (epd_frame_table[0].fw * DPY_H)/2);
635 *((u16 *) (par->metromem_img) + 444 *((u16 *)(par->metromem_img) +
636 (epd_frame_table[0].fw * DPY_H)/2) = cksum; 445 (epd_frame_table[0].fw * DPY_H)/2) = cksum;
637 metronome_display_cmd(par); 446 metronome_display_cmd(par);
638} 447}
@@ -641,8 +450,8 @@ static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index)
641{ 450{
642 int i; 451 int i;
643 u16 csum = 0; 452 u16 csum = 0;
644 u16 *buf = (u16 __force *) (par->info->screen_base + index); 453 u16 *buf = (u16 __force *)(par->info->screen_base + index);
645 u16 *img = (u16 *) (par->metromem_img + index); 454 u16 *img = (u16 *)(par->metromem_img + index);
646 455
647 /* swizzle from vm to metromem and recalc cksum at the same time*/ 456 /* swizzle from vm to metromem and recalc cksum at the same time*/
648 for (i = 0; i < PAGE_SIZE/2; i++) { 457 for (i = 0; i < PAGE_SIZE/2; i++) {
@@ -733,7 +542,7 @@ static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf,
733 count = total_size - p; 542 count = total_size - p;
734 } 543 }
735 544
736 dst = (void __force *) (info->screen_base + p); 545 dst = (void __force *)(info->screen_base + p);
737 546
738 if (copy_from_user(dst, buf, count)) 547 if (copy_from_user(dst, buf, count))
739 err = -EFAULT; 548 err = -EFAULT;
@@ -759,18 +568,10 @@ static struct fb_deferred_io metronomefb_defio = {
759 .deferred_io = metronomefb_dpy_deferred_io, 568 .deferred_io = metronomefb_dpy_deferred_io,
760}; 569};
761 570
762static irqreturn_t metronome_handle_irq(int irq, void *dev_id)
763{
764 struct fb_info *info = dev_id;
765 struct metronomefb_par *par = info->par;
766
767 wake_up_interruptible(&par->waitq);
768 return IRQ_HANDLED;
769}
770
771static int __devinit metronomefb_probe(struct platform_device *dev) 571static int __devinit metronomefb_probe(struct platform_device *dev)
772{ 572{
773 struct fb_info *info; 573 struct fb_info *info;
574 struct metronome_board *board;
774 int retval = -ENOMEM; 575 int retval = -ENOMEM;
775 int videomemorysize; 576 int videomemorysize;
776 unsigned char *videomemory; 577 unsigned char *videomemory;
@@ -779,17 +580,26 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
779 int cmd_size, wfm_size, img_size, padding_size, totalsize; 580 int cmd_size, wfm_size, img_size, padding_size, totalsize;
780 int i; 581 int i;
781 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
782 /* we have two blocks of memory. 592 /* we have two blocks of memory.
783 info->screen_base which is vm, and is the fb used by apps. 593 info->screen_base which is vm, and is the fb used by apps.
784 par->metromem which is physically contiguous memory and 594 par->metromem which is physically contiguous memory and
785 contains the display controller commands, waveform, 595 contains the display controller commands, waveform,
786 processed image data and padding. this is the data pulled 596 processed image data and padding. this is the data pulled
787 by the pxa255's LCD controller and pushed to Metronome */ 597 by the device's LCD controller and pushed to Metronome */
788 598
789 videomemorysize = (DPY_W*DPY_H); 599 videomemorysize = (DPY_W*DPY_H);
790 videomemory = vmalloc(videomemorysize); 600 videomemory = vmalloc(videomemorysize);
791 if (!videomemory) 601 if (!videomemory)
792 return retval; 602 return -ENOMEM;
793 603
794 memset(videomemory, 0, videomemorysize); 604 memset(videomemory, 0, videomemorysize);
795 605
@@ -797,7 +607,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
797 if (!info) 607 if (!info)
798 goto err_vfree; 608 goto err_vfree;
799 609
800 info->screen_base = (char __iomem *) videomemory; 610 info->screen_base = (char __force __iomem *)videomemory;
801 info->fbops = &metronomefb_ops; 611 info->fbops = &metronomefb_ops;
802 612
803 info->var = metronomefb_var; 613 info->var = metronomefb_var;
@@ -805,6 +615,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
805 info->fix.smem_len = videomemorysize; 615 info->fix.smem_len = videomemorysize;
806 par = info->par; 616 par = info->par;
807 par->info = info; 617 par->info = info;
618 par->board = board;
808 init_waitqueue_head(&par->waitq); 619 init_waitqueue_head(&par->waitq);
809 620
810 /* this table caches per page csum values. */ 621 /* this table caches per page csum values. */
@@ -849,11 +660,10 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
849 par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size 660 par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size
850 + img_size + padding_size; 661 + img_size + padding_size;
851 662
852 /* load the waveform in. assume mode 3, temp 31 for now */ 663 /* load the waveform in. assume mode 3, temp 31 for now
853 /* a) request the waveform file from userspace 664 a) request the waveform file from userspace
854 b) process waveform and decode into metromem */ 665 b) process waveform and decode into metromem */
855 666 retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
856 retval = request_firmware(&fw_entry, "waveform.wbf", &dev->dev);
857 if (retval < 0) { 667 if (retval < 0) {
858 printk(KERN_ERR "metronomefb: couldn't get waveform\n"); 668 printk(KERN_ERR "metronomefb: couldn't get waveform\n");
859 goto err_dma_free; 669 goto err_dma_free;
@@ -867,13 +677,8 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
867 } 677 }
868 release_firmware(fw_entry); 678 release_firmware(fw_entry);
869 679
870 retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), metronome_handle_irq, 680 if (board->setup_irq(info))
871 IRQF_DISABLED, "Metronome", info);
872 if (retval) {
873 dev_err(&dev->dev, "request_irq failed: %d\n", retval);
874 goto err_ld_wfm; 681 goto err_ld_wfm;
875 }
876 set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING);
877 682
878 retval = metronome_init_regs(par); 683 retval = metronome_init_regs(par);
879 if (retval < 0) 684 if (retval < 0)
@@ -913,7 +718,7 @@ err_cmap:
913err_fb_rel: 718err_fb_rel:
914 framebuffer_release(info); 719 framebuffer_release(info);
915err_free_irq: 720err_free_irq:
916 free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); 721 board->free_irq(info);
917err_ld_wfm: 722err_ld_wfm:
918 release_firmware(fw_entry); 723 release_firmware(fw_entry);
919err_dma_free: 724err_dma_free:
@@ -923,6 +728,7 @@ err_csum_table:
923 vfree(par->csum_table); 728 vfree(par->csum_table);
924err_vfree: 729err_vfree:
925 vfree(videomemory); 730 vfree(videomemory);
731 module_put(board->owner);
926 return retval; 732 return retval;
927} 733}
928 734
@@ -939,7 +745,8 @@ static int __devexit metronomefb_remove(struct platform_device *dev)
939 vfree(par->csum_table); 745 vfree(par->csum_table);
940 unregister_framebuffer(info); 746 unregister_framebuffer(info);
941 vfree((void __force *)info->screen_base); 747 vfree((void __force *)info->screen_base);
942 free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); 748 par->board->free_irq(info);
749 module_put(par->board->owner);
943 framebuffer_release(info); 750 framebuffer_release(info);
944 } 751 }
945 return 0; 752 return 0;
@@ -949,48 +756,21 @@ static struct platform_driver metronomefb_driver = {
949 .probe = metronomefb_probe, 756 .probe = metronomefb_probe,
950 .remove = metronomefb_remove, 757 .remove = metronomefb_remove,
951 .driver = { 758 .driver = {
759 .owner = THIS_MODULE,
952 .name = "metronomefb", 760 .name = "metronomefb",
953 }, 761 },
954}; 762};
955 763
956static struct platform_device *metronomefb_device;
957
958static int __init metronomefb_init(void) 764static int __init metronomefb_init(void)
959{ 765{
960 int ret; 766 return platform_driver_register(&metronomefb_driver);
961
962 if (!metronomefb_enable) {
963 printk(KERN_ERR
964 "Use metronomefb_enable to enable the device\n");
965 return -ENXIO;
966 }
967
968 ret = platform_driver_register(&metronomefb_driver);
969 if (!ret) {
970 metronomefb_device = platform_device_alloc("metronomefb", 0);
971 if (metronomefb_device)
972 ret = platform_device_add(metronomefb_device);
973 else
974 ret = -ENOMEM;
975
976 if (ret) {
977 platform_device_put(metronomefb_device);
978 platform_driver_unregister(&metronomefb_driver);
979 }
980 }
981 return ret;
982
983} 767}
984 768
985static void __exit metronomefb_exit(void) 769static void __exit metronomefb_exit(void)
986{ 770{
987 platform_device_unregister(metronomefb_device);
988 platform_driver_unregister(&metronomefb_driver); 771 platform_driver_unregister(&metronomefb_driver);
989} 772}
990 773
991module_param(metronomefb_enable, uint, 0);
992MODULE_PARM_DESC(metronomefb_enable, "Enable communication with Metronome");
993
994module_init(metronomefb_init); 774module_init(metronomefb_init);
995module_exit(metronomefb_exit); 775module_exit(metronomefb_exit);
996 776