summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/tty/serial/serial_wmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/drivers/tty/serial/serial_wmt.c')
-rwxr-xr-xANDROID_3.4.5/drivers/tty/serial/serial_wmt.c2720
1 files changed, 2720 insertions, 0 deletions
diff --git a/ANDROID_3.4.5/drivers/tty/serial/serial_wmt.c b/ANDROID_3.4.5/drivers/tty/serial/serial_wmt.c
new file mode 100755
index 00000000..79246cdc
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/tty/serial/serial_wmt.c
@@ -0,0 +1,2720 @@
+/*++
+linux/drivers/serial/serial_wmt.c
+
+Copyright (c) 2008 WonderMedia Technologies, Inc.
+
+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, see <http://www.gnu.org/licenses/>.
+
+WonderMedia Technologies, Inc.
+10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/cpufreq.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <mach/dma.h>
+#include <linux/serial_core.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+
+#define PORT_WMT 54
+#if defined(CONFIG_SERIAL_WMT_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+
+#ifdef CONFIG_SERIAL_WMT_DMA
+/* * DMA processing */
+#define DMA_RX_REQUEST(s, cb) wmt_request_dma(&s->rx_dmach, s->id, s->dma_rx_dev, cb, s)
+#define DMA_RX_FREE(s) {wmt_free_dma(s->rx_dmach); s->rx_dmach = NULL_DMA; }
+#define DMA_RX_START(s, d, l) wmt_start_dma(s->rx_dmach, d, 0, l)
+#define DMA_RX_POS(s) wmt_get_dma_pos(s->rx_dmach)
+#define DMA_RX_STOP(s) wmt_stop_dma(s->rx_dmach)
+#define DMA_RX_CLEAR(s) wmt_clear_dma(s->rx_dmach)
+#define DMA_RX_RESET(s) wmt_reset_dma(s->rx_dmach)
+#define IS_NULLDMA(ch) ((ch) == NULL_DMA)
+#define CHK_DMACH(ch) ((ch) != NULL_DMA)
+#define DMA_TX_REQUEST(s, cb) wmt_request_dma(&s->tx_dmach, s->id, s->dma_tx_dev, cb, s)
+#define DMA_TX_FREE(s) {wmt_free_dma(s->tx_dmach); s->tx_dmach = NULL_DMA; }
+#define DMA_TX_START(s, d, l) wmt_start_dma(s->tx_dmach, d, 0, l)
+#define DMA_TX_POS(s) wmt_get_dma_pos(s->tx_dmach)
+#define DMA_TX_STOP(s) wmt_stop_dma(s->tx_dmach)
+#define DMA_TX_CLEAR(s) wmt_clear_dma(s->tx_dmach)
+#define DMA_TX_RESET(s) wmt_reset_dma(s->tx_dmach)
+#define NULL_DMA ((dmach_t)(-1))
+#endif
+
+
+
+#ifdef DEBUG_SERIAL_WMT
+#define DEBUG_INTR(fmt...) printk(fmt)
+#else
+#define DEBUG_INTR(fmt...) do { } while (0)
+#endif
+
+
+#define UART_BR_115K2 115200
+
+/*
+ * This is for saving useful I/O registers
+ */
+
+/*
+ * RS232 on DB9
+ * Pin No. Name Notes/Description
+ * 1 DCD Data Carrier Detect
+ * 2 RD Receive Data (a.k.a RxD, Rx)
+ * 3 TD Transmit Data (a.k.a TxD, Tx)
+ * 4 DTR Data Terminal Ready
+ * 5 SGND Ground
+ * 6 DSR Data Set Ready
+ * 7 RTS Request To Send
+ * 8 CTS Clear To Send
+ * 9 RI Ring Indicator
+ */
+
+/*
+ * We've been assigned a range on the "Low-density serial ports" major
+ *
+ * dev Major Minor
+ * ttyVT0 204 90
+ * ttyS0 4 64
+ */
+#ifdef CONFIG_SERIAL_WMT_TTYVT
+ #define SERIAL_WMT_MAJOR 204
+ #define MINOR_START 90 /* Start from ttyVT0 */
+ #define CALLOUT_WMT_MAJOR 205 /* for callout device */
+#else
+ #define SERIAL_WMT_MAJOR 4
+ #define MINOR_START 64 /* Start from ttyS0 */
+ #define CALLOUT_WMT_MAJOR 5 /* for callout device */
+#endif
+
+#ifdef CONFIG_UART_2_3_ENABLE
+#define NR_PORTS 4
+#else
+#define NR_PORTS 2
+#endif
+#define WMT_ISR_PASS_LIMIT 256
+
+struct wmt_port {
+ struct uart_port port;
+ struct timer_list timer;
+ struct timer_list rx_timer;
+#ifdef CONFIG_SERIAL_WMT_DMA
+ /* RX Buffer0 physical address */
+ dma_addr_t uart_rx_dma_phy0_org;
+ /* RX Buffer1 physical address */
+ dma_addr_t uart_rx_dma_phy1_org;
+ /* RX Buffer2 physical address */
+ dma_addr_t uart_rx_dma_phy2_org;
+ /* RX Buffer0 virtual address */
+ char *uart_rx_dma_buf0_org;
+ /* RX Buffer1 virtual address */
+ char *uart_rx_dma_buf1_org;
+ /* RX Buffer2 virtual address */
+ char *uart_rx_dma_buf2_org;
+ /* RX Buffer0 virtual address, this address is the data should be read */
+ char *uart_dma_tmp_buf0;
+ /* RX Buffer1 virtual address, this address is the data should be read */
+ char *uart_dma_tmp_buf1;
+ /* RX Buffer2 virtual address, this address is the data should be read */
+ char *uart_dma_tmp_buf2;
+ /* RX Buffer0 physical address, this address is the data should be read */
+ dma_addr_t uart_dma_tmp_phy0;
+ /* RX Buffer1 physical address, this address is the data should be read */
+ dma_addr_t uart_dma_tmp_phy1;
+ /* RX Buffer2 physical address, this address is the data should be read */
+ dma_addr_t uart_dma_tmp_phy2;
+ /* RX device identifier for DMA */
+ enum dma_device_e dma_rx_dev;
+ /* TX device identifier for DMA */
+ enum dma_device_e dma_tx_dev;
+ /* RX DMA device config */
+ struct dma_device_cfg_s dma_rx_cfg;
+ /* TX DMA device config */
+ struct dma_device_cfg_s dma_tx_cfg;
+ /* RX DMA channel number */
+ dmach_t rx_dmach;
+ /* TX DMA channel number */
+ dmach_t tx_dmach;
+ /* RX dma callback function record which buffer the DMA used */
+ unsigned int buffer_used;
+ /* The buffer rx_char function should used (virtual address) */
+ unsigned int buffer_selected;
+ /* The buffer rx_count function should used (physical address) */
+ unsigned int buffer_rx_count_selected;
+ /* TX Buffer0 virtual address */
+ char *uart_tx_dma_buf0_org;
+ /* TX Buffer0 physical address */
+ dma_addr_t uart_tx_dma_phy0_org;
+ /* Record TX DMA running status : DMA_TX_END, DMA_TX_CHAR, DMA_TX_XMIT */
+ unsigned int uart_tx_dma_flag;
+ /* TX dma transmit counter*/
+ unsigned int uart_tx_count;
+ /* RX dma buffer last position*/
+ unsigned int last_pos;
+ /* Record the number of RX dma timeout function with no data transmit*/
+ unsigned int uart_rx_dma_flag;
+ unsigned int dma_tx_cnt;
+#endif
+ unsigned int old_status;
+ /* identification string */
+ char *id;
+ unsigned int old_urdiv;
+ unsigned int old_urlcr;
+ unsigned int old_urier;
+ unsigned int old_urfcr;
+ unsigned int old_urtod;
+};
+
+#ifdef CONFIG_SERIAL_WMT_DMA
+#define DMA_TX_END 0
+#define DMA_TX_CHAR 1
+#define DMA_TX_XMIT 2
+#endif
+
+
+/*
+ * WMT UART registers set structure.
+ */
+struct wmt_uart {
+ unsigned int volatile urtdr; /* 0x00*/
+ unsigned int volatile urrdr; /* 0x04*/
+ unsigned int volatile urdiv; /* 0x08*/
+ unsigned int volatile urlcr; /* 0x0C*/
+ unsigned int volatile uricr; /* 0x10*/
+ unsigned int volatile urier; /* 0x14*/
+ unsigned int volatile urisr; /* 0x18*/
+ unsigned int volatile urusr; /* 0x1C*/
+ unsigned int volatile urfcr; /* 0x20*/
+ unsigned int volatile urfidx; /* 0x24*/
+ unsigned int volatile urbkr; /* 0x28*/
+ unsigned int volatile urtod; /* 0x2C*/
+ unsigned int volatile resv30_FFF[0x3F4]; /* 0x0030 - 0x0FFF Reserved*/
+ unsigned char volatile urtxf[32]; /* 0x1000 - 0x101F*/
+ unsigned char volatile urrxf[32]; /* 0x1020 - 0x103F*/
+};
+
+struct baud_info_s {
+ unsigned int baud; /* baud rate */
+ unsigned int brd; /* baud rate divisor */
+ unsigned int bcv; /* break counter value at this baud rate
+ * simply be calculated by baud * 0.004096
+ */
+};
+#ifdef UART_DEBUG
+unsigned int *DMA_pbuf =NULL;
+unsigned int *COUNT_pbuf =NULL;
+unsigned int *CPU_pbuf =NULL;
+unsigned int dma_write_index = 0x00;
+#endif
+int mtk6622_tty = -1;
+extern int wmt_getsyspara(char *varname, char *varval, int *varlen);
+
+static struct baud_info_s baud_table[] = {
+ { 3600, 0x100FF, 15 },
+ { 7600, 0x1007F, 30 },
+ { 9600, 0x2003F, 39 },
+ { 14400, 0x1003F, 59 },
+ { 19200, 0x2001F, 79 },
+ { 28800, 0x1001F, 118 },
+ { 38400, 0x2000F, 157 },
+ { 57600, 0x1000F, 236 },
+ { 115200, 0x10007, 472 },
+ { 230400, 0x10003, 944 },
+ { 460800, 0x10001, 1920 },
+ { 921600, 0x10000, 3775 },
+};
+
+#define BAUD_TABLE_SIZE ARRAY_SIZE(baud_table)
+
+#ifdef CONFIG_SERIAL_WMT_DMA
+#define UART_BUFFER_SIZE (1024*16)
+#endif
+/*
+ * Macros to put URISR and URUSR into a 32-bit status variable
+ * URISR in bit[ 0:15]
+ * URUSR in bit[16:31]
+ */
+#define URISR_TO_SM(x) ((x) & URISR_MASK)
+#define URUSR_TO_SM(x) (((x) & URUSR_MASK) << 16)
+#define SM_TO_URISR(x) ((x) & 0xffff)
+#define SM_TO_URUSR(x) ((x) >> 16)
+
+/*
+ * Following is a trick if we're interesting to listen break signal,
+ * but due to WMT UART doesn't suppout this interrupt status.
+ * So I make a fake interrupt status and use URISR_FER event to implement
+ * break signal detect.
+ */
+#ifdef CONFIG_SERIAL_WMT_BKSIG
+#define SW_BKSIG (BIT31 | URISR_FER)
+#endif
+/*
+ * Macros to manipulate WMT UART module.
+ *
+ * s = sport, o = offset, v = value
+ *
+ * registers offset table as follows:
+ *
+ * URTDR 0x0000
+ * URRDR 0x0004
+ * URBRD 0x0008
+ * URLCR 0x000C
+ * URICR 0x0010
+ * URIER 0x0014
+ * URISR 0x0018
+ * URUSR 0x001C
+ * URFCR 0x0020
+ * URFIDX 0x0024
+ * URBKR 0x0028
+ *
+ * Offset 0x002C-0x002F reserved
+ *
+ * URTXF 0x0030
+ * URRXF 0x0040
+ */
+#define PORT_TO_BASE(s) ((s)->port.membase)
+#define WMT_UART_GET(s, o) __raw_readl((s)->port.membase + o)
+#define WMT_UART_PUT(s, o, v) __raw_writel(v, (s)->port.membase + o)
+#define WMT_UART_TXFIFO(s) (volatile unsigned char *)((s)->port.membase + URTXF)
+#define WMT_UART_RXFIFO(s) (volatile unsigned short *)((s)->port.membase + URRXF)
+
+/*
+ * This is the size of our serial port register set.
+ */
+#define UART_PORT_SIZE 0x1040
+
+/*
+ * This determines how often we check the modem status signals
+ * for any change. They generally aren't connected to an IRQ
+ * so we have to poll them. We also check immediately before
+ * filling the TX fifo incase CTS has been dropped.
+ */
+#define MCTRL_TIMEOUT (250*HZ/1000)
+
+/*{2007/11/10 JHT Support the VT8500 Serial Port Driver Because the*/
+/* definition of URSIRT Bit[0] & Bit[3] are different.*/
+/* Before VT8500 these bit are defined as RO, in VT8500*/
+/* they are changed into the W1C. Therefore the xmit function*/
+/* for the FIFO mode should be modified as well.*/
+static void wmt_tx_chars(struct wmt_port *sport);
+static void wmt_rx_chars(struct wmt_port *sport, unsigned int status);
+static struct wmt_port wmt_ports[NR_PORTS];
+
+/*}2007/11/10-JHT*/
+
+enum {
+ SHARE_PIN_UART = 0,
+ SHARE_PIN_SPI,
+};
+static int wmt_uart_spi_sel = SHARE_PIN_UART; /* 0:uart, 1:spi */
+
+void uart_dump_reg(struct wmt_port *sport)
+{
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+
+ unsigned int urtdr = uart->urtdr; /* 0x00*/
+ unsigned int urrdr = uart->urrdr; /* 0x04*/
+ unsigned int urdiv = uart->urdiv; /* 0x08*/
+ unsigned int urlcr = uart->urlcr; /* 0x0C*/
+ unsigned int uricr = uart->uricr; /* 0x10*/
+ unsigned int urier = uart->urier; /* 0x14*/
+ unsigned int urisr = uart->urisr; /* 0x18*/
+ unsigned int urusr = uart->urusr; /* 0x1C*/
+ unsigned int urfcr = uart->urfcr; /* 0x20*/
+ unsigned int urfidx = uart->urfidx; /* 0x24*/
+ unsigned int urbkr = uart->urbkr; /* 0x28*/
+ unsigned int urtod = uart->urtod; /* 0x2C*/
+#if 1
+
+ printk("urtdr=0x%.8x urrdr=0x%.8x urdiv=0x%.8x urlcr=0x%.8x\n" \
+ "uricr=0x%.8x urier=0x%.8x urisr=0x%.8x urusr=0x%.8x\n" \
+ "urfcr=0x%.8x uridx=0x%.8x urbkr=0x%.8x urtod=0x%.8x\n",
+ urtdr, urrdr, urdiv, urlcr,
+ uricr, urier, urisr, urusr,
+ urfcr, urfidx, urbkr, urtod);
+#endif
+}
+
+static void wmt_mctrl_check(struct wmt_port *sport)
+{
+ unsigned int status, changed;
+
+ status = sport->port.ops->get_mctrl(&sport->port);
+ changed = status ^ sport->old_status;
+
+ if (changed == 0)
+ return;
+
+ sport->old_status = status;
+
+ if (changed & TIOCM_RI)
+ sport->port.icount.rng++;
+ if (changed & TIOCM_DSR)
+ sport->port.icount.dsr++;
+ if (changed & TIOCM_CAR)
+ uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+ if (changed & TIOCM_CTS)
+ uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+ wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void wmt_timeout(unsigned long data)
+{
+ struct wmt_port *sport = (struct wmt_port *)data;
+ unsigned long flags;
+
+
+
+ if (sport->port.state) {
+ spin_lock_irqsave(&sport->port.lock, flags);
+ wmt_mctrl_check(sport);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+ }
+}
+
+unsigned int rx_timeout = 1;
+
+static void wmt_rx_timeout(unsigned long data)
+{
+ struct wmt_port *sport = (struct wmt_port *)data;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ unsigned long flags;
+ unsigned int status;
+ unsigned int pos = 0;
+
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ pos = DMA_RX_POS(sport);
+ status = URISR_TO_SM(uart->urisr) | URUSR_TO_SM(uart->urusr);
+ uart->urisr |= SM_TO_URISR(status);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ /* DMA didn't transmit any data */
+ if (sport->last_pos == pos) {
+ sport->uart_rx_dma_flag++;
+
+ /* RX DMA didn't trasmit any data in two times, */
+ /* enable interrupt and do the last time mod timer */
+ if (sport->uart_rx_dma_flag == 2) {
+ sport->uart_rx_dma_flag++;
+ uart->urier = URIER_ERXFAF |
+ URIER_ERXFF |
+ URIER_ERXTOUT |
+ URIER_EPER |
+ URIER_EFER |
+ URIER_ERXDOVR;
+ mod_timer(&sport->rx_timer, jiffies + rx_timeout);
+ return;
+ } else if (sport->uart_rx_dma_flag == 3) {
+ sport->uart_rx_dma_flag = 0;
+ return;
+ }
+ mod_timer(&sport->rx_timer, jiffies + rx_timeout);
+ return;
+ }
+
+ sport->uart_rx_dma_flag = 0;
+
+ wmt_rx_chars(sport, URISR_RXFAF | URISR_RXFF | status);
+
+ mod_timer(&sport->rx_timer, jiffies + rx_timeout);
+
+}
+
+
+/*
+ * Interrupts should be disabled on entry.
+ */
+static void wmt_stop_tx(struct uart_port *port)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+
+ #ifndef CONFIG_SERIAL_WMT_DMA
+ uart->urier &= ~(URIER_ETXFAE | URIER_ETXFE);
+ sport->port.read_status_mask &= ~URISR_TO_SM(URISR_TXFAE | URISR_TXFE);
+ #else
+ if ((unsigned int)(sport->port.membase) == UART0_BASE_ADDR) {
+ uart->urier &= ~(URIER_ETXFAE | URIER_ETXFE);
+ sport->port.read_status_mask &= ~URISR_TO_SM(URISR_TXFAE | URISR_TXFE);
+ }
+ #endif
+}
+/*
+ * Interrupts may not be disabled on entry.
+ */
+static void wmt_start_tx(struct uart_port *port)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+
+ /*{2007/11/10 JHT Support the VT8500 Serial Port Driver Because the
+ * definition of URSIRT Bit[0] & Bit[3] are different.
+ * Before VT8500 these bit are defined as RO, in VT8500
+ * they are changed into the W1C. Therefore the xmit function
+ * for the FIFO mode should be modified as well.
+ */
+#ifdef CONFIG_SERIAL_WMT_DMA
+ if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) {
+ uart->urlcr |= URLCR_DMAEN;
+ uart->urier &= ~(URIER_ETXFAE | URIER_ETXFE);
+ } else
+ uart->urier &= ~(URIER_ETXFAE | URIER_ETXFE);
+#else
+ uart->urier &= ~(URIER_ETXFAE | URIER_ETXFE);
+ #endif
+ wmt_tx_chars(sport);
+ /*}2007/11/10-JHT*/
+#ifndef CONFIG_SERIAL_WMT_DMA
+ sport->port.read_status_mask |= URISR_TO_SM(URISR_TXFAE | URISR_TXFE);
+ uart->urier |= URIER_ETXFAE | URIER_ETXFE;
+#else
+ if ((unsigned int)(sport->port.membase) == UART0_BASE_ADDR) {
+ sport->port.read_status_mask |= URISR_TO_SM(URISR_TXFAE | URISR_TXFE);
+ uart->urier |= URIER_ETXFAE | URIER_ETXFE;
+ }
+ #endif
+}
+
+/*
+ * Interrupts enabled
+ */
+static void wmt_stop_rx(struct uart_port *port)
+{
+/*
+ struct wmt_port *sport = (struct wmt_port *)port;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+
+
+ uart->urier &= ~URIER_ERXFAF;
+*/
+}
+
+/*
+ * No modem control lines
+ */
+static void wmt_enable_ms(struct uart_port *port)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+
+ mod_timer(&sport->timer, jiffies);
+}
+
+#ifdef CONFIG_SERIAL_WMT_DMA
+static unsigned int wmt_rx_count(struct wmt_port *sport)
+{
+ unsigned int rx_count = 0;
+ unsigned int pos;
+
+ pos = DMA_RX_POS(sport);
+
+ if (pos == sport->last_pos) /*have no data to drain */
+ return 0;
+
+ if (sport->buffer_rx_count_selected == 0) {
+ sport->buffer_selected = 0; /*shoud read buffer 0*/
+
+ /*pos in the range of the buffer0*/
+ if ((pos >= sport->uart_dma_tmp_phy0) &&
+ (pos <= (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE))) {
+ rx_count = (pos - (unsigned int)sport->uart_dma_tmp_phy0);
+ } else if (pos == 0) {
+ if (sport->uart_dma_tmp_phy0 == sport->uart_rx_dma_phy0_org)
+ rx_count = 0;
+ else {
+ rx_count = (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE)
+ - (unsigned int)sport->uart_dma_tmp_phy0;
+ }
+ } else if (((pos >= sport->uart_rx_dma_phy1_org) &&
+ (pos <= (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE)))
+ ||
+ ((pos >= sport->uart_rx_dma_phy2_org) &&
+ (pos <= (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE)))) {
+ /* Buffer is full, dma pos in buffer 1 or 2, read all left data*/
+ rx_count = (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE) -
+ (unsigned int)sport->uart_dma_tmp_phy0;
+ }
+ sport->uart_dma_tmp_phy0 += rx_count; /*update tmp physical address*/
+ sport->last_pos = sport->uart_dma_tmp_phy0;
+
+ /* Buffer0 has reach to end*/
+ if (sport->uart_dma_tmp_phy0 == (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE)) {
+ sport->buffer_rx_count_selected = 1;
+ sport->uart_dma_tmp_phy0 = sport->uart_rx_dma_phy0_org;
+ }
+ } else if (sport->buffer_rx_count_selected == 1) {
+ sport->buffer_selected = 1; /*shoud read buffer 1*/
+
+ /*pos in the range of the buffer1*/
+ if ((pos >= sport->uart_dma_tmp_phy1) &&
+ (pos <= (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE))) {
+ rx_count = (pos - (unsigned int)sport->uart_dma_tmp_phy1);
+ } else if (pos == 0) {
+ if (sport->uart_dma_tmp_phy1 == sport->uart_rx_dma_phy1_org)
+ rx_count = 0;
+ else {
+ rx_count = (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE) -
+ (unsigned int)sport->uart_dma_tmp_phy1;
+ }
+ } else if (((pos >= sport->uart_rx_dma_phy0_org) &&
+ (pos <= (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE)))
+ ||
+ ((pos >= sport->uart_rx_dma_phy2_org) &&
+ (pos <= (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE)))) {
+ /* Buffer is full, dma pos in buffer 0 or 2, read all left data*/
+ rx_count = (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE) -
+ (unsigned int)sport->uart_dma_tmp_phy1;
+ }
+ sport->uart_dma_tmp_phy1 += rx_count;
+ sport->last_pos = sport->uart_dma_tmp_phy1;
+ /* Buffer1 has reach to end*/
+ if (sport->uart_dma_tmp_phy1 == (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE)) {
+ sport->buffer_rx_count_selected = 2;
+ sport->uart_dma_tmp_phy1 = sport->uart_rx_dma_phy1_org;
+ }
+ } else if (sport->buffer_rx_count_selected == 2) {
+ sport->buffer_selected = 2; /*shoud read buffer 2*/
+
+ /*pos in the range of the buffer1*/
+ if ((pos >= sport->uart_dma_tmp_phy2) &&
+ (pos <= (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE))) {
+ rx_count = (pos - (unsigned int)sport->uart_dma_tmp_phy2);
+ } else if (pos == 0) {
+ if (sport->uart_dma_tmp_phy2 == sport->uart_rx_dma_phy2_org)
+ rx_count = 0;
+ else {
+ rx_count = (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE) -
+ (unsigned int)sport->uart_dma_tmp_phy2;
+ }
+ } else if (((pos >= sport->uart_rx_dma_phy0_org) &&
+ (pos <= (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE)))
+ ||
+ ((pos >= sport->uart_rx_dma_phy1_org) &&
+ (pos <= (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE)))) {
+ /* Buffer is full, dma pos in buffer 0 or 1, read all left data*/
+ rx_count = (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE) -
+ (unsigned int)sport->uart_dma_tmp_phy2;
+ }
+ sport->uart_dma_tmp_phy2 += rx_count;
+ sport->last_pos = sport->uart_dma_tmp_phy2;
+
+ /* Buffer2 has reach to end*/
+ if (sport->uart_dma_tmp_phy2 == (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE)) {
+ sport->buffer_rx_count_selected = 0;
+ sport->uart_dma_tmp_phy2 = sport->uart_rx_dma_phy2_org;
+ }
+ }
+ return rx_count;
+}
+/*
+* we can use mu command to check memory content
+*/
+int volatile last_submit = 0x0;
+void dump_rx_dma_buf(struct wmt_port *sport)
+{
+ unsigned int rx_count = 0;
+ unsigned int pos;
+ int i;
+ int size=0;
+ unsigned char *tmpbuf;
+ pos = DMA_RX_POS(sport);
+ printk("sport->last_pos:0x%x,pos:0x%x,sport->buffer_rx_count_selected:0x%x,last_submit:0x%x\n",sport->last_pos,pos,sport->buffer_rx_count_selected,last_submit);
+ if ((sport->uart_rx_dma_phy0_org) <= pos && pos <= (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE)){
+ i = pos - sport->uart_rx_dma_phy0_org;
+ tmpbuf = sport->uart_rx_dma_buf0_org + i;
+ size = (unsigned int)(sport->uart_rx_dma_buf0_org) + UART_BUFFER_SIZE - (unsigned int)tmpbuf;
+ if(size > 16)
+ size = 16;
+ }else if ((sport->uart_rx_dma_phy1_org) <= pos && pos <= (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE)){
+ i = pos - sport->uart_rx_dma_phy1_org;
+ tmpbuf = sport->uart_rx_dma_buf1_org + i;
+ size =(unsigned int)( sport->uart_rx_dma_buf1_org) + UART_BUFFER_SIZE - (unsigned int)tmpbuf;
+ if(size > 16)
+ size = 16;
+ }else if ((sport->uart_rx_dma_phy2_org) <= pos && pos <= (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE)){
+ i = pos - sport->uart_rx_dma_phy2_org;
+ tmpbuf = sport->uart_rx_dma_buf2_org + i;
+ size = (unsigned int)(sport->uart_rx_dma_buf2_org) + UART_BUFFER_SIZE - (unsigned int)tmpbuf;
+ if(size > 16)
+ size = 16;
+ }
+
+ for(i=0;i<size;i++)
+ printk("0x%x ",*tmpbuf++);
+
+ printk("\nsport->uart_rx_dma_phy0_org:0x%x\n",sport->uart_rx_dma_phy0_org);
+ printk("sport->uart_rx_dma_phy1_org:0x%x\n",sport->uart_rx_dma_phy1_org);
+ printk("sport->uart_rx_dma_phy2_org:0x%x\n",sport->uart_rx_dma_phy2_org);
+}
+#endif
+/*
+ * Inside the UART interrupt service routine dut to following
+ * reason:
+ *
+ * URISR_RXFAF: RX FIFO almost full (FIFO mode)
+ * URISR_RXDF: RX data register full (Register mode)
+ * URISR_RXTOUT: RX timeout
+ */
+
+#ifndef CONFIG_SERIAL_WMT_DMA
+static void
+wmt_rx_chars(struct wmt_port *sport, unsigned int status)
+{
+ struct tty_struct *tty = sport->port.state->port.tty;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ unsigned int flg, urfidx, ignored = 0;
+ char ch;
+
+ urfidx = URFIDX_RXFIDX(uart->urfidx);
+
+ /*
+ * Check if there is data ready to be read.
+ *
+ * Note: We only receive characters.
+ */
+ while ((status & URUSR_TO_SM(URUSR_RXDRDY)) && (URFIDX_RXFIDX(uart->urfidx))) {
+ ch = (uart->urrxf[0] & 0xFF);
+ /*urfidx--;*/
+
+ sport->port.icount.rx++;
+
+ flg = TTY_NORMAL;
+
+ /*
+ * Check interrupt status information using status[URISR_bits].
+ *
+ * Notice that the error handling code is out of
+ * the main execution path and the URISR has already
+ * been read by ISR.
+ */
+ if (status & URISR_TO_SM(URISR_PER | URISR_FER | URISR_RXDOVR)) {
+ if (urfidx > 1) {
+ if (uart_handle_sysrq_char(&sport->port, ch))
+ goto ignore_char;
+ /*
+ * Pop all TTY_NORMAL data.
+ */
+ goto error_return;
+ } else {
+ /*
+ * Now we have poped up to the data with
+ * parity error or frame error.
+ */
+ goto handle_error;
+ }
+ }
+
+ if (uart_handle_sysrq_char(&sport->port, ch))
+ goto ignore_char;
+
+error_return:
+
+ uart_insert_char(&sport->port, (status & 0xFFFF), URISR_TO_SM(URISR_RXDOVR) , ch, flg);
+
+ignore_char:
+ status &= 0xffff; /* Keep URISR field*/
+ status |= URUSR_TO_SM(uart->urusr);
+ }
+out:
+ tty_flip_buffer_push(tty);
+ return;
+
+handle_error:
+ /*
+ * Update error counters.
+ */
+ if (status & URISR_TO_SM(URISR_PER))
+ sport->port.icount.parity++;
+ else
+ if (status & URISR_TO_SM(URISR_FER)) {
+
+ #ifdef CONFIG_SERIAL_WMT_BKSIG
+ /*
+ * Experimental software patch for break signal detection.
+ *
+ * When I got there is a frame error in next frame data,
+ * I check the next data to judge if it is a break signal.
+ *
+ * FIXME: Open these if Bluetooth or IrDA need this patch.
+ * Dec.29.2004 by Harry.
+ */
+ if ((ch & RX_PERMASK) == 0) {
+ sport->port.icount.brk++;
+ uart_handle_break(&sport->port);
+ } else
+ sport->port.icount.frame++;
+
+ #else /* Don't support break sinal detection */
+
+ sport->port.icount.frame++;
+
+ #endif
+
+ }
+
+ /*
+ * RX Over Run event
+ */
+ if (status & URISR_TO_SM(URISR_RXDOVR))
+ sport->port.icount.overrun++;
+
+ if (status & sport->port.ignore_status_mask) {
+ if (++ignored > 100)
+ goto out;
+ goto ignore_char;
+ }
+
+ /*
+ * Second, handle the events which we're interesting to listen.
+ */
+ status &= sport->port.read_status_mask;
+
+ if (status & URISR_TO_SM(URISR_PER))
+ flg = TTY_PARITY;
+ else
+ if (status & URISR_TO_SM(URISR_FER)) {
+
+ #ifdef CONFIG_SERIAL_WMT_BKSIG
+ /* Software patch for break signal detection.
+ *
+ * When I got there is a frame error in next frame data,
+ * I check the next data to judge if it is a break signal.
+ *
+ * FIXME: Open these if Bluetooth or IrDA need this patch.
+ * Dec.29.2004 by Harry.
+ */
+ if (sport->port.read_status_mask & SW_BKSIG) {
+ if ((ch & RX_PERMASK) == 0) {
+ DEBUG_INTR("handling break....");
+ flg = TTY_BREAK;
+ /*goto error_return;*/
+ } else {
+ flg = TTY_FRAME;
+ /*goto error_return;*/
+ }
+ } else {
+ flg = TTY_FRAME;
+ /*goto error_return;*/
+ }
+
+ #else /* Don't support break sinal detection */
+
+ flg = TTY_FRAME;
+
+ #endif
+ }
+
+ if (status & URISR_TO_SM(URISR_RXDOVR)) {
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character.
+ */
+
+ ch = 0;
+ flg = TTY_OVERRUN;
+ }
+ #ifdef SUPPORT_SYSRQ
+ sport->port.sysrq = 0;
+ #endif
+ goto error_return;
+}
+#else
+
+
+static inline int put_strings_tty_io(struct tty_struct *tty,
+ const unsigned char *chars, char flag, size_t size)
+{
+ int i;
+
+ i = tty_insert_flip_string_fixed_flag(tty, chars, flag, size);
+ tty_flip_buffer_push(tty);
+ return i;
+}
+
+static void
+wmt_rx_chars(struct wmt_port *sport, unsigned int status)
+{
+ struct tty_struct *tty = sport->port.state->port.tty;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ unsigned int receive_rx_count = 0;
+ unsigned long flags;
+
+ unsigned int flg, urfidx, ignored = 0;
+ char ch;
+ char *pchar = NULL;
+ char rx_flag;
+
+ urfidx = URFIDX_RXFIDX(uart->urfidx);
+
+ /*
+ * Check if there is data ready to be read.
+ *
+ * Note: We only receive characters.
+ */
+
+ if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) {
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ receive_rx_count = wmt_rx_count(sport);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ rx_flag = TTY_NORMAL;
+
+ if (status & URISR_TO_SM(URISR_PER))
+ rx_flag = TTY_PARITY;
+
+ if (status & URISR_TO_SM(URISR_FER))
+ rx_flag = TTY_FRAME;
+
+ if (receive_rx_count > 0) {
+ if (sport->buffer_selected == 0) {
+ pchar = sport->uart_dma_tmp_buf0;
+ sport->uart_dma_tmp_buf0 += receive_rx_count;
+ put_strings_tty_io(tty, pchar, rx_flag, receive_rx_count);
+
+ if (sport->uart_dma_tmp_buf0 ==
+ (sport->uart_rx_dma_buf0_org + UART_BUFFER_SIZE)) {
+ sport->uart_dma_tmp_buf0 = sport->uart_rx_dma_buf0_org;
+ }
+
+ } else if (sport->buffer_selected == 1) {
+ pchar = sport->uart_dma_tmp_buf1;
+ sport->uart_dma_tmp_buf1 += receive_rx_count;
+ put_strings_tty_io(tty, pchar, rx_flag, receive_rx_count);
+
+ if (sport->uart_dma_tmp_buf1 ==
+ (sport->uart_rx_dma_buf1_org + UART_BUFFER_SIZE)) {
+ sport->uart_dma_tmp_buf1 = sport->uart_rx_dma_buf1_org;
+ }
+ } else if (sport->buffer_selected == 2) {
+ pchar = sport->uart_dma_tmp_buf2;
+ sport->uart_dma_tmp_buf2 += receive_rx_count ;
+ put_strings_tty_io(tty, pchar, rx_flag, receive_rx_count);
+
+ if (sport->uart_dma_tmp_buf2 ==
+ (sport->uart_rx_dma_buf2_org + UART_BUFFER_SIZE)) {
+ sport->uart_dma_tmp_buf2 = sport->uart_rx_dma_buf2_org;
+ }
+ }
+ sport->port.icount.rx += receive_rx_count;
+
+ if (rx_flag == TTY_PARITY)
+ sport->port.icount.parity += receive_rx_count;
+
+ if (rx_flag == TTY_FRAME)
+ sport->port.icount.frame += receive_rx_count;
+
+ receive_rx_count = 0;
+ }
+ tty_flip_buffer_push(tty);
+ return;
+
+ } else {
+
+ while ((status & URUSR_TO_SM(URUSR_RXDRDY)) && (URFIDX_RXFIDX(uart->urfidx))) {
+
+ ch = (unsigned int)(uart->urrxf[0] & 0xFF);
+ sport->port.icount.rx++;
+
+ flg = TTY_NORMAL;
+
+ /*
+ * Check interrupt status information using status[URISR_bits].
+ *
+ * Notice that the error handling code is out of
+ * the main execution path and the URISR has already
+ * been read by ISR.
+ */
+ if (status & URISR_TO_SM(URISR_PER | URISR_FER | URISR_RXDOVR)) {
+ if (urfidx > 1) {
+ if (uart_handle_sysrq_char(&sport->port, ch))
+ goto ignore_char2;
+ /*
+ * Pop all TTY_NORMAL data.
+ */
+ goto error_return2;
+ } else {
+ /*
+ * Now we have poped up to the data with
+ * parity error or frame error.
+ */
+ goto handle_error2;
+ }
+ }
+
+ if (uart_handle_sysrq_char(&sport->port, ch))
+ goto ignore_char2;
+
+error_return2:
+ uart_insert_char(&sport->port, (status & 0xFFFF),
+ URISR_TO_SM(URISR_RXDOVR) , ch, flg);
+ignore_char2:
+ status &= 0xffff; /* Keep URISR field*/
+ status |= URUSR_TO_SM(uart->urusr);
+ }
+out2:
+ tty_flip_buffer_push(tty);
+ return;
+
+handle_error2:
+ /*
+ * Update error counters.
+ */
+ if (status & URISR_TO_SM(URISR_PER))
+ sport->port.icount.parity++;
+ else {
+ if (status & URISR_TO_SM(URISR_FER)) {
+#ifdef CONFIG_SERIAL_WMT_BKSIG
+ /*
+ * Experimental software patch for break signal detection.
+ *
+ * When I got there is a frame error in next frame data,
+ * I check the next data to judge if it is a break signal.
+ *
+ * FIXME: Open these if Bluetooth or IrDA need this patch.
+ * Dec.29.2004 by Harry.
+ */
+ if ((ch & RX_PERMASK) == 0) {
+ sport->port.icount.brk++;
+ uart_handle_break(&sport->port);
+ } else
+ sport->port.icount.frame++;
+
+#else /* Don't support break sinal detection */
+ sport->port.icount.frame++;
+#endif
+ }
+ }
+ /*
+ * RX Over Run event
+ */
+ if (status & URISR_TO_SM(URISR_RXDOVR))
+ sport->port.icount.overrun++;
+
+ if (status & sport->port.ignore_status_mask) {
+ if (++ignored > 100)
+ goto out2;
+ goto ignore_char2;
+ }
+
+ /*
+ * Second, handle the events which we're interesting to listen.
+ */
+ status &= sport->port.read_status_mask;
+
+ if (status & URISR_TO_SM(URISR_PER))
+ flg = TTY_PARITY;
+ else
+ if (status & URISR_TO_SM(URISR_FER)) {
+
+#ifdef CONFIG_SERIAL_WMT_BKSIG
+ /* Software patch for break signal detection.
+ *
+ * When I got there is a frame error in next frame data,
+ * I check the next data to judge if it is a break signal.
+ *
+ * FIXME: Open these if Bluetooth or IrDA need this patch.
+ * Dec.29.2004 by Harry.
+ */
+ if (sport->port.read_status_mask & SW_BKSIG) {
+ if ((ch & RX_PERMASK) == 0) {
+ DEBUG_INTR("handling break....");
+ flg = TTY_BREAK;
+ /*goto error_return;*/
+ } else {
+ flg = TTY_FRAME;
+ /*goto error_return;*/
+ }
+ } else {
+ flg = TTY_FRAME;
+ /*goto error_return;*/
+ }
+#else /* Don't support break sinal detection */
+ flg = TTY_FRAME;
+#endif
+ }
+
+ if (status & URISR_TO_SM(URISR_RXDOVR)) {
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character.
+ */
+
+ ch = 0;
+ flg = TTY_OVERRUN;
+ }
+ #ifdef SUPPORT_SYSRQ
+ sport->port.sysrq = 0;
+ #endif
+ goto error_return2;
+ }
+
+}
+#endif
+/*
+ * Inside the UART interrupt service routine dut to following
+ * reason:
+ *
+ * URISR_TXFAE: TX FIFO almost empty (FIFO mode)
+ * URISR_TXFE: TX FIFO empty(FIFO mode)
+ */
+#ifndef CONFIG_SERIAL_WMT_DMA
+static void wmt_tx_chars(struct wmt_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+
+ if (sport->port.x_char) {
+ /*
+ * Fill character to the TX FIFO entry.
+ */
+ uart->urtxf[0] = sport->port.x_char;
+ sport->port.icount.tx++;
+ sport->port.x_char = 0;
+ return;
+ }
+
+ /*Check the modem control lines before transmitting anything.*/
+ wmt_mctrl_check(sport);
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+ wmt_stop_tx(&sport->port);
+ return;
+ }
+
+ /*{2007/11/10 JHT Support the WMT Serial Port Driver Because the
+ * definition of URSIRT Bit[0] & Bit[3] are different.
+ * Before WMT these bit are defined as RO, in WMT
+ * they are changed into the W1C. Therefore the xmit function
+ * for the FIFO mode should be modified as well.
+ */
+ while ((uart->urfidx & 0x1F) < 16) {
+ if (uart_circ_empty(xmit))
+ break;
+
+ if (uart->urusr & URUSR_TXDBSY)
+ continue;
+ uart->urtxf[0] = xmit->buf[xmit->tail];
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ sport->port.icount.tx++;
+ }
+ /*}2007/11/10-JHT*/
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ if (uart_circ_empty(xmit))
+ wmt_stop_tx(&sport->port);
+}
+#else
+
+static void wmt_tx_chars(struct wmt_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ int head = xmit->head;
+ int tail = xmit->tail;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ char *dma_buf = sport->uart_tx_dma_buf0_org;
+ unsigned int tx_count;
+
+ if (sport->port.x_char) {
+ /*
+ * Fill character to the TX FIFO entry.
+ */
+ if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) {
+ /*Dma is still running*/
+ if (sport->uart_tx_dma_flag != DMA_TX_END)
+ return;
+
+ *dma_buf = sport->port.x_char;
+ sport->uart_tx_dma_flag = DMA_TX_CHAR;
+ DMA_TX_START(sport, sport->uart_tx_dma_phy0_org, 1);
+ } else {
+ uart->urtxf[0] = sport->port.x_char;
+ sport->port.icount.tx++;
+ sport->port.x_char = 0;
+ }
+ return;
+ }
+ /*Check the modem control lines before transmitting anything.*/
+ wmt_mctrl_check(sport);
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+ wmt_stop_tx(&sport->port);
+ return;
+ }
+
+ /*{2007/11/10 JHT Support the WMT Serial Port Driver Because the
+ * definition of URSIRT Bit[0] & Bit[3] are different.
+ * Before WMT these bit are defined as RO, in WMT
+ * they are changed into the W1C. Therefore the xmit function
+ * for the FIFO mode should be modified as well.
+ */
+
+
+ if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) {
+ while((uart->urusr & URUSR_TXON));
+ if(sport->port.line == mtk6622_tty){
+ while ((uart->urusr & URUSR_TXDBSY));
+ }
+
+ if (sport->uart_tx_dma_flag == DMA_TX_END) {
+ sport->uart_tx_dma_flag = DMA_TX_XMIT;
+ tx_count = 0;
+ head = xmit->head;
+ tail = xmit->tail;
+ sport->uart_tx_count = 0;
+ while (head != tail) {
+ *dma_buf = xmit->buf[tail];
+ tail = (tail + 1) & (UART_XMIT_SIZE - 1);
+ dma_buf++;
+ tx_count++;
+ sport->uart_tx_count++;
+
+ if (tx_count == UART_BUFFER_SIZE)
+ break;
+ }
+ DMA_TX_START(sport, sport->uart_tx_dma_phy0_org, tx_count);
+ }
+ } else {
+ while ((uart->urfidx & 0x1F) < 16) {
+ if (uart_circ_empty(xmit))
+ break;
+
+ if (uart->urusr & URUSR_TXDBSY)
+ continue;
+ uart->urtxf[0] = xmit->buf[xmit->tail];
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ sport->port.icount.tx++;
+ }
+
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ if (uart_circ_empty(xmit))
+ wmt_stop_tx(&sport->port);
+ }
+
+}
+#endif
+
+static irqreturn_t wmt_int(int irq, void *dev_id)
+{
+ struct wmt_port *sport = dev_id;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ unsigned int status, pass_counter = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ /*
+ * Put interrupts status information to status bit[0:15]
+ * Put UART status register to status bit[16:31].
+ */
+
+ status = URISR_TO_SM(uart->urisr) | URUSR_TO_SM(uart->urusr);
+ uart->urisr |= SM_TO_URISR(status);
+
+ do {
+ /*
+ * First, we handle RX events.
+ *
+ * RX FIFO Almost Full. (URUSR_RXFAF)
+ * RX Timeout. (URISR_RXTOUT)
+ * Frame error (URISR_FER)
+ *
+ * Note that also allow URISR_FER and URISR_PER event to do rx.
+ */
+
+ if (status & URISR_TO_SM(URISR_RXFAF | URISR_RXFF | URISR_RXTOUT |\
+ URISR_PER | URISR_FER)) {
+
+ if ((unsigned int)(sport->port.membase) == UART0_BASE_ADDR)
+ wmt_rx_chars(sport, status);
+
+ if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) {
+ uart->urier = 0; /*close uart rx interruption */
+ uart->urisr |= SM_TO_URISR(status); /* clear uart rx int status */
+ sport->uart_rx_dma_flag = 0;
+ mod_timer(&sport->rx_timer, jiffies + rx_timeout);
+ break;
+ }
+ }
+ /*
+ * Second, we handle TX events.
+ *
+ * If there comes a TX FIFO Almost event, try to fill TX FIFO.
+ */
+
+#ifndef CONFIG_SERIAL_WMT_DMA
+ wmt_tx_chars(sport);
+#else
+ if ((unsigned int)(sport->port.membase) == UART0_BASE_ADDR)
+ wmt_tx_chars(sport);
+#endif
+ if (pass_counter++ > WMT_ISR_PASS_LIMIT)
+ break;
+
+ /*
+ * Update UART interrupt status and general status information.
+ */
+ status = (URISR_TO_SM(uart->urisr) | URUSR_TO_SM(uart->urusr));
+ uart->urisr |= SM_TO_URISR(status);
+
+ /*
+ * Inside the loop, we handle events that we're interesting.
+ */
+ status &= sport->port.read_status_mask;
+
+ /*
+ * Continue loop while following condition:
+ *
+ * TX FIFO Almost Empty. (URISR_TXFAE)
+ * RX FIFO Almost Full. (URISR_RXFAF)
+ * RX Receive Time Out. (URISR_RXTOUT)
+ */
+ } while (status & (URISR_TXFE |
+ URISR_TXFAE |
+ URISR_RXFAF |
+ URISR_RXFF |
+ URISR_RXTOUT |
+ URISR_RXDOVR));
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ return IRQ_HANDLED;
+}
+
+/* wmt_tx_empty()
+ *
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int wmt_tx_empty(struct uart_port *port)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+
+ return (uart->urusr & URUSR_TXDBSY) ? 0 : TIOCSER_TEMT;
+}
+
+/* wmt_get_mctrl()
+ *
+ * Returns the current state of modem control inputs.
+ *
+ * Note: Only support CTS now.
+ */
+static u_int wmt_get_mctrl(struct uart_port *port)
+{
+ u_int ret = TIOCM_DSR | TIOCM_CAR;
+ struct wmt_port *sport = (struct wmt_port *)port;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+
+ ret |= (uart->urusr & URUSR_CTS) ? TIOCM_CTS : 0;
+
+ return ret;
+}
+
+/* wmt_set_mctrl()
+ *
+ * This function sets the modem control lines for port described
+ * by 'port' to the state described by mctrl. More detail please
+ * refer to Documentation/serial/driver.
+ *
+ * Note: Only support RTS now.
+ */
+static void wmt_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+
+ if (mctrl & TIOCM_RTS)
+ uart->urlcr |= URLCR_RTS;
+ else
+ uart->urlcr &= ~URLCR_RTS;
+
+}
+
+/*
+ * Interrupts always disabled.
+ */
+static void wmt_break_ctl(struct uart_port *port, int break_state)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ if (break_state == -1) {
+ int i;
+ unsigned int urbrd = URBRD_BRD(uart->urdiv);
+
+ /*
+ * This looks something tricky.
+ * Anyway, we need to get current baud rate divisor,
+ * search bcv in baud_table[], program it into
+ * URBKR, then generate break signal.
+ */
+ for (i = 0; i < BAUD_TABLE_SIZE; i++) {
+ if ((baud_table[i].brd & URBRD_BRDMASK) == urbrd)
+ break;
+ }
+
+ if (i < BAUD_TABLE_SIZE) {
+ uart->urbkr = URBKR_BCV(baud_table[i].bcv);
+ uart->urlcr |= URLCR_BKINIT;
+ }
+ }
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static char *wmt_uartname[] = {
+ "uart0",
+ "uart1",
+#ifdef CONFIG_UART_2_3_ENABLE
+ "uart2",
+ "uart3",
+#endif
+};
+
+#ifdef CONFIG_SERIAL_WMT_DMA
+static void uart_dma_callback_rx(void *data)
+{
+ struct wmt_port *sport = data;
+#ifdef UART_DEBUG
+ static int out_range =0x00;
+ if(dma_write_index >=4096){
+ printk("out of 4096\n");
+ dma_write_index = 0x00;
+ out_range++;
+ }
+#endif
+ if (sport->buffer_used == 0) {
+ sport->buffer_used = 1;
+ DMA_RX_START(sport, sport->uart_rx_dma_phy0_org, UART_BUFFER_SIZE);
+ } else if (sport->buffer_used == 1) {
+ sport->buffer_used = 2;
+ DMA_RX_START(sport, sport->uart_rx_dma_phy1_org, UART_BUFFER_SIZE);
+ } else if (sport->buffer_used == 2) {
+ sport->buffer_used = 0;
+ DMA_RX_START(sport, sport->uart_rx_dma_phy2_org, UART_BUFFER_SIZE);
+ }
+#ifdef UART_DEBUG
+ DMA_pbuf[dma_write_index] = sport->buffer_used + (out_range<<24);
+ //printk("0x%x dma rx DMA_pbuf[%d]:0x%x\n",(unsigned int)DMA_pbuf,dma_write_index,DMA_pbuf[dma_write_index]);
+ if(sport->buffer_rx_count_selected == 0){
+ COUNT_pbuf[dma_write_index] = sport->uart_dma_tmp_phy0;
+ }else if(sport->buffer_rx_count_selected == 1) {
+ COUNT_pbuf[dma_write_index] = sport->uart_dma_tmp_phy1;
+ }else if(sport->buffer_rx_count_selected == 2) {
+ COUNT_pbuf[dma_write_index] = sport->uart_dma_tmp_phy2;
+ }
+
+ if(sport->buffer_selected == 0){
+ CPU_pbuf[dma_write_index] = sport->uart_dma_tmp_buf0;
+ }else if(sport->buffer_selected == 1){
+ CPU_pbuf[dma_write_index] = sport->uart_dma_tmp_buf1;
+ }else if(sport->buffer_selected == 2){
+ CPU_pbuf[dma_write_index] = sport->uart_dma_tmp_buf2;
+ }
+ dma_write_index++;
+#endif
+
+}
+#ifdef UART_DEBUG
+void print_dma_count_cpu_buf_pos(struct wmt_port *sport)
+{
+ int i;
+ for(i=0;i<UART_BUFFER_SIZE;i++){
+ //printk("0x%x DMA_pbuf[%d]:0x%x\n",DMA_pbuf,i,DMA_pbuf[i]);
+ if(DMA_pbuf[i] == 0x5a5a5a5a)
+ break;
+ printk("dma buf index:0x%x ",DMA_pbuf[i]);
+ if((sport->uart_rx_dma_phy0_org <= COUNT_pbuf[i]) && (COUNT_pbuf[i] <= (sport->uart_rx_dma_phy0_org+UART_BUFFER_SIZE))){
+ printk("count buf index:0x00 offset:0x%x ",COUNT_pbuf[i]-sport->uart_rx_dma_phy0_org);
+ }else if((sport->uart_rx_dma_phy1_org <= COUNT_pbuf[i]) && (COUNT_pbuf[i] <= (sport->uart_rx_dma_phy1_org+UART_BUFFER_SIZE))){
+ printk("count buf index:0x01 offset:0x%x ",COUNT_pbuf[i]-sport->uart_rx_dma_phy1_org);
+ }if((sport->uart_rx_dma_phy2_org <= COUNT_pbuf[i]) && (COUNT_pbuf[i] <= (sport->uart_rx_dma_phy2_org+UART_BUFFER_SIZE))){
+ printk("count buf index:0x02 offset:0x%x ",COUNT_pbuf[i]-sport->uart_rx_dma_phy2_org);
+ }
+
+ if((sport->uart_rx_dma_buf0_org <= CPU_pbuf[i]) && (CPU_pbuf[i] <= (sport->uart_rx_dma_buf0_org+UART_BUFFER_SIZE))){
+ printk("cpu buf index:0x00 offset:0x%x\n",CPU_pbuf[i]-(unsigned int)sport->uart_rx_dma_buf0_org);
+ }else if((sport->uart_rx_dma_buf1_org <= CPU_pbuf[i]) && (CPU_pbuf[i] <= (sport->uart_rx_dma_buf1_org+UART_BUFFER_SIZE))){
+ printk("cpu buf index:0x01 offset:0x%x\n",CPU_pbuf[i]-(unsigned int)sport->uart_rx_dma_buf1_org);
+ }if((sport->uart_rx_dma_buf2_org <= CPU_pbuf[i]) && (CPU_pbuf[i] <= (sport->uart_rx_dma_buf2_org+UART_BUFFER_SIZE))){
+ printk("cpu buf index:0x02 offset:0x%x\n",CPU_pbuf[i]-(unsigned int)sport->uart_rx_dma_buf2_org);
+ }
+ printk("\n");
+ }
+}
+#endif
+static void uart_dma_callback_tx(void *data)
+{
+ struct wmt_port *sport = data;
+ unsigned long flags;
+ sport->dma_tx_cnt++;
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ if (sport->uart_tx_dma_flag == DMA_TX_CHAR) {
+ sport->port.icount.tx++;
+ sport->port.x_char = 0;
+ } else {
+ sport->port.state->xmit.tail =
+ (sport->port.state->xmit.tail + sport->uart_tx_count) & (UART_XMIT_SIZE - 1);
+ sport->port.icount.tx += sport->uart_tx_count;
+ }
+ sport->uart_tx_dma_flag = DMA_TX_END;
+
+ wmt_tx_chars(sport);
+
+ if (uart_circ_chars_pending(&sport->port.state->xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ if (uart_circ_empty(&sport->port.state->xmit))
+ wmt_stop_tx(&sport->port);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+}
+#endif
+
+wmt_uart1_pre_init(void)
+{
+ GPIO_CTRL_GP18_UART_BYTE_VAL &= ~(BIT4 | BIT5);
+ auto_pll_divisor(DEV_UART1, CLK_ENABLE, 0, 0);
+ printk("wmt_uart1_pre_init\n");
+}
+
+wmt_uart1_post_deinit(void)
+{
+ GPIO_CTRL_GP18_UART_BYTE_VAL |= (BIT4 | BIT5);
+ auto_pll_divisor(DEV_UART1, CLK_DISABLE, 0, 0);
+ printk("wmt_uart1_post_deinit\n");
+}
+
+static int wmt_startup(struct uart_port *port)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ char *uartname = NULL;
+ int retval;
+ int i;
+ unsigned long flags;
+
+ switch (sport->port.irq) {
+
+ case IRQ_UART0:
+ uartname = wmt_uartname[0];
+/*#ifdef CONFIG_SERIAL_WMT_DMA
+ sport->port.dma_rx_dev = UART_0_RX_DMA_REQ;
+ sport->port.dma_tx_dev = UART_0_TX_DMA_REQ;
+ sport->id = "uart0";
+ sport->port.dma_rx_cfg = dma_device_cfg_table[UART_0_RX_DMA_REQ];
+ sport->port.dma_tx_cfg = dma_device_cfg_table[UART_0_TX_DMA_REQ];
+#endif*/
+ break;
+
+ case IRQ_UART1:
+ wmt_uart1_pre_init();//added by rubbitxiao
+ uartname = wmt_uartname[1];
+#ifdef CONFIG_SERIAL_WMT_DMA
+ sport->dma_rx_dev = UART_1_RX_DMA_REQ;
+ sport->dma_tx_dev = UART_1_TX_DMA_REQ;
+ sport->id = "uart1";
+ sport->dma_rx_cfg = dma_device_cfg_table[UART_1_RX_DMA_REQ];
+ sport->dma_tx_cfg = dma_device_cfg_table[UART_1_TX_DMA_REQ];
+#endif
+ break;
+
+#ifdef CONFIG_UART_2_3_ENABLE
+ case IRQ_UART2:
+ uartname = wmt_uartname[2];
+#ifdef CONFIG_SERIAL_WMT_DMA
+ sport->dma_rx_dev = UART_2_RX_DMA_REQ;
+ sport->dma_tx_dev = UART_2_TX_DMA_REQ;
+ sport->id = "uart2";
+ sport->dma_rx_cfg = dma_device_cfg_table[UART_2_RX_DMA_REQ];
+ sport->dma_tx_cfg = dma_device_cfg_table[UART_2_TX_DMA_REQ];
+#endif
+ break;
+ case IRQ_UART3:
+ uartname = wmt_uartname[3];
+#ifdef CONFIG_SERIAL_WMT_DMA
+ sport->dma_rx_dev = UART_3_RX_DMA_REQ;
+ sport->dma_tx_dev = UART_3_TX_DMA_REQ;
+ sport->id = "uart3";
+ sport->dma_rx_cfg = dma_device_cfg_table[UART_3_RX_DMA_REQ];
+ sport->dma_tx_cfg = dma_device_cfg_table[UART_3_TX_DMA_REQ];
+#endif
+ break;
+#endif
+
+ }
+#ifdef CONFIG_SERIAL_WMT_DMA
+ if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) {
+ memset(sport->uart_rx_dma_buf0_org, 0x0, UART_BUFFER_SIZE);
+ memset(sport->uart_rx_dma_buf1_org, 0x0, UART_BUFFER_SIZE);
+ memset(sport->uart_rx_dma_buf2_org, 0x0, UART_BUFFER_SIZE);
+ memset(sport->uart_tx_dma_buf0_org, 0x0, UART_BUFFER_SIZE);
+ sport->uart_dma_tmp_buf0 = sport->uart_rx_dma_buf0_org;
+ sport->uart_dma_tmp_phy0 = sport->uart_rx_dma_phy0_org;
+ sport->uart_dma_tmp_buf1 = sport->uart_rx_dma_buf1_org;
+ sport->uart_dma_tmp_buf2 = sport->uart_rx_dma_buf2_org;
+ sport->uart_dma_tmp_phy1 = sport->uart_rx_dma_phy1_org;
+ sport->uart_dma_tmp_phy2 = sport->uart_rx_dma_phy2_org;
+ sport->buffer_used = 0; /*to record which buf DMA hardware used*/
+ sport->buffer_selected = 0; /* to record which buf software is used to put data to kernel*/
+ sport->buffer_rx_count_selected = 0; /* to record which buf rx_count is used*/
+ sport->rx_dmach = NULL_DMA;
+ sport->tx_dmach = NULL_DMA;
+ sport->last_pos = 0;
+ sport->uart_tx_dma_flag = DMA_TX_END;
+ sport->uart_tx_count = 0;
+ sport->dma_tx_cnt = 0x00;
+ init_timer(&sport->rx_timer);
+ sport->rx_timer.function = wmt_rx_timeout;
+ sport->rx_timer.data = (unsigned long)sport;
+ DMA_RX_REQUEST(sport, uart_dma_callback_rx);
+ DMA_TX_REQUEST(sport, uart_dma_callback_tx);
+ wmt_setup_dma(sport->rx_dmach, sport->dma_rx_cfg);
+ wmt_setup_dma(sport->tx_dmach, sport->dma_tx_cfg);
+ DMA_RX_START(sport, sport->uart_rx_dma_phy0_org, UART_BUFFER_SIZE);
+ DMA_RX_START(sport, sport->uart_rx_dma_phy1_org, UART_BUFFER_SIZE);
+ DMA_RX_START(sport, sport->uart_rx_dma_phy2_org, UART_BUFFER_SIZE);
+#ifdef UART_DEBUG
+ DMA_pbuf = kmalloc(UART_BUFFER_SIZE*sizeof(unsigned int*), GFP_KERNEL);
+ COUNT_pbuf = kmalloc(UART_BUFFER_SIZE*sizeof(unsigned int*), GFP_KERNEL);
+ CPU_pbuf = kmalloc(UART_BUFFER_SIZE*sizeof(unsigned int*), GFP_KERNEL);
+ if(!DMA_pbuf || !COUNT_pbuf || !CPU_pbuf){
+ printk("kmalloc buf for debug buf failed\n");
+ return;
+ }else{
+ memset(DMA_pbuf,0x5a,UART_BUFFER_SIZE*sizeof(unsigned int*));
+ memset(COUNT_pbuf,0x00,UART_BUFFER_SIZE*sizeof(unsigned int*));
+ memset(CPU_pbuf,0x00,UART_BUFFER_SIZE*sizeof(unsigned int*));
+ }
+ dma_write_index =0x00;
+#endif
+ {
+ char uboot_buf[256];
+ int varlen = sizeof(uboot_buf);
+ if(wmt_getsyspara("wmt.bt.tty",uboot_buf,&varlen) == 0)
+ {
+ sscanf(uboot_buf,"%d",&mtk6622_tty);
+ printk("mtk6622_tty:%d\n",mtk6622_tty);
+ if(1<=mtk6622_tty && mtk6622_tty <=3){
+ printk("wmt.bt.tty is correct\n");
+ }else{
+ printk("wmt.bt.tty is illegal\n");
+ mtk6622_tty = -1;
+ }
+ }else{
+ printk("have not set uboot variant:wmt.bt.tty\n");
+ }
+ }
+ }
+#endif
+ /*
+ * Allocate the IRQ
+ */
+ retval = request_irq(sport->port.irq, wmt_int, 0, uartname, sport);
+ if (retval)
+ return retval;
+
+ /*
+ * Setup the UART clock divisor
+ */
+ for (i = 0; i < BAUD_TABLE_SIZE; i++) {
+ if (baud_table[i].baud == 115200)
+ break;
+ }
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ uart->urdiv = baud_table[i].brd;
+
+ /* Disable TX,RX*/
+ uart->urlcr = 0;
+ /* Disable all interrupt*/
+ uart->urier = 0;
+
+ /*Reset TX,RX Fifo*/
+ uart->urfcr = URFCR_TXFRST | URFCR_RXFRST;
+
+ while (uart->urfcr)
+ ;
+
+ /* Disable Fifo*/
+ uart->urfcr &= ~(URFCR_FIFOEN);
+
+ uart->urlcr |= (URLCR_DLEN & ~URLCR_STBLEN & ~URLCR_PTYEN);
+#ifdef CONFIG_SERIAL_WMT_DMA
+ if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) {
+ uart->urfcr = URFCR_FIFOEN | URFCR_TXFLV(8) | URFCR_RXFLV(1) | URFCR_TRAIL;
+ uart->urtod = 0x0a;
+ } else
+ uart->urfcr = URFCR_FIFOEN | URFCR_TXFLV(8) | URFCR_RXFLV(4);
+#else
+ /* Enable Fifo, Tx 16 , Rx 16*/
+ uart->urfcr = URFCR_FIFOEN | URFCR_TXFLV(8) | URFCR_RXFLV(4);
+#endif
+ /* Enable Fifo, Tx 8 , Rx 8*/
+#ifdef CONFIG_SERIAL_WMT_DMA
+ if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) {
+ uart->urlcr |= URLCR_RXEN | URLCR_TXEN | URLCR_DMAEN | URLCR_RCTSSW;
+ uart->urier = URIER_ERXFAF | URIER_ERXFF | URIER_ERXTOUT |
+ URIER_EPER | URIER_EFER | URIER_ERXDOVR;
+ } else {
+ uart->urlcr |= URLCR_RXEN | URLCR_TXEN | URLCR_RCTSSW;
+ uart->urier = URIER_ERXFAF | URIER_ERXFF | URIER_ERXTOUT |
+ URIER_EPER | URIER_EFER | URIER_ERXDOVR;
+ }
+#else
+ uart->urlcr |= URLCR_RXEN | URLCR_TXEN | URLCR_RCTSSW;
+ uart->urier = URIER_ERXFAF | URIER_ERXFF | URIER_ERXTOUT | URIER_EPER |
+ URIER_EFER | URIER_ERXDOVR;
+
+#endif
+ /*
+ * Enable RX FIFO almost full, timeout, and overrun interrupts.
+ */
+
+ /*
+ * Enable modem status interrupts
+ */
+
+ wmt_enable_ms(&sport->port);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ return 0;
+}
+
+static void wmt_shutdown(struct uart_port *port)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ unsigned long flags;
+ //added begin by rubbitxiao
+ spin_lock_irqsave(&sport->port.lock, flags);
+ /* Disable TX,RX*/
+ uart->urlcr = 0;
+ /* Disable all interrupt*/
+ uart->urier = 0;
+ /*Reset TX,RX Fifo*/
+ uart->urfcr = URFCR_TXFRST | URFCR_RXFRST;
+ while (uart->urfcr)
+ ;
+ /* Disable Fifo*/
+ uart->urfcr &= ~(URFCR_FIFOEN);
+ uart->urlcr |= (URLCR_DLEN & ~URLCR_STBLEN & ~URLCR_PTYEN);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ //added end by rubbitxiao
+ /*
+ * Stop our timer.
+ */
+ del_timer_sync(&sport->timer);
+
+ /*
+ * Free the allocated interrupt
+ */
+ free_irq(sport->port.irq, sport);
+
+ /*
+ * Disable all interrupts, port and break condition.
+ */
+ //spin_lock_irqsave(&sport->port.lock, flags);
+ //uart->urier &= ~(URIER_ETXFE | URIER_ETXFAE | URIER_ERXFF | URIER_ERXFAF);
+ //spin_unlock_irqrestore(&sport->port.lock, flags);
+
+#ifdef CONFIG_SERIAL_WMT_DMA
+ if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) {
+ del_timer_sync(&sport->rx_timer);
+ DMA_RX_STOP(sport);
+ DMA_RX_CLEAR(sport);
+ DMA_RX_FREE(sport);
+ while (sport->uart_tx_dma_flag != DMA_TX_END)
+ msleep(1);
+
+ DMA_TX_STOP(sport);
+ DMA_TX_CLEAR(sport);
+ DMA_TX_FREE(sport);
+ }
+#endif
+ if ((unsigned int)(sport->port.membase) == UART1_BASE_ADDR)
+ wmt_uart1_post_deinit();
+}
+
+/* wmt_uart_pm()
+ *
+ * Switch on/off uart in powersave mode.
+ *
+ * Hint: Identify port by irq number.
+ */
+static void wmt_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
+{
+ return;
+}
+
+static void
+wmt_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ unsigned long flags;
+ unsigned int new_urlcr, old_urlcr, old_urier, tmp_urisr, baud;
+ unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+ int i;
+
+ /*
+ * If we don't support modem control lines, don't allow
+ * these to be set.
+ */
+ if (0) {
+ termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
+ termios->c_cflag |= CLOCAL;
+ }
+ /*
+ * Only support CS7 and CS8.
+ */
+ while ((termios->c_cflag & CSIZE) != CS7 && (termios->c_cflag & CSIZE) != CS8) {
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= old_csize;
+ old_csize = CS8;
+ }
+
+ if ((termios->c_cflag & CSIZE) == CS8)
+ new_urlcr = URLCR_DLEN;
+ else
+ new_urlcr = 0;
+
+ if (termios->c_cflag & CRTSCTS)
+ new_urlcr &= ~URLCR_RCTSSW;
+ else
+ new_urlcr |= URLCR_RCTSSW;
+
+ if (termios->c_cflag & CSTOPB)
+ new_urlcr |= URLCR_STBLEN;
+
+ if (termios->c_cflag & PARENB) {
+ /*
+ * Enable parity.
+ */
+ new_urlcr |= URLCR_PTYEN;
+
+ /*
+ * Parity mode select.
+ */
+ if (termios->c_cflag & PARODD)
+ new_urlcr |= URLCR_PTYMODE;
+ }
+
+ /*
+ * Ask the core to get baud rate, but we need to
+ * calculate quot by ourself.
+ */
+ baud = uart_get_baud_rate(port, termios, old, 9600, 921600);
+
+ /*
+ * We need to calculate quot by ourself.
+ *
+ * FIXME: Be careful, following result is not an
+ * interger quotient, fix it if need.
+ */
+ /*quot = port->uartclk / (13 * baud);*/
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ /*
+ * Mask out other interesting to listen expect TX FIFO almost empty event.
+ */
+ sport->port.read_status_mask &= URISR_TO_SM(URISR_TXFAE | URISR_TXFE);
+
+ /*
+ * We're also interested in receiving RX FIFO events.
+ */
+ sport->port.read_status_mask |= URISR_TO_SM(URISR_RXDOVR | URISR_RXFAF | URISR_RXFF);
+
+ /*
+ * Check if we need to enable frame and parity error events
+ * to be passed to the TTY layer.
+ */
+ if (termios->c_iflag & INPCK)
+ sport->port.read_status_mask |= URISR_TO_SM(URISR_FER | URISR_PER);
+
+#ifdef CONFIG_SERIAL_WMT_BKSIG
+ /*
+ * check if we need to enable break events to be passed to the TTY layer.
+ */
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ /*
+ * WMT UART doesn't support break signal detection interrupt.
+ *
+ * I try to implement this using URISR_FER.
+ */
+ sport->port.read_status_mask |= SW_BKSIG;
+#endif
+ /*
+ * Characters to ignore
+ */
+ sport->port.ignore_status_mask = 0;
+
+ if (termios->c_iflag & IGNPAR)
+ sport->port.ignore_status_mask |= URISR_TO_SM(URISR_FER | URISR_PER);
+
+ if (termios->c_iflag & IGNBRK) {
+#ifdef CONFIG_SERIAL_WMT_BKSIG
+ /*
+ * WMT UART doesn't support break signal detection interrupt.
+ *
+ * I try to implement this using URISR_FER.
+ */
+ sport->port.ignore_status_mask |= BIT31;/*FIXME*/
+#endif
+
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ sport->port.ignore_status_mask |= URISR_TO_SM(URISR_RXDOVR);
+ }
+
+ del_timer_sync(&sport->timer);
+
+ /*
+ * Update the per-port timeout.
+ */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ /*
+ * Disable FIFO request interrupts and drain transmitter
+ */
+ old_urlcr = uart->urlcr;
+ old_urier = uart->urier;
+ uart->urier = old_urier & ~(URIER_ETXFAE | URIER_ERXFAF);
+
+ /*
+ * Two step polling, first step polling the remaining
+ * entries in TX FIFO. This step make it safe to drain
+ * out all of remaining data in FIFO.
+ */
+ while (URFIDX_TXFIDX(uart->urfidx))
+ barrier();
+
+ /*
+ * Second step to make sure the last one data has been sent.
+ */
+ while (uart->urusr & URUSR_TXDBSY)
+ barrier();
+
+ /*
+ * Disable this UART port.
+ */
+ uart->urier = 0;
+
+ /*
+ * Set the parity, stop bits and data size
+ */
+ uart->urlcr = new_urlcr;
+
+ /*
+ * Set baud rate
+ */
+
+ for (i = 0; i < BAUD_TABLE_SIZE; i++) {
+ if (baud_table[i].baud == baud)
+ break;
+ }
+ uart->urdiv = baud_table[i].brd;
+
+ /*
+ * Read to clean any pending pulse interrupts.
+ */
+ tmp_urisr = uart->urisr;
+
+ /*
+ * Restore FIFO interrupt, TXEN bit, RXEN bit settings.
+ */
+ uart->urier = old_urier;
+#ifdef CONFIG_SERIAL_WMT_DMA
+ uart->urlcr |= old_urlcr & (URLCR_TXEN | URLCR_RXEN | URLCR_DMAEN);
+#else
+ uart->urlcr |= old_urlcr & (URLCR_TXEN | URLCR_RXEN);
+#endif
+
+ if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
+ wmt_enable_ms(&sport->port);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static const char *wmt_type(struct uart_port *port)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+
+ return (sport->port.type == PORT_WMT) ? "wmt serial" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void wmt_release_port(struct uart_port *port)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+
+ release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int wmt_request_port(struct uart_port *port)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+
+ return request_mem_region(sport->port.mapbase,
+ UART_PORT_SIZE,
+ "uart") != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void wmt_config_port(struct uart_port *port, int flags)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+
+ if (flags & UART_CONFIG_TYPE && wmt_request_port(&sport->port) == 0)
+ sport->port.type = PORT_WMT;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_WMT and PORT_UNKNOWN
+ */
+static int wmt_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ struct wmt_port *sport = (struct wmt_port *)port;
+ int ret = 0;
+
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_WMT)
+ ret = -EINVAL;
+ if (sport->port.irq != ser->irq)
+ ret = -EINVAL;
+ if (ser->io_type != SERIAL_IO_MEM)
+ ret = -EINVAL;
+ if (sport->port.uartclk / 16 != ser->baud_base)
+ ret = -EINVAL;
+
+ if ((void *)sport->port.mapbase != ser->iomem_base)
+ ret = -EINVAL;
+ if (sport->port.iobase != ser->port)
+ ret = -EINVAL;
+ if (ser->hub6 != 0)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops wmt_pops = {
+ .tx_empty = wmt_tx_empty,
+ .set_mctrl = wmt_set_mctrl,
+ .get_mctrl = wmt_get_mctrl,
+ .stop_tx = wmt_stop_tx,
+ .start_tx = wmt_start_tx,
+ .stop_rx = wmt_stop_rx,
+ .enable_ms = wmt_enable_ms,
+ .break_ctl = wmt_break_ctl,
+ .startup = wmt_startup,
+ .shutdown = wmt_shutdown,
+ .pm = wmt_uart_pm,
+ .set_termios = wmt_set_termios,
+ .type = wmt_type,
+ .release_port = wmt_release_port,
+ .request_port = wmt_request_port,
+ .config_port = wmt_config_port,
+ .verify_port = wmt_verify_port,
+};
+
+static int parse_spi1_param(void)
+{
+ char buf[64];
+ size_t l = sizeof(buf);
+ int uart_spi_sel = 0;
+
+ if (wmt_getsyspara("wmt.spi1.param", buf, &l) == 0) {
+ sscanf(buf, "%d", &uart_spi_sel);
+ }
+ return uart_spi_sel;
+}
+
+/* Setup the WMT serial ports. Note that we don't include the IrDA
+ * port here since we have our own SIR/FIR driver (see drivers/net/irda)
+ *
+ * Note also that we support "console=ttyVTx" where "x" is either 0 to 2.
+ * Which serial port this ends up being depends on the machine you're
+ * running this kernel on.
+ */
+static void wmt_init_ports(void)
+{
+ static int first = 1;
+ int i;
+
+ if (!first)
+ return;
+
+ first = 0;
+
+ wmt_uart_spi_sel = parse_spi1_param();
+
+ for (i = 0; i < NR_PORTS; i++) {
+ wmt_ports[i].port.uartclk = 24000000;
+ wmt_ports[i].port.ops = &wmt_pops;
+ wmt_ports[i].port.fifosize = 16;
+ wmt_ports[i].port.line = i;
+ wmt_ports[i].port.iotype = SERIAL_IO_MEM;
+ init_timer(&wmt_ports[i].timer);
+ wmt_ports[i].timer.function = wmt_timeout;
+ wmt_ports[i].timer.data = (unsigned long)&wmt_ports[i];
+ }
+
+ /*
+ * Make sure all UARTs are not configured as GPIO function.
+ *
+ * This step may be redundant due to bootloader has already
+ * done this for us.
+ */
+
+
+ /* Switch the Uart's pin from default GPIO into uart function pins for UART0 ~ UART3 */
+ GPIO_CTRL_GP18_UART_BYTE_VAL &= ~(BIT0 | BIT1 | BIT2 | BIT3 |
+ BIT4 | BIT5 | BIT6 | BIT7); /*UART0 UART1*/
+#ifdef CONFIG_UART_2_3_ENABLE
+ GPIO_CTRL_GP18_UART_BYTE_VAL &= ~(BIT2 | BIT3 | BIT6 | BIT7); /*UART2 UART3*/
+#endif
+
+ /*Set Uart0 and Uart1, Uart2 and Uart3 pin share*/
+ PIN_SHARING_SEL_4BYTE_VAL &= ~(BIT9 | BIT8);
+ if (wmt_uart_spi_sel == SHARE_PIN_UART)
+ PIN_SHARING_SEL_4BYTE_VAL &= ~(BIT10);
+
+#ifdef CONFIG_UART_2_3_ENABLE
+ //kevin modify uart0,uart1(hw flow control),uart2
+ PIN_SHARING_SEL_4BYTE_VAL |= (BIT8);
+#endif
+
+ auto_pll_divisor(DEV_UART0, CLK_ENABLE, 0, 0);
+ auto_pll_divisor(DEV_UART1, CLK_ENABLE, 0, 0);
+#ifdef CONFIG_UART_2_3_ENABLE
+ auto_pll_divisor(DEV_UART2, CLK_ENABLE, 0, 0);
+ auto_pll_divisor(DEV_UART3, CLK_ENABLE, 0, 0);
+#endif
+}
+
+void __init wmt_register_uart_fns(struct wmt_port_fns *fns)
+{
+ if (fns->get_mctrl)
+ wmt_pops.get_mctrl = fns->get_mctrl;
+ if (fns->set_mctrl)
+ wmt_pops.set_mctrl = fns->set_mctrl;
+
+ wmt_pops.pm = fns->pm;
+ wmt_pops.set_wake = fns->set_wake;
+}
+
+void __init wmt_register_uart(int idx, int port)
+{
+ if (idx >= NR_PORTS) {
+ printk(KERN_ERR "%s: bad index number %d\n", __func__, idx);
+ return;
+ }
+
+ switch (port) {
+ case 0:
+ wmt_ports[idx].port.membase = (void *)(REG32_PTR(UART0_BASE_ADDR));
+ wmt_ports[idx].port.mapbase = UART0_BASE_ADDR;
+ wmt_ports[idx].port.irq = IRQ_UART0;
+ wmt_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF;
+ break;
+ case 1:
+ wmt_ports[idx].port.membase = (void *)(REG32_PTR(UART1_BASE_ADDR));
+ wmt_ports[idx].port.mapbase = UART1_BASE_ADDR;
+ wmt_ports[idx].port.irq = IRQ_UART1;
+ wmt_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF;
+ break;
+#ifdef CONFIG_UART_2_3_ENABLE
+ case 2:
+ wmt_ports[idx].port.membase = (void *)(REG32_PTR(UART2_BASE_ADDR));
+ wmt_ports[idx].port.mapbase = UART2_BASE_ADDR;
+ wmt_ports[idx].port.irq = IRQ_UART2;
+ wmt_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF;
+ break;
+ case 3:
+ wmt_ports[idx].port.membase = (void *)(REG32_PTR(UART3_BASE_ADDR));
+ wmt_ports[idx].port.mapbase = UART3_BASE_ADDR;
+ wmt_ports[idx].port.irq = IRQ_UART3;
+ wmt_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF;
+ break;
+#endif
+
+ default:
+ printk(KERN_ERR "%s: bad port number %d\n", __func__, port);
+ }
+}
+
+#ifdef CONFIG_SERIAL_WMT_CONSOLE
+
+/*
+ * Interrupts are disabled on entering
+ *
+ * Note: We do console writing with UART register mode.
+ */
+
+static void wmt_console_write(struct console *co, const char *s, u_int count)
+{
+ struct wmt_port *sport = &wmt_ports[co->index];
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ unsigned int i, old_urlcr, old_urier;
+ /*{JHT*/
+ unsigned int old_urfcr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ /*}JHT*/
+ /*
+ * First, save URLCR and URIER.
+ */
+ old_urlcr = uart->urlcr;
+ old_urier = uart->urier;
+ /*{JHT*/
+ old_urfcr = uart->urfcr;
+ /*}JHT*/
+
+ /*
+ * Second, switch to register mode with follows method:
+ *
+ * Disable FIFO threshold interrupts, and enable transmitter.
+ */
+ uart->urier &= ~(URIER_ETXFAE | URIER_ERXFAF);
+ uart->urlcr |= URLCR_TXEN;
+ /*{JHT*/
+ uart->urfcr &= ~URFCR_FIFOEN;
+ /*}JHT*/
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++) {
+ /*
+ * Polling until free for transmitting.
+ */
+ while (uart->urusr & URUSR_TXDBSY)
+ ;
+
+ uart->urtdr = (unsigned int)s[i];
+
+ /*
+ * Do CR if there comes a LF.
+ */
+ if (s[i] == '\n') {
+ /*
+ * Polling until free for transmitting.
+ */
+ while (uart->urusr & URUSR_TXDBSY)
+ ;
+
+ uart->urtdr = (unsigned int)'\r';
+ }
+ }
+
+ /*
+ * Finally, wait for transmitting done and restore URLCR and URIER.
+ */
+ while (uart->urusr & URUSR_TXDBSY)
+ ;
+
+ uart->urlcr = old_urlcr;
+ uart->urier = old_urier;
+ /*{JHT*/
+ uart->urfcr = old_urfcr;
+ /*}JHT*/
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader), try to determine
+ * the current setup.
+ */
+static void __init wmt_console_get_options(struct wmt_port *sport, int *baud, int *parity, int *bits)
+{
+ int i;
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+
+ if ((uart->urlcr & (URLCR_RXEN | URLCR_TXEN)) == (URLCR_RXEN | URLCR_TXEN)) {
+ /*
+ * Port was enabled.
+ */
+ unsigned quot;
+
+ *parity = 'n';
+ /*
+ * Check parity mode, 0:evev 1:odd
+ */
+ if (uart->urlcr & URLCR_PTYEN) {
+ if (uart->urlcr & URLCR_PTYMODE)
+ *parity = 'o';
+ else
+ *parity = 'e';
+ }
+
+ /*
+ * Check data length, 0:7-bit 1:8-bit
+ */
+ if (uart->urlcr & URLCR_DLEN)
+ *bits = 8;
+ else
+ *bits = 7;
+
+ /*
+ * Get baud rate divisor.
+ */
+ quot = (uart->urdiv & URBRD_BRDMASK);
+ /*
+ * FIXME: I didn't trace the console driver want me
+ * report baud rate whether actual baud rate or ideal
+ * target baud rate, current I report baud as actual
+ * one, if it need value as target baud rate, just
+ * creat an array to fix it, Dec.23 by Harry.
+ */
+
+ for (i = 0; i < BAUD_TABLE_SIZE; i++) {
+ if ((baud_table[i].brd & URBRD_BRDMASK) == quot) {
+ *baud = baud_table[i].baud;
+ break;
+ }
+ }
+
+ /*
+ * If this condition is true, something might be wrong.
+ * I reprot the actual baud rate temporary.
+ * Check the printk information then fix it.
+ */
+ if (i >= BAUD_TABLE_SIZE)
+ *baud = sport->port.uartclk / (13 * (quot + 1));
+ }
+}
+
+#ifndef CONFIG_WMT_DEFAULT_BAUDRATE
+#define CONFIG_WMT_DEFAULT_BAUDRATE 115200
+#endif
+
+static int __init
+wmt_console_setup(struct console *co, char *options)
+{
+ struct wmt_port *sport;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+ int baud = CONFIG_WMT_DEFAULT_BAUDRATE;
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index == -1 || co->index >= NR_PORTS)
+ co->index = 0;
+
+ sport = &wmt_ports[co->index];
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ wmt_console_get_options(sport, &baud, &parity, &bits);
+
+ return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver wmt_reg;
+
+static struct console wmt_console = {
+
+#ifdef CONFIG_SERIAL_WMT_TTYVT
+ .name = "ttyVT",
+#else
+ .name = "ttyS",
+#endif
+ .write = wmt_console_write,
+ .device = uart_console_device,
+ .setup = wmt_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &wmt_reg,
+};
+
+static int __init wmt_rs_console_init(void)
+{
+ wmt_init_ports();
+ register_console(&wmt_console);
+ return 0;
+}
+
+console_initcall(wmt_rs_console_init);
+
+#define WMT_CONSOLE (&wmt_console)
+
+#else /* CONFIG_SERIAL_WMT_CONSOLE */
+
+#define WMT_CONSOLE NULL
+
+#endif
+
+static struct uart_driver wmt_reg = {
+ .owner = THIS_MODULE,
+
+#ifdef CONFIG_SERIAL_WMT_TTYVT
+ .driver_name = "ttyVT",
+ .dev_name = "ttyVT",
+#else
+ .driver_name = "ttyS",
+ .dev_name = "ttyS",
+#endif
+ .major = SERIAL_WMT_MAJOR,
+ .minor = MINOR_START,
+ .nr = NR_PORTS,
+ .cons = WMT_CONSOLE,
+};
+
+
+void wmt_serial_set_reg(void)
+{
+ *(volatile unsigned int *) (UART0_BASE_ADDR + 0x00000008) = BRD_115200BPS;
+ *(volatile unsigned int *) (UART0_BASE_ADDR + 0x0000000c) = URLCR_TXEN |
+ URLCR_RXEN |
+ URLCR_DLEN |
+ URLCR_RCTSSW;
+
+ *(volatile unsigned int *) (UART0_BASE_ADDR + 0x00000014) = URIER_ERXFAF |
+ URIER_ERXFF |
+ URIER_ERXTOUT |
+ URIER_EPER |
+ URIER_EFER |
+ URIER_ERXDOVR;
+
+ *(volatile unsigned int *) (UART0_BASE_ADDR + 0x00000020) = URFCR_FIFOEN |
+ URFCR_TXFLV(8) |
+ URFCR_RXFLV(8);
+}
+
+static int wmt_serial_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct device *dev = &pdev->dev;
+ struct wmt_port *sport = dev_get_drvdata(dev);
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ unsigned long flags;
+
+ if (sport) {
+ if (sport->port.irq != IRQ_UART0)
+ uart_suspend_port(&wmt_reg, &sport->port);
+ }
+ if (!sport)
+ return 0;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ /* save host register */
+ sport->old_urdiv = uart->urdiv;
+ sport->old_urlcr = uart->urlcr;
+ sport->old_urier = uart->urier;
+ sport->old_urfcr = uart->urfcr;
+ sport->old_urtod = uart->urtod;
+
+ uart->urier = 0;
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ switch (sport->port.irq) {
+ case IRQ_UART0:
+ /*auto_pll_divisor(DEV_UART0, CLK_DISABLE, 0, 0);*/
+ break;
+ case IRQ_UART1:
+ auto_pll_divisor(DEV_UART1, CLK_DISABLE, 0, 0);
+ break;
+#ifdef CONFIG_UART_2_3_ENABLE
+ case IRQ_UART2:
+ auto_pll_divisor(DEV_UART2, CLK_DISABLE, 0, 0);
+ break;
+
+ case IRQ_UART3:
+ auto_pll_divisor(DEV_UART3, CLK_DISABLE, 0, 0);
+ break;
+#endif
+ default:
+ break;
+
+ }
+ return 0;
+}
+
+static int wmt_serial_resume(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct wmt_port *sport = dev_get_drvdata(dev);
+ struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport);
+ unsigned long flags;
+
+ if (!sport)
+ return 0;
+
+ GPIO_CTRL_GP18_UART_BYTE_VAL &= ~(BIT0 | BIT1 | BIT2 | BIT3 |
+ BIT4 | BIT5 | BIT6 | BIT7); /*UART0 UART1*/
+#ifdef CONFIG_UART_2_3_ENABLE
+ GPIO_CTRL_GP18_UART_BYTE_VAL &= ~(BIT2 | BIT3 | BIT6 | BIT7); /*UART2 UART3*/
+#endif
+
+ /*Set Uart0 and Uart1, Uart2 and Uart3 pin share*/
+ PIN_SHARING_SEL_4BYTE_VAL &= ~(BIT9 | BIT8);
+ if (wmt_uart_spi_sel == SHARE_PIN_UART)
+ PIN_SHARING_SEL_4BYTE_VAL &= ~(BIT10);
+
+#ifdef CONFIG_UART_2_3_ENABLE
+ //kevin modify, uart0,uart1(hw flow control),uart2
+ PIN_SHARING_SEL_4BYTE_VAL |= (BIT8);
+#endif
+
+ switch (sport->port.irq) {
+ case IRQ_UART0:
+ auto_pll_divisor(DEV_UART0, CLK_ENABLE, 0, 0);
+ break;
+ case IRQ_UART1:
+ auto_pll_divisor(DEV_UART1, CLK_ENABLE, 0, 0);
+ break;
+#ifdef CONFIG_UART_2_3_ENABLE
+ case IRQ_UART2:
+ auto_pll_divisor(DEV_UART2, CLK_ENABLE, 0, 0);
+ break;
+ case IRQ_UART3:
+ auto_pll_divisor(DEV_UART3, CLK_ENABLE, 0, 0);
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (sport->port.irq != IRQ_UART0) {
+ /* Disable TX,RX */
+ uart->urlcr = 0;
+ /* Disable all interrupt */
+ uart->urier = 0;
+ /* Clear all interrupt */
+ uart->urisr = 0xffffffff;
+
+ /* Disable Fifo */
+ uart->urfcr &= ~(URFCR_FIFOEN);
+
+ /* Reset TX,RX Fifo */
+ uart->urfcr = URFCR_TXFRST | URFCR_RXFRST;
+
+ while (uart->urfcr)
+ ;
+ }
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ /*store back the interrupt enable status*/
+ uart->urdiv = sport->old_urdiv;
+ uart->urfcr = sport->old_urfcr;
+ uart->urtod = sport->old_urtod;
+ uart->urier = sport->old_urier;
+ uart->urlcr = sport->old_urlcr;
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ if (sport) {
+ if (sport->port.irq != IRQ_UART0)
+ uart_resume_port(&wmt_reg, &sport->port);
+
+ }
+
+ return 0;
+}
+#if 1
+void print_dma_position(struct wmt_port *sport)
+{
+ unsigned int *rx_dma = (unsigned int *)(0xfe001904 + (0x20*sport->rx_dmach));
+ printk("address 0x%p = 0x%x(value)\n",rx_dma,*rx_dma);
+}
+
+void print_dma_buf_pointer(struct wmt_port *sport)
+{
+ printk("buf0:0x%p; buf1:0x%p; buf2:0x%p\n",sport->uart_dma_tmp_buf0,sport->uart_dma_tmp_buf1,sport->uart_dma_tmp_buf2);
+ printk("phy0:0x%x; phy1:0x%x; phy2:0x%x\n",sport->uart_dma_tmp_phy0,sport->uart_dma_tmp_phy1,sport->uart_dma_tmp_phy2);
+}
+void dump_uart_info(void)
+{
+ unsigned long flags;
+ struct wmt_port * p_wmt_port = &wmt_ports[1];
+ uart_dump_reg(p_wmt_port);
+ printk("sport1->port.icount.rx0:0x%x,uart_tx_dma_phy0_org:0x%x\n",p_wmt_port->port.icount.rx,p_wmt_port->uart_tx_dma_phy0_org);
+ print_dma_position(p_wmt_port);
+
+ //spin_lock_irqsave(&(p_wmt_port->port.lock), flags);
+ wmt_rx_chars(p_wmt_port,URISR_RXFAF | URISR_RXFF);
+ //spin_unlock_irqrestore(&(p_wmt_port->port.lock), flags);
+
+ print_dma_position(p_wmt_port);
+ printk("sport1->port.icount.rx1:0x%x,uart_tx_dma_phy0_org:0x%x\n",p_wmt_port->port.icount.rx,p_wmt_port->uart_tx_dma_phy0_org);
+ printk("uart rxxx dma channel register:\n");
+ wmt_dump_dma_regs(p_wmt_port->rx_dmach);
+ printk("uart tttx dma channel register:\n");
+ wmt_dump_dma_regs(p_wmt_port->tx_dmach);
+ printk("buf pointer position\n");
+ print_dma_buf_pointer(p_wmt_port);
+ printk("#######################################\n");
+ dump_rx_dma_buf(p_wmt_port);
+#ifdef UART_DEBUG
+ printk("##########################################\n");
+ print_dma_count_cpu_buf_pos(p_wmt_port);
+#endif
+ printk("#############debug dma tx failed begin#############\n");
+ printk("sport->port.icount.tx:0x%x,sport->uart_tx_count:0x%x\n",p_wmt_port->port.icount.tx,
+ p_wmt_port->uart_tx_count);
+ printk("dma_tx_cnt:0x%x\n",p_wmt_port->dma_tx_cnt);
+ printk("uart_tx_dma_flag:0x%x\n",p_wmt_port->uart_tx_dma_flag);
+ printk("uart_tx_stopped:%d\n",uart_tx_stopped(&p_wmt_port->port));
+ if(uart_tx_stopped(&p_wmt_port->port))
+ {
+ printk("stopped:%d\n",(&p_wmt_port->port)->state->port.tty->stopped);
+ printk("hw_stopped:%d\n",(&p_wmt_port->port)->state->port.tty->hw_stopped);
+ }
+ printk("#############debug dma tx failed end#############\n");
+
+}
+EXPORT_SYMBOL(dump_uart_info);
+#endif
+static int wmt_serial_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res = pdev->resource;
+ int i;
+
+ for (i = 0; i < pdev->num_resources; i++, res++)
+ if (res->flags & IORESOURCE_MEM)
+ break;
+
+ if (i < pdev->num_resources) {
+ for (i = 0; i < NR_PORTS; i++) {
+ if (wmt_ports[i].port.mapbase != res->start)
+ continue;
+
+ wmt_ports[i].port.dev = dev;
+ uart_add_one_port(&wmt_reg, &wmt_ports[i].port);
+ dev_set_drvdata(dev, &wmt_ports[i]);
+ if (i >= 1) {
+ wmt_ports[i].uart_rx_dma_buf0_org =
+ dma_alloc_coherent(NULL,
+ UART_BUFFER_SIZE,
+ &wmt_ports[i].uart_rx_dma_phy0_org,
+ GFP_KERNEL);
+ wmt_ports[i].uart_rx_dma_buf1_org =
+ dma_alloc_coherent(NULL,
+ UART_BUFFER_SIZE,
+ &wmt_ports[i].uart_rx_dma_phy1_org,
+ GFP_KERNEL);
+ wmt_ports[i].uart_rx_dma_buf2_org =
+ dma_alloc_coherent(NULL,
+ UART_BUFFER_SIZE,
+ &wmt_ports[i].uart_rx_dma_phy2_org,
+ GFP_KERNEL);
+ wmt_ports[i].uart_tx_dma_buf0_org =
+ dma_alloc_coherent(NULL,
+ UART_BUFFER_SIZE,
+ &wmt_ports[i].uart_tx_dma_phy0_org,
+ GFP_KERNEL);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static int wmt_serial_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct wmt_port *sport = dev_get_drvdata(dev);
+
+ dev_set_drvdata(dev, NULL);
+
+ if (sport)
+ uart_remove_one_port(&wmt_reg, &sport->port);
+
+ return 0;
+}
+
+static struct platform_driver wmt_serial_driver = {
+ .driver.name = "uart",
+ .probe = wmt_serial_probe,
+ .remove = wmt_serial_remove,
+ .suspend = wmt_serial_suspend,
+ .resume = wmt_serial_resume,
+};
+
+static int __init wmt_serial_init(void)
+{
+ int ret;
+
+ wmt_init_ports();
+ ret = uart_register_driver(&wmt_reg);
+
+ if (ret == 0) {
+ ret = platform_driver_register(&wmt_serial_driver);
+ if (ret)
+ uart_unregister_driver(&wmt_reg);
+ }
+#ifndef CONFIG_SKIP_DRIVER_MSG
+ printk(KERN_INFO "WMT Serial driver initialized: %s\n",
+ (ret == 0) ? "ok" : "failed");
+#endif
+ return ret;
+}
+
+static void __exit wmt_serial_exit(void)
+{
+ platform_driver_unregister(&wmt_serial_driver);
+ uart_unregister_driver(&wmt_reg);
+}
+
+module_init(wmt_serial_init);
+module_exit(wmt_serial_exit);
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT [generic serial port] driver");
+MODULE_LICENSE("GPL");