/*
- * File: drivers/serial/bfin_5xx.c
- * Based on: Based on drivers/serial/sa1100.c
- * Author: Aubrey Li <aubrey.li@analog.com>
+ * Blackfin On-Chip Serial Driver
*
- * Created:
- * Description: Driver for blackfin 5xx serial ports
+ * Copyright 2006-2007 Analog Devices Inc.
*
- * Modified:
- * Copyright 2006 Analog Devices Inc.
+ * Enter bugs at http://blackfin.uclinux.org/
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define DMA_RX_XCOUNT 512
#define DMA_RX_YCOUNT (PAGE_SIZE / DMA_RX_XCOUNT)
-#define DMA_RX_FLUSH_JIFFIES 5
+#define DMA_RX_FLUSH_JIFFIES (HZ / 50)
#ifdef CONFIG_SERIAL_BFIN_DMA
static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
#else
-static void bfin_serial_do_work(struct work_struct *work);
static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
#endif
static void bfin_serial_stop_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ struct circ_buf *xmit = &uart->port.info->xmit;
#if !defined(CONFIG_BF54x) && !defined(CONFIG_SERIAL_BFIN_DMA)
unsigned short ier;
#endif
while (!(UART_GET_LSR(uart) & TEMT))
- continue;
+ cpu_relax();
#ifdef CONFIG_SERIAL_BFIN_DMA
disable_dma(uart->tx_dma_channel);
+ xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+ uart->port.icount.tx += uart->tx_count;
+ uart->tx_count = 0;
+ uart->tx_done = 1;
#else
#ifdef CONFIG_BF54x
/* Clear TFI bit */
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
#ifdef CONFIG_SERIAL_BFIN_DMA
- bfin_serial_dma_tx_chars(uart);
+ if (uart->tx_done)
+ bfin_serial_dma_tx_chars(uart);
#else
#ifdef CONFIG_BF54x
UART_SET_IER(uart, ETBEI);
return IRQ_HANDLED;
}
+#endif
-
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
static void bfin_serial_do_work(struct work_struct *work)
{
struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue);
{
struct circ_buf *xmit = &uart->port.info->xmit;
unsigned short ier;
- int flags = 0;
- if (!uart->tx_done)
- return;
uart->tx_done = 0;
if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
- bfin_serial_stop_tx(&uart->port);
+ uart->tx_count = 0;
uart->tx_done = 1;
return;
}
*/
bfin_serial_mctrl_check(uart);
- spin_lock_irqsave(&uart->port.lock, flags);
uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
uart->tx_count = UART_XMIT_SIZE - xmit->tail;
set_dma_x_modify(uart->tx_dma_channel, 1);
enable_dma(uart->tx_dma_channel);
- xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
- uart->port.icount.tx += uart->tx_count;
-
#ifdef CONFIG_BF54x
UART_SET_IER(uart, ETBEI);
#else
ier |= ETBEI;
UART_PUT_IER(uart, ier);
#endif
- spin_unlock_irqrestore(&uart->port.lock, flags);
}
static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
status = UART_GET_LSR(uart);
UART_CLEAR_LSR(uart);
- uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);;
+ uart->port.icount.rx +=
+ CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail,
+ UART_XMIT_SIZE);
if (status & BI) {
uart->port.icount.brk++;
else
flg = TTY_NORMAL;
- for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) {
- if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
- goto dma_ignore_char;
- uart_insert_char(&uart->port, status, OE, uart->rx_dma_buf.buf[i], flg);
+ for (i = uart->rx_dma_buf.tail; i != uart->rx_dma_buf.head; i++) {
+ if (i >= UART_XMIT_SIZE)
+ i = 0;
+ if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
+ uart_insert_char(&uart->port, status, OE,
+ uart->rx_dma_buf.buf[i], flg);
}
dma_ignore_char:
void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
{
int x_pos, pos;
- int flags = 0;
- spin_lock_irqsave(&uart->port.lock, flags);
- x_pos = DMA_RX_XCOUNT - get_dma_curr_xcount(uart->rx_dma_channel);
+ uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
+ x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
+ uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
+ if (uart->rx_dma_nrows == DMA_RX_YCOUNT)
+ uart->rx_dma_nrows = 0;
+ x_pos = DMA_RX_XCOUNT - x_pos;
if (x_pos == DMA_RX_XCOUNT)
x_pos = 0;
pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
-
- if (pos>uart->rx_dma_buf.tail) {
- uart->rx_dma_buf.tail = pos;
+ if (pos != uart->rx_dma_buf.tail) {
+ uart->rx_dma_buf.head = pos;
bfin_serial_dma_rx_chars(uart);
- uart->rx_dma_buf.head = uart->rx_dma_buf.tail;
+ uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
}
- spin_unlock_irqrestore(&uart->port.lock, flags);
+
uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
add_timer(&(uart->rx_dma_timer));
}
spin_lock(&uart->port.lock);
if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
- clear_dma_irqstat(uart->tx_dma_channel);
disable_dma(uart->tx_dma_channel);
+ clear_dma_irqstat(uart->tx_dma_channel);
#ifdef CONFIG_BF54x
UART_CLEAR_IER(uart, ETBEI);
#else
ier &= ~ETBEI;
UART_PUT_IER(uart, ier);
#endif
+ xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+ uart->port.icount.tx += uart->tx_count;
+
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uart->port);
- uart->tx_done = 1;
-
bfin_serial_dma_tx_chars(uart);
}
struct bfin_serial_port *uart = dev_id;
unsigned short irqstat;
- uart->rx_dma_nrows++;
- if (uart->rx_dma_nrows == DMA_RX_YCOUNT) {
- uart->rx_dma_nrows = 0;
- uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT;
- bfin_serial_dma_rx_chars(uart);
- uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0;
- }
spin_lock(&uart->port.lock);
irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
clear_dma_irqstat(uart->rx_dma_channel);
-
spin_unlock(&uart->port.lock);
+
+ del_timer(&(uart->rx_dma_timer));
+ uart->rx_dma_timer.expires = jiffies;
+ add_timer(&(uart->rx_dma_timer));
+
return IRQ_HANDLED;
}
#endif
if (uart->cts_pin < 0)
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+# ifdef BF54x
+ if (UART_GET_MSR(uart) & CTS)
+# else
if (gpio_get_value(uart->cts_pin))
+# endif
return TIOCM_DSR | TIOCM_CAR;
else
#endif
return;
if (mctrl & TIOCM_RTS)
+# ifdef BF54x
+ UART_PUT_MCR(uart, UART_GET_MCR(uart) & ~MRTS);
+# else
gpio_set_value(uart->rts_pin, 0);
+# endif
else
+# ifdef BF54x
+ UART_PUT_MCR(uart, UART_GET_MCR(uart) | MRTS);
+# else
gpio_set_value(uart->rts_pin, 1);
+# endif
#endif
}
{
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
unsigned int status;
-# ifdef CONFIG_SERIAL_BFIN_DMA
struct uart_info *info = uart->port.info;
struct tty_struct *tty = info->tty;
status = bfin_serial_get_mctrl(&uart->port);
+ uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
if (!(status & TIOCM_CTS)) {
tty->hw_stopped = 1;
+ schedule_work(&uart->cts_workqueue);
} else {
tty->hw_stopped = 0;
}
-# else
- status = bfin_serial_get_mctrl(&uart->port);
- uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
- if (!(status & TIOCM_CTS))
- schedule_work(&uart->cts_workqueue);
-# endif
#endif
}
bfin_serial_ports[i].rx_dma_channel =
bfin_serial_resource[i].uart_rx_dma_channel;
init_timer(&(bfin_serial_ports[i].rx_dma_timer));
-#else
- INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work);
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work);
bfin_serial_ports[i].cts_pin =
bfin_serial_resource[i].uart_cts_pin;
bfin_serial_ports[i].rts_pin =
.resume = bfin_serial_resume,
.driver = {
.name = "bfin-uart",
+ .owner = THIS_MODULE,
},
};
MODULE_DESCRIPTION("Blackfin generic serial port driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR);
+MODULE_ALIAS("platform:bfin-uart");