2011-01-04 20:16:32 +05:30
/*
2014-03-12 23:04:35 +00:00
* sst_mfld_platform . c - Intel MID Platform driver
2011-01-04 20:16:32 +05:30
*
2014-06-13 18:03:56 +05:30
* Copyright ( C ) 2010 - 2014 Intel Corp
2011-01-04 20:16:32 +05:30
* Author : Vinod Koul < vinod . koul @ intel . com >
* Author : Harsha Priya < priya . harsha @ 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 ; version 2 of the License .
*
* 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 .
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/slab.h>
# include <linux/io.h>
2011-07-15 12:38:28 -04:00
# include <linux/module.h>
2011-01-04 20:16:32 +05:30
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
2012-08-16 17:10:42 +05:30
# include <sound/compress_driver.h>
2014-06-13 18:03:56 +05:30
# include <asm/platform_sst_audio.h>
2014-03-12 23:04:35 +00:00
# include "sst-mfld-platform.h"
2014-06-13 18:03:56 +05:30
# include "sst-atom-controls.h"
2011-01-04 20:16:32 +05:30
2014-05-05 14:27:50 +05:30
struct sst_device * sst ;
2011-12-05 19:13:41 +05:30
static DEFINE_MUTEX ( sst_lock ) ;
int sst_register_dsp ( struct sst_device * dev )
{
2013-11-05 18:40:01 +01:00
if ( WARN_ON ( ! dev ) )
return - EINVAL ;
2011-12-05 19:13:41 +05:30
if ( ! try_module_get ( dev - > dev - > driver - > owner ) )
return - ENODEV ;
mutex_lock ( & sst_lock ) ;
if ( sst ) {
2014-09-02 18:05:56 +05:30
dev_err ( dev - > dev , " we already have a device %s \n " , sst - > name ) ;
2011-12-05 19:13:41 +05:30
module_put ( dev - > dev - > driver - > owner ) ;
mutex_unlock ( & sst_lock ) ;
return - EEXIST ;
}
2014-09-02 18:05:56 +05:30
dev_dbg ( dev - > dev , " registering device %s \n " , dev - > name ) ;
2011-12-05 19:13:41 +05:30
sst = dev ;
mutex_unlock ( & sst_lock ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( sst_register_dsp ) ;
int sst_unregister_dsp ( struct sst_device * dev )
{
2013-11-05 18:40:01 +01:00
if ( WARN_ON ( ! dev ) )
return - EINVAL ;
2011-12-05 19:13:41 +05:30
if ( dev ! = sst )
return - EINVAL ;
mutex_lock ( & sst_lock ) ;
if ( ! sst ) {
mutex_unlock ( & sst_lock ) ;
return - EIO ;
}
module_put ( sst - > dev - > driver - > owner ) ;
2014-09-02 18:05:56 +05:30
dev_dbg ( dev - > dev , " unreg %s \n " , sst - > name ) ;
2011-12-05 19:13:41 +05:30
sst = NULL ;
mutex_unlock ( & sst_lock ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( sst_unregister_dsp ) ;
2011-01-04 20:16:32 +05:30
static struct snd_pcm_hardware sst_platform_pcm_hw = {
. info = ( SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_DOUBLE |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_SYNC_START ) ,
. buffer_bytes_max = SST_MAX_BUFFER ,
. period_bytes_min = SST_MIN_PERIOD_BYTES ,
. period_bytes_max = SST_MAX_PERIOD_BYTES ,
. periods_min = SST_MIN_PERIODS ,
. periods_max = SST_MAX_PERIODS ,
. fifo_size = SST_FIFO_SIZE ,
} ;
2014-06-13 18:03:56 +05:30
static struct sst_dev_stream_map dpcm_strm_map [ ] = {
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } , /* Reserved, not in use */
{ MERR_DPCM_AUDIO , 0 , SNDRV_PCM_STREAM_PLAYBACK , PIPE_MEDIA1_IN , SST_TASK_ID_MEDIA , 0 } ,
{ MERR_DPCM_COMPR , 0 , SNDRV_PCM_STREAM_PLAYBACK , PIPE_MEDIA0_IN , SST_TASK_ID_MEDIA , 0 } ,
{ MERR_DPCM_AUDIO , 0 , SNDRV_PCM_STREAM_CAPTURE , PIPE_PCM1_OUT , SST_TASK_ID_MEDIA , 0 } ,
} ;
2014-10-15 20:12:59 +05:30
static int sst_media_digital_mute ( struct snd_soc_dai * dai , int mute , int stream )
2011-01-04 20:16:32 +05:30
{
2014-10-15 20:12:59 +05:30
return sst_send_pipe_gains ( dai , stream , mute ) ;
}
2011-01-11 14:50:35 +05:30
2011-01-04 20:16:32 +05:30
/* helper functions */
2014-05-05 14:27:49 +05:30
void sst_set_stream_status ( struct sst_runtime_stream * stream ,
2011-01-11 14:50:35 +05:30
int state )
{
2011-04-08 15:38:48 +08:00
unsigned long flags ;
spin_lock_irqsave ( & stream - > status_lock , flags ) ;
2011-01-11 14:50:35 +05:30
stream - > stream_status = state ;
2011-04-08 15:38:48 +08:00
spin_unlock_irqrestore ( & stream - > status_lock , flags ) ;
2011-01-11 14:50:35 +05:30
}
static inline int sst_get_stream_status ( struct sst_runtime_stream * stream )
{
int state ;
2011-04-08 15:38:48 +08:00
unsigned long flags ;
2011-01-11 14:50:35 +05:30
2011-04-08 15:38:48 +08:00
spin_lock_irqsave ( & stream - > status_lock , flags ) ;
2011-01-11 14:50:35 +05:30
state = stream - > stream_status ;
2011-04-08 15:38:48 +08:00
spin_unlock_irqrestore ( & stream - > status_lock , flags ) ;
2011-01-11 14:50:35 +05:30
return state ;
}
2014-06-13 18:03:55 +05:30
static void sst_fill_alloc_params ( struct snd_pcm_substream * substream ,
struct snd_sst_alloc_params_ext * alloc_param )
{
unsigned int channels ;
snd_pcm_uframes_t period_size ;
ssize_t periodbytes ;
ssize_t buffer_bytes = snd_pcm_lib_buffer_bytes ( substream ) ;
u32 buffer_addr = virt_to_phys ( substream - > dma_buffer . area ) ;
channels = substream - > runtime - > channels ;
period_size = substream - > runtime - > period_size ;
periodbytes = samples_to_bytes ( substream - > runtime , period_size ) ;
alloc_param - > ring_buf_info [ 0 ] . addr = buffer_addr ;
alloc_param - > ring_buf_info [ 0 ] . size = buffer_bytes ;
alloc_param - > sg_count = 1 ;
alloc_param - > reserved = 0 ;
alloc_param - > frag_size = periodbytes * channels ;
}
2011-01-11 14:50:35 +05:30
static void sst_fill_pcm_params ( struct snd_pcm_substream * substream ,
2014-06-13 18:03:55 +05:30
struct snd_sst_stream_params * param )
2011-01-11 14:50:35 +05:30
{
2014-06-13 18:03:55 +05:30
param - > uc . pcm_params . num_chan = ( u8 ) substream - > runtime - > channels ;
param - > uc . pcm_params . pcm_wd_sz = substream - > runtime - > sample_bits ;
param - > uc . pcm_params . sfreq = substream - > runtime - > rate ;
2011-01-11 14:50:35 +05:30
2014-06-13 18:03:55 +05:30
/* PCM stream via ALSA interface */
param - > uc . pcm_params . use_offload_path = 0 ;
param - > uc . pcm_params . reserved2 = 0 ;
memset ( param - > uc . pcm_params . channel_map , 0 , sizeof ( u8 ) ) ;
}
2014-06-13 18:03:56 +05:30
static int sst_get_stream_mapping ( int dev , int sdev , int dir ,
struct sst_dev_stream_map * map , int size )
{
int i ;
if ( map = = NULL )
return - EINVAL ;
/* index 0 is not used in stream map */
for ( i = 1 ; i < size ; i + + ) {
if ( ( map [ i ] . dev_num = = dev ) & & ( map [ i ] . direction = = dir ) )
return i ;
}
return 0 ;
}
2014-06-13 18:03:55 +05:30
int sst_fill_stream_params ( void * substream ,
2014-06-13 18:03:56 +05:30
const struct sst_data * ctx , struct snd_sst_params * str_params , bool is_compress )
2014-06-13 18:03:55 +05:30
{
2014-06-13 18:03:56 +05:30
int map_size ;
int index ;
struct sst_dev_stream_map * map ;
2014-06-13 18:03:55 +05:30
struct snd_pcm_substream * pstream = NULL ;
struct snd_compr_stream * cstream = NULL ;
2014-06-13 18:03:56 +05:30
map = ctx - > pdata - > pdev_strm_map ;
map_size = ctx - > pdata - > strm_map_size ;
2014-06-13 18:03:55 +05:30
if ( is_compress = = true )
cstream = ( struct snd_compr_stream * ) substream ;
else
pstream = ( struct snd_pcm_substream * ) substream ;
str_params - > stream_type = SST_STREAM_TYPE_MUSIC ;
/* For pcm streams */
2014-06-13 18:03:56 +05:30
if ( pstream ) {
index = sst_get_stream_mapping ( pstream - > pcm - > device ,
pstream - > number , pstream - > stream ,
map , map_size ) ;
if ( index < = 0 )
return - EINVAL ;
str_params - > stream_id = index ;
str_params - > device_type = map [ index ] . device_id ;
str_params - > task = map [ index ] . task_id ;
2014-06-13 18:03:55 +05:30
str_params - > ops = ( u8 ) pstream - > stream ;
2014-06-13 18:03:56 +05:30
}
if ( cstream ) {
index = sst_get_stream_mapping ( cstream - > device - > device ,
0 , cstream - > direction ,
map , map_size ) ;
if ( index < = 0 )
return - EINVAL ;
str_params - > stream_id = index ;
str_params - > device_type = map [ index ] . device_id ;
str_params - > task = map [ index ] . task_id ;
2014-06-13 18:03:55 +05:30
2014-06-13 18:03:56 +05:30
str_params - > ops = ( u8 ) cstream - > direction ;
}
2014-06-13 18:03:55 +05:30
return 0 ;
2011-01-11 14:50:35 +05:30
}
2014-06-13 18:03:55 +05:30
static int sst_platform_alloc_stream ( struct snd_pcm_substream * substream ,
2014-09-09 15:11:32 +05:30
struct snd_soc_dai * dai )
2011-01-04 20:16:32 +05:30
{
struct sst_runtime_stream * stream =
substream - > runtime - > private_data ;
2014-06-13 18:03:55 +05:30
struct snd_sst_stream_params param = { { { 0 , } , } , } ;
struct snd_sst_params str_params = { 0 } ;
struct snd_sst_alloc_params_ext alloc_params = { 0 } ;
int ret_val = 0 ;
2014-09-09 15:11:32 +05:30
struct sst_data * ctx = snd_soc_dai_get_drvdata ( dai ) ;
2011-01-04 20:16:32 +05:30
/* set codec params and inform SST driver the same */
2011-01-11 14:50:35 +05:30
sst_fill_pcm_params ( substream , & param ) ;
2014-06-13 18:03:55 +05:30
sst_fill_alloc_params ( substream , & alloc_params ) ;
2011-01-04 20:16:32 +05:30
substream - > runtime - > dma_area = substream - > dma_buffer . area ;
str_params . sparams = param ;
2014-06-13 18:03:55 +05:30
str_params . aparams = alloc_params ;
str_params . codec = SST_CODEC_TYPE_PCM ;
/* fill the device type and stream id to pass to SST driver */
2014-06-13 18:03:56 +05:30
ret_val = sst_fill_stream_params ( substream , ctx , & str_params , false ) ;
2011-01-04 20:16:32 +05:30
if ( ret_val < 0 )
return ret_val ;
2014-06-13 18:03:55 +05:30
stream - > stream_info . str_id = str_params . stream_id ;
2014-08-04 15:04:21 +05:30
ret_val = stream - > ops - > open ( sst - > dev , & str_params ) ;
2014-06-13 18:03:55 +05:30
if ( ret_val < = 0 )
return ret_val ;
2011-01-04 20:16:32 +05:30
return ret_val ;
}
2014-06-13 18:03:52 +05:30
static void sst_period_elapsed ( void * arg )
2011-01-04 20:16:32 +05:30
{
2014-06-13 18:03:52 +05:30
struct snd_pcm_substream * substream = arg ;
2011-01-04 20:16:32 +05:30
struct sst_runtime_stream * stream ;
2011-01-11 14:50:35 +05:30
int status ;
2011-01-04 20:16:32 +05:30
if ( ! substream | | ! substream - > runtime )
return ;
stream = substream - > runtime - > private_data ;
if ( ! stream )
return ;
2011-01-11 14:50:35 +05:30
status = sst_get_stream_status ( stream ) ;
if ( status ! = SST_PLATFORM_RUNNING )
2011-01-04 20:16:32 +05:30
return ;
snd_pcm_period_elapsed ( substream ) ;
}
static int sst_platform_init_stream ( struct snd_pcm_substream * substream )
{
struct sst_runtime_stream * stream =
substream - > runtime - > private_data ;
2014-09-02 18:05:56 +05:30
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
2011-01-04 20:16:32 +05:30
int ret_val ;
2014-09-02 18:05:56 +05:30
dev_dbg ( rtd - > dev , " setting buffer ptr param \n " ) ;
2011-01-11 14:50:35 +05:30
sst_set_stream_status ( stream , SST_PLATFORM_INIT ) ;
2011-01-04 20:16:32 +05:30
stream - > stream_info . period_elapsed = sst_period_elapsed ;
2014-06-13 18:03:52 +05:30
stream - > stream_info . arg = substream ;
2011-01-04 20:16:32 +05:30
stream - > stream_info . buffer_ptr = 0 ;
stream - > stream_info . sfreq = substream - > runtime - > rate ;
2014-08-04 15:04:21 +05:30
ret_val = stream - > ops - > stream_init ( sst - > dev , & stream - > stream_info ) ;
2011-01-04 20:16:32 +05:30
if ( ret_val )
2014-09-02 18:05:56 +05:30
dev_err ( rtd - > dev , " control_set ret error %d \n " , ret_val ) ;
2011-01-04 20:16:32 +05:30
return ret_val ;
}
2014-09-19 16:46:03 +05:30
static int power_up_sst ( struct sst_runtime_stream * stream )
{
return stream - > ops - > power ( sst - > dev , true ) ;
}
static void power_down_sst ( struct sst_runtime_stream * stream )
{
stream - > ops - > power ( sst - > dev , false ) ;
}
2014-06-13 18:03:51 +05:30
static int sst_media_open ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
2011-01-04 20:16:32 +05:30
{
2014-06-13 18:03:51 +05:30
int ret_val = 0 ;
2011-09-06 15:21:38 +08:00
struct snd_pcm_runtime * runtime = substream - > runtime ;
2011-01-04 20:16:32 +05:30
struct sst_runtime_stream * stream ;
2011-09-06 15:21:38 +08:00
2011-01-04 20:16:32 +05:30
stream = kzalloc ( sizeof ( * stream ) , GFP_KERNEL ) ;
if ( ! stream )
return - ENOMEM ;
spin_lock_init ( & stream - > status_lock ) ;
2011-12-05 19:13:41 +05:30
/* get the sst ops */
mutex_lock ( & sst_lock ) ;
2014-06-13 18:03:51 +05:30
if ( ! sst | |
! try_module_get ( sst - > dev - > driver - > owner ) ) {
2014-09-02 18:05:56 +05:30
dev_err ( dai - > dev , " no device available to run \n " ) ;
2014-06-13 18:03:51 +05:30
ret_val = - ENODEV ;
goto out_ops ;
2011-01-04 20:16:32 +05:30
}
2011-12-05 19:13:41 +05:30
stream - > ops = sst - > ops ;
mutex_unlock ( & sst_lock ) ;
stream - > stream_info . str_id = 0 ;
2014-06-13 18:03:51 +05:30
2014-06-13 18:03:52 +05:30
stream - > stream_info . arg = substream ;
2011-12-05 19:13:41 +05:30
/* allocate memory for SST API set */
2011-01-04 20:16:32 +05:30
runtime - > private_data = stream ;
2011-09-06 15:21:43 +08:00
2014-09-19 16:46:03 +05:30
ret_val = power_up_sst ( stream ) ;
if ( ret_val < 0 )
return ret_val ;
2014-06-13 18:03:51 +05:30
/* Make sure, that the period size is always even */
snd_pcm_hw_constraint_step ( substream - > runtime , 0 ,
SNDRV_PCM_HW_PARAM_PERIODS , 2 ) ;
return snd_pcm_hw_constraint_integer ( runtime ,
SNDRV_PCM_HW_PARAM_PERIODS ) ;
out_ops :
kfree ( stream ) ;
mutex_unlock ( & sst_lock ) ;
return ret_val ;
2011-01-04 20:16:32 +05:30
}
2014-06-13 18:03:51 +05:30
static void sst_media_close ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
2011-01-04 20:16:32 +05:30
{
struct sst_runtime_stream * stream ;
int ret_val = 0 , str_id ;
stream = substream - > runtime - > private_data ;
2014-09-19 16:46:03 +05:30
power_down_sst ( stream ) ;
2011-01-04 20:16:32 +05:30
str_id = stream - > stream_info . str_id ;
if ( str_id )
2014-08-04 15:04:21 +05:30
ret_val = stream - > ops - > close ( sst - > dev , str_id ) ;
2011-12-05 19:13:41 +05:30
module_put ( sst - > dev - > driver - > owner ) ;
2011-01-04 20:16:32 +05:30
kfree ( stream ) ;
2014-06-13 18:03:56 +05:30
}
2014-09-09 15:11:32 +05:30
static inline unsigned int get_current_pipe_id ( struct snd_soc_dai * dai ,
2014-06-13 18:03:56 +05:30
struct snd_pcm_substream * substream )
{
2014-09-09 15:11:32 +05:30
struct sst_data * sst = snd_soc_dai_get_drvdata ( dai ) ;
2014-06-13 18:03:56 +05:30
struct sst_dev_stream_map * map = sst - > pdata - > pdev_strm_map ;
struct sst_runtime_stream * stream =
substream - > runtime - > private_data ;
u32 str_id = stream - > stream_info . str_id ;
unsigned int pipe_id ;
2014-09-02 18:05:56 +05:30
2014-06-13 18:03:56 +05:30
pipe_id = map [ str_id ] . device_id ;
2014-09-09 15:11:32 +05:30
dev_dbg ( dai - > dev , " got pipe_id = %#x for str_id = %d \n " ,
2014-09-02 18:05:56 +05:30
pipe_id , str_id ) ;
2014-06-13 18:03:56 +05:30
return pipe_id ;
2011-01-04 20:16:32 +05:30
}
2014-06-13 18:03:51 +05:30
static int sst_media_prepare ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
2011-01-04 20:16:32 +05:30
{
struct sst_runtime_stream * stream ;
int ret_val = 0 , str_id ;
stream = substream - > runtime - > private_data ;
str_id = stream - > stream_info . str_id ;
if ( stream - > stream_info . str_id ) {
2014-08-04 15:04:21 +05:30
ret_val = stream - > ops - > stream_drop ( sst - > dev , str_id ) ;
2011-01-04 20:16:32 +05:30
return ret_val ;
}
2014-09-09 15:11:32 +05:30
ret_val = sst_platform_alloc_stream ( substream , dai ) ;
2014-06-13 18:03:55 +05:30
if ( ret_val < = 0 )
2011-01-04 20:16:32 +05:30
return ret_val ;
snprintf ( substream - > pcm - > id , sizeof ( substream - > pcm - > id ) ,
" %d " , stream - > stream_info . str_id ) ;
ret_val = sst_platform_init_stream ( substream ) ;
if ( ret_val )
return ret_val ;
substream - > runtime - > hw . info = SNDRV_PCM_INFO_BLOCK_TRANSFER ;
return ret_val ;
}
2014-06-13 18:03:51 +05:30
static int sst_media_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
snd_pcm_lib_malloc_pages ( substream , params_buffer_bytes ( params ) ) ;
memset ( substream - > runtime - > dma_area , 0 , params_buffer_bytes ( params ) ) ;
return 0 ;
}
static int sst_media_hw_free ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
return snd_pcm_lib_free_pages ( substream ) ;
}
2014-10-15 20:12:59 +05:30
static int sst_enable_ssp ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
int ret = 0 ;
if ( ! dai - > active ) {
ret = sst_handle_vb_timer ( dai , true ) ;
2015-05-06 22:06:42 +05:30
sst_fill_ssp_defaults ( dai ) ;
2014-10-15 20:12:59 +05:30
}
return ret ;
}
2015-05-06 22:06:42 +05:30
static int sst_be_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
int ret = 0 ;
if ( dai - > active = = 1 )
ret = send_ssp_cmd ( dai , dai - > name , 1 ) ;
return ret ;
}
2015-05-06 22:06:43 +05:30
static int sst_set_format ( struct snd_soc_dai * dai , unsigned int fmt )
{
int ret = 0 ;
if ( ! dai - > active )
return 0 ;
ret = sst_fill_ssp_config ( dai , fmt ) ;
if ( ret < 0 )
dev_err ( dai - > dev , " sst_set_format failed.. \n " ) ;
return ret ;
}
2015-05-06 22:06:44 +05:30
static int sst_platform_set_ssp_slot ( struct snd_soc_dai * dai ,
unsigned int tx_mask , unsigned int rx_mask ,
int slots , int slot_width ) {
int ret = 0 ;
if ( ! dai - > active )
return ret ;
ret = sst_fill_ssp_slot ( dai , tx_mask , rx_mask , slots , slot_width ) ;
if ( ret < 0 )
dev_err ( dai - > dev , " sst_fill_ssp_slot failed..%d \n " , ret ) ;
return ret ;
}
2014-10-15 20:12:59 +05:30
static void sst_disable_ssp ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
if ( ! dai - > active ) {
send_ssp_cmd ( dai , dai - > name , 0 ) ;
sst_handle_vb_timer ( dai , false ) ;
}
}
2014-06-13 18:03:51 +05:30
static struct snd_soc_dai_ops sst_media_dai_ops = {
. startup = sst_media_open ,
. shutdown = sst_media_close ,
. prepare = sst_media_prepare ,
. hw_params = sst_media_hw_params ,
. hw_free = sst_media_hw_free ,
2014-10-15 20:12:59 +05:30
. mute_stream = sst_media_digital_mute ,
} ;
static struct snd_soc_dai_ops sst_compr_dai_ops = {
. mute_stream = sst_media_digital_mute ,
} ;
static struct snd_soc_dai_ops sst_be_dai_ops = {
. startup = sst_enable_ssp ,
2015-05-06 22:06:42 +05:30
. hw_params = sst_be_hw_params ,
2015-05-06 22:06:43 +05:30
. set_fmt = sst_set_format ,
2015-05-06 22:06:44 +05:30
. set_tdm_slot = sst_platform_set_ssp_slot ,
2014-10-15 20:12:59 +05:30
. shutdown = sst_disable_ssp ,
} ;
static struct snd_soc_dai_driver sst_platform_dai [ ] = {
{
. name = " media-cpu-dai " ,
. ops = & sst_media_dai_ops ,
. playback = {
. stream_name = " Headset Playback " ,
. channels_min = SST_STEREO ,
. channels_max = SST_STEREO ,
. rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
} ,
. capture = {
. stream_name = " Headset Capture " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
} ,
} ,
{
. name = " compress-cpu-dai " ,
. compress_dai = 1 ,
. ops = & sst_compr_dai_ops ,
. playback = {
. stream_name = " Compress Playback " ,
. channels_min = SST_STEREO ,
. channels_max = SST_STEREO ,
. rates = SNDRV_PCM_RATE_48000 ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
} ,
} ,
/* BE CPU Dais */
{
. name = " ssp0-port " ,
. ops = & sst_be_dai_ops ,
. playback = {
. stream_name = " ssp0 Tx " ,
. channels_min = SST_STEREO ,
. channels_max = SST_STEREO ,
. rates = SNDRV_PCM_RATE_48000 ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
} ,
. capture = {
. stream_name = " ssp0 Rx " ,
. channels_min = SST_STEREO ,
. channels_max = SST_STEREO ,
. rates = SNDRV_PCM_RATE_48000 ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
} ,
} ,
{
. name = " ssp1-port " ,
. ops = & sst_be_dai_ops ,
. playback = {
. stream_name = " ssp1 Tx " ,
. channels_min = SST_STEREO ,
. channels_max = SST_STEREO ,
. rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000 ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
} ,
. capture = {
. stream_name = " ssp1 Rx " ,
. channels_min = SST_STEREO ,
. channels_max = SST_STEREO ,
. rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000 ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
} ,
} ,
{
. name = " ssp2-port " ,
. ops = & sst_be_dai_ops ,
. playback = {
. stream_name = " ssp2 Tx " ,
. channels_min = SST_STEREO ,
. channels_max = SST_STEREO ,
. rates = SNDRV_PCM_RATE_48000 ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
} ,
. capture = {
. stream_name = " ssp2 Rx " ,
. channels_min = SST_STEREO ,
. channels_max = SST_STEREO ,
. rates = SNDRV_PCM_RATE_48000 ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
} ,
} ,
2014-06-13 18:03:51 +05:30
} ;
static int sst_platform_open ( struct snd_pcm_substream * substream )
{
struct snd_pcm_runtime * runtime ;
if ( substream - > pcm - > internal )
return 0 ;
runtime = substream - > runtime ;
runtime - > hw = sst_platform_pcm_hw ;
return 0 ;
}
2014-05-15 21:38:15 +05:30
static int sst_platform_pcm_trigger ( struct snd_pcm_substream * substream ,
2011-01-04 20:16:32 +05:30
int cmd )
{
int ret_val = 0 , str_id ;
struct sst_runtime_stream * stream ;
2014-08-04 15:04:20 +05:30
int status ;
2014-09-02 18:05:56 +05:30
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
2011-01-04 20:16:32 +05:30
2014-09-02 18:05:56 +05:30
dev_dbg ( rtd - > dev , " sst_platform_pcm_trigger called \n " ) ;
2014-09-09 15:11:24 +05:30
if ( substream - > pcm - > internal )
return 0 ;
2011-01-04 20:16:32 +05:30
stream = substream - > runtime - > private_data ;
str_id = stream - > stream_info . str_id ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
2014-09-02 18:05:56 +05:30
dev_dbg ( rtd - > dev , " sst: Trigger Start \n " ) ;
2011-01-11 14:50:59 +05:30
status = SST_PLATFORM_RUNNING ;
2014-06-13 18:03:52 +05:30
stream - > stream_info . arg = substream ;
2014-08-04 15:04:21 +05:30
ret_val = stream - > ops - > stream_start ( sst - > dev , str_id ) ;
2011-01-04 20:16:32 +05:30
break ;
case SNDRV_PCM_TRIGGER_STOP :
2014-09-02 18:05:56 +05:30
dev_dbg ( rtd - > dev , " sst: in stop \n " ) ;
2011-01-11 14:50:59 +05:30
status = SST_PLATFORM_DROPPED ;
2014-08-04 15:04:21 +05:30
ret_val = stream - > ops - > stream_drop ( sst - > dev , str_id ) ;
2011-01-04 20:16:32 +05:30
break ;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
2015-02-12 09:59:57 +05:30
case SNDRV_PCM_TRIGGER_SUSPEND :
2014-09-02 18:05:56 +05:30
dev_dbg ( rtd - > dev , " sst: in pause \n " ) ;
2011-01-11 14:50:59 +05:30
status = SST_PLATFORM_PAUSED ;
2014-08-04 15:04:21 +05:30
ret_val = stream - > ops - > stream_pause ( sst - > dev , str_id ) ;
2011-01-04 20:16:32 +05:30
break ;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
2015-02-12 09:59:57 +05:30
case SNDRV_PCM_TRIGGER_RESUME :
2014-09-02 18:05:56 +05:30
dev_dbg ( rtd - > dev , " sst: in pause release \n " ) ;
2011-01-11 14:50:59 +05:30
status = SST_PLATFORM_RUNNING ;
2014-08-04 15:04:21 +05:30
ret_val = stream - > ops - > stream_pause_release ( sst - > dev , str_id ) ;
2011-01-04 20:16:32 +05:30
break ;
default :
2011-01-11 14:50:59 +05:30
return - EINVAL ;
2011-01-04 20:16:32 +05:30
}
2014-08-04 15:04:20 +05:30
2011-01-11 14:50:59 +05:30
if ( ! ret_val )
sst_set_stream_status ( stream , status ) ;
2011-01-04 20:16:32 +05:30
return ret_val ;
}
2014-05-15 21:38:15 +05:30
static snd_pcm_uframes_t sst_platform_pcm_pointer
2011-01-04 20:16:32 +05:30
( struct snd_pcm_substream * substream )
{
struct sst_runtime_stream * stream ;
2011-01-11 14:50:35 +05:30
int ret_val , status ;
2011-01-04 20:16:32 +05:30
struct pcm_stream_info * str_info ;
2014-09-02 18:05:56 +05:30
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
2011-01-04 20:16:32 +05:30
stream = substream - > runtime - > private_data ;
2011-01-11 14:50:35 +05:30
status = sst_get_stream_status ( stream ) ;
if ( status = = SST_PLATFORM_INIT )
2011-01-04 20:16:32 +05:30
return 0 ;
str_info = & stream - > stream_info ;
2014-08-04 15:04:21 +05:30
ret_val = stream - > ops - > stream_read_tstamp ( sst - > dev , str_info ) ;
2011-01-04 20:16:32 +05:30
if ( ret_val ) {
2014-09-02 18:05:56 +05:30
dev_err ( rtd - > dev , " sst: error code = %d \n " , ret_val ) ;
2011-01-04 20:16:32 +05:30
return ret_val ;
}
2014-06-13 18:03:53 +05:30
substream - > runtime - > delay = str_info - > pcm_delay ;
2014-06-13 18:03:51 +05:30
return str_info - > buffer_ptr ;
2011-04-27 16:58:54 -04:00
}
2011-01-04 20:16:32 +05:30
static struct snd_pcm_ops sst_platform_ops = {
2014-05-15 21:38:15 +05:30
. open = sst_platform_open ,
2011-01-04 20:16:32 +05:30
. ioctl = snd_pcm_lib_ioctl ,
2014-05-15 21:38:15 +05:30
. trigger = sst_platform_pcm_trigger ,
. pointer = sst_platform_pcm_pointer ,
2011-01-04 20:16:32 +05:30
} ;
2011-12-13 17:13:45 +08:00
static int sst_pcm_new ( struct snd_soc_pcm_runtime * rtd )
2011-01-04 20:16:32 +05:30
{
2014-06-13 18:03:51 +05:30
struct snd_soc_dai * dai = rtd - > cpu_dai ;
2011-06-07 16:08:33 +01:00
struct snd_pcm * pcm = rtd - > pcm ;
2011-01-04 20:16:32 +05:30
int retval = 0 ;
2014-06-13 18:03:51 +05:30
if ( dai - > driver - > playback . channels_min | |
dai - > driver - > capture . channels_min ) {
2011-01-04 20:16:32 +05:30
retval = snd_pcm_lib_preallocate_pages_for_all ( pcm ,
SNDRV_DMA_TYPE_CONTINUOUS ,
2014-06-13 18:03:51 +05:30
snd_dma_continuous_data ( GFP_DMA ) ,
2011-01-04 20:16:32 +05:30
SST_MIN_BUFFER , SST_MAX_BUFFER ) ;
if ( retval ) {
2014-09-02 18:05:56 +05:30
dev_err ( rtd - > dev , " dma buffer allocationf fail \n " ) ;
2011-01-04 20:16:32 +05:30
return retval ;
}
}
return retval ;
}
2012-08-16 17:10:42 +05:30
2014-08-04 15:15:55 +05:30
static int sst_soc_probe ( struct snd_soc_platform * platform )
{
2015-02-12 09:59:58 +05:30
struct sst_data * drv = dev_get_drvdata ( platform - > dev ) ;
drv - > soc_card = platform - > component . card ;
2014-08-04 15:15:55 +05:30
return sst_dsp_init_v2_dpcm ( platform ) ;
}
static struct snd_soc_platform_driver sst_soc_platform_drv = {
. probe = sst_soc_probe ,
2011-01-04 20:16:32 +05:30
. ops = & sst_platform_ops ,
2012-08-16 17:10:42 +05:30
. compr_ops = & sst_platform_compr_ops ,
2011-01-04 20:16:32 +05:30
. pcm_new = sst_pcm_new ,
} ;
2014-05-05 22:19:25 +05:30
static const struct snd_soc_component_driver sst_component = {
. name = " sst " ,
} ;
2011-01-04 20:16:32 +05:30
static int sst_platform_probe ( struct platform_device * pdev )
{
2014-06-13 18:03:56 +05:30
struct sst_data * drv ;
2011-01-04 20:16:32 +05:30
int ret ;
2014-07-30 18:39:05 +05:30
struct sst_platform_data * pdata ;
2014-06-13 18:03:56 +05:30
drv = devm_kzalloc ( & pdev - > dev , sizeof ( * drv ) , GFP_KERNEL ) ;
2014-07-30 18:36:00 +05:30
if ( drv = = NULL ) {
2014-06-13 18:03:56 +05:30
return - ENOMEM ;
}
2014-07-30 18:39:05 +05:30
pdata = devm_kzalloc ( & pdev - > dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( pdata = = NULL ) {
return - ENOMEM ;
}
2014-06-13 18:03:56 +05:30
pdata - > pdev_strm_map = dpcm_strm_map ;
pdata - > strm_map_size = ARRAY_SIZE ( dpcm_strm_map ) ;
drv - > pdata = pdata ;
2014-10-30 16:21:44 +05:30
drv - > pdev = pdev ;
2014-06-13 18:03:56 +05:30
mutex_init ( & drv - > lock ) ;
dev_set_drvdata ( & pdev - > dev , drv ) ;
2011-01-04 20:16:32 +05:30
ret = snd_soc_register_platform ( & pdev - > dev , & sst_soc_platform_drv ) ;
if ( ret ) {
2014-09-02 18:05:56 +05:30
dev_err ( & pdev - > dev , " registering soc platform failed \n " ) ;
2011-01-04 20:16:32 +05:30
return ret ;
}
2011-01-11 14:50:35 +05:30
2013-03-21 03:32:50 -07:00
ret = snd_soc_register_component ( & pdev - > dev , & sst_component ,
2011-01-04 20:16:32 +05:30
sst_platform_dai , ARRAY_SIZE ( sst_platform_dai ) ) ;
if ( ret ) {
2014-09-02 18:05:56 +05:30
dev_err ( & pdev - > dev , " registering cpu dais failed \n " ) ;
2011-01-04 20:16:32 +05:30
snd_soc_unregister_platform ( & pdev - > dev ) ;
}
return ret ;
}
static int sst_platform_remove ( struct platform_device * pdev )
{
2013-03-21 03:32:50 -07:00
snd_soc_unregister_component ( & pdev - > dev ) ;
2011-01-04 20:16:32 +05:30
snd_soc_unregister_platform ( & pdev - > dev ) ;
2014-09-02 18:05:56 +05:30
dev_dbg ( & pdev - > dev , " sst_platform_remove success \n " ) ;
2011-01-04 20:16:32 +05:30
return 0 ;
}
2015-02-12 09:59:58 +05:30
# ifdef CONFIG_PM_SLEEP
static int sst_soc_prepare ( struct device * dev )
{
struct sst_data * drv = dev_get_drvdata ( dev ) ;
int i ;
/* suspend all pcms first */
snd_soc_suspend ( drv - > soc_card - > dev ) ;
snd_soc_poweroff ( drv - > soc_card - > dev ) ;
/* set the SSPs to idle */
for ( i = 0 ; i < drv - > soc_card - > num_rtd ; i + + ) {
struct snd_soc_dai * dai = drv - > soc_card - > rtd [ i ] . cpu_dai ;
if ( dai - > active ) {
send_ssp_cmd ( dai , dai - > name , 0 ) ;
sst_handle_vb_timer ( dai , false ) ;
}
}
return 0 ;
}
static void sst_soc_complete ( struct device * dev )
{
struct sst_data * drv = dev_get_drvdata ( dev ) ;
int i ;
/* restart SSPs */
for ( i = 0 ; i < drv - > soc_card - > num_rtd ; i + + ) {
struct snd_soc_dai * dai = drv - > soc_card - > rtd [ i ] . cpu_dai ;
if ( dai - > active ) {
sst_handle_vb_timer ( dai , true ) ;
send_ssp_cmd ( dai , dai - > name , 1 ) ;
}
}
snd_soc_resume ( drv - > soc_card - > dev ) ;
}
# else
# define sst_soc_prepare NULL
# define sst_soc_complete NULL
# endif
static const struct dev_pm_ops sst_platform_pm = {
. prepare = sst_soc_prepare ,
. complete = sst_soc_complete ,
} ;
2011-01-04 20:16:32 +05:30
static struct platform_driver sst_platform_driver = {
. driver = {
2014-03-12 23:04:35 +00:00
. name = " sst-mfld-platform " ,
2015-02-12 09:59:58 +05:30
. pm = & sst_platform_pm ,
2011-01-04 20:16:32 +05:30
} ,
. probe = sst_platform_probe ,
. remove = sst_platform_remove ,
} ;
2011-11-24 11:51:56 +08:00
module_platform_driver ( sst_platform_driver ) ;
2011-01-04 20:16:32 +05:30
MODULE_DESCRIPTION ( " ASoC Intel(R) MID Platform driver " ) ;
MODULE_AUTHOR ( " Vinod Koul <vinod.koul@intel.com> " ) ;
MODULE_AUTHOR ( " Harsha Priya <priya.harsha@intel.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
2014-03-12 23:04:35 +00:00
MODULE_ALIAS ( " platform:sst-mfld-platform " ) ;