Commit 2e68c22f authored by Elen Song's avatar Elen Song Committed by Greg Kroah-Hartman

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: default avatarElen Song <elen.song@atmel.com>
Signed-off-by: default avatarLudovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 055560b0
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <linux/atmel_serial.h> #include <linux/atmel_serial.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/platform_data/atmel.h> #include <linux/platform_data/atmel.h>
#include <linux/timer.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/ioctls.h> #include <asm/ioctls.h>
...@@ -168,6 +169,7 @@ struct atmel_uart_port { ...@@ -168,6 +169,7 @@ struct atmel_uart_port {
struct serial_rs485 rs485; /* rs485 settings */ struct serial_rs485 rs485; /* rs485 settings */
unsigned int tx_done_mask; unsigned int tx_done_mask;
bool is_usart; /* usart or uart */ bool is_usart; /* usart or uart */
struct timer_list uart_timer; /* uart timer */
int (*prepare_rx)(struct uart_port *port); int (*prepare_rx)(struct uart_port *port);
int (*prepare_tx)(struct uart_port *port); int (*prepare_tx)(struct uart_port *port);
void (*schedule_rx)(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) ...@@ -822,6 +824,9 @@ static void atmel_release_rx_dma(struct uart_port *port)
atmel_port->desc_rx = NULL; atmel_port->desc_rx = NULL;
atmel_port->chan_rx = NULL; atmel_port->chan_rx = NULL;
atmel_port->cookie_rx = -EINVAL; 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) static void atmel_rx_from_dma(struct uart_port *port)
...@@ -951,6 +956,15 @@ static int atmel_prepare_rx_dma(struct uart_port *port) ...@@ -951,6 +956,15 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
return -EINVAL; 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. * receive interrupt handler.
*/ */
...@@ -1214,6 +1228,9 @@ static void atmel_release_rx_pdc(struct uart_port *port) ...@@ -1214,6 +1228,9 @@ static void atmel_release_rx_pdc(struct uart_port *port)
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
kfree(pdc->buf); 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) static void atmel_rx_from_pdc(struct uart_port *port)
...@@ -1575,17 +1592,36 @@ static int atmel_startup(struct uart_port *port) ...@@ -1575,17 +1592,36 @@ static int atmel_startup(struct uart_port *port)
if (atmel_use_pdc_rx(port)) { if (atmel_use_pdc_rx(port)) {
/* set UART timeout */ /* set UART timeout */
UART_PUT_RTOR(port, PDC_RX_TIMEOUT); if (!atmel_port->is_usart) {
UART_PUT_CR(port, ATMEL_US_STTTO); 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 */ /* enable PDC controller */
UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
} else if (atmel_use_dma_rx(port)) { } else if (atmel_use_dma_rx(port)) {
UART_PUT_RTOR(port, PDC_RX_TIMEOUT); /* set UART 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_TIMEOUT); UART_PUT_IER(port, ATMEL_US_TIMEOUT);
}
} else { } else {
/* enable receive only */ /* enable receive only */
UART_PUT_IER(port, ATMEL_US_RXRDY); UART_PUT_IER(port, ATMEL_US_RXRDY);
......
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