/* * (C) Copyright 2003 * * Pantelis Antoniou <panto@intracom.gr> * Intracom S.A. * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include <common.h> #include <watchdog.h> #ifdef CONFIG_MAX3100_SERIAL DECLARE_GLOBAL_DATA_PTR; /**************************************************************/ /* convienient macros */ #define MAX3100_SPI_RXD() (MAX3100_SPI_RXD_PORT & MAX3100_SPI_RXD_BIT) #define MAX3100_SPI_TXD(x) \ do { \ if (x) \ MAX3100_SPI_TXD_PORT |= MAX3100_SPI_TXD_BIT; \ else \ MAX3100_SPI_TXD_PORT &= ~MAX3100_SPI_TXD_BIT; \ } while(0) #define MAX3100_SPI_CLK(x) \ do { \ if (x) \ MAX3100_SPI_CLK_PORT |= MAX3100_SPI_CLK_BIT; \ else \ MAX3100_SPI_CLK_PORT &= ~MAX3100_SPI_CLK_BIT; \ } while(0) #define MAX3100_SPI_CLK_TOGGLE() (MAX3100_SPI_CLK_PORT ^= MAX3100_SPI_CLK_BIT) #define MAX3100_CS(x) \ do { \ if (x) \ MAX3100_CS_PORT |= MAX3100_CS_BIT; \ else \ MAX3100_CS_PORT &= ~MAX3100_CS_BIT; \ } while(0) /**************************************************************/ /* MAX3100 definitions */ #define MAX3100_WC (3 << 14) /* write configuration */ #define MAX3100_RC (1 << 14) /* read configuration */ #define MAX3100_WD (2 << 14) /* write data */ #define MAX3100_RD (0 << 14) /* read data */ /* configuration register bits */ #define MAX3100_FEN (1 << 13) /* FIFO enable */ #define MAX3100_SHDN (1 << 12) /* shutdown bit */ #define MAX3100_TM (1 << 11) /* T bit irq mask */ #define MAX3100_RM (1 << 10) /* R bit irq mask */ #define MAX3100_PM (1 << 9) /* P bit irq mask */ #define MAX3100_RAM (1 << 8) /* mask for RA/FE bit */ #define MAX3100_IR (1 << 7) /* IRDA timing mode */ #define MAX3100_ST (1 << 6) /* transmit stop bit */ #define MAX3100_PE (1 << 5) /* parity enable bit */ #define MAX3100_L (1 << 4) /* Length bit */ #define MAX3100_B_MASK (0x000F) /* baud rate bits mask */ #define MAX3100_B(x) ((x) & 0x000F) /* baud rate select bits */ /* data register bits (write) */ #define MAX3100_TE (1 << 10) /* transmit enable bit (active low) */ #define MAX3100_RTS (1 << 9) /* request-to-send bit (inverted ~RTS pin) */ /* data register bits (read) */ #define MAX3100_RA (1 << 10) /* receiver activity when in shutdown mode */ #define MAX3100_FE (1 << 10) /* framing error when in normal mode */ #define MAX3100_CTS (1 << 9) /* clear-to-send bit (inverted ~CTS pin) */ /* data register bits (both directions) */ #define MAX3100_R (1 << 15) /* receive bit */ #define MAX3100_T (1 << 14) /* transmit bit */ #define MAX3100_P (1 << 8) /* parity bit */ #define MAX3100_D_MASK 0x00FF /* data bits mask */ #define MAX3100_D(x) ((x) & 0x00FF) /* data bits */ /* these definitions are valid only for fOSC = 3.6864MHz */ #define MAX3100_B_230400 MAX3100_B(0) #define MAX3100_B_115200 MAX3100_B(1) #define MAX3100_B_57600 MAX3100_B(2) #define MAX3100_B_38400 MAX3100_B(9) #define MAX3100_B_19200 MAX3100_B(10) #define MAX3100_B_9600 MAX3100_B(11) #define MAX3100_B_4800 MAX3100_B(12) #define MAX3100_B_2400 MAX3100_B(13) #define MAX3100_B_1200 MAX3100_B(14) #define MAX3100_B_600 MAX3100_B(15) /**************************************************************/ static inline unsigned int max3100_transfer(unsigned int val) { unsigned int rx; int b; MAX3100_SPI_CLK(0); MAX3100_CS(0); rx = 0; b = 16; while (--b >= 0) { MAX3100_SPI_TXD(val & 0x8000); val <<= 1; MAX3100_SPI_CLK_TOGGLE(); udelay(1); rx <<= 1; if (MAX3100_SPI_RXD()) rx |= 1; MAX3100_SPI_CLK_TOGGLE(); udelay(1); } MAX3100_SPI_CLK(1); MAX3100_CS(1); return rx; } /**************************************************************/ /* must be power of 2 */ #define RXFIFO_SZ 16 static int rxfifo_cnt; static int rxfifo_in; static int rxfifo_out; static unsigned char rxfifo_buf[16]; static void max3100_putc(int c) { unsigned int rx; while (((rx = max3100_transfer(MAX3100_RC)) & MAX3100_T) == 0) WATCHDOG_RESET(); rx = max3100_transfer(MAX3100_WD | (c & 0xff)); if ((rx & MAX3100_RD) != 0 && rxfifo_cnt < RXFIFO_SZ) { rxfifo_cnt++; rxfifo_buf[rxfifo_in++] = rx & 0xff; rxfifo_in &= RXFIFO_SZ - 1; } } static int max3100_getc(void) { int c; unsigned int rx; while (rxfifo_cnt == 0) { rx = max3100_transfer(MAX3100_RD); if ((rx & MAX3100_R) != 0) { do { rxfifo_cnt++; rxfifo_buf[rxfifo_in++] = rx & 0xff; rxfifo_in &= RXFIFO_SZ - 1; if (rxfifo_cnt >= RXFIFO_SZ) break; } while (((rx = max3100_transfer(MAX3100_RD)) & MAX3100_R) != 0); } WATCHDOG_RESET(); } rxfifo_cnt--; c = rxfifo_buf[rxfifo_out++]; rxfifo_out &= RXFIFO_SZ - 1; return c; } static int max3100_tstc(void) { unsigned int rx; if (rxfifo_cnt > 0) return 1; rx = max3100_transfer(MAX3100_RD); if ((rx & MAX3100_R) == 0) return 0; do { rxfifo_cnt++; rxfifo_buf[rxfifo_in++] = rx & 0xff; rxfifo_in &= RXFIFO_SZ - 1; if (rxfifo_cnt >= RXFIFO_SZ) break; } while (((rx = max3100_transfer(MAX3100_RD)) & MAX3100_R) != 0); return 1; } int serial_init(void) { unsigned int wconf, rconf; int i; wconf = 0; /* Set baud rate */ switch (gd->baudrate) { case 1200: wconf = MAX3100_B_1200; break; case 2400: wconf = MAX3100_B_2400; break; case 4800: wconf = MAX3100_B_4800; break; case 9600: wconf = MAX3100_B_9600; break; case 19200: wconf = MAX3100_B_19200; break; case 38400: wconf = MAX3100_B_38400; break; case 57600: wconf = MAX3100_B_57600; break; default: case 115200: wconf = MAX3100_B_115200; break; case 230400: wconf = MAX3100_B_230400; break; } /* try for 10ms, with a 100us gap */ for (i = 0; i < 10000; i += 100) { max3100_transfer(MAX3100_WC | wconf); rconf = max3100_transfer(MAX3100_RC) & 0x3fff; if (rconf == wconf) break; udelay(100); } rxfifo_in = rxfifo_out = rxfifo_cnt = 0; return (0); } void serial_putc(const char c) { if (c == '\n') max3100_putc('\r'); max3100_putc(c); } void serial_puts(const char *s) { while (*s) serial_putc (*s++); } int serial_getc(void) { return max3100_getc(); } int serial_tstc(void) { return max3100_tstc(); } /* XXX WTF? */ void serial_setbrg(void) { } #endif