diff -Nur linux-2.6.10-rc3/arch/arm/mach-s3c2410/devs.c linux-2.6.10-rc3-h1940/arch/arm/mach-s3c2410/devs.c
--- linux-2.6.10-rc3/arch/arm/mach-s3c2410/devs.c	2004-12-04 21:51:52.000000000 +0100
+++ linux-2.6.10-rc3-h1940/arch/arm/mach-s3c2410/devs.c	2004-12-04 23:13:46.000000000 +0100
@@ -27,7 +27,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
-
+#include <asm/arch/s3c2410fb.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -72,6 +72,15 @@
 
 /* LCD Controller */
 
+static struct s3c2410fb_mach_info s3c2410fb_info;
+
+void __init set_s3c2410fb_info(struct s3c2410fb_mach_info *hard_s3c2410fb_info)
+{
+	memcpy(&s3c2410fb_info,hard_s3c2410fb_info,sizeof(struct s3c2410fb_mach_info));
+}
+EXPORT_SYMBOL(set_s3c2410fb_info);
+
+
 static struct resource s3c_lcd_resource[] = {
 	[0] = {
 		.start = S3C2410_PA_LCD,
@@ -94,6 +103,7 @@
 	.num_resources	  = ARRAY_SIZE(s3c_lcd_resource),
 	.resource	  = s3c_lcd_resource,
 	.dev              = {
+ 		.platform_data	= &s3c2410fb_info,
 		.dma_mask = &s3c_device_lcd_dmamask,
 		.coherent_dma_mask = 0xffffffffUL
 	}
diff -Nur linux-2.6.10-rc3/arch/arm/mach-s3c2410/mach-h1940.c linux-2.6.10-rc3-h1940/arch/arm/mach-s3c2410/mach-h1940.c
--- linux-2.6.10-rc3/arch/arm/mach-s3c2410/mach-h1940.c	2004-12-04 21:51:52.000000000 +0100
+++ linux-2.6.10-rc3-h1940/arch/arm/mach-s3c2410/mach-h1940.c	2004-12-04 23:13:46.000000000 +0100
@@ -31,6 +31,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/device.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -44,6 +45,8 @@
 
 //#include <asm/debug-ll.h>
 #include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/s3c2410fb.h>
 
 #include <linux/serial_core.h>
 
@@ -85,8 +88,132 @@
 	}
 };
 
+/**
+ * Set lcd on or off
+ **/
+static void h1940_lcd_power(int on)
+{
+	s3c2410_gpio_setpin(S3C2410_GPC0, on);
+}
+
+/**
+ * Set the backlight on or off.
+ **/
+static void h1940_backlight_power(int on)
+{
+	s3c2410_gpio_setpin(S3C2410_GPB0, 0);
+	s3c2410_gpio_pullup(S3C2410_GPB0, 0);
+
+	s3c2410_gpio_cfgpin(S3C2410_GPB0,
+			    (on) ? S3C2410_GPB0_TOUT0 : S3C2410_GPB0_OUTP);
+}
+
+/* Set the backlight pwm according to the level from wince */
 
+#include <asm/arch/regs-timer.h>
+static void h1940_set_brightness(int level)
+{
+	unsigned long tcfg0;
+	unsigned long tcfg1;
+	unsigned long tcmpb0=0x00;
+	unsigned long tcon;
+
+	/* configure power on/off */
+	h1940_backlight_power(level ? 1 : 0);
+
+	switch (level)
+	{
+		case 0:
+			break;
+		case 1:
+			tcmpb0=0x0b;
+			break;
+		default:
+		case 2:
+			tcmpb0=0x16;
+			break;	
+		case 3:
+			tcmpb0=0x21;
+			break;	
+		case 4:
+			tcmpb0=0x2c;
+			break;
+	}
+	
+	tcfg0=__raw_readl(S3C2410_TCFG0);
+	tcfg1=__raw_readl(S3C2410_TCFG1);
+	
+	tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
+	tcfg0 |= 0x18;
+
+	tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;
+	tcfg1 |= S3C2410_TCFG1_MUX0_DIV2;
+
+	__raw_writel(tcfg0, S3C2410_TCFG0);
+	__raw_writel(tcfg1, S3C2410_TCFG1);
+	__raw_writel(0x31, S3C2410_TCNTB(0));
+
+	tcon = __raw_readl(S3C2410_TCON);
+	tcon &= ~0x0F;
+	tcon |= S3C2410_TCON_T0RELOAD;
+	tcon |= S3C2410_TCON_T0MANUALUPD;
+
+	__raw_writel(tcon, S3C2410_TCON);
+	__raw_writel(0x31, S3C2410_TCNTB(0));
+	__raw_writel(tcmpb0, S3C2410_TCMPB(0));
+
+	/* start the timer running */
+	tcon |= S3C2410_TCON_T0START;
+	tcon &= ~S3C2410_TCON_T0MANUALUPD;
+	__raw_writel(tcon, S3C2410_TCON);
+}
 
