aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-2.6.33/ts72xx/0007-ts72xx_rs485.patch
blob: c1974f6b6d3355b4e16dc144a314bdb2696317de (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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
From 9fe9aa83eb2af8eea9e90c73aaa3ee9e0018b8d7 Mon Sep 17 00:00:00 2001
From: Matthieu Crapet <mcrapet@gmail.com>
Date: Sun, 17 Jan 2010 17:54:33 +0100
Subject: [PATCH 07/16] ts72xx_rs485
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit

Crude hack...

Signed-off-by: Petr Štetiar <ynezz@true.cz>
---
 arch/arm/include/asm/ioctls.h |    3 +
 drivers/serial/Kconfig        |    8 +++
 drivers/serial/amba-pl010.c   |  137 +++++++++++++++++++++++++++++++++++++++--
 3 files changed, 142 insertions(+), 6 deletions(-)

diff --git a/arch/arm/include/asm/ioctls.h b/arch/arm/include/asm/ioctls.h
index a91d8a1..a4b60ae 100644
--- a/arch/arm/include/asm/ioctls.h
+++ b/arch/arm/include/asm/ioctls.h
@@ -70,6 +70,9 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define FIOQSIZE	0x545E
 
+#define TIOC_SBCC485	0x545F /* TS72xx RTS/485 mode clear */
+#define TIOC_SBCS485	0x5460 /* TS72xx RTS/485 mode set */
+
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
 #define TIOCPKT_FLUSHREAD	 1
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index c9afa26..d5d2f8c 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -321,6 +321,14 @@ config SERIAL_AMBA_PL010_CONSOLE
 	  your boot loader (lilo or loadlin) about how to pass options to the
 	  kernel at boot time.)
 
+config SERIAL_AMBA_PL010_TS72XX
+	bool "Support for RS-485 on AMBA serial port (for TS-72XX SBC)"
+	depends on SERIAL_AMBA_PL010 != n && MACH_TS72XX
+	help
+	  This add support for RS-485 on some Technologic System SBC.
+
+	  If unsure, say N.
+
 config SERIAL_AMBA_PL011
 	tristate "ARM AMBA PL011 serial port support"
 	depends on ARM_AMBA
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 429a8ae..aff4d9c 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -50,6 +50,10 @@
 
 #include <asm/io.h>
 
+#if defined(CONFIG_SERIAL_AMBA_PL010_TS72XX)
+#include <mach/ts72xx.h>
+#endif
+
 #define UART_NR		8
 
 #define SERIAL_AMBA_MAJOR	204
@@ -64,6 +68,12 @@
 #define UART_DUMMY_RSR_RX	256
 #define UART_PORT_SIZE		64
 
+#if defined(CONFIG_SERIAL_AMBA_PL010_TS72XX)
+static void __iomem *ts_rs485_data9_register;
+static void __iomem *ts_rs485_control_register;
+#endif
+
+
 /*
  * We wrap our port structure around the generic uart_port.
  */
@@ -385,7 +395,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
 	/*
 	 * Ask the core to calculate the divisor for us.
 	 */
-	baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16); 
+	baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16);
 	quot = uart_get_divisor(port, baud);
 
 	switch (termios->c_cflag & CSIZE) {
@@ -519,6 +529,107 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
 	return ret;
 }
 
