i.MX Framebuffer: remove header file
[linux-2.6.git] / drivers / video / imxfb.c
blob7b3400cfae6d506dc96902cf2e33c585709f4999
1 /*
2 * linux/drivers/video/imxfb.c
4 * Freescale i.MX Frame Buffer device driver
6 * Copyright (C) 2004 Sascha Hauer, Pengutronix
7 * Based on acornfb.c Copyright (C) Russell King.
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive for
11 * more details.
13 * Please direct your questions and comments on this driver to the following
14 * email address:
16 * linux-arm-kernel@lists.arm.linux.org.uk
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/errno.h>
23 #include <linux/string.h>
24 #include <linux/interrupt.h>
25 #include <linux/slab.h>
26 #include <linux/mm.h>
27 #include <linux/fb.h>
28 #include <linux/delay.h>
29 #include <linux/init.h>
30 #include <linux/ioport.h>
31 #include <linux/cpufreq.h>
32 #include <linux/platform_device.h>
33 #include <linux/dma-mapping.h>
34 #include <linux/io.h>
36 #include <mach/imxfb.h>
39 * Complain if VAR is out of range.
41 #define DEBUG_VAR 1
43 #define DRIVER_NAME "imx-fb"
45 #define LCDC_SSA 0x00
47 #define LCDC_SIZE 0x04
48 #define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20)
49 #define SIZE_YMAX(y) ((y) & 0x1ff)
51 #define LCDC_VPW 0x08
52 #define VPW_VPW(x) ((x) & 0x3ff)
54 #define LCDC_CPOS 0x0C
55 #define CPOS_CC1 (1<<31)
56 #define CPOS_CC0 (1<<30)
57 #define CPOS_OP (1<<28)
58 #define CPOS_CXP(x) (((x) & 3ff) << 16)
59 #define CPOS_CYP(y) ((y) & 0x1ff)
61 #define LCDC_LCWHB 0x10
62 #define LCWHB_BK_EN (1<<31)
63 #define LCWHB_CW(w) (((w) & 0x1f) << 24)
64 #define LCWHB_CH(h) (((h) & 0x1f) << 16)
65 #define LCWHB_BD(x) ((x) & 0xff)
67 #define LCDC_LCHCC 0x14
68 #define LCHCC_CUR_COL_R(r) (((r) & 0x1f) << 11)
69 #define LCHCC_CUR_COL_G(g) (((g) & 0x3f) << 5)
70 #define LCHCC_CUR_COL_B(b) ((b) & 0x1f)
72 #define LCDC_PCR 0x18
74 #define LCDC_HCR 0x1C
75 #define HCR_H_WIDTH(x) (((x) & 0x3f) << 26)
76 #define HCR_H_WAIT_1(x) (((x) & 0xff) << 8)
77 #define HCR_H_WAIT_2(x) ((x) & 0xff)
79 #define LCDC_VCR 0x20
80 #define VCR_V_WIDTH(x) (((x) & 0x3f) << 26)
81 #define VCR_V_WAIT_1(x) (((x) & 0xff) << 8)
82 #define VCR_V_WAIT_2(x) ((x) & 0xff)
84 #define LCDC_POS 0x24
85 #define POS_POS(x) ((x) & 1f)
87 #define LCDC_LSCR1 0x28
88 /* bit fields in imxfb.h */
90 #define LCDC_PWMR 0x2C
91 /* bit fields in imxfb.h */
93 #define LCDC_DMACR 0x30
94 /* bit fields in imxfb.h */
96 #define LCDC_RMCR 0x34
97 #define RMCR_LCDC_EN (1<<1)
98 #define RMCR_SELF_REF (1<<0)
100 #define LCDC_LCDICR 0x38
101 #define LCDICR_INT_SYN (1<<2)
102 #define LCDICR_INT_CON (1)
104 #define LCDC_LCDISR 0x40
105 #define LCDISR_UDR_ERR (1<<3)
106 #define LCDISR_ERR_RES (1<<2)
107 #define LCDISR_EOF (1<<1)
108 #define LCDISR_BOF (1<<0)
111 * These are the bitfields for each
112 * display depth that we support.
114 struct imxfb_rgb {
115 struct fb_bitfield red;
116 struct fb_bitfield green;
117 struct fb_bitfield blue;
118 struct fb_bitfield transp;
121 #define RGB_16 (0)
122 #define RGB_8 (1)
123 #define NR_RGB 2
125 struct imxfb_info {
126 struct platform_device *pdev;
127 void __iomem *regs;
129 struct imxfb_rgb *rgb[NR_RGB];
131 u_int max_bpp;
132 u_int max_xres;
133 u_int max_yres;
136 * These are the addresses we mapped
137 * the framebuffer memory region to.
139 dma_addr_t map_dma;
140 u_char *map_cpu;
141 u_int map_size;
143 u_char *screen_cpu;
144 dma_addr_t screen_dma;
145 u_int palette_size;
147 dma_addr_t dbar1;
148 dma_addr_t dbar2;
150 u_int pcr;
151 u_int pwmr;
152 u_int lscr1;
153 u_int dmacr;
154 u_int cmap_inverse:1,
155 cmap_static:1,
156 unused:30;
158 void (*lcd_power)(int);
159 void (*backlight_power)(int);
162 #define IMX_NAME "IMX"
165 * Minimum X and Y resolutions
167 #define MIN_XRES 64
168 #define MIN_YRES 64
170 static struct imxfb_rgb def_rgb_16 = {
171 .red = { .offset = 8, .length = 4, },
172 .green = { .offset = 4, .length = 4, },
173 .blue = { .offset = 0, .length = 4, },
174 .transp = { .offset = 0, .length = 0, },
177 static struct imxfb_rgb def_rgb_8 = {
178 .red = { .offset = 0, .length = 8, },
179 .green = { .offset = 0, .length = 8, },
180 .blue = { .offset = 0, .length = 8, },
181 .transp = { .offset = 0, .length = 0, },
184 static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info);
186 static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
188 chan &= 0xffff;
189 chan >>= 16 - bf->length;
190 return chan << bf->offset;
193 static int
194 imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
195 u_int trans, struct fb_info *info)
197 struct imxfb_info *fbi = info->par;
198 u_int val, ret = 1;
200 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
201 if (regno < fbi->palette_size) {
202 val = (CNVT_TOHW(red, 4) << 8) |
203 (CNVT_TOHW(green,4) << 4) |
204 CNVT_TOHW(blue, 4);
206 writel(val, fbi->regs + 0x800 + (regno << 2));
207 ret = 0;
209 return ret;
212 static int
213 imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
214 u_int trans, struct fb_info *info)
216 struct imxfb_info *fbi = info->par;
217 unsigned int val;
218 int ret = 1;
221 * If inverse mode was selected, invert all the colours
222 * rather than the register number. The register number
223 * is what you poke into the framebuffer to produce the
224 * colour you requested.
226 if (fbi->cmap_inverse) {
227 red = 0xffff - red;
228 green = 0xffff - green;
229 blue = 0xffff - blue;
233 * If greyscale is true, then we convert the RGB value
234 * to greyscale no mater what visual we are using.
236 if (info->var.grayscale)
237 red = green = blue = (19595 * red + 38470 * green +
238 7471 * blue) >> 16;
240 switch (info->fix.visual) {
241 case FB_VISUAL_TRUECOLOR:
243 * 12 or 16-bit True Colour. We encode the RGB value
244 * according to the RGB bitfield information.
246 if (regno < 16) {
247 u32 *pal = info->pseudo_palette;
249 val = chan_to_field(red, &info->var.red);
250 val |= chan_to_field(green, &info->var.green);
251 val |= chan_to_field(blue, &info->var.blue);
253 pal[regno] = val;
254 ret = 0;
256 break;
258 case FB_VISUAL_STATIC_PSEUDOCOLOR:
259 case FB_VISUAL_PSEUDOCOLOR:
260 ret = imxfb_setpalettereg(regno, red, green, blue, trans, info);
261 break;
264 return ret;
268 * imxfb_check_var():
269 * Round up in the following order: bits_per_pixel, xres,
270 * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
271 * bitfields, horizontal timing, vertical timing.
273 static int
274 imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
276 struct imxfb_info *fbi = info->par;
277 int rgbidx;
279 if (var->xres < MIN_XRES)
280 var->xres = MIN_XRES;
281 if (var->yres < MIN_YRES)
282 var->yres = MIN_YRES;
283 if (var->xres > fbi->max_xres)
284 var->xres = fbi->max_xres;
285 if (var->yres > fbi->max_yres)
286 var->yres = fbi->max_yres;
287 var->xres_virtual = max(var->xres_virtual, var->xres);
288 var->yres_virtual = max(var->yres_virtual, var->yres);
290 pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel);
291 switch (var->bits_per_pixel) {
292 case 16:
293 rgbidx = RGB_16;
294 break;
295 case 8:
296 rgbidx = RGB_8;
297 break;
298 default:
299 rgbidx = RGB_16;
303 * Copy the RGB parameters for this display
304 * from the machine specific parameters.
306 var->red = fbi->rgb[rgbidx]->red;
307 var->green = fbi->rgb[rgbidx]->green;
308 var->blue = fbi->rgb[rgbidx]->blue;
309 var->transp = fbi->rgb[rgbidx]->transp;
311 pr_debug("RGBT length = %d:%d:%d:%d\n",
312 var->red.length, var->green.length, var->blue.length,
313 var->transp.length);
315 pr_debug("RGBT offset = %d:%d:%d:%d\n",
316 var->red.offset, var->green.offset, var->blue.offset,
317 var->transp.offset);
319 return 0;
323 * imxfb_set_par():
324 * Set the user defined part of the display for the specified console
326 static int imxfb_set_par(struct fb_info *info)
328 struct imxfb_info *fbi = info->par;
329 struct fb_var_screeninfo *var = &info->var;
331 pr_debug("set_par\n");
333 if (var->bits_per_pixel == 16)
334 info->fix.visual = FB_VISUAL_TRUECOLOR;
335 else if (!fbi->cmap_static)
336 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
337 else {
339 * Some people have weird ideas about wanting static
340 * pseudocolor maps. I suspect their user space
341 * applications are broken.
343 info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
346 info->fix.line_length = var->xres_virtual *
347 var->bits_per_pixel / 8;
348 fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
350 imxfb_activate_var(var, info);
352 return 0;
355 static void imxfb_enable_controller(struct imxfb_info *fbi)
357 pr_debug("Enabling LCD controller\n");
359 /* initialize LCDC */
360 writel(readl(fbi->regs + LCDC_RMCR) & ~RMCR_LCDC_EN,
361 fbi->regs + LCDC_RMCR); /* just to be safe... */
363 writel(fbi->screen_dma, fbi->regs + LCDC_SSA);
365 /* physical screen start address */
366 writel(VPW_VPW(fbi->max_xres * fbi->max_bpp / 8 / 4),
367 fbi->regs + LCDC_VPW);
369 /* panning offset 0 (0 pixel offset) */
370 writel(0x00000000, fbi->regs + LCDC_POS);
372 /* disable hardware cursor */
373 writel(readl(fbi->regs + LCDC_CPOS) & ~(CPOS_CC0 | CPOS_CC1),
374 fbi->regs + LCDC_CPOS);
376 writel(RMCR_LCDC_EN, fbi->regs + LCDC_RMCR);
378 if(fbi->backlight_power)
379 fbi->backlight_power(1);
380 if(fbi->lcd_power)
381 fbi->lcd_power(1);
384 static void imxfb_disable_controller(struct imxfb_info *fbi)
386 pr_debug("Disabling LCD controller\n");
388 if(fbi->backlight_power)
389 fbi->backlight_power(0);
390 if(fbi->lcd_power)
391 fbi->lcd_power(0);
393 writel(0, fbi->regs + LCDC_RMCR);
396 static int imxfb_blank(int blank, struct fb_info *info)
398 struct imxfb_info *fbi = info->par;
400 pr_debug("imxfb_blank: blank=%d\n", blank);
402 switch (blank) {
403 case FB_BLANK_POWERDOWN:
404 case FB_BLANK_VSYNC_SUSPEND:
405 case FB_BLANK_HSYNC_SUSPEND:
406 case FB_BLANK_NORMAL:
407 imxfb_disable_controller(fbi);
408 break;
410 case FB_BLANK_UNBLANK:
411 imxfb_enable_controller(fbi);
412 break;
414 return 0;
417 static struct fb_ops imxfb_ops = {
418 .owner = THIS_MODULE,
419 .fb_check_var = imxfb_check_var,
420 .fb_set_par = imxfb_set_par,
421 .fb_setcolreg = imxfb_setcolreg,
422 .fb_fillrect = cfb_fillrect,
423 .fb_copyarea = cfb_copyarea,
424 .fb_imageblit = cfb_imageblit,
425 .fb_blank = imxfb_blank,
429 * imxfb_activate_var():
430 * Configures LCD Controller based on entries in var parameter. Settings are
431 * only written to the controller if changes were made.
433 static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info)
435 struct imxfb_info *fbi = info->par;
436 pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
437 var->xres, var->hsync_len,
438 var->left_margin, var->right_margin);
439 pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n",
440 var->yres, var->vsync_len,
441 var->upper_margin, var->lower_margin);
443 #if DEBUG_VAR
444 if (var->xres < 16 || var->xres > 1024)
445 printk(KERN_ERR "%s: invalid xres %d\n",
446 info->fix.id, var->xres);
447 if (var->hsync_len < 1 || var->hsync_len > 64)
448 printk(KERN_ERR "%s: invalid hsync_len %d\n",
449 info->fix.id, var->hsync_len);
450 if (var->left_margin > 255)
451 printk(KERN_ERR "%s: invalid left_margin %d\n",
452 info->fix.id, var->left_margin);
453 if (var->right_margin > 255)
454 printk(KERN_ERR "%s: invalid right_margin %d\n",
455 info->fix.id, var->right_margin);
456 if (var->yres < 1 || var->yres > 511)
457 printk(KERN_ERR "%s: invalid yres %d\n",
458 info->fix.id, var->yres);
459 if (var->vsync_len > 100)
460 printk(KERN_ERR "%s: invalid vsync_len %d\n",
461 info->fix.id, var->vsync_len);
462 if (var->upper_margin > 63)
463 printk(KERN_ERR "%s: invalid upper_margin %d\n",
464 info->fix.id, var->upper_margin);
465 if (var->lower_margin > 255)
466 printk(KERN_ERR "%s: invalid lower_margin %d\n",
467 info->fix.id, var->lower_margin);
468 #endif
470 writel(HCR_H_WIDTH(var->hsync_len) |
471 HCR_H_WAIT_1(var->right_margin) |
472 HCR_H_WAIT_2(var->left_margin),
473 fbi->regs + LCDC_HCR);
475 writel(VCR_V_WIDTH(var->vsync_len) |
476 VCR_V_WAIT_1(var->lower_margin) |
477 VCR_V_WAIT_2(var->upper_margin),
478 fbi->regs + LCDC_VCR);
480 writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres),
481 fbi->regs + LCDC_SIZE);
482 writel(fbi->pcr, fbi->regs + LCDC_PCR);
483 writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
484 writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
485 writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
487 return 0;
490 #ifdef CONFIG_PM
492 * Power management hooks. Note that we won't be called from IRQ context,
493 * unlike the blank functions above, so we may sleep.
495 static int imxfb_suspend(struct platform_device *dev, pm_message_t state)
497 struct imxfb_info *fbi = platform_get_drvdata(dev);
498 pr_debug("%s\n",__func__);
500 imxfb_disable_controller(fbi);
501 return 0;
504 static int imxfb_resume(struct platform_device *dev)
506 struct imxfb_info *fbi = platform_get_drvdata(dev);
507 pr_debug("%s\n",__func__);
509 imxfb_enable_controller(fbi);
510 return 0;
512 #else
513 #define imxfb_suspend NULL
514 #define imxfb_resume NULL
515 #endif
517 static int __init imxfb_init_fbinfo(struct platform_device *pdev)
519 struct imxfb_mach_info *inf = pdev->dev.platform_data;
520 struct fb_info *info = dev_get_drvdata(&pdev->dev);
521 struct imxfb_info *fbi = info->par;
523 pr_debug("%s\n",__func__);
525 info->pseudo_palette = kmalloc( sizeof(u32) * 16, GFP_KERNEL);
526 if (!info->pseudo_palette)
527 return -ENOMEM;
529 memset(fbi, 0, sizeof(struct imxfb_info));
531 strlcpy(info->fix.id, IMX_NAME, sizeof(info->fix.id));
533 info->fix.type = FB_TYPE_PACKED_PIXELS;
534 info->fix.type_aux = 0;
535 info->fix.xpanstep = 0;
536 info->fix.ypanstep = 0;
537 info->fix.ywrapstep = 0;
538 info->fix.accel = FB_ACCEL_NONE;
540 info->var.nonstd = 0;
541 info->var.activate = FB_ACTIVATE_NOW;
542 info->var.height = -1;
543 info->var.width = -1;
544 info->var.accel_flags = 0;
545 info->var.vmode = FB_VMODE_NONINTERLACED;
547 info->fbops = &imxfb_ops;
548 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST;
550 fbi->rgb[RGB_16] = &def_rgb_16;
551 fbi->rgb[RGB_8] = &def_rgb_8;
553 fbi->max_xres = inf->xres;
554 info->var.xres = inf->xres;
555 info->var.xres_virtual = inf->xres;
556 fbi->max_yres = inf->yres;
557 info->var.yres = inf->yres;
558 info->var.yres_virtual = inf->yres;
559 fbi->max_bpp = inf->bpp;
560 info->var.bits_per_pixel = inf->bpp;
561 info->var.nonstd = inf->nonstd;
562 info->var.pixclock = inf->pixclock;
563 info->var.hsync_len = inf->hsync_len;
564 info->var.left_margin = inf->left_margin;
565 info->var.right_margin = inf->right_margin;
566 info->var.vsync_len = inf->vsync_len;
567 info->var.upper_margin = inf->upper_margin;
568 info->var.lower_margin = inf->lower_margin;
569 info->var.sync = inf->sync;
570 info->var.grayscale = inf->cmap_greyscale;
571 fbi->cmap_inverse = inf->cmap_inverse;
572 fbi->cmap_static = inf->cmap_static;
573 fbi->pcr = inf->pcr;
574 fbi->lscr1 = inf->lscr1;
575 fbi->dmacr = inf->dmacr;
576 fbi->pwmr = inf->pwmr;
577 fbi->lcd_power = inf->lcd_power;
578 fbi->backlight_power = inf->backlight_power;
579 info->fix.smem_len = fbi->max_xres * fbi->max_yres *
580 fbi->max_bpp / 8;
582 return 0;
585 static int __init imxfb_probe(struct platform_device *pdev)
587 struct imxfb_info *fbi;
588 struct fb_info *info;
589 struct imxfb_mach_info *inf;
590 struct resource *res;
591 int ret;
593 printk("i.MX Framebuffer driver\n");
595 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
596 if(!res)
597 return -ENODEV;
599 inf = pdev->dev.platform_data;
600 if(!inf) {
601 dev_err(&pdev->dev,"No platform_data available\n");
602 return -ENOMEM;
605 info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
606 if(!info)
607 return -ENOMEM;
609 fbi = info->par;
611 platform_set_drvdata(pdev, info);
613 ret = imxfb_init_fbinfo(pdev);
614 if( ret < 0 )
615 goto failed_init;
617 res = request_mem_region(res->start, resource_size(res),
618 DRIVER_NAME);
619 if (!res) {
620 ret = -EBUSY;
621 goto failed_req;
624 fbi->regs = ioremap(res->start, resource_size(res));
625 if (fbi->regs == NULL) {
626 printk(KERN_ERR"Cannot map frame buffer registers\n");
627 goto failed_ioremap;
630 if (!inf->fixed_screen_cpu) {
631 fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
632 fbi->map_cpu = dma_alloc_writecombine(&pdev->dev,
633 fbi->map_size, &fbi->map_dma, GFP_KERNEL);
635 if (!fbi->map_cpu) {
636 dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
637 ret = -ENOMEM;
638 goto failed_map;
641 info->screen_base = fbi->map_cpu;
642 fbi->screen_cpu = fbi->map_cpu;
643 fbi->screen_dma = fbi->map_dma;
644 info->fix.smem_start = fbi->screen_dma;
645 } else {
646 /* Fixed framebuffer mapping enables location of the screen in eSRAM */
647 fbi->map_cpu = inf->fixed_screen_cpu;
648 fbi->map_dma = inf->fixed_screen_dma;
649 info->screen_base = fbi->map_cpu;
650 fbi->screen_cpu = fbi->map_cpu;
651 fbi->screen_dma = fbi->map_dma;
652 info->fix.smem_start = fbi->screen_dma;
656 * This makes sure that our colour bitfield
657 * descriptors are correctly initialised.
659 imxfb_check_var(&info->var, info);
661 ret = fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
662 if (ret < 0)
663 goto failed_cmap;
665 imxfb_set_par(info);
666 ret = register_framebuffer(info);
667 if (ret < 0) {
668 dev_err(&pdev->dev, "failed to register framebuffer\n");
669 goto failed_register;
672 imxfb_enable_controller(fbi);
674 return 0;
676 failed_register:
677 fb_dealloc_cmap(&info->cmap);
678 failed_cmap:
679 if (!inf->fixed_screen_cpu)
680 dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
681 fbi->map_dma);
682 failed_map:
683 iounmap(fbi->regs);
684 failed_ioremap:
685 release_mem_region(res->start, res->end - res->start);
686 failed_req:
687 kfree(info->pseudo_palette);
688 failed_init:
689 platform_set_drvdata(pdev, NULL);
690 framebuffer_release(info);
691 return ret;
694 static int __devexit imxfb_remove(struct platform_device *pdev)
696 struct fb_info *info = platform_get_drvdata(pdev);
697 struct imxfb_info *fbi = info->par;
698 struct resource *res;
700 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
702 imxfb_disable_controller(fbi);
704 unregister_framebuffer(info);
706 fb_dealloc_cmap(&info->cmap);
707 kfree(info->pseudo_palette);
708 framebuffer_release(info);
710 iounmap(fbi->regs);
711 release_mem_region(res->start, res->end - res->start + 1);
712 platform_set_drvdata(pdev, NULL);
714 return 0;
717 void imxfb_shutdown(struct platform_device * dev)
719 struct fb_info *info = platform_get_drvdata(dev);
720 struct imxfb_info *fbi = info->par;
721 imxfb_disable_controller(fbi);
724 static struct platform_driver imxfb_driver = {
725 .suspend = imxfb_suspend,
726 .resume = imxfb_resume,
727 .remove = __devexit_p(imxfb_remove),
728 .shutdown = imxfb_shutdown,
729 .driver = {
730 .name = DRIVER_NAME,
734 int __init imxfb_init(void)
736 return platform_driver_probe(&imxfb_driver, imxfb_probe);
739 static void __exit imxfb_cleanup(void)
741 platform_driver_unregister(&imxfb_driver);
744 module_init(imxfb_init);
745 module_exit(imxfb_cleanup);
747 MODULE_DESCRIPTION("Motorola i.MX framebuffer driver");
748 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
749 MODULE_LICENSE("GPL");