aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/s3c-fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/s3c-fb.c')
-rw-r--r--drivers/video/s3c-fb.c202
1 files changed, 90 insertions, 112 deletions
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index 0753b1cfcb8b..0c63b69b6340 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -192,6 +192,7 @@ struct s3c_fb_vsync {
192 * @regs: The mapped hardware registers. 192 * @regs: The mapped hardware registers.
193 * @variant: Variant information for this hardware. 193 * @variant: Variant information for this hardware.
194 * @enabled: A bitmask of enabled hardware windows. 194 * @enabled: A bitmask of enabled hardware windows.
195 * @output_on: Flag if the physical output is enabled.
195 * @pdata: The platform configuration data passed with the device. 196 * @pdata: The platform configuration data passed with the device.
196 * @windows: The hardware windows that have been claimed. 197 * @windows: The hardware windows that have been claimed.
197 * @irq_no: IRQ line number 198 * @irq_no: IRQ line number
@@ -208,6 +209,7 @@ struct s3c_fb {
208 struct s3c_fb_variant variant; 209 struct s3c_fb_variant variant;
209 210
210 unsigned char enabled; 211 unsigned char enabled;
212 bool output_on;
211 213
212 struct s3c_fb_platdata *pdata; 214 struct s3c_fb_platdata *pdata;
213 struct s3c_fb_win *windows[S3C_FB_MAX_WIN]; 215 struct s3c_fb_win *windows[S3C_FB_MAX_WIN];
@@ -441,6 +443,39 @@ static void shadow_protect_win(struct s3c_fb_win *win, bool protect)
441} 443}
442 444
443/** 445/**
446 * s3c_fb_enable() - Set the state of the main LCD output
447 * @sfb: The main framebuffer state.
448 * @enable: The state to set.
449 */
450static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
451{
452 u32 vidcon0 = readl(sfb->regs + VIDCON0);
453
454 if (enable && !sfb->output_on)
455 pm_runtime_get_sync(sfb->dev);
456
457 if (enable) {
458 vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
459 } else {
460 /* see the note in the framebuffer datasheet about
461 * why you cannot take both of these bits down at the
462 * same time. */
463
464 if (vidcon0 & VIDCON0_ENVID) {
465 vidcon0 |= VIDCON0_ENVID;
466 vidcon0 &= ~VIDCON0_ENVID_F;
467 }
468 }
469
470 writel(vidcon0, sfb->regs + VIDCON0);
471
472 if (!enable && sfb->output_on)
473 pm_runtime_put_sync(sfb->dev);
474
475 sfb->output_on = enable;
476}
477
478/**
444 * s3c_fb_set_par() - framebuffer request to set new framebuffer state. 479 * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
445 * @info: The framebuffer to change. 480 * @info: The framebuffer to change.
446 * 481 *
@@ -461,6 +496,8 @@ static int s3c_fb_set_par(struct fb_info *info)
461 496
462 dev_dbg(sfb->dev, "setting framebuffer parameters\n"); 497 dev_dbg(sfb->dev, "setting framebuffer parameters\n");
463 498
499 pm_runtime_get_sync(sfb->dev);
500
464 shadow_protect_win(win, 1); 501 shadow_protect_win(win, 1);
465 502
466 switch (var->bits_per_pixel) { 503 switch (var->bits_per_pixel) {
@@ -510,9 +547,10 @@ static int s3c_fb_set_par(struct fb_info *info)
510 if (sfb->variant.is_2443) 547 if (sfb->variant.is_2443)
511 data |= (1 << 5); 548 data |= (1 << 5);
512 549
513 data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
514 writel(data, regs + VIDCON0); 550 writel(data, regs + VIDCON0);
515 551
552 s3c_fb_enable(sfb, 1);
553
516 data = VIDTCON0_VBPD(var->upper_margin - 1) | 554 data = VIDTCON0_VBPD(var->upper_margin - 1) |
517 VIDTCON0_VFPD(var->lower_margin - 1) | 555 VIDTCON0_VFPD(var->lower_margin - 1) |
518 VIDTCON0_VSPW(var->vsync_len - 1); 556 VIDTCON0_VSPW(var->vsync_len - 1);
@@ -574,6 +612,7 @@ static int s3c_fb_set_par(struct fb_info *info)
574 } 612 }
575 613
576 data = WINCONx_ENWIN; 614 data = WINCONx_ENWIN;
615 sfb->enabled |= (1 << win->index);
577 616
578 /* note, since we have to round up the bits-per-pixel, we end up 617 /* note, since we have to round up the bits-per-pixel, we end up
579 * relying on the bitfield information for r/g/b/a to work out 618 * relying on the bitfield information for r/g/b/a to work out
@@ -621,7 +660,8 @@ static int s3c_fb_set_par(struct fb_info *info)
621 } else if (var->transp.length == 1) 660 } else if (var->transp.length == 1)
622 data |= WINCON1_BPPMODE_25BPP_A1888 661 data |= WINCON1_BPPMODE_25BPP_A1888
623 | WINCON1_BLD_PIX; 662 | WINCON1_BLD_PIX;
624 else if (var->transp.length == 4) 663 else if ((var->transp.length == 4) ||
664 (var->transp.length == 8))
625 data |= WINCON1_BPPMODE_28BPP_A4888 665 data |= WINCON1_BPPMODE_28BPP_A4888
626 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; 666 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
627 else 667 else
@@ -654,6 +694,8 @@ static int s3c_fb_set_par(struct fb_info *info)
654 694
655 shadow_protect_win(win, 0); 695 shadow_protect_win(win, 0);
656 696
697 pm_runtime_put_sync(sfb->dev);
698
657 return 0; 699 return 0;
658} 700}
659 701
@@ -725,6 +767,8 @@ static int s3c_fb_setcolreg(unsigned regno,
725 dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n", 767 dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
726 __func__, win->index, regno, red, green, blue); 768 __func__, win->index, regno, red, green, blue);
727 769
770 pm_runtime_get_sync(sfb->dev);
771
728 switch (info->fix.visual) { 772 switch (info->fix.visual) {
729 case FB_VISUAL_TRUECOLOR: 773 case FB_VISUAL_TRUECOLOR:
730 /* true-colour, use pseudo-palette */ 774 /* true-colour, use pseudo-palette */
@@ -752,39 +796,15 @@ static int s3c_fb_setcolreg(unsigned regno,
752 break; 796 break;
753 797
754 default: 798 default:
799 pm_runtime_put_sync(sfb->dev);
755 return 1; /* unknown type */ 800 return 1; /* unknown type */
756 } 801 }
757 802
803 pm_runtime_put_sync(sfb->dev);
758 return 0; 804 return 0;
759} 805}
760 806
761/** 807/**
762 * s3c_fb_enable() - Set the state of the main LCD output
763 * @sfb: The main framebuffer state.
764 * @enable: The state to set.
765 */
766static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
767{
768 u32 vidcon0 = readl(sfb->regs + VIDCON0);
769
770 if (enable)
771 vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
772 else {
773 /* see the note in the framebuffer datasheet about
774 * why you cannot take both of these bits down at the
775 * same time. */
776
777 if (!(vidcon0 & VIDCON0_ENVID))
778 return;
779
780 vidcon0 |= VIDCON0_ENVID;
781 vidcon0 &= ~VIDCON0_ENVID_F;
782 }
783
784 writel(vidcon0, sfb->regs + VIDCON0);
785}
786
787/**
788 * s3c_fb_blank() - blank or unblank the given window 808 * s3c_fb_blank() - blank or unblank the given window
789 * @blank_mode: The blank state from FB_BLANK_* 809 * @blank_mode: The blank state from FB_BLANK_*
790 * @info: The framebuffer to blank. 810 * @info: The framebuffer to blank.
@@ -800,6 +820,8 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
800 820
801 dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); 821 dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
802 822
823 pm_runtime_get_sync(sfb->dev);
824
803 wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4)); 825 wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
804 826
805 switch (blank_mode) { 827 switch (blank_mode) {
@@ -810,12 +832,16 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
810 832
811 case FB_BLANK_NORMAL: 833 case FB_BLANK_NORMAL:
812 /* disable the DMA and display 0x0 (black) */ 834 /* disable the DMA and display 0x0 (black) */
835 shadow_protect_win(win, 1);
813 writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0), 836 writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
814 sfb->regs + sfb->variant.winmap + (index * 4)); 837 sfb->regs + sfb->variant.winmap + (index * 4));
838 shadow_protect_win(win, 0);
815 break; 839 break;
816 840
817 case FB_BLANK_UNBLANK: 841 case FB_BLANK_UNBLANK:
842 shadow_protect_win(win, 1);
818 writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4)); 843 writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
844 shadow_protect_win(win, 0);
819 wincon |= WINCONx_ENWIN; 845 wincon |= WINCONx_ENWIN;
820 sfb->enabled |= (1 << index); 846 sfb->enabled |= (1 << index);
821 break; 847 break;
@@ -823,10 +849,13 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
823 case FB_BLANK_VSYNC_SUSPEND: 849 case FB_BLANK_VSYNC_SUSPEND:
824 case FB_BLANK_HSYNC_SUSPEND: 850 case FB_BLANK_HSYNC_SUSPEND:
825 default: 851 default:
852 pm_runtime_put_sync(sfb->dev);
826 return 1; 853 return 1;
827 } 854 }
828 855
856 shadow_protect_win(win, 1);
829 writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4)); 857 writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
858 shadow_protect_win(win, 0);
830 859
831 /* Check the enabled state to see if we need to be running the 860 /* Check the enabled state to see if we need to be running the
832 * main LCD interface, as if there are no active windows then 861 * main LCD interface, as if there are no active windows then
@@ -845,8 +874,13 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
845 /* we're stuck with this until we can do something about overriding 874 /* we're stuck with this until we can do something about overriding
846 * the power control using the blanking event for a single fb. 875 * the power control using the blanking event for a single fb.
847 */ 876 */
848 if (index == sfb->pdata->default_win) 877 if (index == sfb->pdata->default_win) {
878 shadow_protect_win(win, 1);
849 s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0); 879 s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
880 shadow_protect_win(win, 0);
881 }
882
883 pm_runtime_put_sync(sfb->dev);
850 884
851 return 0; 885 return 0;
852} 886}
@@ -870,6 +904,8 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
870 void __iomem *buf = sfb->regs + win->index * 8; 904 void __iomem *buf = sfb->regs + win->index * 8;
871 unsigned int start_boff, end_boff; 905 unsigned int start_boff, end_boff;
872 906
907 pm_runtime_get_sync(sfb->dev);
908
873 /* Offset in bytes to the start of the displayed area */ 909 /* Offset in bytes to the start of the displayed area */
874 start_boff = var->yoffset * info->fix.line_length; 910 start_boff = var->yoffset * info->fix.line_length;
875 /* X offset depends on the current bpp */ 911 /* X offset depends on the current bpp */
@@ -888,6 +924,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
888 break; 924 break;
889 default: 925 default:
890 dev_err(sfb->dev, "invalid bpp\n"); 926 dev_err(sfb->dev, "invalid bpp\n");
927 pm_runtime_put_sync(sfb->dev);
891 return -EINVAL; 928 return -EINVAL;
892 } 929 }
893 } 930 }
@@ -903,6 +940,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
903 940
904 shadow_protect_win(win, 0); 941 shadow_protect_win(win, 0);
905 942
943 pm_runtime_put_sync(sfb->dev);
906 return 0; 944 return 0;
907} 945}
908 946
@@ -992,11 +1030,16 @@ static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
992 if (crtc != 0) 1030 if (crtc != 0)
993 return -ENODEV; 1031 return -ENODEV;
994 1032
1033 pm_runtime_get_sync(sfb->dev);
1034
995 count = sfb->vsync_info.count; 1035 count = sfb->vsync_info.count;
996 s3c_fb_enable_irq(sfb); 1036 s3c_fb_enable_irq(sfb);
997 ret = wait_event_interruptible_timeout(sfb->vsync_info.wait, 1037 ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
998 count != sfb->vsync_info.count, 1038 count != sfb->vsync_info.count,
999 msecs_to_jiffies(VSYNC_TIMEOUT_MSEC)); 1039 msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
1040
1041 pm_runtime_put_sync(sfb->dev);
1042
1000 if (ret == 0) 1043 if (ret == 0)
1001 return -ETIMEDOUT; 1044 return -ETIMEDOUT;
1002 1045
@@ -1027,30 +1070,8 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
1027 return ret; 1070 return ret;
1028} 1071}
1029 1072
1030static int s3c_fb_open(struct fb_info *info, int user)
1031{
1032 struct s3c_fb_win *win = info->par;
1033 struct s3c_fb *sfb = win->parent;
1034
1035 pm_runtime_get_sync(sfb->dev);
1036
1037 return 0;
1038}
1039
1040static int s3c_fb_release(struct fb_info *info, int user)
1041{
1042 struct s3c_fb_win *win = info->par;
1043 struct s3c_fb *sfb = win->parent;
1044
1045 pm_runtime_put_sync(sfb->dev);
1046
1047 return 0;
1048}
1049
1050static struct fb_ops s3c_fb_ops = { 1073static struct fb_ops s3c_fb_ops = {
1051 .owner = THIS_MODULE, 1074 .owner = THIS_MODULE,
1052 .fb_open = s3c_fb_open,
1053 .fb_release = s3c_fb_release,
1054 .fb_check_var = s3c_fb_check_var, 1075 .fb_check_var = s3c_fb_check_var,
1055 .fb_set_par = s3c_fb_set_par, 1076 .fb_set_par = s3c_fb_set_par,
1056 .fb_blank = s3c_fb_blank, 1077 .fb_blank = s3c_fb_blank,
@@ -1452,7 +1473,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
1452 dev_err(dev, "failed to create window %d\n", win); 1473 dev_err(dev, "failed to create window %d\n", win);
1453 for (; win >= 0; win--) 1474 for (; win >= 0; win--)
1454 s3c_fb_release_win(sfb, sfb->windows[win]); 1475 s3c_fb_release_win(sfb, sfb->windows[win]);
1455 goto err_irq; 1476 goto err_pm_runtime;
1456 } 1477 }
1457 } 1478 }
1458 1479
@@ -1461,7 +1482,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
1461 1482
1462 return 0; 1483 return 0;
1463 1484
1464err_irq: 1485err_pm_runtime:
1486 pm_runtime_put_sync(sfb->dev);
1465 free_irq(sfb->irq_no, sfb); 1487 free_irq(sfb->irq_no, sfb);
1466 1488
1467err_ioremap: 1489err_ioremap:
@@ -1471,6 +1493,8 @@ err_req_region:
1471 release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); 1493 release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
1472 1494
1473err_lcd_clk: 1495err_lcd_clk:
1496 pm_runtime_disable(sfb->dev);
1497
1474 if (!sfb->variant.has_clksel) { 1498 if (!sfb->variant.has_clksel) {
1475 clk_disable(sfb->lcd_clk); 1499 clk_disable(sfb->lcd_clk);
1476 clk_put(sfb->lcd_clk); 1500 clk_put(sfb->lcd_clk);
@@ -1524,7 +1548,7 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
1524 return 0; 1548 return 0;
1525} 1549}
1526 1550
1527#ifdef CONFIG_PM 1551#ifdef CONFIG_PM_SLEEP
1528static int s3c_fb_suspend(struct device *dev) 1552static int s3c_fb_suspend(struct device *dev)
1529{ 1553{
1530 struct platform_device *pdev = to_platform_device(dev); 1554 struct platform_device *pdev = to_platform_device(dev);
@@ -1571,10 +1595,15 @@ static int s3c_fb_resume(struct device *dev)
1571 1595
1572 for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { 1596 for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
1573 void __iomem *regs = sfb->regs + sfb->variant.keycon; 1597 void __iomem *regs = sfb->regs + sfb->variant.keycon;
1598 win = sfb->windows[win_no];
1599 if (!win)
1600 continue;
1574 1601
1602 shadow_protect_win(win, 1);
1575 regs += (win_no * 8); 1603 regs += (win_no * 8);
1576 writel(0xffffff, regs + WKEYCON0); 1604 writel(0xffffff, regs + WKEYCON0);
1577 writel(0xffffff, regs + WKEYCON1); 1605 writel(0xffffff, regs + WKEYCON1);
1606 shadow_protect_win(win, 0);
1578 } 1607 }
1579 1608
1580 /* restore framebuffers */ 1609 /* restore framebuffers */
@@ -1589,27 +1618,19 @@ static int s3c_fb_resume(struct device *dev)
1589 1618
1590 return 0; 1619 return 0;
1591} 1620}
1621#endif
1592 1622
1623#ifdef CONFIG_PM_RUNTIME
1593static int s3c_fb_runtime_suspend(struct device *dev) 1624static int s3c_fb_runtime_suspend(struct device *dev)
1594{ 1625{
1595 struct platform_device *pdev = to_platform_device(dev); 1626 struct platform_device *pdev = to_platform_device(dev);
1596 struct s3c_fb *sfb = platform_get_drvdata(pdev); 1627 struct s3c_fb *sfb = platform_get_drvdata(pdev);
1597 struct s3c_fb_win *win;
1598 int win_no;
1599
1600 for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
1601 win = sfb->windows[win_no];
1602 if (!win)
1603 continue;
1604
1605 /* use the blank function to push into power-down */
1606 s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
1607 }
1608 1628
1609 if (!sfb->variant.has_clksel) 1629 if (!sfb->variant.has_clksel)
1610 clk_disable(sfb->lcd_clk); 1630 clk_disable(sfb->lcd_clk);
1611 1631
1612 clk_disable(sfb->bus_clk); 1632 clk_disable(sfb->bus_clk);
1633
1613 return 0; 1634 return 0;
1614} 1635}
1615 1636
@@ -1618,8 +1639,6 @@ static int s3c_fb_runtime_resume(struct device *dev)
1618 struct platform_device *pdev = to_platform_device(dev); 1639 struct platform_device *pdev = to_platform_device(dev);
1619 struct s3c_fb *sfb = platform_get_drvdata(pdev); 1640 struct s3c_fb *sfb = platform_get_drvdata(pdev);
1620 struct s3c_fb_platdata *pd = sfb->pdata; 1641 struct s3c_fb_platdata *pd = sfb->pdata;
1621 struct s3c_fb_win *win;
1622 int win_no;
1623 1642
1624 clk_enable(sfb->bus_clk); 1643 clk_enable(sfb->bus_clk);
1625 1644
@@ -1630,39 +1649,10 @@ static int s3c_fb_runtime_resume(struct device *dev)
1630 pd->setup_gpio(); 1649 pd->setup_gpio();
1631 writel(pd->vidcon1, sfb->regs + VIDCON1); 1650 writel(pd->vidcon1, sfb->regs + VIDCON1);
1632 1651
1633 /* zero all windows before we do anything */
1634 for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
1635 s3c_fb_clear_win(sfb, win_no);
1636
1637 for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
1638 void __iomem *regs = sfb->regs + sfb->variant.keycon;
1639
1640 regs += (win_no * 8);
1641 writel(0xffffff, regs + WKEYCON0);
1642 writel(0xffffff, regs + WKEYCON1);
1643 }
1644
1645 /* restore framebuffers */
1646 for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
1647 win = sfb->windows[win_no];
1648 if (!win)
1649 continue;
1650
1651 dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
1652 s3c_fb_set_par(win->fbinfo);
1653 }
1654
1655 return 0; 1652 return 0;
1656} 1653}
1657
1658#else
1659#define s3c_fb_suspend NULL
1660#define s3c_fb_resume NULL
1661#define s3c_fb_runtime_suspend NULL
1662#define s3c_fb_runtime_resume NULL
1663#endif 1654#endif
1664 1655
1665
1666#define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4)) 1656#define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
1667#define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8)) 1657#define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
1668 1658
@@ -1985,10 +1975,9 @@ static struct platform_device_id s3c_fb_driver_ids[] = {
1985MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids); 1975MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
1986 1976
1987static const struct dev_pm_ops s3cfb_pm_ops = { 1977static const struct dev_pm_ops s3cfb_pm_ops = {
1988 .suspend = s3c_fb_suspend, 1978 SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume)
1989 .resume = s3c_fb_resume, 1979 SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume,
1990 .runtime_suspend = s3c_fb_runtime_suspend, 1980 NULL)
1991 .runtime_resume = s3c_fb_runtime_resume,
1992}; 1981};
1993 1982
1994static struct platform_driver s3c_fb_driver = { 1983static struct platform_driver s3c_fb_driver = {
@@ -2002,18 +1991,7 @@ static struct platform_driver s3c_fb_driver = {
2002 }, 1991 },
2003}; 1992};
2004 1993
2005static int __init s3c_fb_init(void) 1994module_platform_driver(s3c_fb_driver);
2006{
2007 return platform_driver_register(&s3c_fb_driver);
2008}
2009
2010static void __exit s3c_fb_cleanup(void)
2011{
2012 platform_driver_unregister(&s3c_fb_driver);
2013}
2014
2015module_init(s3c_fb_init);
2016module_exit(s3c_fb_cleanup);
2017 1995
2018MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 1996MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
2019MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver"); 1997MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");