[PATCH 1/3] serial: 8250_pci: rewrite pericom_do_set_divisor

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Fixes: 6bf4e42f1d19de10800f4483b4bb7945aab283cb

Have pericom_do_set_divisor() use the uartclk instead of a hardcoded
value to work with different speed crystals. Tested with 14.7456 and 24
MHz crystals
Have pericom_do_set_divisor always calculate the divisor rather than
call serial8250_do_set_divisor() for rates below baud_base.
Do not write registers or call serial8250_do_set_divisor() if valid
divisors could not be found.

Signed-off-by: Jay Dolan <jay.dolan@xxxxxxxxxxx>
---
 drivers/tty/serial/8250/8250_pci.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 5d43de143f33..aea43683b76d 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1325,28 +1325,32 @@ pericom_do_set_divisor(struct uart_port *port, unsigned int baud,
 	int scr;
 	int lcr;
 	int actual_baud;
-	int tolerance;
+	int divisor;
 
-	for (scr = 5 ; scr <= 15 ; scr++) {
-		actual_baud = 921600 * 16 / scr;
-		tolerance = actual_baud / 50;
+	for (scr = 16 ; scr > 4 ; scr--) {
+		if (baud > (port->uartclk / scr) + (baud/50))
+			continue;
 
-		if ((baud < actual_baud + tolerance) &&
-			(baud > actual_baud - tolerance)) {
+		divisor = port->uartclk / scr / baud;
+		if (divisor == 0 ||
+			port->uartclk / scr / divisor - baud > baud/50) {
+			divisor++;
+		}
+
+		if (divisor > 0xffff)
+			continue;
 
+		actual_baud = port->uartclk / scr / divisor;
+		if (abs(actual_baud - baud) < baud/50) {
 			lcr = serial_port_in(port, UART_LCR);
 			serial_port_out(port, UART_LCR, lcr | 0x80);
-
-			serial_port_out(port, UART_DLL, 1);
-			serial_port_out(port, UART_DLM, 0);
+			serial_port_out(port, UART_DLL, divisor & 0xff);
+			serial_port_out(port, UART_DLM, divisor >> 8 & 0xff);
 			serial_port_out(port, 2, 16 - scr);
 			serial_port_out(port, UART_LCR, lcr);
 			return;
-		} else if (baud > actual_baud) {
-			break;
 		}
 	}
-	serial8250_do_set_divisor(port, baud, quot, quot_frac);
 }
 static int pci_pericom_setup(struct serial_private *priv,
 		  const struct pciserial_board *board,
-- 
2.25.1




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux