aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/atmel_serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial/atmel_serial.c')
-rw-r--r--drivers/serial/atmel_serial.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 3320bcd92c0a..4d6b3c56d20e 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -114,6 +114,7 @@ struct atmel_uart_port {
114 struct uart_port uart; /* uart */ 114 struct uart_port uart; /* uart */
115 struct clk *clk; /* uart clock */ 115 struct clk *clk; /* uart clock */
116 unsigned short suspended; /* is port suspended? */ 116 unsigned short suspended; /* is port suspended? */
117 int break_active; /* break being received */
117}; 118};
118 119
119static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; 120static 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)
252 */ 253 */
253static void atmel_rx_chars(struct uart_port *port) 254static void atmel_rx_chars(struct uart_port *port)
254{ 255{
256 struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
255 struct tty_struct *tty = port->info->tty; 257 struct tty_struct *tty = port->info->tty;
256 unsigned int status, ch, flg; 258 unsigned int status, ch, flg;
257 259
@@ -267,13 +269,29 @@ static void atmel_rx_chars(struct uart_port *port)
267 * note that the error handling code is 269 * note that the error handling code is
268 * out of the main execution path 270 * out of the main execution path
269 */ 271 */
270 if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK))) { 272 if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
273 | ATMEL_US_OVRE | ATMEL_US_RXBRK)
274 || atmel_port->break_active)) {
271 UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */ 275 UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */
272 if (status & ATMEL_US_RXBRK) { 276 if (status & ATMEL_US_RXBRK
277 && !atmel_port->break_active) {
273 status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */ 278 status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */
274 port->icount.brk++; 279 port->icount.brk++;
280 atmel_port->break_active = 1;
281 UART_PUT_IER(port, ATMEL_US_RXBRK);
275 if (uart_handle_break(port)) 282 if (uart_handle_break(port))
276 goto ignore_char; 283 goto ignore_char;
284 } else {
285 /*
286 * This is either the end-of-break
287 * condition or we've received at
288 * least one character without RXBRK
289 * being set. In both cases, the next
290 * RXBRK will indicate start-of-break.
291 */
292 UART_PUT_IDR(port, ATMEL_US_RXBRK);
293 status &= ~ATMEL_US_RXBRK;
294 atmel_port->break_active = 0;
277 } 295 }
278 if (status & ATMEL_US_PARE) 296 if (status & ATMEL_US_PARE)
279 port->icount.parity++; 297 port->icount.parity++;
@@ -352,6 +370,16 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
352 /* Interrupt receive */ 370 /* Interrupt receive */
353 if (pending & ATMEL_US_RXRDY) 371 if (pending & ATMEL_US_RXRDY)
354 atmel_rx_chars(port); 372 atmel_rx_chars(port);
373 else if (pending & ATMEL_US_RXBRK) {
374 /*
375 * End of break detected. If it came along
376 * with a character, atmel_rx_chars will
377 * handle it.
378 */
379 UART_PUT_CR(port, ATMEL_US_RSTSTA);
380 UART_PUT_IDR(port, ATMEL_US_RXBRK);
381 atmel_port->break_active = 0;
382 }
355 383
356 // TODO: All reads to CSR will clear these interrupts! 384 // TODO: All reads to CSR will clear these interrupts!
357 if (pending & ATMEL_US_RIIC) port->icount.rng++; 385 if (pending & ATMEL_US_RIIC) port->icount.rng++;