@@ -1492,18 +1492,36 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int lcr_h, old_cr;
unsigned long flags;
- unsigned int baud, quot, clkdiv;
+ unsigned int max_baud, baud, quot;
if (uap->vendor->oversampling)
- clkdiv = 8;
+ max_baud = port->uartclk / 8;
else
- clkdiv = 16;
+ max_baud = port->uartclk / 16;
/*
- * Ask the core to calculate the divisor for us.
+ * For "zero" speeds or in the case where in and output
+ * speed differs, fall back on using the serial core to
+ * determine applicable baudrate.
*/
- baud = uart_get_baud_rate(port, termios, old, 0,
- port->uartclk / clkdiv);
+ if ((termios->c_ispeed != termios->c_ospeed) ||
+ (termios->c_ispeed == 0) ||
+ (termios->c_ospeed == 0))
+ baud = uart_get_baud_rate(port, termios, old, 0,
+ max_baud);
+ else {
+ /*
+ * Else we just use the requested speed from
+ * termios. But we sanity check it so as not to
+ * exceed hardware limits.
+ */
+ baud = termios->c_ospeed;
+ if (baud > max_baud)
+ baud = max_baud;
+ }
+ dev_dbg(uap->port.dev, "c_ispeed: %u, c_ospeed: %u, "
+ "max_baud: %u, resulting baud rate %u bps\n",
+ termios->c_ispeed, termios->c_ospeed, max_baud, baud);
if (baud > port->uartclk/16)
quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);