serial: 8250_pci: rewrite pericom_do_set_divisor()

Have pericom_do_set_divisor() use the uartclk instead of a hard coded
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.

Fixes: 6bf4e42f1d19 ("serial: 8250: Add support for higher baud rates to Pericom chips")
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Jay Dolan <jay.dolan@accesio.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20211122120604.3909-3-andriy.shevchenko@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by Jay Dolan and committed by Greg Kroah-Hartman bb1201d4 c525c5d2

Changed files
+17 -13
drivers
tty
serial
8250
+17 -13
drivers/tty/serial/8250/8250_pci.c
··· 1324 1324 { 1325 1325 int scr; 1326 1326 int lcr; 1327 - int actual_baud; 1328 - int tolerance; 1329 1327 1330 - for (scr = 5 ; scr <= 15 ; scr++) { 1331 - actual_baud = 921600 * 16 / scr; 1332 - tolerance = actual_baud / 50; 1328 + for (scr = 16; scr > 4; scr--) { 1329 + unsigned int maxrate = port->uartclk / scr; 1330 + unsigned int divisor = max(maxrate / baud, 1U); 1331 + int delta = maxrate / divisor - baud; 1333 1332 1334 - if ((baud < actual_baud + tolerance) && 1335 - (baud > actual_baud - tolerance)) { 1333 + if (baud > maxrate + baud / 50) 1334 + continue; 1336 1335 1336 + if (delta > baud / 50) 1337 + divisor++; 1338 + 1339 + if (divisor > 0xffff) 1340 + continue; 1341 + 1342 + /* Update delta due to possible divisor change */ 1343 + delta = maxrate / divisor - baud; 1344 + if (abs(delta) < baud / 50) { 1337 1345 lcr = serial_port_in(port, UART_LCR); 1338 1346 serial_port_out(port, UART_LCR, lcr | 0x80); 1339 - 1340 - serial_port_out(port, UART_DLL, 1); 1341 - serial_port_out(port, UART_DLM, 0); 1347 + serial_port_out(port, UART_DLL, divisor & 0xff); 1348 + serial_port_out(port, UART_DLM, divisor >> 8 & 0xff); 1342 1349 serial_port_out(port, 2, 16 - scr); 1343 1350 serial_port_out(port, UART_LCR, lcr); 1344 1351 return; 1345 - } else if (baud > actual_baud) { 1346 - break; 1347 1352 } 1348 1353 } 1349 - serial8250_do_set_divisor(port, baud, quot, quot_frac); 1350 1354 } 1351 1355 static int pci_pericom_setup(struct serial_private *priv, 1352 1356 const struct pciserial_board *board,