]>
Commit | Line | Data |
---|---|---|
993cad93 WD |
1 | /* |
2 | * (C) Copyright 2003 | |
3 | * | |
4 | * Pantelis Antoniou <panto@intracom.gr> | |
5 | * Intracom S.A. | |
6 | * | |
7 | * See file CREDITS for list of people who contributed to this | |
8 | * project. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU General Public License as | |
12 | * published by the Free Software Foundation; either version 2 of | |
13 | * the License, or (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
23 | * MA 02111-1307 USA | |
24 | */ | |
25 | ||
26 | #include <common.h> | |
27 | #include <watchdog.h> | |
28 | ||
29 | #ifdef CONFIG_MAX3100_SERIAL | |
30 | ||
d87080b7 WD |
31 | DECLARE_GLOBAL_DATA_PTR; |
32 | ||
993cad93 WD |
33 | /**************************************************************/ |
34 | ||
35 | /* convienient macros */ | |
36 | #define MAX3100_SPI_RXD() (MAX3100_SPI_RXD_PORT & MAX3100_SPI_RXD_BIT) | |
37 | ||
38 | #define MAX3100_SPI_TXD(x) \ | |
39 | do { \ | |
40 | if (x) \ | |
41 | MAX3100_SPI_TXD_PORT |= MAX3100_SPI_TXD_BIT; \ | |
42 | else \ | |
43 | MAX3100_SPI_TXD_PORT &= ~MAX3100_SPI_TXD_BIT; \ | |
44 | } while(0) | |
45 | ||
46 | #define MAX3100_SPI_CLK(x) \ | |
47 | do { \ | |
48 | if (x) \ | |
49 | MAX3100_SPI_CLK_PORT |= MAX3100_SPI_CLK_BIT; \ | |
50 | else \ | |
51 | MAX3100_SPI_CLK_PORT &= ~MAX3100_SPI_CLK_BIT; \ | |
52 | } while(0) | |
53 | ||
54 | #define MAX3100_SPI_CLK_TOGGLE() (MAX3100_SPI_CLK_PORT ^= MAX3100_SPI_CLK_BIT) | |
55 | ||
56 | #define MAX3100_CS(x) \ | |
57 | do { \ | |
58 | if (x) \ | |
59 | MAX3100_CS_PORT |= MAX3100_CS_BIT; \ | |
60 | else \ | |
61 | MAX3100_CS_PORT &= ~MAX3100_CS_BIT; \ | |
62 | } while(0) | |
63 | ||
64 | /**************************************************************/ | |
65 | ||
66 | /* MAX3100 definitions */ | |
67 | ||
68 | #define MAX3100_WC (3 << 14) /* write configuration */ | |
69 | #define MAX3100_RC (1 << 14) /* read configuration */ | |
70 | #define MAX3100_WD (2 << 14) /* write data */ | |
71 | #define MAX3100_RD (0 << 14) /* read data */ | |
72 | ||
73 | /* configuration register bits */ | |
74 | #define MAX3100_FEN (1 << 13) /* FIFO enable */ | |
75 | #define MAX3100_SHDN (1 << 12) /* shutdown bit */ | |
76 | #define MAX3100_TM (1 << 11) /* T bit irq mask */ | |
77 | #define MAX3100_RM (1 << 10) /* R bit irq mask */ | |
78 | #define MAX3100_PM (1 << 9) /* P bit irq mask */ | |
79 | #define MAX3100_RAM (1 << 8) /* mask for RA/FE bit */ | |
80 | #define MAX3100_IR (1 << 7) /* IRDA timing mode */ | |
81 | #define MAX3100_ST (1 << 6) /* transmit stop bit */ | |
82 | #define MAX3100_PE (1 << 5) /* parity enable bit */ | |
83 | #define MAX3100_L (1 << 4) /* Length bit */ | |
84 | #define MAX3100_B_MASK (0x000F) /* baud rate bits mask */ | |
85 | #define MAX3100_B(x) ((x) & 0x000F) /* baud rate select bits */ | |
86 | ||
87 | /* data register bits (write) */ | |
88 | #define MAX3100_TE (1 << 10) /* transmit enable bit (active low) */ | |
89 | #define MAX3100_RTS (1 << 9) /* request-to-send bit (inverted ~RTS pin) */ | |
90 | ||
91 | /* data register bits (read) */ | |
92 | #define MAX3100_RA (1 << 10) /* receiver activity when in shutdown mode */ | |
93 | #define MAX3100_FE (1 << 10) /* framing error when in normal mode */ | |
94 | #define MAX3100_CTS (1 << 9) /* clear-to-send bit (inverted ~CTS pin) */ | |
95 | ||
96 | /* data register bits (both directions) */ | |
97 | #define MAX3100_R (1 << 15) /* receive bit */ | |
98 | #define MAX3100_T (1 << 14) /* transmit bit */ | |
99 | #define MAX3100_P (1 << 8) /* parity bit */ | |
100 | #define MAX3100_D_MASK 0x00FF /* data bits mask */ | |
101 | #define MAX3100_D(x) ((x) & 0x00FF) /* data bits */ | |
102 | ||
103 | /* these definitions are valid only for fOSC = 3.6864MHz */ | |
104 | #define MAX3100_B_230400 MAX3100_B(0) | |
105 | #define MAX3100_B_115200 MAX3100_B(1) | |
106 | #define MAX3100_B_57600 MAX3100_B(2) | |
107 | #define MAX3100_B_38400 MAX3100_B(9) | |
108 | #define MAX3100_B_19200 MAX3100_B(10) | |
109 | #define MAX3100_B_9600 MAX3100_B(11) | |
110 | #define MAX3100_B_4800 MAX3100_B(12) | |
111 | #define MAX3100_B_2400 MAX3100_B(13) | |
112 | #define MAX3100_B_1200 MAX3100_B(14) | |
113 | #define MAX3100_B_600 MAX3100_B(15) | |
114 | ||
115 | /**************************************************************/ | |
116 | ||
117 | static inline unsigned int max3100_transfer(unsigned int val) | |
118 | { | |
119 | unsigned int rx; | |
120 | int b; | |
121 | ||
122 | MAX3100_SPI_CLK(0); | |
123 | MAX3100_CS(0); | |
124 | ||
125 | rx = 0; b = 16; | |
126 | while (--b >= 0) { | |
127 | MAX3100_SPI_TXD(val & 0x8000); | |
128 | val <<= 1; | |
129 | MAX3100_SPI_CLK_TOGGLE(); | |
130 | udelay(1); | |
131 | rx <<= 1; | |
132 | if (MAX3100_SPI_RXD()) | |
133 | rx |= 1; | |
134 | MAX3100_SPI_CLK_TOGGLE(); | |
135 | udelay(1); | |
136 | } | |
137 | ||
138 | MAX3100_SPI_CLK(1); | |
139 | MAX3100_CS(1); | |
140 | ||
141 | return rx; | |
142 | } | |
143 | ||
144 | /**************************************************************/ | |
145 | ||
146 | /* must be power of 2 */ | |
147 | #define RXFIFO_SZ 16 | |
148 | ||
149 | static int rxfifo_cnt; | |
150 | static int rxfifo_in; | |
151 | static int rxfifo_out; | |
152 | static unsigned char rxfifo_buf[16]; | |
153 | ||
154 | static void max3100_putc(int c) | |
155 | { | |
156 | unsigned int rx; | |
157 | ||
158 | while (((rx = max3100_transfer(MAX3100_RC)) & MAX3100_T) == 0) | |
159 | WATCHDOG_RESET(); | |
160 | ||
161 | rx = max3100_transfer(MAX3100_WD | (c & 0xff)); | |
162 | if ((rx & MAX3100_RD) != 0 && rxfifo_cnt < RXFIFO_SZ) { | |
163 | rxfifo_cnt++; | |
164 | rxfifo_buf[rxfifo_in++] = rx & 0xff; | |
165 | rxfifo_in &= RXFIFO_SZ - 1; | |
166 | } | |
167 | } | |
168 | ||
169 | static int max3100_getc(void) | |
170 | { | |
171 | int c; | |
172 | unsigned int rx; | |
173 | ||
174 | while (rxfifo_cnt == 0) { | |
175 | rx = max3100_transfer(MAX3100_RD); | |
176 | if ((rx & MAX3100_R) != 0) { | |
177 | do { | |
178 | rxfifo_cnt++; | |
179 | rxfifo_buf[rxfifo_in++] = rx & 0xff; | |
180 | rxfifo_in &= RXFIFO_SZ - 1; | |
181 | ||
182 | if (rxfifo_cnt >= RXFIFO_SZ) | |
183 | break; | |
184 | } while (((rx = max3100_transfer(MAX3100_RD)) & MAX3100_R) != 0); | |
185 | } | |
186 | WATCHDOG_RESET(); | |
187 | } | |
188 | ||
189 | rxfifo_cnt--; | |
190 | c = rxfifo_buf[rxfifo_out++]; | |
191 | rxfifo_out &= RXFIFO_SZ - 1; | |
192 | return c; | |
193 | } | |
194 | ||
195 | static int max3100_tstc(void) | |
196 | { | |
197 | unsigned int rx; | |
198 | ||
199 | if (rxfifo_cnt > 0) | |
200 | return 1; | |
201 | ||
202 | rx = max3100_transfer(MAX3100_RD); | |
203 | if ((rx & MAX3100_R) == 0) | |
204 | return 0; | |
205 | ||
206 | do { | |
207 | rxfifo_cnt++; | |
208 | rxfifo_buf[rxfifo_in++] = rx & 0xff; | |
209 | rxfifo_in &= RXFIFO_SZ - 1; | |
210 | ||
211 | if (rxfifo_cnt >= RXFIFO_SZ) | |
212 | break; | |
213 | } while (((rx = max3100_transfer(MAX3100_RD)) & MAX3100_R) != 0); | |
214 | ||
215 | return 1; | |
216 | } | |
217 | ||
218 | int serial_init(void) | |
219 | { | |
220 | unsigned int wconf, rconf; | |
221 | int i; | |
993cad93 WD |
222 | |
223 | wconf = 0; | |
224 | ||
225 | /* Set baud rate */ | |
226 | switch (gd->baudrate) { | |
227 | case 1200: | |
228 | wconf = MAX3100_B_1200; | |
229 | break; | |
230 | case 2400: | |
231 | wconf = MAX3100_B_2400; | |
232 | break; | |
233 | case 4800: | |
234 | wconf = MAX3100_B_4800; | |
235 | break; | |
236 | case 9600: | |
237 | wconf = MAX3100_B_9600; | |
238 | break; | |
239 | case 19200: | |
240 | wconf = MAX3100_B_19200; | |
241 | break; | |
242 | case 38400: | |
243 | wconf = MAX3100_B_38400; | |
244 | break; | |
245 | case 57600: | |
246 | wconf = MAX3100_B_57600; | |
247 | break; | |
248 | default: | |
249 | case 115200: | |
250 | wconf = MAX3100_B_115200; | |
251 | break; | |
252 | case 230400: | |
253 | wconf = MAX3100_B_230400; | |
254 | break; | |
255 | } | |
256 | ||
257 | /* try for 10ms, with a 100us gap */ | |
258 | for (i = 0; i < 10000; i += 100) { | |
259 | ||
260 | max3100_transfer(MAX3100_WC | wconf); | |
261 | rconf = max3100_transfer(MAX3100_RC) & 0x3fff; | |
262 | ||
263 | if (rconf == wconf) | |
264 | break; | |
265 | udelay(100); | |
266 | } | |
267 | ||
268 | rxfifo_in = rxfifo_out = rxfifo_cnt = 0; | |
269 | ||
270 | return (0); | |
271 | } | |
272 | ||
273 | void serial_putc(const char c) | |
274 | { | |
275 | if (c == '\n') | |
276 | max3100_putc('\r'); | |
277 | ||
278 | max3100_putc(c); | |
279 | } | |
280 | ||
281 | void serial_puts(const char *s) | |
282 | { | |
283 | while (*s) | |
284 | serial_putc (*s++); | |
285 | } | |
286 | ||
287 | int serial_getc(void) | |
288 | { | |
289 | return max3100_getc(); | |
290 | } | |
291 | ||
292 | int serial_tstc(void) | |
293 | { | |
294 | return max3100_tstc(); | |
295 | } | |
296 | ||
297 | /* XXX WTF? */ | |
298 | void serial_setbrg(void) | |
299 | { | |
300 | } | |
301 | ||
302 | #endif |