2012-08-16 17:10:41 +05:30
/*
* soc - compress . c - - ALSA SoC Compress
*
* Copyright ( C ) 2012 Intel Corp .
*
* Authors : Namarta Kohli < namartax . kohli @ intel . com >
* Ramesh Babu K V < ramesh . babu @ linux . intel . com >
* Vinod Koul < vinod . koul @ linux . intel . com >
*
* This program is free software ; you can redistribute it and / or modify 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 .
*
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/workqueue.h>
# include <sound/core.h>
# include <sound/compress_params.h>
# include <sound/compress_driver.h>
# include <sound/soc.h>
# include <sound/initval.h>
static int soc_compr_open ( struct snd_compr_stream * cstream )
{
struct snd_soc_pcm_runtime * rtd = cstream - > private_data ;
struct snd_soc_platform * platform = rtd - > platform ;
struct snd_soc_dai * cpu_dai = rtd - > cpu_dai ;
struct snd_soc_dai * codec_dai = rtd - > codec_dai ;
int ret = 0 ;
if ( platform - > driver - > compr_ops & & platform - > driver - > compr_ops - > open ) {
ret = platform - > driver - > compr_ops - > open ( cstream ) ;
if ( ret < 0 ) {
pr_err ( " compress asoc: can't open platform %s \n " , platform - > name ) ;
goto out ;
}
}
if ( rtd - > dai_link - > compr_ops & & rtd - > dai_link - > compr_ops - > startup ) {
ret = rtd - > dai_link - > compr_ops - > startup ( cstream ) ;
if ( ret < 0 ) {
pr_err ( " compress asoc: %s startup failed \n " , rtd - > dai_link - > name ) ;
goto machine_err ;
}
}
if ( cstream - > direction = = SND_COMPRESS_PLAYBACK ) {
cpu_dai - > playback_active + + ;
codec_dai - > playback_active + + ;
} else {
cpu_dai - > capture_active + + ;
codec_dai - > capture_active + + ;
}
cpu_dai - > active + + ;
codec_dai - > active + + ;
rtd - > codec - > active + + ;
return 0 ;
machine_err :
if ( platform - > driver - > compr_ops & & platform - > driver - > compr_ops - > free )
platform - > driver - > compr_ops - > free ( cstream ) ;
out :
return ret ;
}
static int soc_compr_free ( struct snd_compr_stream * cstream )
{
struct snd_soc_pcm_runtime * rtd = cstream - > private_data ;
struct snd_soc_platform * platform = rtd - > platform ;
struct snd_soc_dai * cpu_dai = rtd - > cpu_dai ;
struct snd_soc_dai * codec_dai = rtd - > codec_dai ;
struct snd_soc_codec * codec = rtd - > codec ;
if ( cstream - > direction = = SND_COMPRESS_PLAYBACK ) {
cpu_dai - > playback_active - - ;
codec_dai - > playback_active - - ;
} else {
cpu_dai - > capture_active - - ;
codec_dai - > capture_active - - ;
}
snd_soc_dai_digital_mute ( codec_dai , 1 ) ;
cpu_dai - > active - - ;
codec_dai - > active - - ;
codec - > active - - ;
if ( ! cpu_dai - > active )
cpu_dai - > rate = 0 ;
if ( ! codec_dai - > active )
codec_dai - > rate = 0 ;
if ( rtd - > dai_link - > compr_ops & & rtd - > dai_link - > compr_ops - > shutdown )
rtd - > dai_link - > compr_ops - > shutdown ( cstream ) ;
if ( platform - > driver - > compr_ops & & platform - > driver - > compr_ops - > free )
platform - > driver - > compr_ops - > free ( cstream ) ;
2012-08-21 12:15:02 +05:30
cpu_dai - > runtime = NULL ;
2012-08-16 17:10:41 +05:30
if ( cstream - > direction = = SND_COMPRESS_PLAYBACK ) {
if ( ! rtd - > pmdown_time | | codec - > ignore_pmdown_time | |
rtd - > dai_link - > ignore_pmdown_time ) {
snd_soc_dapm_stream_event ( rtd ,
SNDRV_PCM_STREAM_PLAYBACK ,
SND_SOC_DAPM_STREAM_STOP ) ;
} else
codec_dai - > pop_wait = 1 ;
schedule_delayed_work ( & rtd - > delayed_work ,
msecs_to_jiffies ( rtd - > pmdown_time ) ) ;
} else {
/* capture streams can be powered down now */
snd_soc_dapm_stream_event ( rtd ,
SNDRV_PCM_STREAM_CAPTURE ,
SND_SOC_DAPM_STREAM_STOP ) ;
}
return 0 ;
}
static int soc_compr_trigger ( struct snd_compr_stream * cstream , int cmd )
{
struct snd_soc_pcm_runtime * rtd = cstream - > private_data ;
struct snd_soc_platform * platform = rtd - > platform ;
struct snd_soc_dai * codec_dai = rtd - > codec_dai ;
int ret = 0 ;
if ( platform - > driver - > compr_ops & & platform - > driver - > compr_ops - > trigger ) {
ret = platform - > driver - > compr_ops - > trigger ( cstream , cmd ) ;
if ( ret < 0 )
return ret ;
}
if ( cmd = = SNDRV_PCM_TRIGGER_START )
snd_soc_dai_digital_mute ( codec_dai , 0 ) ;
else if ( cmd = = SNDRV_PCM_TRIGGER_STOP )
snd_soc_dai_digital_mute ( codec_dai , 1 ) ;
return ret ;
}
static int soc_compr_set_params ( struct snd_compr_stream * cstream ,
struct snd_compr_params * params )
{
struct snd_soc_pcm_runtime * rtd = cstream - > private_data ;
struct snd_soc_platform * platform = rtd - > platform ;
int ret = 0 ;
/* first we call set_params for the platform driver
* this should configure the soc side
* if the machine has compressed ops then we call that as well
* expectation is that platform and machine will configure everything
* for this compress path , like configuring pcm port for codec
*/
if ( platform - > driver - > compr_ops & & platform - > driver - > compr_ops - > set_params ) {
ret = platform - > driver - > compr_ops - > set_params ( cstream , params ) ;
if ( ret < 0 )
return ret ;
}
if ( rtd - > dai_link - > compr_ops & & rtd - > dai_link - > compr_ops - > set_params ) {
ret = rtd - > dai_link - > compr_ops - > set_params ( cstream ) ;
if ( ret < 0 )
return ret ;
}
snd_soc_dapm_stream_event ( rtd , SNDRV_PCM_STREAM_PLAYBACK ,
SND_SOC_DAPM_STREAM_START ) ;
return ret ;
}
static int soc_compr_get_params ( struct snd_compr_stream * cstream ,
struct snd_codec * params )
{
struct snd_soc_pcm_runtime * rtd = cstream - > private_data ;
struct snd_soc_platform * platform = rtd - > platform ;
int ret = 0 ;
if ( platform - > driver - > compr_ops & & platform - > driver - > compr_ops - > get_params )
ret = platform - > driver - > compr_ops - > get_params ( cstream , params ) ;
return ret ;
}
static int soc_compr_get_caps ( struct snd_compr_stream * cstream ,
struct snd_compr_caps * caps )
{
struct snd_soc_pcm_runtime * rtd = cstream - > private_data ;
struct snd_soc_platform * platform = rtd - > platform ;
int ret = 0 ;
if ( platform - > driver - > compr_ops & & platform - > driver - > compr_ops - > get_caps )
ret = platform - > driver - > compr_ops - > get_caps ( cstream , caps ) ;
return ret ;
}
static int soc_compr_get_codec_caps ( struct snd_compr_stream * cstream ,
struct snd_compr_codec_caps * codec )
{
struct snd_soc_pcm_runtime * rtd = cstream - > private_data ;
struct snd_soc_platform * platform = rtd - > platform ;
int ret = 0 ;
if ( platform - > driver - > compr_ops & & platform - > driver - > compr_ops - > get_codec_caps )
ret = platform - > driver - > compr_ops - > get_codec_caps ( cstream , codec ) ;
return ret ;
}
static int soc_compr_ack ( struct snd_compr_stream * cstream , size_t bytes )
{
struct snd_soc_pcm_runtime * rtd = cstream - > private_data ;
struct snd_soc_platform * platform = rtd - > platform ;
int ret = 0 ;
if ( platform - > driver - > compr_ops & & platform - > driver - > compr_ops - > ack )
ret = platform - > driver - > compr_ops - > ack ( cstream , bytes ) ;
return ret ;
}
static int soc_compr_pointer ( struct snd_compr_stream * cstream ,
struct snd_compr_tstamp * tstamp )
{
struct snd_soc_pcm_runtime * rtd = cstream - > private_data ;
struct snd_soc_platform * platform = rtd - > platform ;
if ( platform - > driver - > compr_ops & & platform - > driver - > compr_ops - > pointer )
platform - > driver - > compr_ops - > pointer ( cstream , tstamp ) ;
return 0 ;
}
/* ASoC Compress operations */
static struct snd_compr_ops soc_compr_ops = {
. open = soc_compr_open ,
. free = soc_compr_free ,
. set_params = soc_compr_set_params ,
. get_params = soc_compr_get_params ,
. trigger = soc_compr_trigger ,
. pointer = soc_compr_pointer ,
. ack = soc_compr_ack ,
. get_caps = soc_compr_get_caps ,
. get_codec_caps = soc_compr_get_codec_caps
} ;
/* create a new compress */
int soc_new_compress ( struct snd_soc_pcm_runtime * rtd , int num )
{
struct snd_soc_codec * codec = rtd - > codec ;
struct snd_soc_dai * codec_dai = rtd - > codec_dai ;
struct snd_soc_dai * cpu_dai = rtd - > cpu_dai ;
struct snd_compr * compr ;
char new_name [ 64 ] ;
int ret = 0 , direction = 0 ;
/* check client and interface hw capabilities */
snprintf ( new_name , sizeof ( new_name ) , " %s %s-%d " ,
rtd - > dai_link - > stream_name , codec_dai - > name , num ) ;
direction = SND_COMPRESS_PLAYBACK ;
compr = kzalloc ( sizeof ( * compr ) , GFP_KERNEL ) ;
if ( compr = = NULL ) {
snd_printk ( KERN_ERR " Cannot allocate compr \n " ) ;
return - ENOMEM ;
}
compr - > ops = & soc_compr_ops ;
mutex_init ( & compr - > lock ) ;
ret = snd_compress_new ( rtd - > card - > snd_card , num , direction , compr ) ;
if ( ret < 0 ) {
pr_err ( " compress asoc: can't create compress for codec %s \n " ,
codec - > name ) ;
kfree ( compr ) ;
return ret ;
}
rtd - > compr = compr ;
compr - > private_data = rtd ;
printk ( KERN_INFO " compress asoc: %s <-> %s mapping ok \n " , codec_dai - > name ,
cpu_dai - > name ) ;
return ret ;
}