Skip to content

Commit

Permalink
serial: samsung: add dma reqest/release functions
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Robert Baldyga authored and gregkh committed Jan 9, 2015
1 parent a291b7d commit 62c37ee
Showing 1 changed file with 101 additions and 0 deletions.
101 changes: 101 additions & 0 deletions drivers/tty/serial/samsung.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#define SUPPORT_SYSRQ
#endif

#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/io.h>
Expand Down Expand Up @@ -453,6 +456,93 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&port->lock, flags);
}

static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
{
struct s3c24xx_uart_dma *dma = p->dma;
dma_cap_mask_t mask;
unsigned long flags;

/* Default slave configuration parameters */
dma->rx_conf.direction = DMA_DEV_TO_MEM;
dma->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma->rx_conf.src_addr = p->port.mapbase + S3C2410_URXH;
dma->rx_conf.src_maxburst = 16;

dma->tx_conf.direction = DMA_MEM_TO_DEV;
dma->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma->tx_conf.dst_addr = p->port.mapbase + S3C2410_UTXH;
if (dma_get_cache_alignment() >= 16)
dma->tx_conf.dst_maxburst = 16;
else
dma->tx_conf.dst_maxburst = 1;

dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);

dma->rx_chan = dma_request_slave_channel_compat(mask, dma->fn,
dma->rx_param, p->port.dev, "rx");
if (!dma->rx_chan)
return -ENODEV;

dmaengine_slave_config(dma->rx_chan, &dma->rx_conf);

dma->tx_chan = dma_request_slave_channel_compat(mask, dma->fn,
dma->tx_param, p->port.dev, "tx");
if (!dma->tx_chan) {
dma_release_channel(dma->rx_chan);
return -ENODEV;
}

dmaengine_slave_config(dma->tx_chan, &dma->tx_conf);

/* RX buffer */
dma->rx_size = PAGE_SIZE;

dma->rx_buf = kmalloc(dma->rx_size, GFP_KERNEL);

if (!dma->rx_buf) {
dma_release_channel(dma->rx_chan);
dma_release_channel(dma->tx_chan);
return -ENOMEM;
}

dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
dma->rx_size, DMA_FROM_DEVICE);

spin_lock_irqsave(&p->port.lock, flags);

/* TX buffer */
dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
p->port.state->xmit.buf,
UART_XMIT_SIZE, DMA_TO_DEVICE);

spin_unlock_irqrestore(&p->port.lock, flags);

return 0;
}

static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
{
struct s3c24xx_uart_dma *dma = p->dma;

if (dma->rx_chan) {
dmaengine_terminate_all(dma->rx_chan);
dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
kfree(dma->rx_buf);
dma_release_channel(dma->rx_chan);
dma->rx_chan = NULL;
}

if (dma->tx_chan) {
dmaengine_terminate_all(dma->tx_chan);
dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_release_channel(dma->tx_chan);
dma->tx_chan = NULL;
}
}

static void s3c24xx_serial_shutdown(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
Expand All @@ -478,6 +568,10 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
wr_regl(port, S3C64XX_UINTP, 0xf);
wr_regl(port, S3C64XX_UINTM, 0xf);
}

if (ourport->dma)
s3c24xx_serial_release_dma(ourport);

}

static int s3c24xx_serial_startup(struct uart_port *port)
Expand Down Expand Up @@ -535,6 +629,13 @@ static int s3c64xx_serial_startup(struct uart_port *port)
port, (unsigned long long)port->mapbase, port->membase);

wr_regl(port, S3C64XX_UINTM, 0xf);
if (ourport->dma) {
ret = s3c24xx_serial_request_dma(ourport);
if (ret < 0) {
dev_warn(port->dev, "DMA request failed\n");
return ret;
}
}

ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
s3c24xx_serial_portname(port), ourport);
Expand Down

0 comments on commit 62c37ee

Please sign in to comment.