aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/coldfire/patches/005-Add-serial-driver-and-irda-driver-support-for-MCF544.patch
blob: 1ccbb123b6c750b1f15560dc87564fc398358486 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
From 5c37079957c5e5555aa8284a879f8cc44fa8eb25 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:39 +0800
Subject: [PATCH 05/52] Add serial driver and irda driver support for MCF5445x and MCF547x/MCF548x

Add common serial driver for MCF5445x and MCF547x/MCF548x.
Also add irda support for MCF547x/MCF548x.

Signed-off-by: Alison Wang <b18965@freescale.com>
---
 drivers/tty/serial/Kconfig |   20 ++++++++++
 drivers/tty/serial/mcf.c   |   87 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+), 0 deletions(-)

--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1027,6 +1027,26 @@ config SERIAL_68328_RTS_CTS
 	bool "Support RTS/CTS on 68328 serial port"
 	depends on SERIAL_68328
 
+config SERIAL_COLDFIRE_IRDA
+	bool "ColdFire IRDA support"
+	depends on SERIAL_MCF
+	help
+	  This driver supports IrDA on the ColdFire platform,
+	  such as MCF547x and MCF548x.
+
+	  Say Y here if you want to use IrDA 1.1 SIR mode.
+
+config SERIAL_COLDFIRE_EDMA
+	bool "ColdFire serial EDMA support"
+	depends on SERIAL_MCF
+	default n
+	help
+	  Enables Enhanced Direct Memory Access(eDMA) in the Coldfire
+          serial driver.
+
+          Say Y here if you want to use DMA processing of transmit
+          and receive data for the serial driver.
+
 config SERIAL_MCF
 	bool "Coldfire serial support"
 	depends on COLDFIRE
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -4,6 +4,10 @@
  *	mcf.c -- Freescale ColdFire UART driver
  *
  *	(C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *	Jason Jin Jason.Jin@freescale.com
+ *	Shrek Wu B16972@freescale.com
+ *	Chengju Cai b22600@freescale.com
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,9 +27,11 @@
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/io.h>
+#include <linux/delay.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
+#include <asm/m5485psc.h>
 #include <asm/nettel.h>
 
 /****************************************************************************/
@@ -46,6 +52,10 @@
 #define	mcf_setppdtr(p, v)	do { } while (0)
 #endif
 
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+#define SERIAL_IRDA_LINE (2)
+#endif
+
 /****************************************************************************/
 
 /*
@@ -101,6 +111,15 @@ static void mcf_start_tx(struct uart_por
 {
 	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
 
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+	if (port->line == SERIAL_IRDA_LINE) {
+		/* Disable IRDA receiver*/
+		writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+		writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+
+		writeb(MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR);
+	}
+#endif
 	pp->imr |= MCFUART_UIR_TXREADY;
 	writeb(pp->imr, port->membase + MCFUART_UIMR);
 }
@@ -154,6 +173,30 @@ static int mcf_startup(struct uart_port
 
 	spin_lock_irqsave(&port->lock, flags);
 
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+	if (port->line == SERIAL_IRDA_LINE) {
+		/* Put PSC in IrDA mode */
+		MCF_PSC_SICR(port->line) = MCF_PSC_SICR_SIM_SIR;
+
+		/* Set pulse width to 1.6 uS */
+		MCF_PSC_IRSDR(port->line) = (uint8_t)
+					    (16 * (CONFIG_MCFCLK / 10000000));
+		MCF_PSC_IRCR1(port->line) = MCF_PSC_IRCR1_SPUL;
+		MCF_PSC_IRCR2(port->line) = 0;
+
+		/* Enable RTS to send */
+		MCF_PSC_OPSET(port->line) = MCF_PSC_OPSET_RTS;
+
+		/* Setup FIFO Alarms */
+		MCF_PSC_RFAR(port->line) = MCF_PSC_RFAR_ALARM(248);
+		MCF_PSC_TFAR(port->line) = MCF_PSC_TFAR_ALARM(248);
+
+		MCF_PSC_RFCR(port->line) = MCF_PSC_RFCR_FRMEN
+					 | MCF_PSC_RFCR_GR(4);
+		MCF_PSC_TFCR(port->line) = MCF_PSC_TFCR_FRMEN
+					 | MCF_PSC_RFCR_GR(4);
+	}
+#endif
 	/* Reset UART, get it into known state... */
 	writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
 	writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
@@ -177,7 +220,17 @@ static void mcf_shutdown(struct uart_por
 {
 	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
 	unsigned long flags;
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+	unsigned long delay_counter = 0;
+#endif
 
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+	while (!((readb(port->membase + MCFUART_USR)) & MCFUART_USR_TXEMPTY)) {
+		if (delay_counter++ > 25000)
+			break;
+		udelay(10);
+	}
+#endif
 	spin_lock_irqsave(&port->lock, flags);
 
 	/* Disable all interrupts now */
@@ -202,7 +255,14 @@ static void mcf_set_termios(struct uart_
 	unsigned int baudfr;
 #endif
 	unsigned char mr1, mr2;
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+	int i = 0;	/* hush GCC */
+#endif
 
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+	while (i++ < 35000)
+		udelay(1);
+#endif
 	baud = uart_get_baud_rate(port, termios, old, 0, 230400);
 #if defined(CONFIG_M5272)
 	baudclk = (MCF_BUSCLK / baud) / 32;
@@ -331,6 +391,23 @@ static void mcf_tx_chars(struct mcf_uart
 	while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
 		if (xmit->head == xmit->tail)
 			break;
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+		if (port->line == SERIAL_IRDA_LINE) {
+			while (!((readb(port->membase + MCFUART_USR))\
+				& MCFUART_USR_TXEMPTY))
+				;
+			/* delay for settle */
+#if defined(CONFIG_M548X)
+			udelay(1);
+#elif defined(CONFIG_M547X)
+			udelay(2);
+#else
+			int i = 0;
+			while (i++ < 25000)
+				udelay(1);
+#endif
+		}
+#endif
 		writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
 		port->icount.tx++;
@@ -340,6 +417,16 @@ static void mcf_tx_chars(struct mcf_uart
 		uart_write_wakeup(port);
 
 	if (xmit->head == xmit->tail) {
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+		if (port->line == SERIAL_IRDA_LINE) {
+			/* Enable receiver for IRDA */
+			writeb(MCFUART_UCR_CMDRESETRX,\
+				port->membase + MCFUART_UCR);
+			/* reset RX */
+			writeb(MCFUART_UCR_TXENABLE | MCFUART_UCR_RXENABLE,\
+				port->membase + MCFUART_UCR);
+		}
+#endif
 		pp->imr &= ~MCFUART_UIR_TXREADY;
 		writeb(pp->imr, port->membase + MCFUART_UIMR);
 	}