serial: sh-sci: Fix (AUTO)RTS in sci_init_pins()

If a UART has dedicated RTS/CTS pins, and hardware control flow is
disabled (or AUTORTS is not yet effective), changing any serial port
configuration deasserts RTS, as .set_termios() calls sci_init_pins().

To fix this, consider the current (AUTO)RTS state when (re)initializing
the pins.  Note that for SCIFA/SCIFB, AUTORTS needs explicit
configuration of the RTS# pin function, while (H)SCIF handles this
automatically.

Fixes: d2b9775d79 ("serial: sh-sci: Correct pin initialization on (H)SCIF")
Fixes: e9d7a45a03 ("serial: sh-sci: Add pin initialization for SCIFA/SCIFB")
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Geert Uytterhoeven 2017-03-28 11:13:46 +02:00 коммит произвёл Greg Kroah-Hartman
Родитель 5f76895e4c
Коммит cfa6eb2391
1 изменённых файлов: 19 добавлений и 6 удалений

Просмотреть файл

@ -683,24 +683,37 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
} }
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
u16 data = serial_port_in(port, SCPDR);
u16 ctrl = serial_port_in(port, SCPCR); u16 ctrl = serial_port_in(port, SCPCR);
/* Enable RXD and TXD pin functions */ /* Enable RXD and TXD pin functions */
ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC); ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC);
if (to_sci_port(port)->has_rtscts) { if (to_sci_port(port)->has_rtscts) {
/* RTS# is output, driven 1 */ /* RTS# is output, active low, unless autorts */
ctrl |= SCPCR_RTSC; if (!(port->mctrl & TIOCM_RTS)) {
serial_port_out(port, SCPDR, ctrl |= SCPCR_RTSC;
serial_port_in(port, SCPDR) | SCPDR_RTSD); data |= SCPDR_RTSD;
} else if (!s->autorts) {
ctrl |= SCPCR_RTSC;
data &= ~SCPDR_RTSD;
} else {
/* Enable RTS# pin function */
ctrl &= ~SCPCR_RTSC;
}
/* Enable CTS# pin function */ /* Enable CTS# pin function */
ctrl &= ~SCPCR_CTSC; ctrl &= ~SCPCR_CTSC;
} }
serial_port_out(port, SCPDR, data);
serial_port_out(port, SCPCR, ctrl); serial_port_out(port, SCPCR, ctrl);
} else if (sci_getreg(port, SCSPTR)->size) { } else if (sci_getreg(port, SCSPTR)->size) {
u16 status = serial_port_in(port, SCSPTR); u16 status = serial_port_in(port, SCSPTR);
/* RTS# is output, driven 1 */ /* RTS# is always output; and active low, unless autorts */
status |= SCSPTR_RTSIO | SCSPTR_RTSDT; status |= SCSPTR_RTSIO;
if (!(port->mctrl & TIOCM_RTS))
status |= SCSPTR_RTSDT;
else if (!s->autorts)
status &= ~SCSPTR_RTSDT;
/* CTS# and SCK are inputs */ /* CTS# and SCK are inputs */
status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO); status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO);
serial_port_out(port, SCSPTR, status); serial_port_out(port, SCSPTR, status);