+#include <asm/arch/regs-lcd.h>
+
+static struct s3c2410fb_mach_info h1940_lcdcfg = {
+	.lcdcon1=	S3C2410_LCDCON1_TFT16BPP | \
+			S3C2410_LCDCON1_TFT | \
+			S3C2410_LCDCON1_CLKVAL(0x0C),
+	
+	.lcdcon2=	S3C2410_LCDCON2_VBPD(7) | \
+			S3C2410_LCDCON2_LINEVAL(319) | \
+			S3C2410_LCDCON2_VFPD(6) | \
+			S3C2410_LCDCON2_VSPW(0),
+			  
+	.lcdcon3=	S3C2410_LCDCON3_HBPD(19) | \
+			S3C2410_LCDCON3_HOZVAL(239) | \
+			S3C2410_LCDCON3_HFPD(7),
+			  
+	.lcdcon4=	S3C2410_LCDCON4_MVAL(0) | \
+			S3C2410_LCDCON4_HSPW(3),
+	
+	.lcdcon5=	S3C2410_LCDCON5_FRM565 | \
+			S3C2410_LCDCON5_INVVLINE | \
+			S3C2410_LCDCON5_HWSWP,
+	.lpcsel=	0x02,
+	.gpccon=	0xaa940659,
+	.gpccon_mask=	0xffffffff,
+	.gpcup=		0x0000ffff,
+	.gpcup_mask=	0xffffffff,
+	.gpdcon=	0xaa84aaa0,
+	.gpdcon_mask=	0xffffffff,
+	.gpdup=		0x0000faff,
+	.gpdup_mask=	0xffffffff,
+
+	.width=		240,
+	.height=	320,
+	.xres=		240,
+	.yres=		320,
+	.bpp=		16,
+
+	.backlight_min		= 0,
+	.backlight_max		= 4,
+	.backlight_default	= 2,
+
+	.lcd_power		= h1940_lcd_power,
+	.backlight_power	= h1940_backlight_power,
+	.set_brightness		= h1940_set_brightness,
+};
 
 static struct platform_device *h1940_devices[] __initdata = {
 	&s3c_device_usb,
@@ -116,11 +243,17 @@
 
 }
 
+void __init h1940_init(void)
+{
+	s3c_device_lcd.dev.platform_data = &h1940_lcdcfg;
+}
+		
 MACHINE_START(H1940, "IPAQ-H1940")
      MAINTAINER("Ben Dooks <ben@fluff.org>")
      BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART)
      BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
      MAPIO(h1940_map_io)
      INITIRQ(h1940_init_irq)
+     INIT_MACHINE(h1940_init)
 	.timer		= &s3c24xx_timer,
 MACHINE_END
diff -Nur linux-2.6.10-rc3/drivers/video/Kconfig linux-2.6.10-rc3-h1940/drivers/video/Kconfig
--- linux-2.6.10-rc3/drivers/video/Kconfig	2004-12-04 21:52:02.000000000 +0100
+++ linux-2.6.10-rc3-h1940/drivers/video/Kconfig	2004-12-05 00:11:43.000000000 +0100
@@ -1111,6 +1111,26 @@
 
 	  <file:Documentation/fb/pxafb.txt> describes the available parameters.
 
+config FB_S3C2410
+	tristate "S3C2410 LCD framebuffer support"
+	depends on FB && ARCH_S3C2410
+	---help---
+	  Frame buffer driver for the built-in LCD controller in the Samsung
+	  S3C2410 processor.
+
+	  This driver is also available as a module ( = code which can be
+	  inserted and removed from the running kernel whenever you want). The
+	  module will be called s3c2410fb. If you want to compile it as a module,
+	  say M here and read <file:Documentation/modules.txt>.
+
+	  If unsure, say N.
+config FB_S3C2410_DEBUG
+	bool "S3C2410 lcd debug messages"
+	depends on FB_S3C2410
+	help
+	  Turn on debugging messages. Note that you can set/unset at run time 
+	  through sysfs
+
 config FB_VIRTUAL
 	tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
 	depends on FB
diff -Nur linux-2.6.10-rc3/drivers/video/Makefile linux-2.6.10-rc3-h1940/drivers/video/Makefile
--- linux-2.6.10-rc3/drivers/video/Makefile	2004-12-04 21:52:02.000000000 +0100
+++ linux-2.6.10-rc3-h1940/drivers/video/Makefile	2004-12-04 23:13:46.000000000 +0100
@@ -92,6 +92,7 @@
 obj-$(CONFIG_FB_ASILIANT)	  += asiliantfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_PXA)		  += pxafb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o
 obj-$(CONFIG_FB_W100)		   += w100fb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o
