diff options
| -rw-r--r-- | drivers/serial/mfd.c | 50 |
1 files changed, 47 insertions, 3 deletions
diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c index 300dcb134e07..ed2bf6b14a4a 100644 --- a/drivers/serial/mfd.c +++ b/drivers/serial/mfd.c | |||
| @@ -64,6 +64,8 @@ | |||
| 64 | #define mfd_readl(obj, offset) readl(obj->reg + offset) | 64 | #define mfd_readl(obj, offset) readl(obj->reg + offset) |
| 65 | #define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) | 65 | #define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) |
| 66 | 66 | ||
| 67 | #define HSU_DMA_TIMEOUT_CHECK_FREQ (HZ/10) | ||
| 68 | |||
| 67 | struct hsu_dma_buffer { | 69 | struct hsu_dma_buffer { |
| 68 | u8 *buf; | 70 | u8 *buf; |
| 69 | dma_addr_t dma_addr; | 71 | dma_addr_t dma_addr; |
| @@ -75,7 +77,8 @@ struct hsu_dma_chan { | |||
| 75 | u32 id; | 77 | u32 id; |
| 76 | u32 dirt; /* to or from device */ | 78 | u32 dirt; /* to or from device */ |
| 77 | struct uart_hsu_port *uport; | 79 | struct uart_hsu_port *uport; |
| 78 | void __iomem *reg; | 80 | void __iomem *reg; |
| 81 | struct timer_list rx_timer; /* only needed by RX channel */ | ||
| 79 | }; | 82 | }; |
| 80 | 83 | ||
| 81 | struct uart_hsu_port { | 84 | struct uart_hsu_port { |
| @@ -377,6 +380,8 @@ void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf | |||
| 377 | | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ | 380 | | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ |
| 378 | ); | 381 | ); |
| 379 | chan_writel(rxc, HSU_CH_CR, 0x3); | 382 | chan_writel(rxc, HSU_CH_CR, 0x3); |
| 383 | |||
| 384 | mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); | ||
| 380 | } | 385 | } |
| 381 | 386 | ||
| 382 | /* Protected by spin_lock_irqsave(port->lock) */ | 387 | /* Protected by spin_lock_irqsave(port->lock) */ |
| @@ -437,8 +442,13 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts) | |||
| 437 | /* We can use 2 ways to calc the actual transfer len */ | 442 | /* We can use 2 ways to calc the actual transfer len */ |
| 438 | count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; | 443 | count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; |
| 439 | 444 | ||
| 440 | if (!count) | 445 | if (!count) { |
| 446 | /* restart the channel before we leave */ | ||
| 447 | chan_writel(chan, HSU_CH_CR, 0x3); | ||
| 441 | return; | 448 | return; |
| 449 | } | ||
| 450 | |||
| 451 | del_timer(&chan->rx_timer); | ||
| 442 | 452 | ||
| 443 | dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, | 453 | dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, |
| 444 | dbuf->dma_size, DMA_FROM_DEVICE); | 454 | dbuf->dma_size, DMA_FROM_DEVICE); |
| @@ -463,9 +473,12 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts) | |||
| 463 | | (0x1 << 16) | 473 | | (0x1 << 16) |
| 464 | | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ | 474 | | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ |
| 465 | ); | 475 | ); |
| 476 | tty_flip_buffer_push(tty); | ||
| 477 | |||
| 466 | chan_writel(chan, HSU_CH_CR, 0x3); | 478 | chan_writel(chan, HSU_CH_CR, 0x3); |
| 479 | chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ; | ||
| 480 | add_timer(&chan->rx_timer); | ||
| 467 | 481 | ||
| 468 | tty_flip_buffer_push(tty); | ||
| 469 | } | 482 | } |
| 470 | 483 | ||
| 471 | static void serial_hsu_stop_rx(struct uart_port *port) | 484 | static void serial_hsu_stop_rx(struct uart_port *port) |
| @@ -893,6 +906,8 @@ static void serial_hsu_shutdown(struct uart_port *port) | |||
| 893 | container_of(port, struct uart_hsu_port, port); | 906 | container_of(port, struct uart_hsu_port, port); |
| 894 | unsigned long flags; | 907 | unsigned long flags; |
| 895 | 908 | ||
| 909 | del_timer_sync(&up->rxc->rx_timer); | ||
| 910 | |||
| 896 | /* Disable interrupts from this port */ | 911 | /* Disable interrupts from this port */ |
| 897 | up->ier = 0; | 912 | up->ier = 0; |
| 898 | serial_out(up, UART_IER, 0); | 913 | serial_out(up, UART_IER, 0); |
| @@ -1348,6 +1363,28 @@ err_disable: | |||
| 1348 | return ret; | 1363 | return ret; |
| 1349 | } | 1364 | } |
| 1350 | 1365 | ||
| 1366 | static void hsu_dma_rx_timeout(unsigned long data) | ||
| 1367 | { | ||
| 1368 | struct hsu_dma_chan *chan = (void *)data; | ||
| 1369 | struct uart_hsu_port *up = chan->uport; | ||
| 1370 | struct hsu_dma_buffer *dbuf = &up->rxbuf; | ||
| 1371 | int count = 0; | ||
| 1372 | unsigned long flags; | ||
| 1373 | |||
| 1374 | spin_lock_irqsave(&up->port.lock, flags); | ||
| 1375 | |||
| 1376 | count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; | ||
| 1377 | |||
| 1378 | if (!count) { | ||
| 1379 | mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); | ||
| 1380 | goto exit; | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | hsu_dma_rx(up, 0); | ||
| 1384 | exit: | ||
| 1385 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
| 1386 | } | ||
| 1387 | |||
| 1351 | static void hsu_global_init(void) | 1388 | static void hsu_global_init(void) |
| 1352 | { | 1389 | { |
| 1353 | struct hsu_port *hsu; | 1390 | struct hsu_port *hsu; |
| @@ -1409,6 +1446,13 @@ static void hsu_global_init(void) | |||
| 1409 | dchan->uport = &hsu->port[i/2]; | 1446 | dchan->uport = &hsu->port[i/2]; |
| 1410 | dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + | 1447 | dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + |
| 1411 | i * HSU_DMA_CHANS_REG_LENGTH; | 1448 | i * HSU_DMA_CHANS_REG_LENGTH; |
| 1449 | |||
| 1450 | /* Work around for RX */ | ||
| 1451 | if (dchan->dirt == DMA_FROM_DEVICE) { | ||
| 1452 | init_timer(&dchan->rx_timer); | ||
| 1453 | dchan->rx_timer.function = hsu_dma_rx_timeout; | ||
| 1454 | dchan->rx_timer.data = (unsigned long)dchan; | ||
| 1455 | } | ||
| 1412 | dchan++; | 1456 | dchan++; |
| 1413 | } | 1457 | } |
| 1414 | 1458 | ||
