2006-10-12 16:26:55 +04:00
/*
* linux / sound / arm / pxa2xx - pcm . c - - ALSA PCM interface for the Intel PXA2xx chip
*
* Author : Nicolas Pitre
* Created : Nov 30 , 2004
* Copyright : ( C ) 2004 MontaVista Software , Inc .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/dma-mapping.h>
2011-07-15 20:38:28 +04:00
# include <linux/module.h>
2006-10-12 16:26:55 +04:00
# include <sound/core.h>
# include <sound/soc.h>
2008-09-10 05:01:20 +04:00
# include <sound/pxa2xx-lib.h>
2006-10-12 16:26:55 +04:00
2008-09-10 05:01:20 +04:00
# include "../../arm/pxa2xx-pcm.h"
2006-10-12 16:26:55 +04:00
static int pxa2xx_pcm_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct pxa2xx_runtime_data * prtd = runtime - > private_data ;
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
2010-03-22 12:11:15 +03:00
struct pxa2xx_pcm_dma_params * dma ;
2006-10-12 16:26:55 +04:00
int ret ;
2010-03-17 23:15:21 +03:00
dma = snd_soc_dai_get_dma_data ( rtd - > cpu_dai , substream ) ;
2010-03-22 12:11:15 +03:00
2007-02-02 19:21:50 +03:00
/* return if this is a bufferless transfer e.g.
* codec < - - > BT codec or GSM modem - - lg FIXME */
2008-04-23 17:14:18 +04:00
if ( ! dma )
return 0 ;
2007-02-02 19:21:50 +03:00
2006-10-12 16:26:55 +04:00
/* this may get called several times by oss emulation
* with different params */
if ( prtd - > params = = NULL ) {
prtd - > params = dma ;
ret = pxa_request_dma ( prtd - > params - > name , DMA_PRIO_LOW ,
pxa2xx_pcm_dma_irq , substream ) ;
if ( ret < 0 )
return ret ;
prtd - > dma_ch = ret ;
} else if ( prtd - > params ! = dma ) {
pxa_free_dma ( prtd - > dma_ch ) ;
prtd - > params = dma ;
ret = pxa_request_dma ( prtd - > params - > name , DMA_PRIO_LOW ,
pxa2xx_pcm_dma_irq , substream ) ;
if ( ret < 0 )
return ret ;
prtd - > dma_ch = ret ;
}
2008-09-10 05:01:20 +04:00
return __pxa2xx_pcm_hw_params ( substream , params ) ;
2006-10-12 16:26:55 +04:00
}
static int pxa2xx_pcm_hw_free ( struct snd_pcm_substream * substream )
{
struct pxa2xx_runtime_data * prtd = substream - > runtime - > private_data ;
2008-09-10 05:01:20 +04:00
__pxa2xx_pcm_hw_free ( substream ) ;
2006-10-12 16:26:55 +04:00
2009-01-01 01:39:23 +03:00
if ( prtd - > dma_ch > = 0 ) {
2006-10-12 16:26:55 +04:00
pxa_free_dma ( prtd - > dma_ch ) ;
2009-01-01 01:39:23 +03:00
prtd - > dma_ch = - 1 ;
2011-04-02 11:54:47 +04:00
prtd - > params = NULL ;
2006-10-12 16:26:55 +04:00
}
return 0 ;
}
2008-11-21 17:05:48 +03:00
static struct snd_pcm_ops pxa2xx_pcm_ops = {
2008-09-10 05:01:20 +04:00
. open = __pxa2xx_pcm_open ,
. close = __pxa2xx_pcm_close ,
2006-10-12 16:26:55 +04:00
. ioctl = snd_pcm_lib_ioctl ,
. hw_params = pxa2xx_pcm_hw_params ,
. hw_free = pxa2xx_pcm_hw_free ,
2008-09-10 05:01:20 +04:00
. prepare = __pxa2xx_pcm_prepare ,
2006-10-12 16:26:55 +04:00
. trigger = pxa2xx_pcm_trigger ,
. pointer = pxa2xx_pcm_pointer ,
. mmap = pxa2xx_pcm_mmap ,
} ;
2009-04-07 06:01:15 +04:00
static u64 pxa2xx_pcm_dmamask = DMA_BIT_MASK ( 32 ) ;
2006-10-12 16:26:55 +04:00
2011-06-07 19:08:33 +04:00
static int pxa2xx_soc_pcm_new ( struct snd_soc_pcm_runtime * rtd )
2006-10-12 16:26:55 +04:00
{
2011-06-07 19:08:33 +04:00
struct snd_card * card = rtd - > card - > snd_card ;
struct snd_pcm * pcm = rtd - > pcm ;
2006-10-12 16:26:55 +04:00
int ret = 0 ;
if ( ! card - > dev - > dma_mask )
card - > dev - > dma_mask = & pxa2xx_pcm_dmamask ;
if ( ! card - > dev - > coherent_dma_mask )
2009-04-07 06:01:15 +04:00
card - > dev - > coherent_dma_mask = DMA_BIT_MASK ( 32 ) ;
2006-10-12 16:26:55 +04:00
2011-06-22 22:48:25 +04:00
if ( pcm - > streams [ SNDRV_PCM_STREAM_PLAYBACK ] . substream ) {
2006-10-12 16:26:55 +04:00
ret = pxa2xx_pcm_preallocate_dma_buffer ( pcm ,
SNDRV_PCM_STREAM_PLAYBACK ) ;
if ( ret )
goto out ;
}
2011-06-22 22:48:25 +04:00
if ( pcm - > streams [ SNDRV_PCM_STREAM_CAPTURE ] . substream ) {
2006-10-12 16:26:55 +04:00
ret = pxa2xx_pcm_preallocate_dma_buffer ( pcm ,
SNDRV_PCM_STREAM_CAPTURE ) ;
if ( ret )
goto out ;
}
out :
return ret ;
}
2010-03-17 23:15:21 +03:00
static struct snd_soc_platform_driver pxa2xx_soc_platform = {
. ops = & pxa2xx_pcm_ops ,
2008-07-29 14:42:24 +04:00
. pcm_new = pxa2xx_soc_pcm_new ,
2006-10-12 16:26:55 +04:00
. pcm_free = pxa2xx_pcm_free_dma_buffers ,
} ;
2010-03-17 23:15:21 +03:00
static int __devinit pxa2xx_soc_platform_probe ( struct platform_device * pdev )
2008-12-03 22:58:17 +03:00
{
2010-03-17 23:15:21 +03:00
return snd_soc_register_platform ( & pdev - > dev , & pxa2xx_soc_platform ) ;
2008-12-03 22:58:17 +03:00
}
2010-03-17 23:15:21 +03:00
static int __devexit pxa2xx_soc_platform_remove ( struct platform_device * pdev )
2008-12-03 22:58:17 +03:00
{
2010-03-17 23:15:21 +03:00
snd_soc_unregister_platform ( & pdev - > dev ) ;
return 0 ;
}
static struct platform_driver pxa_pcm_driver = {
. driver = {
. name = " pxa-pcm-audio " ,
. owner = THIS_MODULE ,
} ,
. probe = pxa2xx_soc_platform_probe ,
. remove = __devexit_p ( pxa2xx_soc_platform_remove ) ,
} ;
2011-11-25 06:13:37 +04:00
module_platform_driver ( pxa_pcm_driver ) ;
2008-12-03 22:58:17 +03:00
2006-10-12 16:26:55 +04:00
MODULE_AUTHOR ( " Nicolas Pitre " ) ;
MODULE_DESCRIPTION ( " Intel PXA2xx PCM DMA module " ) ;
MODULE_LICENSE ( " GPL " ) ;