mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									a291b7d5f6
								
							
						
					
					
						commit
						62c37eedb7
					
				| @ -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> | ||||
| @ -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); | ||||
| @ -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) | ||||
| @ -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); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Robert Baldyga
						Robert Baldyga