diff options
author | Nitin Kumbhar <nkumbhar@nvidia.com> | 2011-03-07 18:38:30 +0530 |
---|---|---|
committer | Nitin Kumbhar <nkumbhar@nvidia.com> | 2011-03-07 18:38:30 +0530 |
commit | 04db8ee9121dbddcccfa5fb0e0e34b9a5028c6c3 (patch) | |
tree | 2a5e287b5f2b58e98e57406f5f8d1b6f6e6b5a38 /drivers/serial | |
parent | 0355ab1e7e6b3c8bf4ce9414cf0afa00cb4e113f (diff) | |
parent | 07a84a1ce6dae0bd521ac30c56ffc22f31da10b1 (diff) |
merging android-tegra-2.6.36 into git-master/linux-2.6/android-tegra-2.6.36
Conflicts:
arch/arm/mach-tegra/include/mach/system.h
arch/arm/mach-tegra/include/mach/usb_phy.h
arch/arm/mach-tegra/usb_phy.c
drivers/usb/host/ehci-tegra.c
drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/hdmi.c
include/linux/tegra_usb.h
Change-Id: Ic1f4f2b360893e8de6b867a8ecc239aca02367da
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/tegra_hsuart.c | 87 |
1 files changed, 56 insertions, 31 deletions
diff --git a/drivers/serial/tegra_hsuart.c b/drivers/serial/tegra_hsuart.c index b683a3d5d2cd..6c669cb613ec 100644 --- a/drivers/serial/tegra_hsuart.c +++ b/drivers/serial/tegra_hsuart.c @@ -324,6 +324,51 @@ static void do_handle_rx_dma(struct tegra_uart_port *t) set_rts(t, true); } +/* Wait for a symbol-time. */ +static void wait_sym_time(struct tegra_uart_port *t, unsigned int syms) +{ + + /* Definitely have a start bit. */ + unsigned int bits = 1; + switch (t->lcr_shadow & 3) { + case UART_LCR_WLEN5: + bits += 5; + break; + case UART_LCR_WLEN6: + bits += 6; + break; + case UART_LCR_WLEN7: + bits += 7; + break; + default: + bits += 8; + break; + } + + /* Technically 5 bits gets 1.5 bits of stop... */ + if (t->lcr_shadow & UART_LCR_STOP) { + bits += 2; + } else { + bits++; + } + + if (t->lcr_shadow & UART_LCR_PARITY) + bits++; + + if (likely(t->baud)) + udelay(DIV_ROUND_UP(syms * bits * 1000000, t->baud)); +} + +/* Flush desired FIFO. */ +static void tegra_fifo_reset(struct tegra_uart_port *t, u8 fcr_bits) +{ + unsigned char fcr = t->fcr_shadow; + fcr |= fcr_bits & (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + uart_writeb(t, fcr, UART_FCR); + uart_readb(t, UART_SCR); /* Dummy read to ensure the write is posted */ + wait_sym_time(t, 1); /* Wait for the flush to propagate. */ +} + static char do_decode_rx_error(struct tegra_uart_port *t, u8 lsr) { char flag = TTY_NORMAL; @@ -347,11 +392,8 @@ static char do_decode_rx_error(struct tegra_uart_port *t, u8 lsr) dev_err(t->uport.dev, "Got Break\n"); t->uport.icount.brk++; /* If FIFO read error without any data, reset Rx FIFO */ - if (!(lsr & UART_LSR_DR) && (lsr & UART_LSR_FIFOE)) { - unsigned char fcr = t->fcr_shadow; - fcr |= UART_FCR_CLEAR_RCVR; - uart_writeb(t, fcr, UART_FCR); - } + if (!(lsr & UART_LSR_DR) && (lsr & UART_LSR_FIFOE)) + tegra_fifo_reset(t, UART_FCR_CLEAR_RCVR); } } return flag; @@ -538,7 +580,6 @@ static void tegra_stop_rx(struct uart_port *u) static void tegra_uart_hw_deinit(struct tegra_uart_port *t) { - unsigned char fcr; unsigned long flags; /* Disable interrupts */ @@ -550,11 +591,7 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *t) spin_lock_irqsave(&t->uport.lock, flags); /* Reset the Rx and Tx FIFOs */ - fcr = t->fcr_shadow; - fcr |= UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR; - uart_writeb(t, fcr, UART_FCR); - - udelay(200); + tegra_fifo_reset(t, UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); clk_disable(t->clk); t->baud = 0; @@ -582,7 +619,6 @@ static void tegra_uart_free_rx_dma(struct tegra_uart_port *t) static int tegra_uart_hw_init(struct tegra_uart_port *t) { - unsigned char fcr; unsigned char ier; dev_vdbg(t->uport.dev, "+tegra_uart_hw_init\n"); @@ -603,20 +639,6 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t) t->rx_in_progress = 0; - /* Reset the FIFO twice with some delay to make sure that the FIFOs are - * really flushed. Wait is needed as the clearing needs to cross - * multiple clock domains. - * */ - t->fcr_shadow = UART_FCR_ENABLE_FIFO; - - fcr = t->fcr_shadow; - fcr |= UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR; - uart_writeb(t, fcr, UART_FCR); - - udelay(100); - uart_writeb(t, t->fcr_shadow, UART_FCR); - udelay(100); - /* Set the trigger level * * For PIO mode: @@ -638,6 +660,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t) * Set the Tx trigger to 4. This should match the DMA burst size that * programmed in the DMA registers. * */ + t->fcr_shadow = UART_FCR_ENABLE_FIFO; t->fcr_shadow |= UART_FCR_R_TRIG_01; t->fcr_shadow |= TEGRA_UART_TX_TRIG_8B; uart_writeb(t, t->fcr_shadow, UART_FCR); @@ -646,7 +669,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t) /* initialize the UART for a simple default configuration * so that the receive DMA buffer may be enqueued */ t->lcr_shadow = 3; /* no parity, stop, 8 data bits */ - tegra_set_baudrate(t, 9600); + tegra_set_baudrate(t, 115200); t->fcr_shadow |= UART_FCR_DMA_SELECT; uart_writeb(t, t->fcr_shadow, UART_FCR); if (tegra_start_dma_rx(t)) { @@ -987,8 +1010,10 @@ static void tegra_set_baudrate(struct tegra_uart_port *t, unsigned int baud) lcr &= ~UART_LCR_DLAB; uart_writeb(t, lcr, UART_LCR); + uart_readb(t, UART_SCR); /* Dummy read to ensure the write is posted */ t->baud = baud; + wait_sym_time(t, 2); /* wait two character intervals at new rate */ dev_dbg(t->uport.dev, "Baud %u clock freq %lu and divisor of %u\n", baud, rate, divisor); } @@ -1012,10 +1037,6 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios, if (t->rts_active) set_rts(t, false); - /* Baud rate */ - baud = uart_get_baud_rate(u, termios, oldtermios, 200, 4000000); - tegra_set_baudrate(t, baud); - /* Parity */ lcr = t->lcr_shadow; lcr &= ~UART_LCR_PARITY; @@ -1059,6 +1080,10 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios, uart_writeb(t, lcr, UART_LCR); t->lcr_shadow = lcr; + /* Baud rate. */ + baud = uart_get_baud_rate(u, termios, oldtermios, 200, 4000000); + tegra_set_baudrate(t, baud); + /* Flow control */ if (termios->c_cflag & CRTSCTS) { mcr = t->mcr_shadow; |