Commit e97e1556 authored by Alexander Shiyan's avatar Alexander Shiyan Committed by Greg Kroah-Hartman

serial: max310x: Setup baud rate generator more precisely

This patch provide more precisely setup of baud rate generator.
If the result of division has a remainder, we use the multiplier
for the base frequency. Additionally, we report result baud rate
back to serial core.
Signed-off-by: default avatarAlexander Shiyan <shc_work@mail.ru>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d0fd413c
/* /*
* Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver * Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver
* *
* Copyright (C) 2012-2013 Alexander Shiyan <shc_work@mail.ru> * Copyright (C) 2012-2014 Alexander Shiyan <shc_work@mail.ru>
* *
* Based on max3100.c, by Christian Pellegrin <chripell@evolware.org> * Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
* Based on max3110.c, by Feng Tang <feng.tang@intel.com> * Based on max3110.c, by Feng Tang <feng.tang@intel.com>
...@@ -504,25 +504,33 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg) ...@@ -504,25 +504,33 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
return false; return false;
} }
static void max310x_set_baud(struct uart_port *port, int baud) static int max310x_set_baud(struct uart_port *port, int baud)
{ {
unsigned int mode = 0, div = port->uartclk / baud; unsigned int mode = 0, clk = port->uartclk, div = clk / baud;
if (!(div / 16)) { /* Check for minimal value for divider */
if (div < 16)
div = 16;
if (clk % baud && (div / 16) < 0x8000) {
/* Mode x2 */ /* Mode x2 */
mode = MAX310X_BRGCFG_2XMODE_BIT; mode = MAX310X_BRGCFG_2XMODE_BIT;
div = (port->uartclk * 2) / baud; clk = port->uartclk * 2;
} div = clk / baud;
if (!(div / 16)) { if (clk % baud && (div / 16) < 0x8000) {
/* Mode x4 */ /* Mode x4 */
mode = MAX310X_BRGCFG_4XMODE_BIT; mode = MAX310X_BRGCFG_4XMODE_BIT;
div = (port->uartclk * 4) / baud; clk = port->uartclk * 4;
div = clk / baud;
}
} }
max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8); max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8);
max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16); max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16);
max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode); max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode);
return DIV_ROUND_CLOSEST(clk, div);
} }
static int max310x_update_best_err(unsigned long f, long *besterr) static int max310x_update_best_err(unsigned long f, long *besterr)
...@@ -875,7 +883,7 @@ static void max310x_set_termios(struct uart_port *port, ...@@ -875,7 +883,7 @@ static void max310x_set_termios(struct uart_port *port,
port->uartclk / 4); port->uartclk / 4);
/* Setup baudrate generator */ /* Setup baudrate generator */
max310x_set_baud(port, baud); baud = max310x_set_baud(port, baud);
/* Update timeout according to new baud rate */ /* Update timeout according to new baud rate */
uart_update_timeout(port, termios->c_cflag, baud); uart_update_timeout(port, termios->c_cflag, baud);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment