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 29DECLARE_GLOBAL_DATA_PTR; 30 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) */ 95#define MAX3100_R (1 << 15) /* receive bit */ 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 115static 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 147static int rxfifo_cnt; 148static int rxfifo_in; 149static int rxfifo_out; 150static unsigned char rxfifo_buf[16]; 151 152static 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 167static 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 193static 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 216int serial_init(void) 217{ 218 unsigned int wconf, rconf; 219 int i; 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 271void serial_putc(const char c) 272{ 273 if (c == '\n') 274 max3100_putc('\r'); 275 276 max3100_putc(c); 277} 278 279void serial_puts(const char *s) 280{ 281 while (*s) 282 serial_putc (*s++); 283} 284 285int serial_getc(void) 286{ 287 return max3100_getc(); 288} 289 290int serial_tstc(void) 291{ 292 return max3100_tstc(); 293} 294 295/* XXX WTF? */ 296void serial_setbrg(void) 297{ 298} 299