aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial
diff options
context:
space:
mode:
authorRobert Baldyga <r.baldyga@samsung.com>2014-12-10 06:49:25 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-01-09 17:25:39 -0500
commit62c37eedb74c8fbf3c92f8f28a871e6bd80c181a (patch)
tree28b553e4d6a37b0f6e14eb2ea2b8aede75e38f18 /drivers/tty/serial
parenta291b7d5f600a068af1e2186ce590a9a39093ddb (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.c101
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
459static 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
524static 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
456static void s3c24xx_serial_shutdown(struct uart_port *port) 546static 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
483static int s3c24xx_serial_startup(struct uart_port *port) 577static 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);