diff options
author | Elen Song <elen.song@atmel.com> | 2013-07-22 04:30:30 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-07-29 16:05:04 -0400 |
commit | 2e68c22fde9b001e41d47185a5b7612da60d8c33 (patch) | |
tree | 758c095f1f23b3da35e0089fca62adec9ed9885b | |
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>
-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 8dbc3e67dfa4..7e2cb31497c3 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/atmel_serial.h> | 40 | #include <linux/atmel_serial.h> |
41 | #include <linux/uaccess.h> | 41 | #include <linux/uaccess.h> |
42 | #include <linux/platform_data/atmel.h> | 42 | #include <linux/platform_data/atmel.h> |
43 | #include <linux/timer.h> | ||
43 | 44 | ||
44 | #include <asm/io.h> | 45 | #include <asm/io.h> |
45 | #include <asm/ioctls.h> | 46 | #include <asm/ioctls.h> |
@@ -168,6 +169,7 @@ struct atmel_uart_port { | |||
168 | struct serial_rs485 rs485; /* rs485 settings */ | 169 | struct serial_rs485 rs485; /* rs485 settings */ |
169 | unsigned int tx_done_mask; | 170 | unsigned int tx_done_mask; |
170 | bool is_usart; /* usart or uart */ | 171 | bool is_usart; /* usart or uart */ |
172 | struct timer_list uart_timer; /* uart timer */ | ||
171 | int (*prepare_rx)(struct uart_port *port); | 173 | int (*prepare_rx)(struct uart_port *port); |
172 | int (*prepare_tx)(struct uart_port *port); | 174 | int (*prepare_tx)(struct uart_port *port); |
173 | void (*schedule_rx)(struct uart_port *port); | 175 | void (*schedule_rx)(struct uart_port *port); |
@@ -822,6 +824,9 @@ static void atmel_release_rx_dma(struct uart_port *port) | |||
822 | atmel_port->desc_rx = NULL; | 824 | atmel_port->desc_rx = NULL; |
823 | atmel_port->chan_rx = NULL; | 825 | atmel_port->chan_rx = NULL; |
824 | atmel_port->cookie_rx = -EINVAL; | 826 | atmel_port->cookie_rx = -EINVAL; |
827 | |||
828 | if (!atmel_port->is_usart) | ||
829 | del_timer_sync(&atmel_port->uart_timer); | ||
825 | } | 830 | } |
826 | 831 | ||
827 | static void atmel_rx_from_dma(struct uart_port *port) | 832 | static void atmel_rx_from_dma(struct uart_port *port) |
@@ -951,6 +956,15 @@ chan_err: | |||
951 | return -EINVAL; | 956 | return -EINVAL; |
952 | } | 957 | } |
953 | 958 | ||
959 | static void atmel_uart_timer_callback(unsigned long data) | ||
960 | { | ||
961 | struct uart_port *port = (void *)data; | ||
962 | struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); | ||
963 | |||
964 | tasklet_schedule(&atmel_port->tasklet); | ||
965 | mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); | ||
966 | } | ||
967 | |||
954 | /* | 968 | /* |
955 | * receive interrupt handler. | 969 | * receive interrupt handler. |
956 | */ | 970 | */ |
@@ -1214,6 +1228,9 @@ static void atmel_release_rx_pdc(struct uart_port *port) | |||
1214 | DMA_FROM_DEVICE); | 1228 | DMA_FROM_DEVICE); |
1215 | kfree(pdc->buf); | 1229 | kfree(pdc->buf); |
1216 | } | 1230 | } |
1231 | |||
1232 | if (!atmel_port->is_usart) | ||
1233 | del_timer_sync(&atmel_port->uart_timer); | ||
1217 | } | 1234 | } |
1218 | 1235 | ||
1219 | static void atmel_rx_from_pdc(struct uart_port *port) | 1236 | static void atmel_rx_from_pdc(struct uart_port *port) |
@@ -1575,17 +1592,36 @@ static int atmel_startup(struct uart_port *port) | |||
1575 | 1592 | ||
1576 | if (atmel_use_pdc_rx(port)) { | 1593 | if (atmel_use_pdc_rx(port)) { |
1577 | /* set UART timeout */ | 1594 | /* set UART timeout */ |
1578 | UART_PUT_RTOR(port, PDC_RX_TIMEOUT); | 1595 | if (!atmel_port->is_usart) { |
1579 | UART_PUT_CR(port, ATMEL_US_STTTO); | 1596 | setup_timer(&atmel_port->uart_timer, |
1597 | atmel_uart_timer_callback, | ||
1598 | (unsigned long)port); | ||
1599 | mod_timer(&atmel_port->uart_timer, | ||
1600 | jiffies + uart_poll_timeout(port)); | ||
1601 | /* set USART timeout */ | ||
1602 | } else { | ||
1603 | UART_PUT_RTOR(port, PDC_RX_TIMEOUT); | ||
1604 | UART_PUT_CR(port, ATMEL_US_STTTO); | ||
1580 | 1605 | ||
1581 | UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); | 1606 | UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); |
1607 | } | ||
1582 | /* enable PDC controller */ | 1608 | /* enable PDC controller */ |
1583 | UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); | 1609 | UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); |
1584 | } else if (atmel_use_dma_rx(port)) { | 1610 | } else if (atmel_use_dma_rx(port)) { |
1585 | UART_PUT_RTOR(port, PDC_RX_TIMEOUT); | 1611 | /* set UART timeout */ |
1586 | UART_PUT_CR(port, ATMEL_US_STTTO); | 1612 | if (!atmel_port->is_usart) { |
1613 | setup_timer(&atmel_port->uart_timer, | ||
1614 | atmel_uart_timer_callback, | ||
1615 | (unsigned long)port); | ||
1616 | mod_timer(&atmel_port->uart_timer, | ||
1617 | jiffies + uart_poll_timeout(port)); | ||
1618 | /* set USART timeout */ | ||
1619 | } else { | ||
1620 | UART_PUT_RTOR(port, PDC_RX_TIMEOUT); | ||
1621 | UART_PUT_CR(port, ATMEL_US_STTTO); | ||
1587 | 1622 | ||
1588 | UART_PUT_IER(port, ATMEL_US_TIMEOUT); | 1623 | UART_PUT_IER(port, ATMEL_US_TIMEOUT); |
1624 | } | ||
1589 | } else { | 1625 | } else { |
1590 | /* enable receive only */ | 1626 | /* enable receive only */ |
1591 | UART_PUT_IER(port, ATMEL_US_RXRDY); | 1627 | UART_PUT_IER(port, ATMEL_US_RXRDY); |