summaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/atmel_serial.c
diff options
context:
space:
mode:
authorElen Song <elen.song@atmel.com>2013-07-22 16:30:30 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-29 13:05:04 -0700
commit2e68c22fde9b001e41d47185a5b7612da60d8c33 (patch)
tree758c095f1f23b3da35e0089fca62adec9ed9885b /drivers/tty/serial/atmel_serial.c
parent055560b04a8cd063aea916fd083b7aec02c2adb8 (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.c48
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);