Merge with /home/m8/git/u-boot
[oweals/u-boot.git] / drivers / serial_max3100.c
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
31 DECLARE_GLOBAL_DATA_PTR;
32
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;
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