aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/omap-serial.c
diff options
context:
space:
mode:
authorAlexey Pelykh <alexey.pelykh@gmail.com>2013-01-16 05:08:06 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-17 20:20:09 -0500
commit5fe2123647c15089c3a905137bea87b16973c896 (patch)
tree45cca444ffc582deca9cb292d6d26bfb11208b25 /drivers/tty/serial/omap-serial.c
parent795b5bbe215c7b988fcf218613d2f3357924f0d2 (diff)
OMAP/serial: Support 1Mbaud and similar baudrates that require Mode16 instead of Mode13
Original table in OMAP TRM named "UART Mode Baud Rates, Divisor Values, and Error Rates" determines modes not for all common baud rates. E.g. for 1000000 baud rate mode should be 16x, but according to that table it's determined as 13x. According to current implementation of mode divisor selection, after requesting 1000000 baudrate from driver, later one will configure chip to use MODE13 divisor. Assuming 48Mhz as common UART clock speed, MODE13 divisor will effectively give 1230769 baudrate, what is quite far from desired 1000000 baudrate. While with MODE16 divisor, chip will produce exact 1000000 baudrate. In old driver that served UART devices (8250.c and serial_core.c) this divisor could have been configured by user-space program, but in omap_serial.c driver implementation this ability was not implemented (afaik, by design) thus disallowing proper usage of MODE16-compatible baudrates. Signed-off-by: Alexey Pelykh <alexey.pelykh@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/omap-serial.c')
-rw-r--r--drivers/tty/serial/omap-serial.c38
1 files changed, 28 insertions, 10 deletions
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 6f3dbf740f05..9915e4d1418c 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -232,24 +232,42 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
232} 232}
233 233
234/* 234/*
235 * serial_omap_baud_is_mode16 - check if baud rate is MODE16X
236 * @port: uart port info
237 * @baud: baudrate for which mode needs to be determined
238 *
239 * Returns true if baud rate is MODE16X and false if MODE13X
240 * Original table in OMAP TRM named "UART Mode Baud Rates, Divisor Values,
241 * and Error Rates" determines modes not for all common baud rates.
242 * E.g. for 1000000 baud rate mode must be 16x, but according to that
243 * table it's determined as 13x.
244 */
245static bool
246serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud)
247{
248 unsigned int n13 = port->uartclk / (13 * baud);
249 unsigned int n16 = port->uartclk / (16 * baud);
250 int baudAbsDiff13 = baud - (port->uartclk / (13 * n13));
251 int baudAbsDiff16 = baud - (port->uartclk / (16 * n16));
252 if(baudAbsDiff13 < 0)
253 baudAbsDiff13 = -baudAbsDiff13;
254 if(baudAbsDiff16 < 0)
255 baudAbsDiff16 = -baudAbsDiff16;
256
257 return (baudAbsDiff13 > baudAbsDiff16);
258}
259
260/*
235 * serial_omap_get_divisor - calculate divisor value 261 * serial_omap_get_divisor - calculate divisor value
236 * @port: uart port info 262 * @port: uart port info
237 * @baud: baudrate for which divisor needs to be calculated. 263 * @baud: baudrate for which divisor needs to be calculated.
238 *
239 * We have written our own function to get the divisor so as to support
240 * 13x mode. 3Mbps Baudrate as an different divisor.
241 * Reference OMAP TRM Chapter 17:
242 * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates
243 * referring to oversampling - divisor value
244 * baudrate 460,800 to 3,686,400 all have divisor 13
245 * except 3,000,000 which has divisor value 16
246 */ 264 */
247static unsigned int 265static unsigned int
248serial_omap_get_divisor(struct uart_port *port, unsigned int baud) 266serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
249{ 267{
250 unsigned int divisor; 268 unsigned int divisor;
251 269
252 if (baud > OMAP_MODE13X_SPEED && baud != 3000000) 270 if (!serial_omap_baud_is_mode16(port, baud))
253 divisor = 13; 271 divisor = 13;
254 else 272 else
255 divisor = 16; 273 divisor = 16;
@@ -916,7 +934,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
916 serial_out(up, UART_EFR, up->efr); 934 serial_out(up, UART_EFR, up->efr);
917 serial_out(up, UART_LCR, cval); 935 serial_out(up, UART_LCR, cval);
918 936
919 if (baud > 230400 && baud != 3000000) 937 if (!serial_omap_baud_is_mode16(port, baud))
920 up->mdr1 = UART_OMAP_MDR1_13X_MODE; 938 up->mdr1 = UART_OMAP_MDR1_13X_MODE;
921 else 939 else
922 up->mdr1 = UART_OMAP_MDR1_16X_MODE; 940 up->mdr1 = UART_OMAP_MDR1_16X_MODE;