#
# Patch managed by http://www.holgerschurig.de/patcher.html
#

--- linux-2.4.27/include/asm-arm/arch-sa1100/simpad.h~simpad-serial
+++ linux-2.4.27/include/asm-arm/arch-sa1100/simpad.h
@@ -16,7 +16,7 @@
 #error "include <asm/hardware.h> instead"
 #endif
 
-#define GPIO_UART1_RTS	GPIO_GPIO14
+#define GPIO_UART1_RTS	GPIO_GPIO9
 #define GPIO_UART1_DTR	GPIO_GPIO7
 #define GPIO_UART1_CTS	GPIO_GPIO8
 #define GPIO_UART1_DCD	GPIO_GPIO23
@@ -31,12 +31,12 @@
 #define GPIO_POWER_BUTTON       GPIO_GPIO0
 #define GPIO_UCB1300_IRQ	GPIO_GPIO (22)	/* UCB GPIO and touchscreen */
 
-#define IRQ_UART1_CTS	IRQ_GPIO15
-#define IRQ_UART1_DCD	GPIO_GPIO23
-#define IRQ_UART1_DSR	GPIO_GPIO6
-#define IRQ_UART3_CTS	GPIO_GPIO13
-#define IRQ_UART3_DCD	GPIO_GPIO18
-#define IRQ_UART3_DSR	GPIO_GPIO17
+#define IRQ_GPIO_UART1_CTS	IRQ_GPIO8
+#define IRQ_GPIO_UART1_DCD	IRQ_GPIO23
+#define IRQ_GPIO_UART1_DSR	IRQ_GPIO6
+#define IRQ_GPIO_UART3_CTS	IRQ_GPIO13
+#define IRQ_GPIO_UART3_DCD	IRQ_GPIO18
+#define IRQ_GPIO_UART3_DSR	IRQ_GPIO17
 
 #define IRQ_GPIO_UCB1300_IRQ IRQ_GPIO22
 #define IRQ_GPIO_POWER_BUTTON    IRQ_GPIO0
--- linux-2.4.27/arch/arm/mach-sa1100/simpad.c~simpad-serial
+++ linux-2.4.27/arch/arm/mach-sa1100/simpad.c
@@ -22,9 +22,11 @@
 
 #include "generic.h"
 
+#undef SIMPAD_UART_USE_IRQ  // irq handling on CTS/DCD doesn't work yet
+
 long cs3_shadow;
 
-long get_cs3_shadow()
+long get_cs3_shadow(void)
 {
 	return cs3_shadow;
 }
@@ -107,18 +109,170 @@
   LAST_DESC
 };
 
