diff options
Diffstat (limited to 'drivers/video/metronomefb.c')
-rw-r--r-- | drivers/video/metronomefb.c | 314 |
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 | ||
56 | struct metromem_desc { | ||
57 | u32 mFDADR0; | ||
58 | u32 mFSADR0; | ||
59 | u32 mFIDR0; | ||
60 | u32 mLDCMD0; | ||
61 | }; | ||
62 | |||
63 | struct metromem_cmd { | ||
64 | u16 opcode; | ||
65 | u16 args[((64-2)/2)]; | ||
66 | u16 csum; | ||
67 | }; | ||
68 | |||
69 | struct 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 */ |
86 | struct epd_frame { | 57 | struct 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 | ||
123 | static unsigned int metronomefb_enable; | 94 | /* the waveform structure that is coming from userspace firmware */ |
124 | |||
125 | struct waveform_hdr { | 95 | struct 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 | |||
322 | static 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 | |||
348 | static 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 | |||
387 | static 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 | |||
406 | static 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 | |||
415 | static 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 | |||
422 | static 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 | |||
463 | static int metronome_display_cmd(struct metronomefb_par *par) | 274 | static 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 | ||
500 | static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) | 310 | static 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 | ||
530 | static int __devinit metronome_config_cmd(struct metronomefb_par *par) | 339 | static 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 | ||
576 | static int __devinit metronome_init_cmd(struct metronomefb_par *par) | 384 | static 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 | ||
603 | static int __devinit metronome_init_regs(struct metronomefb_par *par) | 410 | static 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 | ||
762 | static 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 | |||
771 | static int __devinit metronomefb_probe(struct platform_device *dev) | 571 | static 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: | |||
913 | err_fb_rel: | 718 | err_fb_rel: |
914 | framebuffer_release(info); | 719 | framebuffer_release(info); |
915 | err_free_irq: | 720 | err_free_irq: |
916 | free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); | 721 | board->free_irq(info); |
917 | err_ld_wfm: | 722 | err_ld_wfm: |
918 | release_firmware(fw_entry); | 723 | release_firmware(fw_entry); |
919 | err_dma_free: | 724 | err_dma_free: |
@@ -923,6 +728,7 @@ err_csum_table: | |||
923 | vfree(par->csum_table); | 728 | vfree(par->csum_table); |
924 | err_vfree: | 729 | err_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 | ||
956 | static struct platform_device *metronomefb_device; | ||
957 | |||
958 | static int __init metronomefb_init(void) | 764 | static 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 | ||
985 | static void __exit metronomefb_exit(void) | 769 | static 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 | ||
991 | module_param(metronomefb_enable, uint, 0); | ||
992 | MODULE_PARM_DESC(metronomefb_enable, "Enable communication with Metronome"); | ||
993 | |||
994 | module_init(metronomefb_init); | 774 | module_init(metronomefb_init); |
995 | module_exit(metronomefb_exit); | 775 | module_exit(metronomefb_exit); |
996 | 776 | ||