diff options
author | Ulrich Hecht <ulrich.hecht+renesas@gmail.com> | 2018-04-04 17:48:51 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-04-23 10:08:18 +0200 |
commit | 63ba1e00f178a4483b473489cadc4eb52a77df2a (patch) | |
tree | 0c5c157f62ea8a446807e9d4a9d217085f670d9f /drivers/tty/serial/sh-sci.c | |
parent | 7678f4c20fa7670fcc23e2537a26543c5c6a7772 (diff) | |
download | blackbird-op-linux-63ba1e00f178a4483b473489cadc4eb52a77df2a.tar.gz blackbird-op-linux-63ba1e00f178a4483b473489cadc4eb52a77df2a.zip |
serial: sh-sci: Support for HSCIF RX sampling point adjustment
HSCIF has facilities that allow moving the RX sampling point by between
-8 and 7 sampling cycles (one sampling cycles equals 1/15 of a bit
by default) to improve the error margin in case of slightly mismatched
bit rates between sender and receiver.
This patch tries to determine if shifting the sampling point can improve
the error margin and will enable it if so.
Signed-off-by: Ulrich Hecht <ulrich.hecht+renesas@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
-rw-r--r-- | drivers/tty/serial/sh-sci.c | 65 |
1 files changed, 42 insertions, 23 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 919706988c72..cc0504f30a1d 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2391,6 +2391,27 @@ done: uart_update_timeout(port, termios->c_cflag, baud); + /* byte size and parity */ + switch (termios->c_cflag & CSIZE) { + case CS5: + bits = 7; + break; + case CS6: + bits = 8; + break; + case CS7: + bits = 9; + break; + default: + bits = 10; + break; + } + + if (termios->c_cflag & CSTOPB) + bits++; + if (termios->c_cflag & PARENB) + bits++; + if (best_clk >= 0) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) switch (srr + 1) { @@ -2407,8 +2428,27 @@ done: serial_port_out(port, SCSCR, scr_val | s->hscif_tot); serial_port_out(port, SCSMR, smr_val); serial_port_out(port, SCBRR, brr); - if (sci_getreg(port, HSSRR)->size) - serial_port_out(port, HSSRR, srr | HSCIF_SRE); + if (sci_getreg(port, HSSRR)->size) { + unsigned int hssrr = srr | HSCIF_SRE; + /* Calculate deviation from intended rate at the + * center of the last stop bit in sampling clocks. + */ + int last_stop = bits * 2 - 1; + int deviation = min_err * srr * last_stop / 2 / baud; + + if (abs(deviation) >= 2) { + /* At least two sampling clocks off at the + * last stop bit; we can increase the error + * margin by shifting the sampling point. + */ + int shift = min(-8, max(7, deviation / 2)); + + hssrr |= (shift << HSCIF_SRHP_SHIFT) & + HSCIF_SRHP_MASK; + hssrr |= HSCIF_SRDE; + } + serial_port_out(port, HSSRR, hssrr); + } /* Wait one bit interval */ udelay((1000000 + (baud - 1)) / baud); @@ -2475,27 +2515,6 @@ done: * value obtained by this formula is too small. Therefore, if the value * is smaller than 20ms, use 20ms as the timeout value for DMA. */ - /* byte size and parity */ - switch (termios->c_cflag & CSIZE) { - case CS5: - bits = 7; - break; - case CS6: - bits = 8; - break; - case CS7: - bits = 9; - break; - default: - bits = 10; - break; - } - - if (termios->c_cflag & CSTOPB) - bits++; - if (termios->c_cflag & PARENB) - bits++; - s->rx_frame = (10000 * bits) / (baud / 100); #ifdef CONFIG_SERIAL_SH_SCI_DMA s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame; |