diff options
author | Elen Song <elen.song@atmel.com> | 2013-07-22 16:30:30 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-07-29 13:05:04 -0700 |
commit | 2e68c22fde9b001e41d47185a5b7612da60d8c33 (patch) | |
tree | 758c095f1f23b3da35e0089fca62adec9ed9885b /drivers/tty/serial/atmel_serial.c | |
parent | 055560b04a8cd063aea916fd083b7aec02c2adb8 (diff) |
serial: at91: make UART support dma and pdc transfers
Because the UART lack of receive timeout register, so we use a timer to trigger
data receive.
The DBGU is regarded as UART.
Signed-off-by: Elen Song <elen.song@atmel.com>
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/atmel_serial.c')
-rw-r--r-- | drivers/tty/serial/atmel_serial.c | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 8dbc3e67dfa..7e2cb31497c 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -40,6 +40,7 @@ #include <linux/atmel_serial.h> #include <linux/uaccess.h> #include <linux/platform_data/atmel.h> +#include <linux/timer.h> #include <asm/io.h> #include <asm/ioctls.h> @@ -168,6 +169,7 @@ struct atmel_uart_port { struct serial_rs485 rs485; /* rs485 settings */ unsigned int tx_done_mask; bool is_usart; /* usart or uart */ + struct timer_list uart_timer; /* uart timer */ int (*prepare_rx)(struct uart_port *port); int (*prepare_tx)(struct uart_port *port); void (*schedule_rx)(struct uart_port *port); @@ -822,6 +824,9 @@ static void atmel_release_rx_dma(struct uart_port *port) atmel_port->desc_rx = NULL; atmel_port->chan_rx = NULL; atmel_port->cookie_rx = -EINVAL; + + if (!atmel_port->is_usart) + del_timer_sync(&atmel_port->uart_timer); } static void atmel_rx_from_dma(struct uart_port *port) @@ -951,6 +956,15 @@ chan_err: return -EINVAL; } +static void atmel_uart_timer_callback(unsigned long data) +{ + struct uart_port *port = (void *)data; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + tasklet_schedule(&atmel_port->tasklet); + mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); +} + /* * receive interrupt handler. */ @@ -1214,6 +1228,9 @@ static void atmel_release_rx_pdc(struct uart_port *port) DMA_FROM_DEVICE); kfree(pdc->buf); } + + if (!atmel_port->is_usart) + del_timer_sync(&atmel_port->uart_timer); } static void atmel_rx_from_pdc(struct uart_port *port) @@ -1575,17 +1592,36 @@ static int atmel_startup(struct uart_port *port) if (atmel_use_pdc_rx(port)) { /* set UART timeout */ - UART_PUT_RTOR(port, PDC_RX_TIMEOUT); - UART_PUT_CR(port, ATMEL_US_STTTO); + if (!atmel_port->is_usart) { + setup_timer(&atmel_port->uart_timer, + atmel_uart_timer_callback, + (unsigned long)port); + mod_timer(&atmel_port->uart_timer, + jiffies + uart_poll_timeout(port)); + /* set USART timeout */ + } else { + UART_PUT_RTOR(port, PDC_RX_TIMEOUT); + UART_PUT_CR(port, ATMEL_US_STTTO); - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + } /* enable PDC controller */ UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); } else if (atmel_use_dma_rx(port)) { - UART_PUT_RTOR(port, PDC_RX_TIMEOUT); - UART_PUT_CR(port, ATMEL_US_STTTO); + /* set UART timeout */ + if (!atmel_port->is_usart) { + setup_timer(&atmel_port->uart_timer, + atmel_uart_timer_callback, + (unsigned long)port); + mod_timer(&atmel_port->uart_timer, + jiffies + uart_poll_timeout(port)); + /* set USART timeout */ + } else { + UART_PUT_RTOR(port, PDC_RX_TIMEOUT); + UART_PUT_CR(port, ATMEL_US_STTTO); - UART_PUT_IER(port, ATMEL_US_TIMEOUT); + UART_PUT_IER(port, ATMEL_US_TIMEOUT); + } } else { /* enable receive only */ UART_PUT_IER(port, ATMEL_US_RXRDY); |