2006-10-06 20:20:14 +04:00
/*
* linux / sound / soc . h - - ALSA SoC Layer
*
* Author : Liam Girdwood
* Created : Aug 11 th 2005
* Copyright : Wolfson Microelectronics . PLC .
*
* 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 .
*/
# ifndef __LINUX_SND_SOC_H
# define __LINUX_SND_SOC_H
# include <linux/platform_device.h>
# include <linux/types.h>
2006-12-15 11:30:07 +03:00
# include <linux/workqueue.h>
2006-10-06 20:20:14 +04:00
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/control.h>
# include <sound/ac97_codec.h>
/*
* Convenience kcontrol builders
*/
2008-07-29 14:42:26 +04:00
# define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \
( ( unsigned long ) & ( struct soc_mixer_control ) \
2008-10-30 15:37:08 +03:00
{ . reg = xreg , . shift = xshift , . rshift = xshift , . max = xmax , \
. invert = xinvert } )
2008-07-29 14:42:26 +04:00
# define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
( ( unsigned long ) & ( struct soc_mixer_control ) \
{ . reg = xreg , . max = xmax , . invert = xinvert } )
2008-01-10 16:37:42 +03:00
# define SOC_SINGLE(xname, reg, shift, max, invert) \
2006-10-06 20:20:14 +04:00
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , \
. info = snd_soc_info_volsw , . get = snd_soc_get_volsw , \
. put = snd_soc_put_volsw , \
2008-01-10 16:37:42 +03:00
. private_value = SOC_SINGLE_VALUE ( reg , shift , max , invert ) }
# define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , \
. access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE , \
. tlv . p = ( tlv_array ) , \
. info = snd_soc_info_volsw , . get = snd_soc_get_volsw , \
. put = snd_soc_put_volsw , \
. private_value = SOC_SINGLE_VALUE ( reg , shift , max , invert ) }
2008-07-29 14:42:26 +04:00
# define SOC_DOUBLE(xname, xreg, shift_left, shift_right, xmax, xinvert) \
2006-10-06 20:20:14 +04:00
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = ( xname ) , \
. info = snd_soc_info_volsw , . get = snd_soc_get_volsw , \
. put = snd_soc_put_volsw , \
2008-07-29 14:42:26 +04:00
. private_value = ( unsigned long ) & ( struct soc_mixer_control ) \
{ . reg = xreg , . shift = shift_left , . rshift = shift_right , \
. max = xmax , . invert = xinvert } }
# define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
2006-10-06 20:20:14 +04:00
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = ( xname ) , \
. info = snd_soc_info_volsw_2r , \
. get = snd_soc_get_volsw_2r , . put = snd_soc_put_volsw_2r , \
2008-07-29 14:42:26 +04:00
. private_value = ( unsigned long ) & ( struct soc_mixer_control ) \
{ . reg = reg_left , . rreg = reg_right , . shift = xshift , \
. max = xmax , . invert = xinvert } }
# define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, tlv_array) \
2008-01-10 16:37:42 +03:00
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = ( xname ) , \
. access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE , \
. tlv . p = ( tlv_array ) , \
. info = snd_soc_info_volsw , . get = snd_soc_get_volsw , \
. put = snd_soc_put_volsw , \
2008-07-29 14:42:26 +04:00
. private_value = ( unsigned long ) & ( struct soc_mixer_control ) \
{ . reg = xreg , . shift = shift_left , . rshift = shift_right , \
. max = xmax , . invert = xinvert } }
# define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
2008-01-10 16:37:42 +03:00
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = ( xname ) , \
. access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE , \
. tlv . p = ( tlv_array ) , \
. info = snd_soc_info_volsw_2r , \
. get = snd_soc_get_volsw_2r , . put = snd_soc_put_volsw_2r , \
2008-07-29 14:42:26 +04:00
. private_value = ( unsigned long ) & ( struct soc_mixer_control ) \
{ . reg = reg_left , . rreg = reg_right , . shift = xshift , \
. max = xmax , . invert = xinvert } }
# define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
2008-05-28 20:58:05 +04:00
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = ( xname ) , \
. access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE , \
. tlv . p = ( tlv_array ) , \
. info = snd_soc_info_volsw_s8 , . get = snd_soc_get_volsw_s8 , \
. put = snd_soc_put_volsw_s8 , \
2008-07-29 14:42:26 +04:00
. private_value = ( unsigned long ) & ( struct soc_mixer_control ) \
{ . reg = xreg , . min = xmin , . max = xmax } }
2008-07-29 14:42:27 +04:00
# define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \
2006-10-06 20:20:14 +04:00
{ . reg = xreg , . shift_l = xshift_l , . shift_r = xshift_r , \
2008-07-29 14:42:27 +04:00
. max = xmax , . texts = xtexts }
# define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \
SOC_ENUM_DOUBLE ( xreg , xshift , xshift , xmax , xtexts )
# define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \
{ . max = xmax , . texts = xtexts }
2006-10-06 20:20:14 +04:00
# define SOC_ENUM(xname, xenum) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , \
. info = snd_soc_info_enum_double , \
. get = snd_soc_get_enum_double , . put = snd_soc_put_enum_double , \
. private_value = ( unsigned long ) & xenum }
2008-07-29 14:42:27 +04:00
# define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\
2006-10-06 20:20:14 +04:00
xhandler_get , xhandler_put ) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , \
2007-02-02 19:13:05 +03:00
. info = snd_soc_info_volsw , \
2006-10-06 20:20:14 +04:00
. get = xhandler_get , . put = xhandler_put , \
2008-07-29 14:42:27 +04:00
. private_value = SOC_SINGLE_VALUE ( xreg , xshift , xmax , xinvert ) }
# define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
2008-06-11 16:47:13 +04:00
xhandler_get , xhandler_put , tlv_array ) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , \
. access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE , \
. tlv . p = ( tlv_array ) , \
. info = snd_soc_info_volsw , \
. get = xhandler_get , . put = xhandler_put , \
2008-07-29 14:42:27 +04:00
. private_value = SOC_SINGLE_VALUE ( xreg , xshift , xmax , xinvert ) }
2006-10-06 20:20:14 +04:00
# define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , \
. info = snd_soc_info_bool_ext , \
. get = xhandler_get , . put = xhandler_put , \
. private_value = xdata }
# define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , \
. info = snd_soc_info_enum_ext , \
. get = xhandler_get , . put = xhandler_put , \
. private_value = ( unsigned long ) & xenum }
2008-05-19 14:31:28 +04:00
/*
* Bias levels
*
* @ ON : Bias is fully on for audio playback and capture operations .
* @ PREPARE : Prepare for audio operations . Called before DAPM switching for
* stream start and stop operations .
* @ STANDBY : Low power standby state when no playback / capture operations are
* in progress . NOTE : The transition time between STANDBY and ON
* should be as fast as possible and no longer than 10 ms .
* @ OFF : Power Off . No restrictions on transition times .
*/
enum snd_soc_bias_level {
SND_SOC_BIAS_ON ,
SND_SOC_BIAS_PREPARE ,
SND_SOC_BIAS_STANDBY ,
SND_SOC_BIAS_OFF ,
} ;
2006-10-06 20:20:14 +04:00
struct snd_soc_device ;
struct snd_soc_pcm_stream ;
struct snd_soc_ops ;
struct snd_soc_dai_mode ;
struct snd_soc_pcm_runtime ;
2008-07-07 19:07:17 +04:00
struct snd_soc_dai ;
2008-12-03 22:40:30 +03:00
struct snd_soc_platform ;
2006-10-06 20:20:14 +04:00
struct snd_soc_codec ;
struct soc_enum ;
struct snd_soc_ac97_ops ;
typedef int ( * hw_write_t ) ( void * , const char * , int ) ;
typedef int ( * hw_read_t ) ( void * , char * , int ) ;
extern struct snd_ac97_bus_ops soc_ac97_ops ;
2008-12-03 22:40:30 +03:00
int snd_soc_register_platform ( struct snd_soc_platform * platform ) ;
void snd_soc_unregister_platform ( struct snd_soc_platform * platform ) ;
2006-10-06 20:20:14 +04:00
/* pcm <-> DAI connect */
void snd_soc_free_pcms ( struct snd_soc_device * socdev ) ;
int snd_soc_new_pcms ( struct snd_soc_device * socdev , int idx , const char * xid ) ;
2008-11-28 14:49:07 +03:00
int snd_soc_init_card ( struct snd_soc_device * socdev ) ;
2006-10-06 20:20:14 +04:00
/* set runtime hw params */
int snd_soc_set_runtime_hwparams ( struct snd_pcm_substream * substream ,
const struct snd_pcm_hardware * hw ) ;
/* codec IO */
# define snd_soc_read(codec, reg) codec->read(codec, reg)
# define snd_soc_write(codec, reg, value) codec->write(codec, reg, value)
/* codec register bit access */
int snd_soc_update_bits ( struct snd_soc_codec * codec , unsigned short reg ,
unsigned short mask , unsigned short value ) ;
int snd_soc_test_bits ( struct snd_soc_codec * codec , unsigned short reg ,
unsigned short mask , unsigned short value ) ;
int snd_soc_new_ac97_codec ( struct snd_soc_codec * codec ,
struct snd_ac97_bus_ops * ops , int num ) ;
void snd_soc_free_ac97_codec ( struct snd_soc_codec * codec ) ;
/*
* Controls
*/
struct snd_kcontrol * snd_soc_cnew ( const struct snd_kcontrol_new * _template ,
void * data , char * long_name ) ;
int snd_soc_info_enum_double ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo ) ;
int snd_soc_info_enum_ext ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo ) ;
int snd_soc_get_enum_double ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol ) ;
int snd_soc_put_enum_double ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol ) ;
int snd_soc_info_volsw ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo ) ;
int snd_soc_info_volsw_ext ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo ) ;
2008-05-13 16:03:40 +04:00
# define snd_soc_info_bool_ext snd_ctl_boolean_mono_info
2006-10-06 20:20:14 +04:00
int snd_soc_get_volsw ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol ) ;
int snd_soc_put_volsw ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol ) ;
int snd_soc_info_volsw_2r ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo ) ;
int snd_soc_get_volsw_2r ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol ) ;
int snd_soc_put_volsw_2r ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol ) ;
2008-05-28 20:58:05 +04:00
int snd_soc_info_volsw_s8 ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo ) ;
int snd_soc_get_volsw_s8 ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol ) ;
int snd_soc_put_volsw_s8 ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol ) ;
2006-10-06 20:20:14 +04:00
/* SoC PCM stream information */
struct snd_soc_pcm_stream {
char * stream_name ;
2007-02-02 19:13:05 +03:00
u64 formats ; /* SNDRV_PCM_FMTBIT_* */
unsigned int rates ; /* SNDRV_PCM_RATE_* */
2006-10-06 20:20:14 +04:00
unsigned int rate_min ; /* min rate */
unsigned int rate_max ; /* max rate */
unsigned int channels_min ; /* min channels */
unsigned int channels_max ; /* max channels */
unsigned int active : 1 ; /* stream is in use */
} ;
/* SoC audio ops */
struct snd_soc_ops {
int ( * startup ) ( struct snd_pcm_substream * ) ;
void ( * shutdown ) ( struct snd_pcm_substream * ) ;
int ( * hw_params ) ( struct snd_pcm_substream * , struct snd_pcm_hw_params * ) ;
int ( * hw_free ) ( struct snd_pcm_substream * ) ;
int ( * prepare ) ( struct snd_pcm_substream * ) ;
int ( * trigger ) ( struct snd_pcm_substream * , int ) ;
} ;
/* SoC Audio Codec */
struct snd_soc_codec {
char * name ;
struct module * owner ;
struct mutex mutex ;
/* callbacks */
2008-05-19 14:31:28 +04:00
int ( * set_bias_level ) ( struct snd_soc_codec * ,
enum snd_soc_bias_level level ) ;
2006-10-06 20:20:14 +04:00
/* runtime */
struct snd_card * card ;
struct snd_ac97 * ac97 ; /* for ad-hoc ac97 devices */
unsigned int active ;
unsigned int pcm_devs ;
void * private_data ;
/* codec IO */
void * control_data ; /* codec control (i2c/3wire) data */
unsigned int ( * read ) ( struct snd_soc_codec * , unsigned int ) ;
int ( * write ) ( struct snd_soc_codec * , unsigned int , unsigned int ) ;
2008-07-29 14:42:25 +04:00
int ( * display_register ) ( struct snd_soc_codec * , char * ,
size_t , unsigned int ) ;
2006-10-06 20:20:14 +04:00
hw_write_t hw_write ;
hw_read_t hw_read ;
void * reg_cache ;
short reg_cache_size ;
short reg_cache_step ;
/* dapm */
2008-10-14 04:42:14 +04:00
u32 pop_time ;
2006-10-06 20:20:14 +04:00
struct list_head dapm_widgets ;
struct list_head dapm_paths ;
2008-05-19 14:31:28 +04:00
enum snd_soc_bias_level bias_level ;
enum snd_soc_bias_level suspend_bias_level ;
2006-12-21 13:02:06 +03:00
struct delayed_work delayed_work ;
2006-10-06 20:20:14 +04:00
/* codec DAI's */
2008-07-07 19:07:17 +04:00
struct snd_soc_dai * dai ;
2006-10-06 20:20:14 +04:00
unsigned int num_dai ;
2008-12-03 20:34:03 +03:00
# ifdef CONFIG_DEBUG_FS
struct dentry * debugfs_reg ;
struct dentry * debugfs_pop_time ;
# endif
2006-10-06 20:20:14 +04:00
} ;
/* codec device */
struct snd_soc_codec_device {
int ( * probe ) ( struct platform_device * pdev ) ;
int ( * remove ) ( struct platform_device * pdev ) ;
int ( * suspend ) ( struct platform_device * pdev , pm_message_t state ) ;
int ( * resume ) ( struct platform_device * pdev ) ;
} ;
/* SoC platform interface */
struct snd_soc_platform {
char * name ;
2008-12-03 22:40:30 +03:00
struct list_head list ;
2006-10-06 20:20:14 +04:00
int ( * probe ) ( struct platform_device * pdev ) ;
int ( * remove ) ( struct platform_device * pdev ) ;
2008-12-03 21:17:28 +03:00
int ( * suspend ) ( struct snd_soc_dai * dai ) ;
int ( * resume ) ( struct snd_soc_dai * dai ) ;
2006-10-06 20:20:14 +04:00
/* pcm creation and destruction */
2008-07-07 19:07:17 +04:00
int ( * pcm_new ) ( struct snd_card * , struct snd_soc_dai * ,
2006-10-06 20:20:14 +04:00
struct snd_pcm * ) ;
void ( * pcm_free ) ( struct snd_pcm * ) ;
/* platform stream ops */
struct snd_pcm_ops * pcm_ops ;
} ;
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
struct snd_soc_dai_link {
char * name ; /* Codec name */
char * stream_name ; /* Stream name */
/* DAI */
2008-07-07 19:07:17 +04:00
struct snd_soc_dai * codec_dai ;
struct snd_soc_dai * cpu_dai ;
2007-02-02 19:13:05 +03:00
/* machine stream operations */
struct snd_soc_ops * ops ;
2006-10-06 20:20:14 +04:00
/* codec/machine specific init - e.g. add machine controls */
int ( * init ) ( struct snd_soc_codec * codec ) ;
2008-01-10 16:39:01 +03:00
/* DAI pcm */
struct snd_pcm * pcm ;
2006-10-06 20:20:14 +04:00
} ;
2008-11-18 23:50:34 +03:00
/* SoC card */
struct snd_soc_card {
2006-10-06 20:20:14 +04:00
char * name ;
2008-11-28 16:29:45 +03:00
struct device * dev ;
struct list_head list ;
int instantiated ;
2006-10-06 20:20:14 +04:00
int ( * probe ) ( struct platform_device * pdev ) ;
int ( * remove ) ( struct platform_device * pdev ) ;
/* the pre and post PM functions are used to do any PM work before and
* after the codec and DAI ' s do any PM work . */
int ( * suspend_pre ) ( struct platform_device * pdev , pm_message_t state ) ;
int ( * suspend_post ) ( struct platform_device * pdev , pm_message_t state ) ;
int ( * resume_pre ) ( struct platform_device * pdev ) ;
int ( * resume_post ) ( struct platform_device * pdev ) ;
2008-01-10 16:36:20 +03:00
/* callbacks */
2008-11-18 23:50:34 +03:00
int ( * set_bias_level ) ( struct snd_soc_card * ,
2008-05-19 14:31:28 +04:00
enum snd_soc_bias_level level ) ;
2008-01-10 16:36:20 +03:00
2006-10-06 20:20:14 +04:00
/* CPU <--> Codec DAI links */
struct snd_soc_dai_link * dai_link ;
int num_links ;
2008-12-02 18:08:03 +03:00
struct snd_soc_device * socdev ;
2008-12-02 19:01:14 +03:00
struct snd_soc_platform * platform ;
2008-12-02 18:08:03 +03:00
struct delayed_work delayed_work ;
struct work_struct deferred_resume_work ;
2006-10-06 20:20:14 +04:00
} ;
/* SoC Device - the audio subsystem */
struct snd_soc_device {
struct device * dev ;
2008-11-18 23:50:34 +03:00
struct snd_soc_card * card ;
2006-10-06 20:20:14 +04:00
struct snd_soc_codec * codec ;
struct snd_soc_codec_device * codec_dev ;
void * codec_data ;
} ;
/* runtime channel data */
struct snd_soc_pcm_runtime {
2007-02-02 19:13:05 +03:00
struct snd_soc_dai_link * dai ;
2006-10-06 20:20:14 +04:00
struct snd_soc_device * socdev ;
} ;
2008-07-29 14:42:26 +04:00
/* mixer control */
struct soc_mixer_control {
int min , max ;
2008-07-29 18:22:24 +04:00
unsigned int reg , rreg , shift , rshift , invert ;
2008-07-29 14:42:26 +04:00
} ;
2006-10-06 20:20:14 +04:00
/* enumerated kcontrol */
struct soc_enum {
unsigned short reg ;
unsigned short reg2 ;
unsigned char shift_l ;
unsigned char shift_r ;
2008-07-29 14:42:27 +04:00
unsigned int max ;
2006-10-06 20:20:14 +04:00
const char * * texts ;
void * dapm ;
} ;
2008-07-23 17:03:07 +04:00
# include <sound/soc-dai.h>
2006-10-06 20:20:14 +04:00
# endif