2008-10-03 16:57:50 +02:00
/*
* atmel - pcm . c - - ALSA PCM interface for the Atmel atmel SoC .
2008-06-05 13:49:34 +01:00
*
2008-10-03 16:57:50 +02:00
* Copyright ( C ) 2005 SAN People
* Copyright ( C ) 2008 Atmel
*
* Authors : Sedji Gaouaou < sedji . gaouaou @ atmel . com >
*
* Based on at91 - pcm . by :
* Frank Mandarino < fmandarino @ endrelia . com >
* Copyright 2006 Endrelia Technologies Inc .
*
* Based on pxa2xx - pcm . c by :
*
* Author : Nicolas Pitre
* Created : Nov 30 , 2004
* Copyright : ( C ) 2004 MontaVista Software , Inc .
2008-06-05 13:49:34 +01:00
*
* This program is free software ; you can redistribute it and / or modify
2008-10-03 16:57:50 +02:00
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
2008-06-05 13:49:34 +01:00
*
2008-10-03 16:57:50 +02:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2008-06-05 13:49:34 +01:00
*/
# include <linux/module.h>
# include <linux/dma-mapping.h>
# include <sound/pcm.h>
# include <sound/soc.h>
2008-10-03 16:57:50 +02:00
# include "atmel-pcm.h"
2008-06-05 13:49:34 +01:00
2008-10-03 16:57:50 +02:00
static int atmel_pcm_preallocate_dma_buffer ( struct snd_pcm * pcm ,
int stream )
2008-06-05 13:49:34 +01:00
{
struct snd_pcm_substream * substream = pcm - > streams [ stream ] . substream ;
2008-10-03 16:57:50 +02:00
struct snd_dma_buffer * buf = & substream - > dma_buffer ;
2012-11-28 11:46:12 +08:00
size_t size = ATMEL_SSC_DMABUF_SIZE ;
2008-10-03 16:57:50 +02:00
buf - > dev . type = SNDRV_DMA_TYPE_DEV ;
buf - > dev . dev = pcm - > card - > dev ;
buf - > private_data = NULL ;
buf - > area = dma_alloc_coherent ( pcm - > card - > dev , size ,
2012-11-28 11:46:12 +08:00
& buf - > addr , GFP_KERNEL ) ;
2012-12-08 14:23:22 +01:00
pr_debug ( " atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu \n " ,
2013-09-20 15:54:54 -07:00
( void * ) buf - > area , ( void * ) ( long ) buf - > addr , size ) ;
2008-10-03 16:57:50 +02:00
if ( ! buf - > area )
2008-06-05 13:49:34 +01:00
return - ENOMEM ;
2008-10-03 16:57:50 +02:00
buf - > bytes = size ;
2008-06-05 13:49:34 +01:00
return 0 ;
}
2012-11-28 11:46:12 +08:00
int atmel_pcm_mmap ( struct snd_pcm_substream * substream ,
2008-10-03 16:57:50 +02:00
struct vm_area_struct * vma )
2008-06-05 13:49:34 +01:00
{
return remap_pfn_range ( vma , vma - > vm_start ,
2008-10-03 16:57:50 +02:00
substream - > dma_buffer . addr > > PAGE_SHIFT ,
vma - > vm_end - vma - > vm_start , vma - > vm_page_prot ) ;
2008-06-05 13:49:34 +01:00
}
2012-11-28 11:46:12 +08:00
EXPORT_SYMBOL_GPL ( atmel_pcm_mmap ) ;
2008-06-05 13:49:34 +01:00
2012-11-28 11:46:12 +08:00
int atmel_pcm_new ( struct snd_soc_pcm_runtime * rtd )
2008-06-05 13:49:34 +01:00
{
2011-06-07 16:08:33 +01:00
struct snd_card * card = rtd - > card - > snd_card ;
struct snd_pcm * pcm = rtd - > pcm ;
2013-06-27 12:53:37 +01:00
int ret ;
2008-06-05 13:49:34 +01:00
2013-06-27 12:53:37 +01:00
ret = dma_coerce_mask_and_coherent ( card - > dev , DMA_BIT_MASK ( 32 ) ) ;
if ( ret )
return ret ;
2008-06-05 13:49:34 +01:00
2012-01-01 01:58:44 +01:00
if ( pcm - > streams [ SNDRV_PCM_STREAM_PLAYBACK ] . substream ) {
2012-11-28 11:46:12 +08:00
pr_debug ( " atmel-pcm: allocating PCM playback DMA buffer \n " ) ;
2008-10-03 16:57:50 +02:00
ret = atmel_pcm_preallocate_dma_buffer ( pcm ,
SNDRV_PCM_STREAM_PLAYBACK ) ;
2008-06-05 13:49:34 +01:00
if ( ret )
goto out ;
}
2012-01-01 01:58:44 +01:00
if ( pcm - > streams [ SNDRV_PCM_STREAM_CAPTURE ] . substream ) {
2012-11-28 11:46:12 +08:00
pr_debug ( " atmel-pcm: allocating PCM capture DMA buffer \n " ) ;
2008-10-03 16:57:50 +02:00
ret = atmel_pcm_preallocate_dma_buffer ( pcm ,
SNDRV_PCM_STREAM_CAPTURE ) ;
2008-06-05 13:49:34 +01:00
if ( ret )
goto out ;
}
2008-10-03 16:57:50 +02:00
out :
2008-06-05 13:49:34 +01:00
return ret ;
}
2012-11-28 11:46:12 +08:00
EXPORT_SYMBOL_GPL ( atmel_pcm_new ) ;
2008-06-05 13:49:34 +01:00
2012-11-28 11:46:12 +08:00
void atmel_pcm_free ( struct snd_pcm * pcm )
2008-06-05 13:49:34 +01:00
{
struct snd_pcm_substream * substream ;
struct snd_dma_buffer * buf ;
int stream ;
for ( stream = 0 ; stream < 2 ; stream + + ) {
substream = pcm - > streams [ stream ] . substream ;
2008-10-03 16:57:50 +02:00
if ( ! substream )
2008-06-05 13:49:34 +01:00
continue ;
buf = & substream - > dma_buffer ;
if ( ! buf - > area )
continue ;
dma_free_coherent ( pcm - > card - > dev , buf - > bytes ,
buf - > area , buf - > addr ) ;
buf - > area = NULL ;
}
}
2012-11-28 11:46:12 +08:00
EXPORT_SYMBOL_GPL ( atmel_pcm_free ) ;
2008-06-05 13:49:34 +01:00