+obj-$(CONFIG_FB_S3C2410)	  += s3c2410fb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o
 obj-$(CONFIG_FB_AU1100)		  += au1100fb.o fbgen.o
 obj-$(CONFIG_FB_PMAG_AA)	  += pmag-aa-fb.o  cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_PMAG_BA)	  += pmag-ba-fb.o  cfbfillrect.o cfbcopyarea.o cfbimgblt.o
diff -Nur linux-2.6.10-rc3/drivers/video/s3c2410fb.c linux-2.6.10-rc3-h1940/drivers/video/s3c2410fb.c
--- linux-2.6.10-rc3/drivers/video/s3c2410fb.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10-rc3-h1940/drivers/video/s3c2410fb.c	2004-12-05 00:12:38.000000000 +0100
@@ -0,0 +1,764 @@
+/*
+ * linux/drivers/s3c2410fb.c
+ * Copyright (c) Arnaud Patard
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ *	    S3C2410 LCD Controller Frame Buffer Driver
+ *	    based on skeletonfb.c, sa1100fb.c
+ *
+ * ChangeLog
+ *
+ * 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org>
+ *      - Added the possibility to set on or off the 
+ *      debugging mesaages
+ *      - Replaced 0 and 1 by on or off when reading the
+ *      /sys files
+ * 
+ * 2004-11-11: Arnaud Patard <arnaud.patard@rtp-net.org>
+ * 	- Removed the use of currcon as it no more exist
+ * 	- Added LCD power sysfs interface
+ *
+ * 2004-11-03: Ben Dooks <ben-linux@fluff.org>
+ *	- minor cleanups
+ *	- add suspend/resume support
+ *	- s3c2410fb_setcolreg() not valid in >8bpp modes
+ *	- removed last CONFIG_FB_S3C2410_FIXED
+ *	- ensure lcd controller stopped before cleanup
+ *	- added sysfs interface for backlight power
+ *	- added mask for gpio configuration
+ *	- ensured IRQs disabled during GPIO configuration
+ *	- disable TPAL before enabling video
+ *
+ * 2004-09-20: Arnaud Patard <arnaud.patard@rtp-net.org>
+ *      - Suppress command line options
+ *
+ * 2004-09-15: Arnaud Patard <arnaud.patard@rtp-net.org>
+ * 	- code cleanup
+ *
+ * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org>
+ * 	- Renamed from h1940fb.c to s3c2410fb.c
+ * 	- Add support for different devices
+ * 	- Backlight support
+ *
+ * 2004-09-05: Herbert Pötzl <herbert@13thfloor.at>
+ *	- added clock (de-)allocation code
+ *	- added fixem fbmem option
+ *
+ * 2004-07-27: Arnaud Patard <arnaud.patard@rtp-net.org>
+ *	- code cleanup
+ *	- added a forgotten return in h1940fb_init
+ *
+ * 2004-07-19: Herbert Pötzl <herbert@13thfloor.at>
+ *	- code cleanup and extended debugging
+ *
+ * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org>
+ *	- First version
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/string.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <asm/mach/map.h>
+#include <asm/arch/regs-lcd.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/s3c2410fb.h>
+#include <asm/hardware/clock.h>
+
+#include "s3c2410fb.h"
+
+#define S3C2410_FBIO_SETBRIGHTNESS	_IOW('F', 0x50, int)
+#define DEFAULT_BACKLIGHT_LEVEL		2
+
+static struct s3c2410fb_info info;
+static struct s3c2410fb_mach_info *mach_info;
+
+/* backlight and power control functions */
+
+static int backlight_level = DEFAULT_BACKLIGHT_LEVEL;
+static int backlight_power = 1;
+static int lcd_power	   = 1;
+
+/* Debugging stuff */
+#ifdef CONFIG_FB_S3C2410_DEBUG
+static int debug	   = 1;
+#else
+static int debug	   = 0;
+#endif
+
+#define dprintk(msg...)	if (debug) { printk(KERN_DEBUG "s3c2410fb: " msg); }
+
+static inline void s3c2410fb_lcd_power(int to)
+{
+	if (mach_info == NULL)
+		return;
+
+	lcd_power = to;
+
+	if (mach_info->lcd_power)
+		(mach_info->lcd_power)(to);
+}
+
+static inline void s3c2410fb_backlight_power(int to)
+{
+	if (mach_info == NULL)
+		return;
+
+	backlight_power = to;
+	
+	if (mach_info->backlight_power)
+		(mach_info->backlight_power)(to);
+}
+
+static inline void s3c2410fb_backlight_level(int to)
+{
+	if (mach_info == NULL)
+		return;
+
+	backlight_level = to;
+
+	if (mach_info->set_brightness)
+		(mach_info->set_brightness)(to);
+}
+
+/*
+ *	s3c2410fb_check_var():
+ *	Get the video params out of 'var'. If a value doesn't fit, round it up,
+ *	if it's too big, return -EINVAL.
+ *
+ */
+static int s3c2410fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	dprintk("check_var(var=%p, info=%p)\n", var, info);
+	
+	var->red.offset		= 11;
+	var->green.offset	= 5;
+	var->blue.offset	= 0;
+ 	var->red.length		= 5;
+	var->green.length	= 6;
+	var->blue.length	= 5;
+
+	return 0;
+}
+
+/*
+ *      s3c2410fb_set_par - Optional function. Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ */
+static int s3c2410fb_set_par(struct fb_info *info)
+{
+	struct s3c2410fb_info *fbi = (struct s3c2410fb_info *)info;
+	struct fb_var_screeninfo *var = &info->var;
+
+	/* We support only 16BPP true color */
+	fbi->fb.fix.visual	    = FB_VISUAL_TRUECOLOR;
+	fbi->fb.fix.line_length     = (var->width*var->bits_per_pixel)/8;
+	return 0;
+}
+
+
+static int s3c2410fb_setcolreg(unsigned regno,
+			       unsigned red, unsigned green, unsigned blue,
+			       unsigned transp, struct fb_info *info)
+{
+	struct s3c2410fb_info *fbi = (struct s3c2410fb_info *)info;
+	int bpp, m = 0;
+
+	bpp = fbi->fb.var.bits_per_pixel;
+	m = 1 << bpp;
+
+	if (regno >= m) {
+		return -EINVAL;
+	}
+
+	switch (bpp) {
+	case 16:
+		/* RGB 565 */
+		fbi->pseudo_pal[regno] = ((red & 0xF800)
+			| ((green & 0xFC00) >> 5)
+			| ((blue & 0xF800) >> 11));
+		break;
+	}
+
+	return 0;
+}
+
+
+/**
+ *	s3c2410fb_pan_display
+ *	@var: frame buffer variable screen structure
+ *	@info: frame buffer structure that represents a single frame buffer
+ *
+ *	Pan (or wrap, depending on the `vmode' field) the display using the
+ *	`xoffset' and `yoffset' fields of the `var' structure.
+ *	If the values don't fit, return -EINVAL.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int s3c2410fb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	dprintk("pan_display(var=%p, info=%p)\n", var, info);
+	return 0;
+}
+
+/**
+ *      s3c2410fb_blank
+ *	@blank_mode: the blank mode we want.
+ *	@info: frame buffer structure that represents a single frame buffer
+ *
+ *	Blank the screen if blank_mode != 0, else unblank. Return 0 if
+ *	blanking succeeded, != 0 if un-/blanking failed due to e.g. a
+ *	video mode which doesn't support it. Implements VESA suspend
+ *	and powerdown modes on hardware that supports disabling hsync/vsync:
+ *	blank_mode == 2: suspend vsync
+ *	blank_mode == 3: suspend hsync
+ *	blank_mode == 4: powerdown
+ *
+ *	Returns negative errno on error, or zero on success.
+ *
+ */
+static int s3c2410fb_blank(int blank_mode, struct fb_info *info)
+{
+	dprintk("blank(mode=%d, info=%p)\n", blank_mode, info);
+	
+	if (mach_info == NULL)
+		return -EINVAL;
+
+	switch (blank_mode) {
+	case VESA_NO_BLANKING:	/* lcd on, backlight on */
+		s3c2410fb_lcd_power(1);
+		s3c2410fb_backlight_power(1);
+		break;
+
+	case VESA_VSYNC_SUSPEND: /* lcd on, backlight off */
+	case VESA_HSYNC_SUSPEND:
+		s3c2410fb_lcd_power(1);
+		s3c2410fb_backlight_power(0);
+		break;
+
+	case VESA_POWERDOWN: /* lcd and backlight off */
+		s3c2410fb_lcd_power(0);
+		s3c2410fb_backlight_power(0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * s3c2410fb_ioctl - non standard ioctls (atm, only level)
+ */
+static int s3c2410fb_ioctl(struct inode *inode, struct file *file,
+			   u_int cmd, u_long arg,
+			   struct fb_info *info)
+{
+	int value;
+
+	switch(cmd)
+	{
+		case S3C2410_FBIO_SETBRIGHTNESS:
+			if (copy_from_user(&value, (__user void *)arg,
+					   sizeof(int)))
+				return(-EFAULT);
+			s3c2410fb_backlight_level(value);
+			return(0);
+			break;
+		default:
+			return(-EINVAL);
+	}
+}
+
+static int s3c2410fb_debug_show(struct device *dev, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", debug ? "on" : "off");
+}
+static int s3c2410fb_debug_store(struct device *dev,
+					   const char *buf, size_t len)
+{
+	if (mach_info == NULL)
+		return -EINVAL;
+
+	if (len < 1)
+		return -EINVAL;
+
+	if (strnicmp(buf, "on", 2) == 0 ||
+	    strnicmp(buf, "1", 1) == 0) {
+		debug = 1;
+		printk(KERN_DEBUG "s3c2410fb: Debug On");
+	} else if (strnicmp(buf, "off", 3) == 0 ||
+		   strnicmp(buf, "0", 1) == 0) {
+		debug = 0;
+		printk(KERN_DEBUG "s3c2410fb: Debug Off");
+	} else {
+		return -EINVAL;
+	}
+
+	return len;
+}
+
+
+/* sysfs export of baclight control */
+static int s3c2410fb_lcd_power_show(struct device *dev, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", lcd_power ? "on" : "off");
+}
+static int s3c2410fb_lcd_power_store(struct device *dev,
+					   const char *buf, size_t len)
+{
+	if (mach_info == NULL)
+		return -EINVAL;
+
+	if (len < 1)
+		return -EINVAL;
+
+	if (strnicmp(buf, "on", 2) == 0 ||
+	    strnicmp(buf, "1", 1) == 0) {
+		s3c2410fb_lcd_power(1);
+	} else if (strnicmp(buf, "off", 3) == 0 ||
+		   strnicmp(buf, "0", 1) == 0) {
+		s3c2410fb_lcd_power(0);
+	} else {
+		return -EINVAL;
+	}
+
+	return len;
+}
+
+static int s3c2410fb_backlight_level_show(struct device *dev, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", backlight_level);
+}
+
+static int s3c2410fb_backlight_power_show(struct device *dev, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", backlight_power ? "on" : "off");
+}
+
+static int s3c2410fb_backlight_level_store(struct device *dev,
+					   const char *buf, size_t len)
+{
+	unsigned long value = simple_strtoul(buf, NULL, 10);
+
+	if (mach_info == NULL)
+		return -EINVAL;
+
+	if (value < mach_info->backlight_min ||
+	    value > mach_info->backlight_max)
+		return -ERANGE;
+
+	s3c2410fb_backlight_level(value);
+	return len;
+}
+
+static int s3c2410fb_backlight_power_store(struct device *dev,
+					   const char *buf, size_t len)
+{
+	if (mach_info == NULL)
+		return -EINVAL;
+
+	if (len < 1)
+		return -EINVAL;
+
+	if (strnicmp(buf, "on", 2) == 0 ||
+	    strnicmp(buf, "1", 1) == 0) {
+		s3c2410fb_backlight_power(1);
+	} else if (strnicmp(buf, "off", 3) == 0 ||
+		   strnicmp(buf, "0", 1) == 0) {
+		s3c2410fb_backlight_power(0);
+	} else {
+		return -EINVAL;
+	}
+
+	return len;
+}
+
+static DEVICE_ATTR(debug, 0666,
+		   s3c2410fb_debug_show,
+		   s3c2410fb_debug_store);
+
+static DEVICE_ATTR(lcd_power, 0644,
+		   s3c2410fb_lcd_power_show,
+		   s3c2410fb_lcd_power_store);
+
+static DEVICE_ATTR(backlight_level, 0644,
+		   s3c2410fb_backlight_level_show,
+		   s3c2410fb_backlight_level_store);
+
+static DEVICE_ATTR(backlight_power, 0644,
+		   s3c2410fb_backlight_power_show,
+		   s3c2410fb_backlight_power_store);
+
+
+
+static struct fb_ops s3c2410fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= s3c2410fb_check_var,
+	.fb_set_par	= s3c2410fb_set_par,	
+	.fb_blank	= s3c2410fb_blank,
+	.fb_pan_display	= s3c2410fb_pan_display,	
+	.fb_setcolreg	= s3c2410fb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,	
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,	
+	.fb_ioctl	= s3c2410fb_ioctl,
+};
+
+
+/* Fake monspecs to fill in fbinfo structure */
+/* Don't know if the values are important    */
+static struct fb_monspecs monspecs __initdata = {
+	.hfmin	= 30000,
+	.hfmax	= 70000,
+	.vfmin	= 50,
+	.vfmax	= 65,
+};
+
+/*
+ * s3c2410fb_map_video_memory():
+ *	Allocates the DRAM memory for the frame buffer.  This buffer is
+ *	remapped into a non-cached, non-buffered, memory region to
+ *	allow palette and pixel writes to occur without flushing the
+ *	cache.  Once this area is remapped, all virtual memory
+ *	access to the video memory should occur at the new region.
+ */
+static int __init s3c2410fb_map_video_memory(struct s3c2410fb_info *fbi)
+{
+	dprintk("map_video_memory(fbi=%p)\n", fbi);
+
+	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+	fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
+					      &fbi->map_dma, GFP_KERNEL);
+
+	fbi->map_size = fbi->fb.fix.smem_len;
+
+	if (fbi->map_cpu) {
+		/* prevent initial garbage on screen */
+		dprintk("map_video_memory: clear %p:%08x\n",
+			fbi->map_cpu, fbi->map_size);
+		memset(fbi->map_cpu, 0xf0, fbi->map_size);
+
+		fbi->screen_dma = fbi->map_dma;
+		fbi->fb.screen_base = fbi->map_cpu;
+		fbi->fb.fix.smem_start = fbi->screen_dma;
+
+		dprintk("map_video_memory: dma=%08x cpu=%p size=%08x\n",
+			fbi->map_dma, fbi->map_cpu, fbi->fb.fix.smem_len);
+	}
+
+	return fbi->map_cpu ? 0 : -ENOMEM;
+}
+
+static inline void modify_gpio(unsigned long reg,
+			       unsigned long set, unsigned long mask)
+{
+	unsigned long tmp;
+	
+	tmp = __raw_readl(reg) & ~mask;
+	__raw_writel(tmp | set, reg);
+
+	dprintk("%08lx set to %08x\n", reg, __raw_readl(reg)); 
+}
+
+/*
+ * s3c2410fb_init_registers - Initialise all LCD-related registers
+ */
+int s3c2410fb_init_registers(struct s3c2410fb_info *fbi)
+{	
+	unsigned long saddr1, saddr2, saddr3;
+	unsigned long flags;
+
+	/* Initialise LCD with values from haret */
+
+	local_irq_save(flags);
+
+	/* modify the gpio(s) with interrupts set (bjd) */
+
+	modify_gpio(S3C2410_GPCUP, mach_info->gpcup, mach_info->gpcup_mask);
+	modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask);
+	modify_gpio(S3C2410_GPDUP, mach_info->gpdup, mach_info->gpdup_mask);
+	modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask);
+
+	local_irq_restore(flags);
+
+	__raw_writel(mach_info->lcdcon1, S3C2410_LCDCON1);
+	__raw_writel(mach_info->lcdcon2, S3C2410_LCDCON2);
+	__raw_writel(mach_info->lcdcon3, S3C2410_LCDCON3);
+	__raw_writel(mach_info->lcdcon4, S3C2410_LCDCON4);
+	__raw_writel(mach_info->lcdcon5, S3C2410_LCDCON5);
+
+
+	saddr1 =  S3C2410_LCDBANK(fbi->fb.fix.smem_start >> 22)
+		| S3C2410_LCDBASEU(fbi->fb.fix.smem_start >> 1);
+	saddr2 = (fbi->fb.fix.smem_start+(mach_info->width*mach_info->height*2)) >> 1;
+	saddr3 =  S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH(mach_info->width);
+	
+	
+	dprintk("LCDSADDR1 = 0x%08lx\n", saddr1);
+	__raw_writel(saddr1, S3C2410_LCDSADDR1);
+
+	dprintk("LCDSADDR2 = 0x%08lx\n", saddr2);
+	__raw_writel(saddr2, S3C2410_LCDSADDR2);
+	
+	dprintk("LCDSADDR3 = 0x%08lx\n", saddr3);
+	__raw_writel(saddr3, S3C2410_LCDSADDR3);
+
+	dprintk("LPCSEL    = 0x%08lx\n", mach_info->lpcsel);
+	__raw_writel(mach_info->lpcsel, S3C2410_LPCSEL);
+
+	dprintk("replacing TPAL %08x\n", __raw_readl(S3C2410_TPAL));
+
+	/* ensure temporary palette disabled */
+	__raw_writel(0x00, S3C2410_TPAL);
+
+	/* probably not required */
+	msleep(10);
+
+	/* Enable video by setting the ENVID bit to 1 */
+	__raw_writel(mach_info->lcdcon1|S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
+	return 0;
+}
+
+static struct clk      *lcd_clock;
+
+int __init s3c2410fb_probe(struct device *dev)
+{
+	char driver_name[]="s3c2410fb";
+	int ret;
+
+	mach_info = dev->platform_data;
+	if (mach_info == NULL)
+	{
+		printk(KERN_ERR "no platform data for lcd, cannot attach\n");
+		return -EINVAL;
+	}
+	
+	s3c2410fb_backlight_power(1);
+	s3c2410fb_lcd_power(1);
+
+	s3c2410fb_backlight_level(DEFAULT_BACKLIGHT_LEVEL);
+
+	dprintk("devinit\n");
+
+	strcpy(info.fb.fix.id, driver_name);
+	info.fb.fix.type	    = FB_TYPE_PACKED_PIXELS;
+	info.fb.fix.type_aux	    = 0;
+	info.fb.fix.xpanstep	    = 0;
+	info.fb.fix.ypanstep	    = 0;
+	info.fb.fix.ywrapstep	    = 0;
+	info.fb.fix.accel	    = FB_ACCEL_NONE;
+
+	info.fb.var.nonstd	    = 0;
+	info.fb.var.activate	    = FB_ACTIVATE_NOW;
+	info.fb.var.height	    = mach_info->height;
+	info.fb.var.width	    = mach_info->width;
+	info.fb.var.accel_flags     = 0;
+	info.fb.var.vmode	    = FB_VMODE_NONINTERLACED;
+
+	info.fb.fbops		    = &s3c2410fb_ops;
+	info.fb.flags		    = FBINFO_FLAG_DEFAULT;
+	info.fb.monspecs	    = monspecs;
+	info.fb.pseudo_palette      = &info.pseudo_pal;
+
+
+	info.fb.var.xres	    = mach_info->xres;
+	info.fb.var.xres_virtual    = mach_info->xres;
+	info.fb.var.yres	    = mach_info->yres;
+	info.fb.var.yres_virtual    = mach_info->yres;
+	info.fb.var.bits_per_pixel  = mach_info->bpp;
+
+
+	info.fb.var.red.offset      = 11;
+	info.fb.var.green.offset    = 5;
+	info.fb.var.blue.offset     = 0;
+	info.fb.var.transp.offset   = 0;
+	info.fb.var.red.length      = 5;
+	info.fb.var.green.length    = 6;
+	info.fb.var.blue.length     = 5;
+	info.fb.var.transp.length   = 0;
+
+	info.fb.fix.smem_len	    = info.fb.var.xres * info.fb.var.yres *
+				      info.fb.var.bits_per_pixel / 8;
+
+	if (!request_mem_region(S3C2410_VA_LCD, SZ_1M, "s3c2410-lcd"))
+		return -EBUSY;
+	dprintk("got LCD region\n");
+
+	lcd_clock = clk_get(NULL, "lcd");
+	if (!lcd_clock) {
+		printk(KERN_ERR "failed to get lcd clock source\n");
+		return -ENOENT;
+	}
+	clk_use(lcd_clock);
+	clk_enable(lcd_clock);
+	dprintk("got and enabled clock\n");
+
+	/* maybe not required */
+	msleep(10);
+
+
+	/* Initialize video memory */
+	ret = s3c2410fb_map_video_memory(&info);
+	if (ret) {
+		printk( KERN_ERR "Failed to allocate video RAM: %d\n", ret);
+		ret = -ENOMEM;
+		goto failed;
+	}
+	dprintk("got video memory\n");
+
+	ret = s3c2410fb_init_registers(&info);
+	s3c2410fb_lcd_power(1);
+
+	ret = s3c2410fb_check_var(&info.fb.var, &info.fb);
+
+	ret = register_framebuffer(&info.fb);
+	if (ret < 0) {
+		printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret);
+		goto failed;
+	}
+
+	/* create device files */
+	device_create_file(dev, &dev_attr_debug);
+	device_create_file(dev, &dev_attr_backlight_power);
+	device_create_file(dev, &dev_attr_backlight_level);
+	device_create_file(dev, &dev_attr_lcd_power);
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+		info.fb.node, info.fb.fix.id);
+
+	return 0;
+failed:
+	release_mem_region(S3C2410_VA_LCD, S3C2410_SZ_LCD);
+	return ret;
+}
+
+/* s3c2410fb_stop_lcd
+ *
+ * shutdown the lcd controller 
+*/
+
+static void s3c2410fb_stop_lcd(void)
+{
+	unsigned long flags;
+	unsigned long tmp;
+
+	local_irq_save(flags);
+	
+	tmp = __raw_readl(S3C2410_LCDCON1);
+	__raw_writel(tmp & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
+	
+	local_irq_restore(flags);
+}
+
+/*
+ *  Cleanup
+ */
+static void __exit s3c2410fb_cleanup(void)
+{
+	s3c2410fb_stop_lcd();
+	msleep(1);
+
+	if (lcd_clock) {
+		clk_disable(lcd_clock);
+		clk_unuse(lcd_clock);
+		clk_put(lcd_clock);
+		lcd_clock = NULL;
+	}
+
+	unregister_framebuffer(&info.fb);
+	release_mem_region(S3C2410_VA_LCD, S3C2410_SZ_LCD);
+}
+
+#ifdef CONFIG_PM
+
+/* suspend and resume support for the lcd controller */
+
+static int s3c2410fb_suspend(struct device *dev, u32 state, u32 level)
+{
+	if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) {
+		s3c2410fb_stop_lcd();
+
+		/* sleep before disabling the clock, we need to ensure
+		 * the LCD DMA engine is not going to get back on the bus
+		 * before the clock goes off again (bjd) */
+
+		if (mach_info != NULL) {
+			/* don't use our helper functions in this file,
+			   becuase we want to save the original values for
+			   when the system wakes up
+			*/
+
+			if (mach_info->lcd_power)
+				(mach_info->lcd_power)(0);
+
+			if (mach_info->backlight_power)
+				(mach_info->backlight_power)(0);
+		}
+
+		msleep(1);
+		clk_disable(lcd_clock);
+	}
+
+	return 0;
+}
+
+static int s3c2410fb_resume(struct device *dev, u32 level)
+{
+	if (level == RESUME_ENABLE) {
+		clk_enable(lcd_clock);
+		msleep(1);
+
+		s3c2410fb_init_registers(&info);
+		
+		/* resume the backlight level */
+		s3c2410fb_backlight_power(backlight_power);
+		s3c2410fb_backlight_level(backlight_level);
+	}
+
+	return 0;
+}
+
+#else
+#define s3c2410fb_suspend NULL
+#define s3c2410fb_resume  NULL
+#endif
+
+static struct device_driver s3c2410fb_driver = {
+	.name		= "s3c2410-lcd",
+	.bus		= &platform_bus_type,
+	.probe		= s3c2410fb_probe,
+	.suspend	= s3c2410fb_suspend,
+	.resume		= s3c2410fb_resume,
+};
+
+int __devinit s3c2410fb_init(void)
+{
+	return driver_register(&s3c2410fb_driver);
+}
+
+module_init(s3c2410fb_init);
+module_exit(s3c2410fb_cleanup);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_DESCRIPTION("Framebuffer driver for the s3c2410");
+MODULE_LICENSE("GPL");
diff -Nur linux-2.6.10-rc3/drivers/video/s3c2410fb.h linux-2.6.10-rc3-h1940/drivers/video/s3c2410fb.h
--- linux-2.6.10-rc3/drivers/video/s3c2410fb.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10-rc3-h1940/drivers/video/s3c2410fb.h	2004-12-04 23:25:27.000000000 +0100
@@ -0,0 +1,44 @@
+#ifndef __S3C2410FB_H
+#define __S3C2410FB_H
+/*
+ * linux/drivers/s3c2410fb.h
+ * Copyright (c) Arnaud Patard
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ *	    S3C2410 LCD Controller Frame Buffer Driver
+ *	    based on skeletonfb.c, sa1100fb.h
+ *
+ * ChangeLog
+ *
+ * 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org>
+ *      - Moved dprintk to s3c2410fb.c
+ *
+ * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org>
+ * 	- Renamed from h1940fb.h to s3c2410fb.h
+ * 	- Chenged h1940 to s3c2410
+ * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org>
+ *	- First version
+ */
+
+struct s3c2410fb_info {
+	struct fb_info		fb;
+	struct device		*dev;
+
+	/* raw memory addresses */
+	dma_addr_t		map_dma;	/* physical */
+	u_char *		map_cpu;	/* virtual */
+	u_int			map_size;
+
+	/* addresses of pieces placed in raw buffer */
+	u_char *		screen_cpu;	/* virtual address of frame buffer */
+	dma_addr_t		screen_dma;	/* physical address of frame buffer */
+
+	u32 pseudo_pal[16];
+};
+
+int s3c2410fb_init(void);
+
+#endif
diff -Nur linux-2.6.10-rc3/include/asm-arm/arch-s3c2410/s3c2410fb.h linux-2.6.10-rc3-h1940/include/asm-arm/arch-s3c2410/s3c2410fb.h
--- linux-2.6.10-rc3/include/asm-arm/arch-s3c2410/s3c2410fb.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10-rc3-h1940/include/asm-arm/arch-s3c2410/s3c2410fb.h	2004-12-04 23:13:46.000000000 +0100
@@ -0,0 +1,64 @@
+/* linux/include/asm/arch-s3c2410/s3c2410fb.h
+ *
+ * Copyright (c) 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * Inspired by pxafb.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ *  Changelog:
+ *	07-Sep-2004	RTP	Created file
+ *	03-Nov-2004	BJD	Updated and minor cleanups      
+*/
+
+#ifndef __ASM_ARM_S3C2410FB_H
+#define __ASM_ARM_S3C2410FB_H
+
+#include <asm/arch/regs-lcd.h>
+
+struct s3c2410fb_mach_info {
+	
+	/* Screen size */
+	int		width;
+	int		height;
+
+	/* Screen info */
+	int		xres;
+	int		yres;
+	int		bpp;
+	
+	/* lcd configuration registers */
+	unsigned long	lcdcon1;
+	unsigned long	lcdcon2;
+	unsigned long	lcdcon3;
+	unsigned long	lcdcon4;
+	unsigned long	lcdcon5;
+
+	/* GPIOs */
+	unsigned long	gpcup;
+	unsigned long	gpcup_mask;
+	unsigned long	gpccon;
+	unsigned long	gpccon_mask;
+	unsigned long	gpdup;
+	unsigned long	gpdup_mask;
+	unsigned long	gpdcon;
+	unsigned long	gpdcon_mask;
+	
+	/* lpc3600 control register */
+	unsigned long	lpcsel;
+
+	/* backlight info */
+	int		backlight_min;
+	int		backlight_max;
+	int		backlight_default;
+	
+	/* Utility fonctions */
+	void		(*backlight_power)(int);
+	void		(*lcd_power)(int);
+	void		(*set_brightness)(int);
+};
+
+#endif /* __ASM_ARM_S3C2410FB_H */
