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