3 * Copyright (c) 2009 Nuvoton technology corporation
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
12 * Nuvoton LCD Controller Driver
14 * Wang Qiang (rurality.linux@gmail.com) 2009/12/11
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/errno.h>
19 #include <linux/string.h>
21 #include <linux/tty.h>
22 #include <linux/slab.h>
23 #include <linux/delay.h>
25 #include <linux/init.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/interrupt.h>
28 #include <linux/workqueue.h>
29 #include <linux/wait.h>
30 #include <linux/platform_device.h>
31 #include <linux/clk.h>
32 #include <linux/cpufreq.h>
35 #include <linux/device.h>
38 #include <mach/regs-clock.h>
39 #include <mach/regs-ldm.h>
41 #include <mach/clkdev.h>
47 * Initialize the nuc900 video (dual) buffer address
49 static void nuc900fb_set_lcdaddr(struct fb_info
*info
)
51 struct nuc900fb_info
*fbi
= info
->par
;
52 void __iomem
*regs
= fbi
->io
;
53 unsigned long vbaddr1
, vbaddr2
;
55 vbaddr1
= info
->fix
.smem_start
;
56 vbaddr2
= info
->fix
.smem_start
;
57 vbaddr2
+= info
->fix
.line_length
* info
->var
.yres
;
59 /* set frambuffer start phy addr*/
60 writel(vbaddr1
, regs
+ REG_LCM_VA_BADDR0
);
61 writel(vbaddr2
, regs
+ REG_LCM_VA_BADDR1
);
63 writel(fbi
->regs
.lcd_va_fbctrl
, regs
+ REG_LCM_VA_FBCTRL
);
64 writel(fbi
->regs
.lcd_va_scale
, regs
+ REG_LCM_VA_SCALE
);
68 * calculate divider for lcd div
70 static unsigned int nuc900fb_calc_pixclk(struct nuc900fb_info
*fbi
,
73 unsigned long clk
= fbi
->clk_rate
;
74 unsigned long long div
;
76 /* pixclk is in picseconds. our clock is in Hz*/
77 /* div = (clk * pixclk)/10^12 */
78 div
= (unsigned long long)clk
* pixclk
;
80 do_div(div
, 625 * 625UL * 625);
82 dev_dbg(fbi
->dev
, "pixclk %ld, divisor is %lld\n", pixclk
, div
);
88 * Check the video params of 'var'.
90 static int nuc900fb_check_var(struct fb_var_screeninfo
*var
,
93 struct nuc900fb_info
*fbi
= info
->par
;
94 struct nuc900fb_mach_info
*mach_info
= fbi
->dev
->platform_data
;
95 struct nuc900fb_display
*display
= NULL
;
96 struct nuc900fb_display
*default_display
= mach_info
->displays
+
97 mach_info
->default_display
;
100 dev_dbg(fbi
->dev
, "check_var(var=%p, info=%p)\n", var
, info
);
102 /* validate x/y resolution */
103 /* choose default mode if possible */
104 if (var
->xres
== default_display
->xres
&&
105 var
->yres
== default_display
->yres
&&
106 var
->bits_per_pixel
== default_display
->bpp
)
107 display
= default_display
;
109 for (i
= 0; i
< mach_info
->num_displays
; i
++)
110 if (var
->xres
== mach_info
->displays
[i
].xres
&&
111 var
->yres
== mach_info
->displays
[i
].yres
&&
112 var
->bits_per_pixel
== mach_info
->displays
[i
].bpp
) {
113 display
= mach_info
->displays
+ i
;
117 if (display
== NULL
) {
118 printk(KERN_ERR
"wrong resolution or depth %dx%d at %d bit per pixel\n",
119 var
->xres
, var
->yres
, var
->bits_per_pixel
);
123 /* it should be the same size as the display */
124 var
->xres_virtual
= display
->xres
;
125 var
->yres_virtual
= display
->yres
;
126 var
->height
= display
->height
;
127 var
->width
= display
->width
;
129 /* copy lcd settings */
130 var
->pixclock
= display
->pixclock
;
131 var
->left_margin
= display
->left_margin
;
132 var
->right_margin
= display
->right_margin
;
133 var
->upper_margin
= display
->upper_margin
;
134 var
->lower_margin
= display
->lower_margin
;
135 var
->vsync_len
= display
->vsync_len
;
136 var
->hsync_len
= display
->hsync_len
;
138 var
->transp
.offset
= 0;
139 var
->transp
.length
= 0;
141 fbi
->regs
.lcd_dccs
= display
->dccs
;
142 fbi
->regs
.lcd_device_ctrl
= display
->devctl
;
143 fbi
->regs
.lcd_va_fbctrl
= display
->fbctrl
;
144 fbi
->regs
.lcd_va_scale
= display
->scale
;
146 /* set R/G/B possions */
147 switch (var
->bits_per_pixel
) {
154 var
->red
.length
= var
->bits_per_pixel
;
155 var
->green
= var
->red
;
156 var
->blue
= var
->red
;
160 var
->green
.length
= 4;
161 var
->blue
.length
= 4;
163 var
->green
.offset
= 4;
164 var
->blue
.offset
= 0;
168 var
->green
.length
= 6;
169 var
->blue
.length
= 5;
170 var
->red
.offset
= 11;
171 var
->green
.offset
= 5;
172 var
->blue
.offset
= 0;
176 var
->green
.length
= 6;
177 var
->blue
.length
= 6;
178 var
->red
.offset
= 12;
179 var
->green
.offset
= 6;
180 var
->blue
.offset
= 0;
184 var
->green
.length
= 8;
185 var
->blue
.length
= 8;
186 var
->red
.offset
= 16;
187 var
->green
.offset
= 8;
188 var
->blue
.offset
= 0;
196 * Calculate lcd register values from var setting & save into hw
198 static void nuc900fb_calculate_lcd_regs(const struct fb_info
*info
,
199 struct nuc900fb_hw
*regs
)
201 const struct fb_var_screeninfo
*var
= &info
->var
;
202 int vtt
= var
->height
+ var
->upper_margin
+ var
->lower_margin
;
203 int htt
= var
->width
+ var
->left_margin
+ var
->right_margin
;
204 int hsync
= var
->width
+ var
->right_margin
;
205 int vsync
= var
->height
+ var
->lower_margin
;
207 regs
->lcd_crtc_size
= LCM_CRTC_SIZE_VTTVAL(vtt
) |
208 LCM_CRTC_SIZE_HTTVAL(htt
);
209 regs
->lcd_crtc_dend
= LCM_CRTC_DEND_VDENDVAL(var
->height
) |
210 LCM_CRTC_DEND_HDENDVAL(var
->width
);
211 regs
->lcd_crtc_hr
= LCM_CRTC_HR_EVAL(var
->width
+ 5) |
212 LCM_CRTC_HR_SVAL(var
->width
+ 1);
213 regs
->lcd_crtc_hsync
= LCM_CRTC_HSYNC_EVAL(hsync
+ var
->hsync_len
) |
214 LCM_CRTC_HSYNC_SVAL(hsync
);
215 regs
->lcd_crtc_vr
= LCM_CRTC_VR_EVAL(vsync
+ var
->vsync_len
) |
216 LCM_CRTC_VR_SVAL(vsync
);
221 * Activate (set) the controller from the given framebuffer
224 static void nuc900fb_activate_var(struct fb_info
*info
)
226 struct nuc900fb_info
*fbi
= info
->par
;
227 void __iomem
*regs
= fbi
->io
;
228 struct fb_var_screeninfo
*var
= &info
->var
;
231 clkdiv
= nuc900fb_calc_pixclk(fbi
, var
->pixclock
) - 1;
235 nuc900fb_calculate_lcd_regs(info
, &fbi
->regs
);
237 /* set the new lcd registers*/
239 dev_dbg(fbi
->dev
, "new lcd register set:\n");
240 dev_dbg(fbi
->dev
, "dccs = 0x%08x\n", fbi
->regs
.lcd_dccs
);
241 dev_dbg(fbi
->dev
, "dev_ctl = 0x%08x\n", fbi
->regs
.lcd_device_ctrl
);
242 dev_dbg(fbi
->dev
, "crtc_size = 0x%08x\n", fbi
->regs
.lcd_crtc_size
);
243 dev_dbg(fbi
->dev
, "crtc_dend = 0x%08x\n", fbi
->regs
.lcd_crtc_dend
);
244 dev_dbg(fbi
->dev
, "crtc_hr = 0x%08x\n", fbi
->regs
.lcd_crtc_hr
);
245 dev_dbg(fbi
->dev
, "crtc_hsync = 0x%08x\n", fbi
->regs
.lcd_crtc_hsync
);
246 dev_dbg(fbi
->dev
, "crtc_vr = 0x%08x\n", fbi
->regs
.lcd_crtc_vr
);
248 writel(fbi
->regs
.lcd_device_ctrl
, regs
+ REG_LCM_DEV_CTRL
);
249 writel(fbi
->regs
.lcd_crtc_size
, regs
+ REG_LCM_CRTC_SIZE
);
250 writel(fbi
->regs
.lcd_crtc_dend
, regs
+ REG_LCM_CRTC_DEND
);
251 writel(fbi
->regs
.lcd_crtc_hr
, regs
+ REG_LCM_CRTC_HR
);
252 writel(fbi
->regs
.lcd_crtc_hsync
, regs
+ REG_LCM_CRTC_HSYNC
);
253 writel(fbi
->regs
.lcd_crtc_vr
, regs
+ REG_LCM_CRTC_VR
);
255 /* set lcd address pointers */
256 nuc900fb_set_lcdaddr(info
);
258 writel(fbi
->regs
.lcd_dccs
, regs
+ REG_LCM_DCCS
);
262 * Alters the hardware state.
265 static int nuc900fb_set_par(struct fb_info
*info
)
267 struct fb_var_screeninfo
*var
= &info
->var
;
269 switch (var
->bits_per_pixel
) {
275 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
278 info
->fix
.visual
= FB_VISUAL_MONO01
;
281 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
285 info
->fix
.line_length
= (var
->xres_virtual
* var
->bits_per_pixel
) / 8;
287 /* activate this new configuration */
288 nuc900fb_activate_var(info
);
292 static inline unsigned int chan_to_field(unsigned int chan
,
293 struct fb_bitfield
*bf
)
296 chan
>>= 16 - bf
->length
;
297 return chan
<< bf
->offset
;
300 static int nuc900fb_setcolreg(unsigned regno
,
301 unsigned red
, unsigned green
, unsigned blue
,
302 unsigned transp
, struct fb_info
*info
)
306 switch (info
->fix
.visual
) {
307 case FB_VISUAL_TRUECOLOR
:
308 /* true-colour, use pseuo-palette */
310 u32
*pal
= info
->pseudo_palette
;
312 val
= chan_to_field(red
, &info
->var
.red
);
313 val
|= chan_to_field(green
, &info
->var
.green
);
314 val
|= chan_to_field(blue
, &info
->var
.blue
);
320 return 1; /* unknown type */
329 static int nuc900fb_blank(int blank_mode
, struct fb_info
*info
)
335 static struct fb_ops nuc900fb_ops
= {
336 .owner
= THIS_MODULE
,
337 .fb_check_var
= nuc900fb_check_var
,
338 .fb_set_par
= nuc900fb_set_par
,
339 .fb_blank
= nuc900fb_blank
,
340 .fb_setcolreg
= nuc900fb_setcolreg
,
341 .fb_fillrect
= cfb_fillrect
,
342 .fb_copyarea
= cfb_copyarea
,
343 .fb_imageblit
= cfb_imageblit
,
347 static inline void modify_gpio(void __iomem
*reg
,
348 unsigned long set
, unsigned long mask
)
351 tmp
= readl(reg
) & ~mask
;
352 writel(tmp
| set
, reg
);
356 * Initialise LCD-related registers
358 static int nuc900fb_init_registers(struct fb_info
*info
)
360 struct nuc900fb_info
*fbi
= info
->par
;
361 struct nuc900fb_mach_info
*mach_info
= fbi
->dev
->platform_data
;
362 void __iomem
*regs
= fbi
->io
;
364 /*reset the display engine*/
365 writel(0, regs
+ REG_LCM_DCCS
);
366 writel(readl(regs
+ REG_LCM_DCCS
) | LCM_DCCS_ENG_RST
,
367 regs
+ REG_LCM_DCCS
);
369 writel(readl(regs
+ REG_LCM_DCCS
) & (~LCM_DCCS_ENG_RST
),
370 regs
+ REG_LCM_DCCS
);
373 writel(0, regs
+ REG_LCM_DEV_CTRL
);
375 /* config gpio output */
376 modify_gpio(W90X900_VA_GPIO
+ 0x54, mach_info
->gpio_dir
,
377 mach_info
->gpio_dir_mask
);
378 modify_gpio(W90X900_VA_GPIO
+ 0x58, mach_info
->gpio_data
,
379 mach_info
->gpio_data_mask
);
386 * Alloc the SDRAM region of NUC900 for the frame buffer.
387 * The buffer should be a non-cached, non-buffered, memory region
388 * to allow palette and pixel writes without flushing the cache.
390 static int __init
nuc900fb_map_video_memory(struct fb_info
*info
)
392 struct nuc900fb_info
*fbi
= info
->par
;
394 unsigned long map_size
= PAGE_ALIGN(info
->fix
.smem_len
);
396 dev_dbg(fbi
->dev
, "nuc900fb_map_video_memory(fbi=%p) map_size %lu\n",
399 info
->screen_base
= dma_alloc_writecombine(fbi
->dev
, map_size
,
400 &map_dma
, GFP_KERNEL
);
402 if (!info
->screen_base
)
405 memset(info
->screen_base
, 0x00, map_size
);
406 info
->fix
.smem_start
= map_dma
;
411 static inline void nuc900fb_unmap_video_memory(struct fb_info
*info
)
413 struct nuc900fb_info
*fbi
= info
->par
;
414 dma_free_writecombine(fbi
->dev
, PAGE_ALIGN(info
->fix
.smem_len
),
415 info
->screen_base
, info
->fix
.smem_start
);
418 static irqreturn_t
nuc900fb_irqhandler(int irq
, void *dev_id
)
420 struct nuc900fb_info
*fbi
= dev_id
;
421 void __iomem
*regs
= fbi
->io
;
422 void __iomem
*irq_base
= fbi
->irq_base
;
423 unsigned long lcdirq
= readl(regs
+ REG_LCM_INT_CS
);
425 if (lcdirq
& LCM_INT_CS_DISP_F_STATUS
) {
426 writel(readl(irq_base
) | 1<<30, irq_base
);
429 if ((readl(regs
+ REG_LCM_DCCS
) &
430 LCM_DCCS_SINGLE
) == LCM_DCCS_SINGLE
)
431 while ((readl(regs
+ REG_LCM_DCCS
) &
432 LCM_DCCS_VA_EN
) == LCM_DCCS_VA_EN
)
434 /* display_out-enable */
435 writel(readl(regs
+ REG_LCM_DCCS
) | LCM_DCCS_DISP_OUT_EN
,
436 regs
+ REG_LCM_DCCS
);
438 writel(readl(regs
+ REG_LCM_DCCS
) | LCM_DCCS_VA_EN
,
439 regs
+ REG_LCM_DCCS
);
440 } else if (lcdirq
& LCM_INT_CS_UNDERRUN_INT
) {
441 writel(readl(irq_base
) | LCM_INT_CS_UNDERRUN_INT
, irq_base
);
442 } else if (lcdirq
& LCM_INT_CS_BUS_ERROR_INT
) {
443 writel(readl(irq_base
) | LCM_INT_CS_BUS_ERROR_INT
, irq_base
);
449 #ifdef CONFIG_CPU_FREQ
451 static int nuc900fb_cpufreq_transition(struct notifier_block
*nb
,
452 unsigned long val
, void *data
)
454 struct nuc900fb_info
*info
;
455 struct fb_info
*fbinfo
;
457 info
= container_of(nb
, struct nuc900fb_info
, freq_transition
);
458 fbinfo
= platform_get_drvdata(to_platform_device(info
->dev
));
460 delta_f
= info
->clk_rate
- clk_get_rate(info
->clk
);
462 if ((val
== CPUFREQ_POSTCHANGE
&& delta_f
> 0) ||
463 (val
== CPUFREQ_PRECHANGE
&& delta_f
< 0)) {
464 info
->clk_rate
= clk_get_rate(info
->clk
);
465 nuc900fb_activate_var(fbinfo
);
471 static inline int nuc900fb_cpufreq_register(struct nuc900fb_info
*fbi
)
473 fbi
->freq_transition
.notifier_call
= nuc900fb_cpufreq_transition
;
474 return cpufreq_register_notifier(&fbi
->freq_transition
,
475 CPUFREQ_TRANSITION_NOTIFIER
);
478 static inline void nuc900fb_cpufreq_deregister(struct nuc900fb_info
*fbi
)
480 cpufreq_unregister_notifier(&fbi
->freq_transition
,
481 CPUFREQ_TRANSITION_NOTIFIER
);
484 static inline int nuc900fb_cpufreq_transition(struct notifier_block
*nb
,
485 unsigned long val
, void *data
)
490 static inline int nuc900fb_cpufreq_register(struct nuc900fb_info
*fbi
)
495 static inline void nuc900fb_cpufreq_deregister(struct nuc900fb_info
*info
)
500 static char driver_name
[] = "nuc900fb";
502 static int __devinit
nuc900fb_probe(struct platform_device
*pdev
)
504 struct nuc900fb_info
*fbi
;
505 struct nuc900fb_display
*display
;
506 struct fb_info
*fbinfo
;
507 struct nuc900fb_mach_info
*mach_info
;
508 struct resource
*res
;
514 dev_dbg(&pdev
->dev
, "devinit\n");
515 mach_info
= pdev
->dev
.platform_data
;
516 if (mach_info
== NULL
) {
518 "no platform data for lcd, cannot attach\n");
522 if (mach_info
->default_display
> mach_info
->num_displays
) {
524 "default display No. is %d but only %d displays \n",
525 mach_info
->default_display
, mach_info
->num_displays
);
530 display
= mach_info
->displays
+ mach_info
->default_display
;
532 irq
= platform_get_irq(pdev
, 0);
534 dev_err(&pdev
->dev
, "no irq for device\n");
538 fbinfo
= framebuffer_alloc(sizeof(struct nuc900fb_info
), &pdev
->dev
);
542 platform_set_drvdata(pdev
, fbinfo
);
545 fbi
->dev
= &pdev
->dev
;
547 #ifdef CONFIG_CPU_NUC950
548 fbi
->drv_type
= LCDDRV_NUC950
;
551 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
553 size
= (res
->end
- res
->start
) + 1;
554 fbi
->mem
= request_mem_region(res
->start
, size
, pdev
->name
);
555 if (fbi
->mem
== NULL
) {
556 dev_err(&pdev
->dev
, "failed to alloc memory region\n");
561 fbi
->io
= ioremap(res
->start
, size
);
562 if (fbi
->io
== NULL
) {
563 dev_err(&pdev
->dev
, "ioremap() of lcd registers failed\n");
565 goto release_mem_region
;
568 fbi
->irq_base
= fbi
->io
+ REG_LCM_INT_CS
;
572 writel(0, fbi
->io
+ REG_LCM_DCCS
);
575 strcpy(fbinfo
->fix
.id
, driver_name
);
576 fbinfo
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
577 fbinfo
->fix
.type_aux
= 0;
578 fbinfo
->fix
.xpanstep
= 0;
579 fbinfo
->fix
.ypanstep
= 0;
580 fbinfo
->fix
.ywrapstep
= 0;
581 fbinfo
->fix
.accel
= FB_ACCEL_NONE
;
582 fbinfo
->var
.nonstd
= 0;
583 fbinfo
->var
.activate
= FB_ACTIVATE_NOW
;
584 fbinfo
->var
.accel_flags
= 0;
585 fbinfo
->var
.vmode
= FB_VMODE_NONINTERLACED
;
586 fbinfo
->fbops
= &nuc900fb_ops
;
587 fbinfo
->flags
= FBINFO_FLAG_DEFAULT
;
588 fbinfo
->pseudo_palette
= &fbi
->pseudo_pal
;
590 ret
= request_irq(irq
, nuc900fb_irqhandler
, IRQF_DISABLED
,
593 dev_err(&pdev
->dev
, "cannot register irq handler %d -err %d\n",
599 fbi
->clk
= clk_get(&pdev
->dev
, NULL
);
600 if (!fbi
->clk
|| IS_ERR(fbi
->clk
)) {
601 printk(KERN_ERR
"nuc900-lcd:failed to get lcd clock source\n");
606 clk_enable(fbi
->clk
);
607 dev_dbg(&pdev
->dev
, "got and enabled clock\n");
609 fbi
->clk_rate
= clk_get_rate(fbi
->clk
);
611 /* calutate the video buffer size */
612 for (i
= 0; i
< mach_info
->num_displays
; i
++) {
613 unsigned long smem_len
= mach_info
->displays
[i
].xres
;
614 smem_len
*= mach_info
->displays
[i
].yres
;
615 smem_len
*= mach_info
->displays
[i
].bpp
;
617 if (fbinfo
->fix
.smem_len
< smem_len
)
618 fbinfo
->fix
.smem_len
= smem_len
;
621 /* Initialize Video Memory */
622 ret
= nuc900fb_map_video_memory(fbinfo
);
624 printk(KERN_ERR
"Failed to allocate video RAM: %x\n", ret
);
628 dev_dbg(&pdev
->dev
, "got video memory\n");
630 fbinfo
->var
.xres
= display
->xres
;
631 fbinfo
->var
.yres
= display
->yres
;
632 fbinfo
->var
.bits_per_pixel
= display
->bpp
;
634 nuc900fb_init_registers(fbinfo
);
636 nuc900fb_check_var(&fbinfo
->var
, fbinfo
);
638 ret
= nuc900fb_cpufreq_register(fbi
);
640 dev_err(&pdev
->dev
, "Failed to register cpufreq\n");
641 goto free_video_memory
;
644 ret
= register_framebuffer(fbinfo
);
646 printk(KERN_ERR
"failed to register framebuffer device: %d\n",
651 printk(KERN_INFO
"fb%d: %s frame buffer device\n",
652 fbinfo
->node
, fbinfo
->fix
.id
);
657 nuc900fb_cpufreq_deregister(fbi
);
659 nuc900fb_unmap_video_memory(fbinfo
);
661 clk_disable(fbi
->clk
);
668 release_mem_region(res
->start
, size
);
670 framebuffer_release(fbinfo
);
675 * shutdown the lcd controller
677 static void nuc900fb_stop_lcd(struct fb_info
*info
)
679 struct nuc900fb_info
*fbi
= info
->par
;
680 void __iomem
*regs
= fbi
->io
;
682 writel((~LCM_DCCS_DISP_INT_EN
) | (~LCM_DCCS_VA_EN
) | (~LCM_DCCS_OSD_EN
),
683 regs
+ REG_LCM_DCCS
);
689 static int nuc900fb_remove(struct platform_device
*pdev
)
691 struct fb_info
*fbinfo
= platform_get_drvdata(pdev
);
692 struct nuc900fb_info
*fbi
= fbinfo
->par
;
695 nuc900fb_stop_lcd(fbinfo
);
698 nuc900fb_unmap_video_memory(fbinfo
);
702 irq
= platform_get_irq(pdev
, 0);
705 release_resource(fbi
->mem
);
708 platform_set_drvdata(pdev
, NULL
);
709 framebuffer_release(fbinfo
);
717 * suspend and resume support for the lcd controller
720 static int nuc900fb_suspend(struct platform_device
*dev
, pm_message_t state
)
722 struct fb_info
*fbinfo
= platform_get_drvdata(dev
);
723 struct nuc900fb_info
*info
= fbinfo
->par
;
727 clk_disable(info
->clk
);
731 static int nuc900fb_resume(struct platform_device
*dev
)
733 struct fb_info
*fbinfo
= platform_get_drvdata(dev
);
734 struct nuc900fb_info
*fbi
= fbinfo
->par
;
736 printk(KERN_INFO
"nuc900fb resume\n");
738 clk_enable(fbi
->clk
);
741 nuc900fb_init_registers(fbinfo
);
742 nuc900fb_activate_var(bfinfo
);
748 #define nuc900fb_suspend NULL
749 #define nuc900fb_resume NULL
752 static struct platform_driver nuc900fb_driver
= {
753 .probe
= nuc900fb_probe
,
754 .remove
= nuc900fb_remove
,
755 .suspend
= nuc900fb_suspend
,
756 .resume
= nuc900fb_resume
,
758 .name
= "nuc900-lcd",
759 .owner
= THIS_MODULE
,
763 int __devinit
nuc900fb_init(void)
765 return platform_driver_register(&nuc900fb_driver
);
768 static void __exit
nuc900fb_cleanup(void)
770 platform_driver_unregister(&nuc900fb_driver
);
773 module_init(nuc900fb_init
);
774 module_exit(nuc900fb_cleanup
);
776 MODULE_DESCRIPTION("Framebuffer driver for the NUC900");
777 MODULE_LICENSE("GPL");