Skip to content

Commit

Permalink
serial: sh-sci: Support for HSCIF RX sampling point adjustment
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ulrich Hecht authored and Greg Kroah-Hartman committed Apr 23, 2018
1 parent 7678f4c commit 63ba1e0
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 23 deletions.
65 changes: 42 additions & 23 deletions drivers/tty/serial/sh-sci.c
Original file line number Diff line number Diff line change
Expand Up @@ -2391,6 +2391,27 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,

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) {
Expand All @@ -2407,8 +2428,27 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
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);
Expand Down Expand Up @@ -2475,27 +2515,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
* 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;
Expand Down
4 changes: 4 additions & 0 deletions drivers/tty/serial/sh-sci.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ enum {

/* HSSRR HSCIF */
#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */
#define HSCIF_SRDE BIT(14) /* Sampling Point Register Enable */

#define HSCIF_SRHP_SHIFT 8
#define HSCIF_SRHP_MASK 0x0f00

/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */
#define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */
Expand Down

0 comments on commit 63ba1e0

Please sign in to comment.