diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c index 2a13a89..b20a825 100644 --- a/drivers/serial/omap-serial.c +++ b/drivers/serial/omap-serial.c @@ -111,6 +111,7 @@ struct uart_omap_port { unsigned char efr; int use_dma; int is_buf_dma_alloced; + int restore_autorts; /* * Some bits in registers are cleared on a read, so they must * be saved whenever the register is read but the bits will not @@ -132,6 +133,7 @@ static struct wake_lock omap_serial_wakelock; static void uart_tx_dma_callback(int lch, u16 ch_status, void *data); static void serial_omap_rx_timeout(unsigned long uart_no); static void serial_omap_start_rxdma(struct uart_omap_port *up); +static void serial_omap_set_autorts(struct uart_omap_port *p, int set); #ifdef DEBUG static void serial_omap_display_reg(struct uart_port *port); @@ -432,6 +434,11 @@ static void serial_omap_start_tx(struct uart_port *port) up->ier |= UART_IER_THRI; serial_out(up, UART_IER, up->ier); } + + if (up->restore_autorts) { + serial_omap_set_autorts(up, 1); + up->restore_autorts = 0; + } } static unsigned int check_modem_status(struct uart_omap_port *up) @@ -529,8 +536,15 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) unsigned char mcr = 0; DPRINTK("serial_omap_set_mctrl+%d\n", up->pdev->id); - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_RTS) { + /* + * We need to be careful not to cause + * RTS to assert when we have a pending + * auto-rts restore. + */ + if (!up->restore_autorts) + mcr |= UART_MCR_RTS; + } if (mctrl & TIOCM_DTR) mcr |= UART_MCR_DTR; if (mctrl & TIOCM_OUT1) @@ -559,6 +573,52 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) spin_unlock_irqrestore(&up->port.lock, flags); } + +static void serial_omap_set_autorts(struct uart_omap_port *p, int set) +{ + u8 lcr_val = 0, mcr_val = 0, efr_val = 0; + u8 lcr_backup = 0, mcr_backup = 0, efr_backup = 0; + + lcr_val = serial_in(p, UART_LCR); + lcr_backup = lcr_val; + /* Enter Config mode B */ + serial_out(p, UART_LCR, 0xbf); + + efr_val = serial_in(p, UART_EFR); + efr_backup = efr_val; + + /* + * Enhanced functions write enable. + * Enables writes to IER[7:4], FCR[5:4], MCR[7:5] + */ + serial_out(p, UART_EFR, efr_val | 0x10); + + mcr_val = serial_in(p, UART_MCR); + mcr_backup = mcr_val; + /* Enable access to TCR_REG and TLR_REG */ + serial_out(p, UART_MCR, mcr_val | 0x40); + + /* Set RX_FIFO_TRIG levels */ + serial_out(p, 0x18, 0x0f); + + efr_val = serial_in(p, UART_EFR); + if (set) + serial_out(p, UART_EFR, efr_val | (1 << 6)); + else + serial_out(p, UART_EFR, efr_val & ~(1 << 6)); + + + mcr_val = serial_in(p, UART_MCR); + /* Restore original state of TCR_TLR access */ + serial_out(p, UART_MCR, (mcr_val & ~0x40) | (mcr_backup & 0x40)); + + /* Enhanced function write disable. */ + serial_out(p, UART_EFR, serial_in(p, UART_EFR) & ~0x10); + + /* Normal operation */ + serial_out(p, UART_LCR, lcr_backup); +} + static int serial_omap_startup(struct uart_port *port) { struct uart_omap_port *up = (struct uart_omap_port *)port; @@ -667,8 +727,23 @@ static void serial_omap_shutdown(struct uart_port *port) { struct uart_omap_port *up = (struct uart_omap_port *)port; unsigned long flags; + u8 lcr, efr; DPRINTK("serial_omap_shutdown+%d\n", up->pdev->id); + + /* + * If we're using auto-rts then disable it. + */ + lcr = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, 0xbf); + efr = serial_in(up, UART_EFR); + serial_out(up, UART_LCR, lcr); + + if (efr & UART_EFR_RTS) { + serial_omap_set_autorts(up, 0); + up->restore_autorts = 1; + } + /* * Disable interrupts from this port */ @@ -930,7 +1005,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, /* Hardware Flow Control Configuration */ if (termios->c_cflag & CRTSCTS) { - efr |= (UART_EFR_CTS | UART_EFR_RTS); + efr |= (UART_EFR_CTS | (up->restore_autorts ? 0 : UART_EFR_RTS)); serial_out(up, UART_LCR, 0x80); up->mcr = serial_in(up, UART_MCR);