Commit d0e462fc authored by David Woodhouse's avatar David Woodhouse

Allow uart drivers to calculate divisors differently.

In order to deal with the weird and wonderful ways of obtaining a uart clock
which a lot of the high-speed hacks for 16550-based chips seem to have, we need
to make uart_update_timeout() and uart_get_divisor() take the desired baud rate
as their arguments, instead of termios or divisor as before. The main reason for the
change to uart_get_divisor(), requiring a call to uart_get_baud_rate() before it, is
so that the drivers actually _have_ the baud rate in order that they can pass it to
uart_update_timeout().
parent 15f1049d
......@@ -237,7 +237,7 @@ serial21285_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned long flags;
unsigned int quot, h_lcr;
unsigned int baud, quot, h_lcr;
/*
* We don't support modem control lines.
......@@ -253,7 +253,8 @@ serial21285_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
case CS5:
......@@ -286,7 +287,7 @@ serial21285_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
/*
* Which character status flags are we interested in?
......
......@@ -1325,7 +1325,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int quot;
unsigned int baud, quot;
switch (termios->c_cflag & CSIZE) {
case CS5:
......@@ -1357,7 +1357,8 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
/*
* Work around a bug in the Oxford Semiconductor 952 rev B
......@@ -1369,7 +1370,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
quot ++;
if (uart_config[up->port.type].flags & UART_USE_FIFO) {
if ((up->port.uartclk / quot) < (2400 * 16))
if (baud < 2400)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
#ifdef CONFIG_SERIAL_8250_RSA
else if (up->port.type == PORT_RSA)
......@@ -1390,7 +1391,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
......
......@@ -408,12 +408,13 @@ ambauart_set_termios(struct uart_port *port, struct termios *termios,
{
unsigned int lcr_h, old_cr;
unsigned long flags;
unsigned int quot;
unsigned int baud, quot;
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
case CS5:
......@@ -444,7 +445,7 @@ ambauart_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = AMBA_UARTRSR_OE;
if (termios->c_iflag & INPCK)
......
......@@ -287,7 +287,7 @@ anakin_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned long flags;
unsigned int quot;
unsigned int baud, quot;
/*
* We don't support parity, stop bits, or anything other
......@@ -304,11 +304,12 @@ anakin_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
spin_lock_irqsave(&port->lock, flags);
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
while (!(anakin_in(port, 0x10) & TXEMPTY))
barrier();
......
......@@ -320,7 +320,7 @@ static void
clps711xuart_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int ubrlcr, quot;
unsigned int ubrlcr, baud, quot;
unsigned long flags;
/*
......@@ -331,7 +331,8 @@ clps711xuart_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
case CS5:
......@@ -362,7 +363,7 @@ clps711xuart_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = UARTDR_OVERR;
if (termios->c_iflag & INPCK)
......
......@@ -271,7 +271,7 @@ static void uart_shutdown(struct uart_info *info)
*/
void
uart_update_timeout(struct uart_port *port, unsigned int cflag,
unsigned int quot)
unsigned int baud)
{
unsigned int bits;
......@@ -305,7 +305,7 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag,
* Figure the timeout to send the above number of bits.
* Add .02 seconds of slop
*/
port->timeout = (HZ * bits) / (port->uartclk / (16 * quot)) + HZ/50;
port->timeout = (HZ * bits) / baud + HZ/50;
}
EXPORT_SYMBOL(uart_update_timeout);
......@@ -321,6 +321,12 @@ EXPORT_SYMBOL(uart_update_timeout);
* Decode the termios structure into a numeric baud rate,
* taking account of the magic 38400 baud rate (with spd_*
* flags), and mapping the %B0 rate to 9600 baud.
*
* If the new baud rate is invalid, try the old termios setting.
* If it's still invalid, we try 9600 baud.
*
* Update the @termios structure to reflect the baud rate
* we're actually going to be using.
*/
unsigned int
uart_get_baud_rate(struct uart_port *port, struct termios *termios,
......@@ -383,26 +389,14 @@ EXPORT_SYMBOL(uart_get_baud_rate);
/**
* uart_get_divisor - return uart clock divisor
* @port: uart_port structure describing the port.
* @termios: desired termios settings
* @old_termios: the original port settings, or NULL
*
* Calculate the uart clock divisor for the port. If the
* divisor is invalid, try the old termios setting. If
* the divisor is still invalid, we try 9600 baud.
* @baud: desired baud rate
*
* Update the @termios structure to reflect the baud rate
* we're actually going to be using.
*
* If 9600 baud fails, we return a zero divisor.
* Calculate the uart clock divisor for the port.
*/
unsigned int
uart_get_divisor(struct uart_port *port, struct termios *termios,
struct termios *old_termios)
uart_get_divisor(struct uart_port *port, unsigned int baud)
{
unsigned int quot, baud, max = port->uartclk / 16;
/* Determine divisor based on baud rate */
baud = uart_get_baud_rate(port, termios, old_termios, 0, max);
unsigned int quot;
/*
* Old custom speed handling.
......
......@@ -441,7 +441,7 @@ sa1100_set_termios(struct uart_port *port, struct termios *termios,
{
struct sa1100_port *sport = (struct sa1100_port *)port;
unsigned long flags;
unsigned int utcr0, old_utcr3, quot;
unsigned int utcr0, old_utcr3, baud, quot;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
/*
......@@ -470,7 +470,8 @@ sa1100_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
spin_lock_irqsave(&sport->port.lock, flags);
......@@ -507,7 +508,7 @@ sa1100_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
/*
* disable interrupts and drain transmitter
......
......@@ -853,7 +853,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, cflag, quot);
uart_update_timeout(port, cflag, (port->uartclk / (16 * quot)));
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (iflag & INPCK)
......@@ -920,12 +920,13 @@ static void
sunsu_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int quot;
unsigned int baud, quot;
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
sunsu_change_speed(port, termios->c_cflag, termios->c_iflag, quot);
}
......
......@@ -317,7 +317,7 @@ static void
uart00_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int uart_mc, old_ies, quot;
unsigned int uart_mc, old_ies, baud, quot;
unsigned long flags;
/*
......@@ -328,7 +328,8 @@ uart00_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
/* byte size and parity */
switch (termios->c_cflag & CSIZE) {
......@@ -358,7 +359,7 @@ uart00_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = UART_RDS_OE_MSK;
if (termios->c_iflag & INPCK)
......
......@@ -279,12 +279,11 @@ void uart_write_wakeup(struct uart_port *port);
* Baud rate helpers.
*/
void uart_update_timeout(struct uart_port *port, unsigned int cflag,
unsigned int quot);
unsigned int baud);
unsigned int uart_get_baud_rate(struct uart_port *port, struct termios *termios,
struct termios *old, unsigned int min,
unsigned int max);
unsigned int uart_get_divisor(struct uart_port *port, struct termios *termios,
struct termios *old_termios);
unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud);
/*
* Console helpers.
......
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