aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2015-01-22 12:24:28 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-02-02 13:11:27 -0500
commite72abd5da0730dfc4c8f566f7896c15c2d1bb88f (patch)
tree8bd40b7a67a98e221997cdde6e8cabbc3a99368b /drivers/tty
parent0ec3f585cfb503a18b82cd181c9bf32b45a24f5e (diff)
serial: 8250: Refactor divisor programming
Refactor divisor register programming into a new function, serial8250_set_divisor; this allows serial console to reinitialize early after resume from suspend. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/8250/8250_core.c87
1 files changed, 48 insertions, 39 deletions
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index b63b9c352cc2..fd9e723926cd 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -2478,6 +2478,50 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
2478 return cval; 2478 return cval;
2479} 2479}
2480 2480
2481void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
2482 unsigned int quot)
2483{
2484 struct uart_8250_port *up = up_to_u8250p(port);
2485
2486 /* Workaround to enable 115200 baud on OMAP1510 internal ports */
2487 if (is_omap1510_8250(up)) {
2488 if (baud == 115200) {
2489 quot = 1;
2490 serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
2491 } else
2492 serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
2493 }
2494
2495 /*
2496 * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
2497 * otherwise just set DLAB
2498 */
2499 if (up->capabilities & UART_NATSEMI)
2500 serial_port_out(port, UART_LCR, 0xe0);
2501 else
2502 serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
2503
2504 serial_dl_write(up, quot);
2505
2506 /*
2507 * XR17V35x UARTs have an extra fractional divisor register (DLD)
2508 *
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}
2524
2481void 2525void
2482serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, 2526serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
2483 struct ktermios *old) 2527 struct ktermios *old)
@@ -2526,6 +2570,8 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
2526 serial8250_rpm_get(up); 2570 serial8250_rpm_get(up);
2527 spin_lock_irqsave(&port->lock, flags); 2571 spin_lock_irqsave(&port->lock, flags);
2528 2572
2573 up->lcr = cval; /* Save computed LCR */
2574
2529 /* 2575 /*
2530 * Update the per-port timeout. 2576 * Update the per-port timeout.
2531 */ 2577 */
@@ -2590,43 +2636,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
2590 serial_port_out(port, UART_EFR, efr); 2636 serial_port_out(port, UART_EFR, efr);
2591 } 2637 }
2592 2638
2593 /* Workaround to enable 115200 baud on OMAP1510 internal ports */ 2639 serial8250_set_divisor(port, baud, quot);
2594 if (is_omap1510_8250(up)) {
2595 if (baud == 115200) {
2596 quot = 1;
2597 serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
2598 } else
2599 serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
2600 }
2601
2602 /*
2603 * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
2604 * otherwise just set DLAB
2605 */
2606 if (up->capabilities & UART_NATSEMI)
2607 serial_port_out(port, UART_LCR, 0xe0);
2608 else
2609 serial_port_out(port, UART_LCR, cval | UART_LCR_DLAB);
2610
2611 serial_dl_write(up, quot);
2612
2613 /*
2614 * XR17V35x UARTs have an extra fractional divisor register (DLD)
2615 *
2616 * We need to recalculate all of the registers, because DLM and DLL
2617 * are already rounded to a whole integer.
2618 *
2619 * When recalculating we use a 32x clock instead of a 16x clock to
2620 * allow 1-bit for rounding in the fractional part.
2621 */
2622 if (up->port.type == PORT_XR17V35X) {
2623 unsigned int baud_x32 = (port->uartclk * 2) / baud;
2624 u16 quot = baud_x32 / 32;
2625 u8 quot_frac = DIV_ROUND_CLOSEST(baud_x32 % 32, 2);
2626
2627 serial_dl_write(up, quot);
2628 serial_port_out(port, 0x2, quot_frac & 0xf);
2629 }
2630 2640
2631 /* 2641 /*
2632 * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR 2642 * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
@@ -2635,8 +2645,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
2635 if (port->type == PORT_16750) 2645 if (port->type == PORT_16750)
2636 serial_port_out(port, UART_FCR, up->fcr); 2646 serial_port_out(port, UART_FCR, up->fcr);
2637 2647
2638 serial_port_out(port, UART_LCR, cval); /* reset DLAB */ 2648 serial_port_out(port, UART_LCR, up->lcr); /* reset DLAB */
2639 up->lcr = cval; /* Save LCR */
2640 if (port->type != PORT_16750) { 2649 if (port->type != PORT_16750) {
2641 /* emulated UARTs (Lucent Venus 167x) need two steps */ 2650 /* emulated UARTs (Lucent Venus 167x) need two steps */
2642 if (up->fcr & UART_FCR_ENABLE_FIFO) 2651 if (up->fcr & UART_FCR_ENABLE_FIFO)