blob: 027d9194a74b1089a3601b027923d86424bc0bb3 [file] [log] [blame]
wdenk70764a32003-06-26 22:04:09 +00001/*
2 * (C) Copyright 2003
3 *
4 * Pantelis Antoniou <panto@intracom.gr>
5 * Intracom S.A.
6 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
wdenk70764a32003-06-26 22:04:09 +00008 */
9
10#include <common.h>
11#include <watchdog.h>
Marek Vasut00797862012-09-14 22:37:17 +020012#include <serial.h>
13#include <linux/compiler.h>
wdenk70764a32003-06-26 22:04:09 +000014
Wolfgang Denk6405a152006-03-31 18:32:53 +020015DECLARE_GLOBAL_DATA_PTR;
16
wdenk70764a32003-06-26 22:04:09 +000017/**************************************************************/
18
19/* convienient macros */
20#define MAX3100_SPI_RXD() (MAX3100_SPI_RXD_PORT & MAX3100_SPI_RXD_BIT)
21
22#define MAX3100_SPI_TXD(x) \
23 do { \
24 if (x) \
25 MAX3100_SPI_TXD_PORT |= MAX3100_SPI_TXD_BIT; \
26 else \
27 MAX3100_SPI_TXD_PORT &= ~MAX3100_SPI_TXD_BIT; \
28 } while(0)
29
30#define MAX3100_SPI_CLK(x) \
31 do { \
32 if (x) \
33 MAX3100_SPI_CLK_PORT |= MAX3100_SPI_CLK_BIT; \
34 else \
35 MAX3100_SPI_CLK_PORT &= ~MAX3100_SPI_CLK_BIT; \
36 } while(0)
37
38#define MAX3100_SPI_CLK_TOGGLE() (MAX3100_SPI_CLK_PORT ^= MAX3100_SPI_CLK_BIT)
39
40#define MAX3100_CS(x) \
41 do { \
42 if (x) \
43 MAX3100_CS_PORT |= MAX3100_CS_BIT; \
44 else \
45 MAX3100_CS_PORT &= ~MAX3100_CS_BIT; \
46 } while(0)
47
48/**************************************************************/
49
50/* MAX3100 definitions */
51
52#define MAX3100_WC (3 << 14) /* write configuration */
53#define MAX3100_RC (1 << 14) /* read configuration */
54#define MAX3100_WD (2 << 14) /* write data */
55#define MAX3100_RD (0 << 14) /* read data */
56
57/* configuration register bits */
58#define MAX3100_FEN (1 << 13) /* FIFO enable */
59#define MAX3100_SHDN (1 << 12) /* shutdown bit */
60#define MAX3100_TM (1 << 11) /* T bit irq mask */
61#define MAX3100_RM (1 << 10) /* R bit irq mask */
62#define MAX3100_PM (1 << 9) /* P bit irq mask */
63#define MAX3100_RAM (1 << 8) /* mask for RA/FE bit */
64#define MAX3100_IR (1 << 7) /* IRDA timing mode */
65#define MAX3100_ST (1 << 6) /* transmit stop bit */
66#define MAX3100_PE (1 << 5) /* parity enable bit */
67#define MAX3100_L (1 << 4) /* Length bit */
68#define MAX3100_B_MASK (0x000F) /* baud rate bits mask */
69#define MAX3100_B(x) ((x) & 0x000F) /* baud rate select bits */
70
71/* data register bits (write) */
72#define MAX3100_TE (1 << 10) /* transmit enable bit (active low) */
73#define MAX3100_RTS (1 << 9) /* request-to-send bit (inverted ~RTS pin) */
74
75/* data register bits (read) */
76#define MAX3100_RA (1 << 10) /* receiver activity when in shutdown mode */
77#define MAX3100_FE (1 << 10) /* framing error when in normal mode */
78#define MAX3100_CTS (1 << 9) /* clear-to-send bit (inverted ~CTS pin) */
79
80/* data register bits (both directions) */
Wolfgang Denka1be4762008-05-20 16:00:29 +020081#define MAX3100_R (1 << 15) /* receive bit */
wdenk70764a32003-06-26 22:04:09 +000082#define MAX3100_T (1 << 14) /* transmit bit */
83#define MAX3100_P (1 << 8) /* parity bit */
84#define MAX3100_D_MASK 0x00FF /* data bits mask */
85#define MAX3100_D(x) ((x) & 0x00FF) /* data bits */
86
87/* these definitions are valid only for fOSC = 3.6864MHz */
88#define MAX3100_B_230400 MAX3100_B(0)
89#define MAX3100_B_115200 MAX3100_B(1)
90#define MAX3100_B_57600 MAX3100_B(2)
91#define MAX3100_B_38400 MAX3100_B(9)
92#define MAX3100_B_19200 MAX3100_B(10)
93#define MAX3100_B_9600 MAX3100_B(11)
94#define MAX3100_B_4800 MAX3100_B(12)
95#define MAX3100_B_2400 MAX3100_B(13)
96#define MAX3100_B_1200 MAX3100_B(14)
97#define MAX3100_B_600 MAX3100_B(15)
98
99/**************************************************************/
100
101static inline unsigned int max3100_transfer(unsigned int val)
102{
103 unsigned int rx;
104 int b;
105
106 MAX3100_SPI_CLK(0);
107 MAX3100_CS(0);
108
109 rx = 0; b = 16;
110 while (--b >= 0) {
111 MAX3100_SPI_TXD(val & 0x8000);
112 val <<= 1;
113 MAX3100_SPI_CLK_TOGGLE();
114 udelay(1);
115 rx <<= 1;
116 if (MAX3100_SPI_RXD())
117 rx |= 1;
118 MAX3100_SPI_CLK_TOGGLE();
119 udelay(1);
120 }
121
122 MAX3100_SPI_CLK(1);
123 MAX3100_CS(1);
124
125 return rx;
126}
127
128/**************************************************************/
129
130/* must be power of 2 */
131#define RXFIFO_SZ 16
132
133static int rxfifo_cnt;
134static int rxfifo_in;
135static int rxfifo_out;
136static unsigned char rxfifo_buf[16];
137
Marek Vasut00797862012-09-14 22:37:17 +0200138static void max3100_serial_putc_raw(int c)
wdenk70764a32003-06-26 22:04:09 +0000139{
140 unsigned int rx;
141
142 while (((rx = max3100_transfer(MAX3100_RC)) & MAX3100_T) == 0)
143 WATCHDOG_RESET();
144
145 rx = max3100_transfer(MAX3100_WD | (c & 0xff));
146 if ((rx & MAX3100_RD) != 0 && rxfifo_cnt < RXFIFO_SZ) {
147 rxfifo_cnt++;
148 rxfifo_buf[rxfifo_in++] = rx & 0xff;
149 rxfifo_in &= RXFIFO_SZ - 1;
150 }
151}
152
Marek Vasut00797862012-09-14 22:37:17 +0200153static int max3100_serial_getc(void)
wdenk70764a32003-06-26 22:04:09 +0000154{
155 int c;
156 unsigned int rx;
157
158 while (rxfifo_cnt == 0) {
159 rx = max3100_transfer(MAX3100_RD);
160 if ((rx & MAX3100_R) != 0) {
161 do {
162 rxfifo_cnt++;
163 rxfifo_buf[rxfifo_in++] = rx & 0xff;
164 rxfifo_in &= RXFIFO_SZ - 1;
165
166 if (rxfifo_cnt >= RXFIFO_SZ)
167 break;
168 } while (((rx = max3100_transfer(MAX3100_RD)) & MAX3100_R) != 0);
169 }
170 WATCHDOG_RESET();
171 }
172
173 rxfifo_cnt--;
174 c = rxfifo_buf[rxfifo_out++];
175 rxfifo_out &= RXFIFO_SZ - 1;
176 return c;
177}
178
Marek Vasut00797862012-09-14 22:37:17 +0200179static int max3100_serial_tstc(void)
wdenk70764a32003-06-26 22:04:09 +0000180{
181 unsigned int rx;
182
183 if (rxfifo_cnt > 0)
184 return 1;
185
186 rx = max3100_transfer(MAX3100_RD);
187 if ((rx & MAX3100_R) == 0)
188 return 0;
189
190 do {
191 rxfifo_cnt++;
192 rxfifo_buf[rxfifo_in++] = rx & 0xff;
193 rxfifo_in &= RXFIFO_SZ - 1;
194
195 if (rxfifo_cnt >= RXFIFO_SZ)
196 break;
197 } while (((rx = max3100_transfer(MAX3100_RD)) & MAX3100_R) != 0);
198
199 return 1;
200}
201
Marek Vasut00797862012-09-14 22:37:17 +0200202static int max3100_serial_init(void)
wdenk70764a32003-06-26 22:04:09 +0000203{
204 unsigned int wconf, rconf;
205 int i;
wdenk70764a32003-06-26 22:04:09 +0000206
207 wconf = 0;
208
209 /* Set baud rate */
210 switch (gd->baudrate) {
211 case 1200:
212 wconf = MAX3100_B_1200;
213 break;
214 case 2400:
215 wconf = MAX3100_B_2400;
216 break;
217 case 4800:
218 wconf = MAX3100_B_4800;
219 break;
220 case 9600:
221 wconf = MAX3100_B_9600;
222 break;
223 case 19200:
224 wconf = MAX3100_B_19200;
225 break;
226 case 38400:
227 wconf = MAX3100_B_38400;
228 break;
229 case 57600:
230 wconf = MAX3100_B_57600;
231 break;
232 default:
233 case 115200:
234 wconf = MAX3100_B_115200;
235 break;
236 case 230400:
237 wconf = MAX3100_B_230400;
238 break;
239 }
240
241 /* try for 10ms, with a 100us gap */
242 for (i = 0; i < 10000; i += 100) {
243
244 max3100_transfer(MAX3100_WC | wconf);
245 rconf = max3100_transfer(MAX3100_RC) & 0x3fff;
246
247 if (rconf == wconf)
248 break;
249 udelay(100);
250 }
251
252 rxfifo_in = rxfifo_out = rxfifo_cnt = 0;
253
254 return (0);
255}
256
Marek Vasut00797862012-09-14 22:37:17 +0200257static void max3100_serial_putc(const char c)
wdenk70764a32003-06-26 22:04:09 +0000258{
259 if (c == '\n')
Marek Vasut00797862012-09-14 22:37:17 +0200260 max3100_serial_putc_raw('\r');
wdenk70764a32003-06-26 22:04:09 +0000261
Marek Vasut00797862012-09-14 22:37:17 +0200262 max3100_serial_putc_raw(c);
wdenk70764a32003-06-26 22:04:09 +0000263}
264
Marek Vasut00797862012-09-14 22:37:17 +0200265static void max3100_serial_puts(const char *s)
wdenk70764a32003-06-26 22:04:09 +0000266{
267 while (*s)
Marek Vasut00797862012-09-14 22:37:17 +0200268 max3100_serial_putc_raw(*s++);
wdenk70764a32003-06-26 22:04:09 +0000269}
270
Marek Vasut00797862012-09-14 22:37:17 +0200271static void max3100_serial_setbrg(void)
wdenk70764a32003-06-26 22:04:09 +0000272{
wdenk70764a32003-06-26 22:04:09 +0000273}
274
Marek Vasut00797862012-09-14 22:37:17 +0200275static struct serial_device max3100_serial_drv = {
276 .name = "max3100_serial",
277 .start = max3100_serial_init,
278 .stop = NULL,
279 .setbrg = max3100_serial_setbrg,
280 .putc = max3100_serial_putc,
281 .puts = max3100_serial_puts,
282 .getc = max3100_serial_getc,
283 .tstc = max3100_serial_tstc,
284};
285
286void max3100_serial_initialize(void)
287{
288 serial_register(&max3100_serial_drv);
289}
290
291__weak struct serial_device *default_serial_console(void)
wdenk70764a32003-06-26 22:04:09 +0000292{
Marek Vasut00797862012-09-14 22:37:17 +0200293 return &max3100_serial_drv;
294}