serial: max310x: Setup baud rate generator more precisely
authorAlexander Shiyan <shc_work@mail.ru>
Fri, 7 Feb 2014 14:16:04 +0000 (18:16 +0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 13 Feb 2014 17:33:04 +0000 (09:33 -0800)
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: Alexander Shiyan <shc_work@mail.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/max310x.c

index 8d71e4047bb300d0e1a12af83f2263297c4a29bc..313bdf0bb21b196dd10de728b8cfbcfeb0db9d8e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  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 max3110.c, by Feng Tang <feng.tang@intel.com>
@@ -504,25 +504,33 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
        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 = MAX310X_BRGCFG_2XMODE_BIT;
-               div = (port->uartclk * 2) / baud;
-       }
-
-       if (!(div / 16)) {
-               /* Mode x4 */
-               mode = MAX310X_BRGCFG_4XMODE_BIT;
-               div = (port->uartclk * 4) / baud;
+               clk = port->uartclk * 2;
+               div = clk / baud;
+
+               if (clk % baud && (div / 16) < 0x8000) {
+                       /* Mode x4 */
+                       mode = MAX310X_BRGCFG_4XMODE_BIT;
+                       clk = port->uartclk * 4;
+                       div = clk / baud;
+               }
        }
 
        max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8);
        max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16);
        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)
@@ -875,7 +883,7 @@ static void max310x_set_termios(struct uart_port *port,
                                  port->uartclk / 4);
 
        /* Setup baudrate generator */
-       max310x_set_baud(port, baud);
+       baud = max310x_set_baud(port, baud);
 
        /* Update timeout according to new baud rate */
        uart_update_timeout(port, termios->c_cflag, baud);