|  | @@ -769,3 +769,63 @@ int s3c2410_dma_request(enum dma_ch channel,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	return chan->number | DMACH_LOW_LEVEL;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +EXPORT_SYMBOL(s3c2410_dma_request);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* s3c2410_dma_free
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * release the given channel back to the system, will stop and flush
 | 
	
		
			
				|  |  | + * any outstanding transfers, and ensure the channel is ready for the
 | 
	
		
			
				|  |  | + * next claimant.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Note, although a warning is currently printed if the freeing client
 | 
	
		
			
				|  |  | + * info is not the same as the registrant's client info, the free is still
 | 
	
		
			
				|  |  | + * allowed to go through.
 | 
	
		
			
				|  |  | +*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
 | 
	
		
			
				|  |  | +	unsigned long flags;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (chan == NULL)
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	local_irq_save(flags);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (chan->client != client) {
 | 
	
		
			
				|  |  | +		printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
 | 
	
		
			
				|  |  | +		       channel, chan->client, client);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* sort out stopping and freeing the channel */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (chan->state != S3C2410_DMA_IDLE) {
 | 
	
		
			
				|  |  | +		pr_debug("%s: need to stop dma channel %p\n",
 | 
	
		
			
				|  |  | +		       __func__, chan);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		/* possibly flush the channel */
 | 
	
		
			
				|  |  | +		s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	chan->client = NULL;
 | 
	
		
			
				|  |  | +	chan->in_use = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (chan->irq_claimed)
 | 
	
		
			
				|  |  | +		free_irq(chan->irq, (void *)chan);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	chan->irq_claimed = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!(channel & DMACH_LOW_LEVEL))
 | 
	
		
			
				|  |  | +		s3c_dma_chan_map[channel] = NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	local_irq_restore(flags);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +EXPORT_SYMBOL(s3c2410_dma_free);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	unsigned long flags;
 |