X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fserial%2Fatmel_serial.c;h=4d6b3c56d20e7df9ea1262ae89cae2e24d18f901;hb=b4e44369a380c1836d0983c2a5011099b7b26eb1;hp=935f48fa501d5b398a3913281b5740e160ec4b85;hpb=874ff01bd9183ad16495acfd54e93a619d12b8b5;p=linux-2.6-omap-h63xx.git diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 935f48fa501..4d6b3c56d20 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -114,6 +114,7 @@ struct atmel_uart_port { struct uart_port uart; /* uart */ struct clk *clk; /* uart clock */ unsigned short suspended; /* is port suspended? */ + int break_active; /* break being received */ }; static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; @@ -252,6 +253,7 @@ static void atmel_break_ctl(struct uart_port *port, int break_state) */ static void atmel_rx_chars(struct uart_port *port) { + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; struct tty_struct *tty = port->info->tty; unsigned int status, ch, flg; @@ -267,13 +269,29 @@ static void atmel_rx_chars(struct uart_port *port) * note that the error handling code is * out of the main execution path */ - if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK))) { + if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME + | ATMEL_US_OVRE | ATMEL_US_RXBRK) + || atmel_port->break_active)) { UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */ - if (status & ATMEL_US_RXBRK) { + if (status & ATMEL_US_RXBRK + && !atmel_port->break_active) { status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */ port->icount.brk++; + atmel_port->break_active = 1; + UART_PUT_IER(port, ATMEL_US_RXBRK); if (uart_handle_break(port)) goto ignore_char; + } else { + /* + * This is either the end-of-break + * condition or we've received at + * least one character without RXBRK + * being set. In both cases, the next + * RXBRK will indicate start-of-break. + */ + UART_PUT_IDR(port, ATMEL_US_RXBRK); + status &= ~ATMEL_US_RXBRK; + atmel_port->break_active = 0; } if (status & ATMEL_US_PARE) port->icount.parity++; @@ -352,6 +370,16 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) /* Interrupt receive */ if (pending & ATMEL_US_RXRDY) atmel_rx_chars(port); + else if (pending & ATMEL_US_RXBRK) { + /* + * End of break detected. If it came along + * with a character, atmel_rx_chars will + * handle it. + */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + UART_PUT_IDR(port, ATMEL_US_RXBRK); + atmel_port->break_active = 0; + } // TODO: All reads to CSR will clear these interrupts! if (pending & ATMEL_US_RIIC) port->icount.rng++; @@ -484,11 +512,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, unsigned long flags; unsigned int mode, imr, quot, baud; + /* Get current mode register */ + mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR); + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); - /* Get current mode register */ - mode = UART_GET_MR(port) & ~(ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR); + if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ + quot /= 8; + mode |= ATMEL_US_USCLKS_MCK_DIV8; + } /* byte size */ switch (termios->c_cflag & CSIZE) {