|
@@ -341,13 +341,37 @@ static u_int atmel_tx_empty(struct uart_port *port)
|
|
|
static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
|
|
|
{
|
|
|
unsigned int control = 0;
|
|
|
- unsigned int mode;
|
|
|
+ unsigned int mode = UART_GET_MR(port);
|
|
|
+ unsigned int rts_paused, rts_ready;
|
|
|
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
|
|
|
|
|
+ /* override mode to RS485 if needed, otherwise keep the current mode */
|
|
|
+ if (port->rs485.flags & SER_RS485_ENABLED) {
|
|
|
+ if ((port->rs485.delay_rts_after_send) > 0)
|
|
|
+ UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
|
|
|
+ mode &= ~ATMEL_US_USMODE;
|
|
|
+ mode |= ATMEL_US_USMODE_RS485;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* set the RTS line state according to the mode */
|
|
|
+ if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
|
|
|
+ /* force RTS line to high level */
|
|
|
+ rts_paused = ATMEL_US_RTSEN;
|
|
|
+
|
|
|
+ /* give the control of the RTS line back to the hardware */
|
|
|
+ rts_ready = ATMEL_US_RTSDIS;
|
|
|
+ } else {
|
|
|
+ /* force RTS line to high level */
|
|
|
+ rts_paused = ATMEL_US_RTSDIS;
|
|
|
+
|
|
|
+ /* force RTS line to low level */
|
|
|
+ rts_ready = ATMEL_US_RTSEN;
|
|
|
+ }
|
|
|
+
|
|
|
if (mctrl & TIOCM_RTS)
|
|
|
- control |= ATMEL_US_RTSEN;
|
|
|
+ control |= rts_ready;
|
|
|
else
|
|
|
- control |= ATMEL_US_RTSDIS;
|
|
|
+ control |= rts_paused;
|
|
|
|
|
|
if (mctrl & TIOCM_DTR)
|
|
|
control |= ATMEL_US_DTREN;
|
|
@@ -359,23 +383,12 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
|
|
|
mctrl_gpio_set(atmel_port->gpios, mctrl);
|
|
|
|
|
|
/* Local loopback mode? */
|
|
|
- mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
|
|
|
+ mode &= ~ATMEL_US_CHMODE;
|
|
|
if (mctrl & TIOCM_LOOP)
|
|
|
mode |= ATMEL_US_CHMODE_LOC_LOOP;
|
|
|
else
|
|
|
mode |= ATMEL_US_CHMODE_NORMAL;
|
|
|
|
|
|
- /* Resetting serial mode to RS232 (0x0) */
|
|
|
- mode &= ~ATMEL_US_USMODE;
|
|
|
-
|
|
|
- if (port->rs485.flags & SER_RS485_ENABLED) {
|
|
|
- dev_dbg(port->dev, "Setting UART to RS485\n");
|
|
|
- if ((port->rs485.delay_rts_after_send) > 0)
|
|
|
- UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
|
|
|
- mode |= ATMEL_US_USMODE_RS485;
|
|
|
- } else {
|
|
|
- dev_dbg(port->dev, "Setting UART to RS232\n");
|
|
|
- }
|
|
|
UART_PUT_MR(port, mode);
|
|
|
}
|
|
|
|
|
@@ -1921,12 +1934,14 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
struct ktermios *old)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
- unsigned int mode, imr, quot, baud;
|
|
|
+ unsigned int old_mode, mode, imr, quot, baud;
|
|
|
+
|
|
|
+ /* save the current mode register */
|
|
|
+ mode = old_mode = UART_GET_MR(port);
|
|
|
|
|
|
- /* Get current mode register */
|
|
|
- mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
|
|
|
- | ATMEL_US_NBSTOP | ATMEL_US_PAR
|
|
|
- | ATMEL_US_USMODE);
|
|
|
+ /* reset the mode, clock divisor, parity, stop bits and data size */
|
|
|
+ mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP |
|
|
|
+ ATMEL_US_PAR | ATMEL_US_USMODE);
|
|
|
|
|
|
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
|
|
|
quot = uart_get_divisor(port, baud);
|
|
@@ -1971,12 +1986,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
} else
|
|
|
mode |= ATMEL_US_PAR_NONE;
|
|
|
|
|
|
- /* hardware handshake (RTS/CTS) */
|
|
|
- if (termios->c_cflag & CRTSCTS)
|
|
|
- mode |= ATMEL_US_USMODE_HWHS;
|
|
|
- else
|
|
|
- mode |= ATMEL_US_USMODE_NORMAL;
|
|
|
-
|
|
|
spin_lock_irqsave(&port->lock, flags);
|
|
|
|
|
|
port->read_status_mask = ATMEL_US_OVRE;
|
|
@@ -2020,18 +2029,40 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
/* disable receiver and transmitter */
|
|
|
UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
|
|
|
|
|
|
- /* Resetting serial mode to RS232 (0x0) */
|
|
|
- mode &= ~ATMEL_US_USMODE;
|
|
|
-
|
|
|
+ /* mode */
|
|
|
if (port->rs485.flags & SER_RS485_ENABLED) {
|
|
|
if ((port->rs485.delay_rts_after_send) > 0)
|
|
|
UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
|
|
|
mode |= ATMEL_US_USMODE_RS485;
|
|
|
+ } else if (termios->c_cflag & CRTSCTS) {
|
|
|
+ /* RS232 with hardware handshake (RTS/CTS) */
|
|
|
+ mode |= ATMEL_US_USMODE_HWHS;
|
|
|
+ } else {
|
|
|
+ /* RS232 without hadware handshake */
|
|
|
+ mode |= ATMEL_US_USMODE_NORMAL;
|
|
|
}
|
|
|
|
|
|
- /* set the parity, stop bits and data size */
|
|
|
+ /* set the mode, clock divisor, parity, stop bits and data size */
|
|
|
UART_PUT_MR(port, mode);
|
|
|
|
|
|
+ /*
|
|
|
+ * when switching the mode, set the RTS line state according to the
|
|
|
+ * new mode, otherwise keep the former state
|
|
|
+ */
|
|
|
+ if ((old_mode & ATMEL_US_USMODE) != (mode & ATMEL_US_USMODE)) {
|
|
|
+ unsigned int rts_state;
|
|
|
+
|
|
|
+ if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
|
|
|
+ /* let the hardware control the RTS line */
|
|
|
+ rts_state = ATMEL_US_RTSDIS;
|
|
|
+ } else {
|
|
|
+ /* force RTS line to low level */
|
|
|
+ rts_state = ATMEL_US_RTSEN;
|
|
|
+ }
|
|
|
+
|
|
|
+ UART_PUT_CR(port, rts_state);
|
|
|
+ }
|
|
|
+
|
|
|
/* set the baud rate */
|
|
|
UART_PUT_BRGR(port, quot);
|
|
|
UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
|