aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/tty/serial/8250/8250_core.c52
1 files changed, 30 insertions, 22 deletions
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index fd9e723926cd..c8ecfaf49eb4 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -2413,7 +2413,26 @@ static void serial8250_shutdown(struct uart_port *port)
2413 serial8250_do_shutdown(port); 2413 serial8250_do_shutdown(port);
2414} 2414}
2415 2415
2416static unsigned int serial8250_get_divisor(struct uart_8250_port *up, unsigned int baud) 2416/*
2417 * XR17V35x UARTs have an extra fractional divisor register (DLD)
2418 * Calculate divisor with extra 4-bit fractional portion
2419 */
2420static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up,
2421 unsigned int baud,
2422 unsigned int *frac)
2423{
2424 struct uart_port *port = &up->port;
2425 unsigned int quot_16;
2426
2427 quot_16 = DIV_ROUND_CLOSEST(port->uartclk, baud);
2428 *frac = quot_16 & 0x0f;
2429
2430 return quot_16 >> 4;
2431}
2432
2433static unsigned int serial8250_get_divisor(struct uart_8250_port *up,
2434 unsigned int baud,
2435 unsigned int *frac)
2417{ 2436{
2418 struct uart_port *port = &up->port; 2437 struct uart_port *port = &up->port;
2419 unsigned int quot; 2438 unsigned int quot;
@@ -2421,6 +2440,7 @@ static unsigned int serial8250_get_divisor(struct uart_8250_port *up, unsigned i
2421 /* 2440 /*
2422 * Handle magic divisors for baud rates above baud_base on 2441 * Handle magic divisors for baud rates above baud_base on
2423 * SMSC SuperIO chips. 2442 * SMSC SuperIO chips.
2443 *
2424 */ 2444 */
2425 if ((port->flags & UPF_MAGIC_MULTIPLIER) && 2445 if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
2426 baud == (port->uartclk/4)) 2446 baud == (port->uartclk/4))
@@ -2428,6 +2448,8 @@ static unsigned int serial8250_get_divisor(struct uart_8250_port *up, unsigned i
2428 else if ((port->flags & UPF_MAGIC_MULTIPLIER) && 2448 else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
2429 baud == (port->uartclk/8)) 2449 baud == (port->uartclk/8))
2430 quot = 0x8002; 2450 quot = 0x8002;
2451 else if (up->port.type == PORT_XR17V35X)
2452 quot = xr17v35x_get_divisor(up, baud, frac);
2431 else 2453 else
2432 quot = uart_get_divisor(port, baud); 2454 quot = uart_get_divisor(port, baud);
2433 2455
@@ -2479,7 +2501,7 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
2479} 2501}
2480 2502
2481void serial8250_set_divisor(struct uart_port *port, unsigned int baud, 2503void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
2482 unsigned int quot) 2504 unsigned int quot, unsigned int quot_frac)
2483{ 2505{
2484 struct uart_8250_port *up = up_to_u8250p(port); 2506 struct uart_8250_port *up = up_to_u8250p(port);
2485 2507
@@ -2503,23 +2525,9 @@ void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
2503 2525
2504 serial_dl_write(up, quot); 2526 serial_dl_write(up, quot);
2505 2527
2506 /* 2528 /* XR17V35x UARTs have an extra fractional divisor register (DLD) */
2507 * XR17V35x UARTs have an extra fractional divisor register (DLD) 2529 if (up->port.type == PORT_XR17V35X)
2508 * 2530 serial_port_out(port, 0x2, quot_frac);
2509 * We need to recalculate all of the registers, because DLM and DLL
2510 * are already rounded to a whole integer.
2511 *
2512 * When recalculating we use a 32x clock instead of a 16x clock to
2513 * allow 1-bit for rounding in the fractional part.
2514 */
2515 if (up->port.type == PORT_XR17V35X) {
2516 unsigned int baud_x32 = (port->uartclk * 2) / baud;
2517 u16 quot = baud_x32 / 32;
2518 u8 quot_frac = DIV_ROUND_CLOSEST(baud_x32 % 32, 2);
2519
2520 serial_dl_write(up, quot);
2521 serial_port_out(port, 0x2, quot_frac & 0xf);
2522 }
2523} 2531}
2524 2532
2525void 2533void
@@ -2529,7 +2537,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
2529 struct uart_8250_port *up = up_to_u8250p(port); 2537 struct uart_8250_port *up = up_to_u8250p(port);
2530 unsigned char cval; 2538 unsigned char cval;
2531 unsigned long flags; 2539 unsigned long flags;
2532 unsigned int baud, quot; 2540 unsigned int baud, quot, frac = 0;
2533 2541
2534 cval = serial8250_compute_lcr(up, termios->c_cflag); 2542 cval = serial8250_compute_lcr(up, termios->c_cflag);
2535 2543
@@ -2539,7 +2547,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
2539 baud = uart_get_baud_rate(port, termios, old, 2547 baud = uart_get_baud_rate(port, termios, old,
2540 port->uartclk / 16 / 0xffff, 2548 port->uartclk / 16 / 0xffff,
2541 port->uartclk / 16); 2549 port->uartclk / 16);
2542 quot = serial8250_get_divisor(up, baud); 2550 quot = serial8250_get_divisor(up, baud, &frac);
2543 2551
2544 if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { 2552 if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
2545 /* NOTE: If fifo_bug is not set, a user can set RX_trigger. */ 2553 /* NOTE: If fifo_bug is not set, a user can set RX_trigger. */
@@ -2636,7 +2644,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
2636 serial_port_out(port, UART_EFR, efr); 2644 serial_port_out(port, UART_EFR, efr);
2637 } 2645 }
2638 2646
2639 serial8250_set_divisor(port, baud, quot); 2647 serial8250_set_divisor(port, baud, quot, frac);
2640 2648
2641 /* 2649 /*
2642 * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR 2650 * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR