diff options
author | Robert Baldyga <r.baldyga@samsung.com> | 2014-12-10 06:49:25 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-01-09 17:25:39 -0500 |
commit | 62c37eedb74c8fbf3c92f8f28a871e6bd80c181a (patch) | |
tree | 28b553e4d6a37b0f6e14eb2ea2b8aede75e38f18 /drivers/tty/serial | |
parent | a291b7d5f600a068af1e2186ce590a9a39093ddb (diff) |
serial: samsung: add dma reqest/release functions
Add functions requesting and releasing RX and TX DMA channels. This
function are called only when "dmas" property in serial device-tree
node is defined.
Based on previous work of Sylwester Nawrocki and Lukasz Czerwinski.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r-- | drivers/tty/serial/samsung.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 7196a3e586cf..825c8192b944 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #define SUPPORT_SYSRQ | 28 | #define SUPPORT_SYSRQ |
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | #include <linux/dmaengine.h> | ||
32 | #include <linux/dma-mapping.h> | ||
33 | #include <linux/slab.h> | ||
31 | #include <linux/module.h> | 34 | #include <linux/module.h> |
32 | #include <linux/ioport.h> | 35 | #include <linux/ioport.h> |
33 | #include <linux/io.h> | 36 | #include <linux/io.h> |
@@ -453,6 +456,93 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) | |||
453 | spin_unlock_irqrestore(&port->lock, flags); | 456 | spin_unlock_irqrestore(&port->lock, flags); |
454 | } | 457 | } |
455 | 458 | ||
459 | static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) | ||
460 | { | ||
461 | struct s3c24xx_uart_dma *dma = p->dma; | ||
462 | dma_cap_mask_t mask; | ||
463 | unsigned long flags; | ||
464 | |||
465 | /* Default slave configuration parameters */ | ||
466 | dma->rx_conf.direction = DMA_DEV_TO_MEM; | ||
467 | dma->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; | ||
468 | dma->rx_conf.src_addr = p->port.mapbase + S3C2410_URXH; | ||
469 | dma->rx_conf.src_maxburst = 16; | ||
470 | |||
471 | dma->tx_conf.direction = DMA_MEM_TO_DEV; | ||
472 | dma->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; | ||
473 | dma->tx_conf.dst_addr = p->port.mapbase + S3C2410_UTXH; | ||
474 | if (dma_get_cache_alignment() >= 16) | ||
475 | dma->tx_conf.dst_maxburst = 16; | ||
476 | else | ||
477 | dma->tx_conf.dst_maxburst = 1; | ||
478 | |||
479 | dma_cap_zero(mask); | ||
480 | dma_cap_set(DMA_SLAVE, mask); | ||
481 | |||
482 | dma->rx_chan = dma_request_slave_channel_compat(mask, dma->fn, | ||
483 | dma->rx_param, p->port.dev, "rx"); | ||
484 | if (!dma->rx_chan) | ||
485 | return -ENODEV; | ||
486 | |||
487 | dmaengine_slave_config(dma->rx_chan, &dma->rx_conf); | ||
488 | |||
489 | dma->tx_chan = dma_request_slave_channel_compat(mask, dma->fn, | ||
490 | dma->tx_param, p->port.dev, "tx"); | ||
491 | if (!dma->tx_chan) { | ||
492 | dma_release_channel(dma->rx_chan); | ||
493 | return -ENODEV; | ||
494 | } | ||
495 | |||
496 | dmaengine_slave_config(dma->tx_chan, &dma->tx_conf); | ||
497 | |||
498 | /* RX buffer */ | ||
499 | dma->rx_size = PAGE_SIZE; | ||
500 | |||
501 | dma->rx_buf = kmalloc(dma->rx_size, GFP_KERNEL); | ||
502 | |||
503 | if (!dma->rx_buf) { | ||
504 | dma_release_channel(dma->rx_chan); | ||
505 | dma_release_channel(dma->tx_chan); | ||
506 | return -ENOMEM; | ||
507 | } | ||
508 | |||
509 | dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf, | ||
510 | dma->rx_size, DMA_FROM_DEVICE); | ||
511 | |||
512 | spin_lock_irqsave(&p->port.lock, flags); | ||
513 | |||
514 | /* TX buffer */ | ||
515 | dma->tx_addr = dma_map_single(dma->tx_chan->device->dev, | ||
516 | p->port.state->xmit.buf, | ||
517 | UART_XMIT_SIZE, DMA_TO_DEVICE); | ||
518 | |||
519 | spin_unlock_irqrestore(&p->port.lock, flags); | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p) | ||
525 | { | ||
526 | struct s3c24xx_uart_dma *dma = p->dma; | ||
527 | |||
528 | if (dma->rx_chan) { | ||
529 | dmaengine_terminate_all(dma->rx_chan); | ||
530 | dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr, | ||
531 | dma->rx_size, DMA_FROM_DEVICE); | ||
532 | kfree(dma->rx_buf); | ||
533 | dma_release_channel(dma->rx_chan); | ||
534 | dma->rx_chan = NULL; | ||
535 | } | ||
536 | |||
537 | if (dma->tx_chan) { | ||
538 | dmaengine_terminate_all(dma->tx_chan); | ||
539 | dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr, | ||
540 | UART_XMIT_SIZE, DMA_TO_DEVICE); | ||
541 | dma_release_channel(dma->tx_chan); | ||
542 | dma->tx_chan = NULL; | ||
543 | } | ||
544 | } | ||
545 | |||
456 | static void s3c24xx_serial_shutdown(struct uart_port *port) | 546 | static void s3c24xx_serial_shutdown(struct uart_port *port) |
457 | { | 547 | { |
458 | struct s3c24xx_uart_port *ourport = to_ourport(port); | 548 | struct s3c24xx_uart_port *ourport = to_ourport(port); |
@@ -478,6 +568,10 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) | |||
478 | wr_regl(port, S3C64XX_UINTP, 0xf); | 568 | wr_regl(port, S3C64XX_UINTP, 0xf); |
479 | wr_regl(port, S3C64XX_UINTM, 0xf); | 569 | wr_regl(port, S3C64XX_UINTM, 0xf); |
480 | } | 570 | } |
571 | |||
572 | if (ourport->dma) | ||
573 | s3c24xx_serial_release_dma(ourport); | ||
574 | |||
481 | } | 575 | } |
482 | 576 | ||
483 | static int s3c24xx_serial_startup(struct uart_port *port) | 577 | static int s3c24xx_serial_startup(struct uart_port *port) |
@@ -535,6 +629,13 @@ static int s3c64xx_serial_startup(struct uart_port *port) | |||
535 | port, (unsigned long long)port->mapbase, port->membase); | 629 | port, (unsigned long long)port->mapbase, port->membase); |
536 | 630 | ||
537 | wr_regl(port, S3C64XX_UINTM, 0xf); | 631 | wr_regl(port, S3C64XX_UINTM, 0xf); |
632 | if (ourport->dma) { | ||
633 | ret = s3c24xx_serial_request_dma(ourport); | ||
634 | if (ret < 0) { | ||
635 | dev_warn(port->dev, "DMA request failed\n"); | ||
636 | return ret; | ||
637 | } | ||
638 | } | ||
538 | 639 | ||
539 | ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED, | 640 | ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED, |
540 | s3c24xx_serial_portname(port), ourport); | 641 | s3c24xx_serial_portname(port), ourport); |