+
+#if defined(CONFIG_SERIAL_AMBA_PL010_TS72XX)
+static int ts72xx_rs485_init(void)
+{
+	ts_rs485_data9_register = ioremap(TS72XX_RS485_MODE_PHYS_BASE, 4096);
+	if (ts_rs485_data9_register == NULL) {
+		return -1;
+	}
+
+	ts_rs485_control_register = ioremap(TS72XX_RS485_CONTROL_PHYS_BASE, 4096);
+	if (ts_rs485_control_register == NULL) {
+		iounmap(ts_rs485_data9_register);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int ts72xx_auto485(struct uart_port *port, unsigned int cmd, unsigned long *arg)
+{
+	int baud, cflag, mode;
+	int datalength;
+
+	mode = (int)*arg;
+	if (!is_rs485_installed()) {
+		printk("amba-pl010.c: this board does not support RS485 auto mode\n");
+		return -EINVAL;
+	}
+
+	if (port->line != 1) {
+		printk("amba-pl010.c: auto RS485 mode is only supported on second port (/dev/ttyAM1)\n");
+		return -EINVAL;
+	}
+
+	datalength = 8;
+	cflag = port->state->port.tty->termios->c_cflag;
+	if (cflag & PARENB)
+		datalength++;
+
+	if (cflag & CSTOPB)
+		datalength++;
+
+	baud = tty_get_baud_rate(port->state->port.tty);
+
+	switch (cmd) {
+		case TIOC_SBCC485:
+			if ((mode & TS72XX_RS485_AUTO485FD) || (mode & TS72XX_RS485_AUTO485HD)) {
+				printk("amba-pl010.c: unsetting auto RS485 mode\n");
+				__raw_writew(TS72XX_RS485_MODE_RS232, ts_rs485_control_register);
+				__raw_writew(TS72XX_RS485_MODE_RS232, ts_rs485_data9_register);
+			}
+			break;
+		case TIOC_SBCS485:
+			if (mode & TS72XX_RS485_AUTO485FD) {
+				printk ("amba-pl010.c: setting FULL duplex auto RS485 mode\n");
+				__raw_writew(TS72XX_RS485_MODE_FD, ts_rs485_control_register);
+				if (datalength > 8)
+					__raw_writew(TS72XX_RS485_MODE_FD, ts_rs485_data9_register);
+			} else if (mode & TS72XX_RS485_AUTO485HD) {
+				printk("amba-pl010.c: setting HALF DUPLEX auto RS485 mode\n");
+				switch (baud) {
+					case 9600:
+						__raw_writew(TS72XX_RS485_MODE_9600_HD, ts_rs485_control_register);
+						break;
+					case 19200:
+						__raw_writew(TS72XX_RS485_MODE_19200_HD, ts_rs485_control_register);
+						break;
+					case 57600:
+						__raw_writew(TS72XX_RS485_MODE_57600_HD, ts_rs485_control_register);
+						break;
+					case 115200:
+						__raw_writew(TS72XX_RS485_MODE_115200_HD, ts_rs485_control_register);
+						break;
+					default:
+						printk("amba-pl010.c: %d baud rate is not supported for auto RS485 mode\n", baud);
+						return -1;
+				}
+				if (datalength > 8)
+					__raw_writew(TS72XX_RS485_MODE_FD, ts_rs485_data9_register);
+			}
+			break;
+	}
+
+	return 0;
+}
+
+static int pl010_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+		case TIOC_SBCC485:
+		case TIOC_SBCS485:
+			return ts72xx_auto485(port, cmd, (unsigned long *)arg);
+		default:
+			return -ENOIOCTLCMD;
+	}
+
+	return -ENOIOCTLCMD;
+}
+#endif /* CONFIG_SERIAL_AMBA_PL010_TS72XX */
+
+
 static struct uart_ops amba_pl010_pops = {
 	.tx_empty	= pl010_tx_empty,
 	.set_mctrl	= pl010_set_mctrl,
@@ -536,6 +647,9 @@ static struct uart_ops amba_pl010_pops = {
 	.request_port	= pl010_request_port,
 	.config_port	= pl010_config_port,
 	.verify_port	= pl010_verify_port,
+#if defined(CONFIG_SERIAL_AMBA_PL010_TS72XX)
+	.ioctl	= pl010_ioctl,
+#endif
 };
 
 static struct uart_amba_port *amba_ports[UART_NR];
@@ -792,11 +906,22 @@ static int __init pl010_init(void)
 	printk(KERN_INFO "Serial: AMBA driver\n");
 
 	ret = uart_register_driver(&amba_reg);
-	if (ret == 0) {
-		ret = amba_driver_register(&pl010_driver);
-		if (ret)
-			uart_unregister_driver(&amba_reg);
-	}
+  if (ret == 0) {
+    ret = amba_driver_register(&pl010_driver);
+
+    #if defined(CONFIG_SERIAL_AMBA_PL010_TS72XX)
+    if (!ret && is_rs485_installed()) {
+      ret = ts72xx_rs485_init();
+      if (ret)
+        printk("amba-pl010.c: ts72xx_rs485_init() failed\n");
+      else
+        printk("amba-pl010.c: auto RS485 mode initialized\n");
+    }
+    #endif
+
+    if (ret)
+      uart_unregister_driver(&amba_reg);
+  }
 	return ret;
 }
 
-- 
1.6.3.3