+#define SER_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
+
+static void simpad_uart_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+	if (port->mapbase == _Ser1UTCR0) {
+	        /* internal serial port (ttySA1, DECT/Bluetooth) */
+		if (mctrl & TIOCM_RTS)	GPCR = GPIO_UART1_RTS;
+		else			GPSR = GPIO_UART1_RTS;
+
+		if (mctrl & TIOCM_DTR)	GPCR = GPIO_UART1_DTR;
+		else			GPSR = GPIO_UART1_DTR;
+	}
+
+	else if (port->mapbase == _Ser3UTCR0) {
+	        /* external serial port (ttySA0, RS232) */
+	        if (mctrl & TIOCM_RTS)  GPCR = GPIO_UART3_RTS;
+		else			GPSR = GPIO_UART3_RTS;
+
+	        if (mctrl & TIOCM_DTR)  GPCR = GPIO_UART3_DTR;
+		else			GPSR = GPIO_UART3_DTR;
+	}
+}
+
+static u_int simpad_uart_get_mctrl(struct uart_port *port)
+{
+	u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
+
+	if (port->mapbase == _Ser1UTCR0) {
+	        /* internal serial port (ttySA1, DECT/Bluetooth) */
+		int gplr = GPLR;
+		if (gplr & GPIO_UART1_DCD) ret &= ~TIOCM_CD;
+		if (gplr & GPIO_UART1_CTS) ret &= ~TIOCM_CTS;
+		if (gplr & GPIO_UART1_DSR) ret &= ~TIOCM_DSR;
+	}
+
+	else if (port->mapbase == _Ser3UTCR0) {
+	        /* external serial port (ttySA0, RS232) */
+		int gplr = GPLR;
+		if (gplr & GPIO_UART3_DCD) ret &= ~TIOCM_CD;
+		if (gplr & GPIO_UART3_CTS) ret &= ~TIOCM_CTS;
+		if (gplr & GPIO_UART3_DSR) ret &= ~TIOCM_DSR;
+	}
+	return ret;
+}
+
 static void simpad_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
 {
-	if (port->mapbase == (u_int)&Ser1UTCR0) {
+	if (port->mapbase == (u_int)&Ser3UTCR0) {
 		if (state)
 			clear_cs3_bit(RS232_ON);
 		else
 			set_cs3_bit(RS232_ON);
 	}
 }
+/*
+ * Enable/Disable wake up events for this serial port.
+ * Obviously, we only support this on the normal COM port.
+ */
+static int simpad_uart_set_wake(struct uart_port *port, u_int enable)
+{
+	int err = -EINVAL;
+
+#if 0  // TODO: port management
+	if (port->mapbase == _Ser3UTCR0) {
+		if (enable)
+			PWER |= PWER_GPIO23 | PWER_GPIO25 ; /* DCD and CTS */
+		else
+			PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
+		err = 0;
+	}
+#endif
+
+	return err;
+}
+
+#ifdef SIMPAD_UART_USE_IRQ
+static void simpad_uart1_dcd_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = dev_id;
+	/* Note: should only call this if something has changed */
+	uart_handle_dcd_change(port, !(GPLR & GPIO_UART1_DCD));
+}
+
+static void simpad_uart1_cts_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = dev_id;
+	/* Note: should only call this if something has changed */
+	uart_handle_cts_change(port, !(GPLR & GPIO_UART1_CTS));
+}
+
+static void simpad_uart3_dcd_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = dev_id;
+	/* Note: should only call this if something has changed */
+	uart_handle_dcd_change(port, !(GPLR & GPIO_UART3_DCD));
+}
+
+static void simpad_uart3_cts_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = dev_id;
+	/* Note: should only call this if something has changed */
+	uart_handle_cts_change(port, !(GPLR & GPIO_UART3_CTS));
+}
+#endif
+
+static int simpad_uart_open(struct uart_port *port)
+{
+	int ret = 0;
+#ifdef SIMPAD_UART_USE_IRQ
+	if (port->mapbase == _Ser1UTCR0) {
+		set_GPIO_IRQ_edge(GPIO_UART1_DCD|GPIO_UART1_CTS,
+				  GPIO_BOTH_EDGES);
+
+		ret = request_irq(IRQ_GPIO_UART1_DCD, simpad_uart1_dcd_intr,
+				  0, "UART1 DCD", port);
+		if (ret)
+			return ret;
+
+		ret = request_irq(IRQ_GPIO_UART1_CTS, simpad_uart1_cts_intr,
+				  0, "UART1 CTS", port);
+		if (ret)
+			free_irq(IRQ_GPIO_UART1_DCD, port);
+	}
+
+	else if (port->mapbase == _Ser3UTCR0) {
+		set_GPIO_IRQ_edge(GPIO_UART3_DCD|GPIO_UART3_CTS,
+				  GPIO_BOTH_EDGES);
+
+		ret = request_irq(IRQ_GPIO_UART3_DCD, simpad_uart3_dcd_intr,
+				  0, "UART3 DCD", port);
+		if (ret)
+			return ret;
+
+		ret = request_irq(IRQ_GPIO_UART3_CTS, simpad_uart3_cts_intr,
+				  0, "UART3 CTS", port);
+		if (ret)
+			free_irq(IRQ_GPIO_UART3_DCD, port);
+	}
+#endif
+	return ret;
+}
+
+static void simpad_uart_close(struct uart_port *port)
+{
+#ifdef SIMPAD_UART_USE_IRQ
+	if (port->mapbase == _Ser1UTCR0) {
+		free_irq(IRQ_GPIO_UART1_DCD, port);
+		free_irq(IRQ_GPIO_UART1_CTS, port);
+	}
+
+	else if (port->mapbase == _Ser3UTCR0) {
+		free_irq(IRQ_GPIO_UART3_DCD, port);
+		free_irq(IRQ_GPIO_UART3_CTS, port);
+	}
+#endif
+}
 
 static struct sa1100_port_fns simpad_port_fns __initdata = {
-	.pm	= simpad_uart_pm,
+	.set_mctrl	= simpad_uart_set_mctrl,
+	.get_mctrl	= simpad_uart_get_mctrl,
+	.pm	        = simpad_uart_pm,
+	.set_wake	= simpad_uart_set_wake,
+	.open		= simpad_uart_open,
+	.close		= simpad_uart_close,
 };
 
 static void __init simpad_map_io(void)
@@ -129,13 +283,32 @@
         set_cs3_bit (EN1 | EN0 | LED2_ON | DISPLAY_ON | RS232_ON |
                       ENABLE_5V | nRESET_SIMCARD);
 
+	sa1100_register_uart_fns(&simpad_port_fns);
+
         //It is only possible to register 3 UART in serial_sa1100.c
         sa1100_register_uart(0, 3);
         sa1100_register_uart(1, 1);
 
+	// txd and rxd use their alternate function
 	GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
+
+	// the control lines are gpio
+	GAFR &= ~(GPIO_UART1_RTS | GPIO_UART1_CTS | GPIO_UART1_DCD);
+	GAFR &= ~(GPIO_UART1_DSR | GPIO_UART1_DTR);
+	GAFR &= ~(GPIO_UART3_RTS | GPIO_UART3_CTS | GPIO_UART3_DCD);
+	GAFR &= ~(GPIO_UART3_DSR | GPIO_UART3_DTR);
+
+	// txd, rts and dtr are outputs
 	GPDR |= GPIO_UART_TXD;
+	GPDR |= GPIO_UART1_RTS | GPIO_UART3_RTS;
+	GPDR |= GPIO_UART1_DTR | GPIO_UART3_DTR;
+
+	// cts, dcd, dsr and rxd are inputs
+	GPDR &= ~(GPIO_UART1_CTS | GPIO_UART3_CTS);
+	GPDR &= ~(GPIO_UART1_DCD | GPIO_UART3_DCD);
+	GPDR &= ~(GPIO_UART1_DSR | GPIO_UART3_DSR);
 	GPDR &= ~GPIO_UART_RXD;
+
 	PPAR |= PPAR_UPR;
 
         set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ, GPIO_RISING_EDGE);
--- linux-2.4.27/drivers/video/mq200fb.c~simpad-serial
+++ linux-2.4.27/drivers/video/mq200fb.c
@@ -672,7 +672,7 @@
 
 #ifdef CONFIG_SA1100_SIMPAD
     GPDR |=   (1<<3);
-    GAFR |=  ~(1<<3);
+    GAFR &=  ~(1<<3);
     GPSR |=   (1<<3);
 #endif