diff options
author | Vijay Mali <vmali@nvidia.com> | 2010-06-25 11:44:05 +0530 |
---|---|---|
committer | Bharat Nihalani <bnihalani@nvidia.com> | 2010-06-25 04:17:01 -0700 |
commit | 5e252bf65a356d960e650f61ab9d446bac8f5872 (patch) | |
tree | 7d4752fbba45ecb9794e7bd52b64ecf11a1abcf5 /sound/soc | |
parent | cceed926fb99e3034443b43e14cfe66fa850acec (diff) |
[tegra ALSA] Adding ALSA Control for audio routing
Added switch control in ALSA SoC to route audio to
SPDIF. Verified using the amixer application.
Renamed init_mixer function to tegra_audiofx_init.
Moved this function to tegra transport source file.
Fix for bug 678749
Change-Id: I892ebd98d276a60e50ef047d31ad7c0e7c8185cc
Reviewed-on: http://git-master/r/3175
Tested-by: Vijay Mali <vmali@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/tegra/tegra_codec_rpc.c | 108 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_pcm_rpc.c | 84 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_sndfx.h | 77 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_transport.c | 85 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_transport.h | 4 |
5 files changed, 225 insertions, 133 deletions
diff --git a/sound/soc/tegra/tegra_codec_rpc.c b/sound/soc/tegra/tegra_codec_rpc.c index 3e22d670f2d8..6868f76afeda 100644 --- a/sound/soc/tegra/tegra_codec_rpc.c +++ b/sound/soc/tegra/tegra_codec_rpc.c @@ -43,15 +43,17 @@ static int tegra_master_volume_info(struct snd_kcontrol *kcontrol, static int tegra_master_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + int rval = NvAudioFxVolumeDefault; + int lval = NvAudioFxVolumeDefault; + if (tegra_snd_cx) { - ucontrol->value.integer.value[0] = tegra_snd_cx->i2s1volume; - ucontrol->value.integer.value[1] = tegra_snd_cx->i2s1volume; - } - else { - ucontrol->value.integer.value[0] = NvAudioFxVolumeDefault; - ucontrol->value.integer.value[1] = NvAudioFxVolumeDefault; + if (!tegra_audiofx_init(tegra_snd_cx)) { + rval = tegra_snd_cx->i2s1volume; + lval = tegra_snd_cx->i2s1volume; + } } - + ucontrol->value.integer.value[0] = rval; + ucontrol->value.integer.value[1] = lval; return 0; } @@ -70,23 +72,24 @@ static int tegra_master_volume_put(struct snd_kcontrol *kcontrol, vd.Mute = 1; } - if (tegra_snd_cx && tegra_snd_cx->mixer_handle) { - if(tegra_snd_cx->i2s1volume != val) { - tegra_snd_cx->i2s1volume = val; - tegra_snd_cx->xrt_fxn.SetProperty( - tegra_snd_cx->mvolume, - NvAudioFxVolumeProperty_Volume, - sizeof(NvAudioFxVolumeDescriptor), - &vd); - change = 1; - snd_printk(KERN_ERR "Put Volume Change = 1\n"); + if (tegra_snd_cx) { + if (!tegra_audiofx_init(tegra_snd_cx)) { + if(tegra_snd_cx->i2s1volume != val) { + tegra_snd_cx->i2s1volume = val; + tegra_snd_cx->xrt_fxn.SetProperty( + tegra_snd_cx->mvolume, + NvAudioFxVolumeProperty_Volume, + sizeof(NvAudioFxVolumeDescriptor), + &vd); + change = 1; + } } } return change; } -static struct snd_kcontrol_new tegra_codec_control = +static struct snd_kcontrol_new tegra_codec_ctrl_volume = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -97,6 +100,64 @@ static struct snd_kcontrol_new tegra_codec_control = .put = tegra_master_volume_put }; +static int tegra_master_route_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int tegra_master_route_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = 0; + if (tegra_snd_cx) { + if (!tegra_audiofx_init(tegra_snd_cx)) { + ucontrol->value.integer.value[0] = + tegra_snd_cx->spdif_plugin; + } + } + return 0; +} + +static int tegra_master_route_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int change = 0, val; + NvAudioFxIoDevice ioDevice = 0; + val = ucontrol->value.integer.value[0] & 0xffff; + if (val) { + ioDevice = NvAudioFxIoDevice_BuiltInSpeaker; + } + + if (tegra_snd_cx) { + if (!tegra_audiofx_init(tegra_snd_cx)) { + tegra_snd_cx->spdif_plugin = val; + tegra_snd_cx->xrt_fxn.SetProperty( + tegra_snd_cx->mroute, + NvAudioFxIoProperty_OutputSelect, + sizeof(NvAudioFxIoDevice), + &ioDevice); + change = 1; + } + } + return change; +} + +static struct snd_kcontrol_new tegra_codec_ctrl_route = +{ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SPDIF Playback Switch", + .private_value = 0xffff, + .info = tegra_master_route_info, + .get = tegra_master_route_get, + .put = tegra_master_route_put +}; + static int tegra_generic_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -208,9 +269,16 @@ static int codec_soc_probe(struct platform_device *pdev) printk(KERN_ERR "codec: failed to register card\n"); goto card_err; } - + /* Add volume control */ + ret = snd_ctl_add(codec->card, + snd_ctl_new1(&tegra_codec_ctrl_volume, codec)); + if (ret < 0) { + printk(KERN_ERR "codec: failed to add control\n"); + goto card_err; + } + /* Add route control */ return snd_ctl_add(codec->card, - snd_ctl_new1(&tegra_codec_control, codec)); + snd_ctl_new1(&tegra_codec_ctrl_route, codec)); card_err: snd_soc_free_pcms(socdev); diff --git a/sound/soc/tegra/tegra_pcm_rpc.c b/sound/soc/tegra/tegra_pcm_rpc.c index c64d5a2f8d62..b1f78ab6e208 100644 --- a/sound/soc/tegra/tegra_pcm_rpc.c +++ b/sound/soc/tegra/tegra_pcm_rpc.c @@ -388,82 +388,6 @@ tegra_pcm_pointer(struct snd_pcm_substream *substream) return (size); } -static int init_mixer(struct snd_pcm_substream *substream) -{ - NvError e = NvSuccess; - int ret = 0; - - if (!tegra_snd_cx->mixer_handle) { - mutex_lock(&tegra_snd_cx->lock); - e = tegra_transport_init(&tegra_snd_cx->xrt_fxn); - mutex_unlock(&tegra_snd_cx->lock); - - if (e != NvSuccess) { - snd_printk(KERN_ERR "tegra_transport_init failed \n"); - return -EFAULT; - } - - tegra_snd_cx->mixer_handle = - tegra_snd_cx->xrt_fxn.MixerOpen(); - - if (!tegra_snd_cx->mixer_handle) { - ret = -EFAULT; - goto fail; - } - - e = tegra_audiofx_createfx(tegra_snd_cx); - if (e != NvSuccess) { - snd_printk(KERN_ERR "tegra_audiofx_createfx failed \n"); - ret = -EFAULT; - goto fail; - } - - tegra_snd_cx->mixer_buffer[0] = - tegra_snd_cx->xrt_fxn.MixerMapBuffer( - tegra_snd_cx->mixer_handle, - NvRmMemGetId(tegra_snd_cx->mem_handle[0]), - 0, - tegra_snd_cx->mapped_buf_size); - - if (!tegra_snd_cx->mixer_buffer[0]) { - snd_printk(KERN_ERR"TransportMixerMapBuffer failed!\n"); - } - - tegra_snd_cx->mixer_buffer[1] = - tegra_snd_cx->xrt_fxn.MixerMapBuffer( - tegra_snd_cx->mixer_handle, - NvRmMemGetId(tegra_snd_cx->mem_handle[1]), - 0, - tegra_snd_cx->mapped_buf_size); - - if (!tegra_snd_cx->mixer_buffer[1]) { - snd_printk(KERN_ERR"TransportMixerMapBuffer failed!\n"); - } - - tegra_snd_cx->mvolume = tegra_snd_cx->xrt_fxn.MixerCreateObject( - tegra_snd_cx->mixer_handle, - NvAudioFxI2s1VolumeId); - tegra_snd_cx->i2s1volume = NvAudioFxVolumeDefault; - } - - return 0; -fail: - snd_printk(KERN_ERR "init mixer failed \n"); - if (tegra_snd_cx->mixer_handle) { - tegra_audiofx_destroyfx(tegra_snd_cx); - - if (tegra_snd_cx->mixer_handle) { - tegra_snd_cx->xrt_fxn.MixerClose( - tegra_snd_cx->mixer_handle); - } - } - mutex_lock(&tegra_snd_cx->lock); - tegra_transport_deinit(); - mutex_unlock(&tegra_snd_cx->lock); - - return ret; -} - static int pcm_common_close(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -543,9 +467,11 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) prtd->state = NVALSA_INVALID_STATE; prtd->stream = substream->stream; - ret = init_mixer(substream); - if (ret) - goto fail; + if (!tegra_snd_cx->mixer_handle) { + ret = tegra_audiofx_init(tegra_snd_cx); + if (ret) + goto fail; + } init_completion(&prtd->thread_comp); init_waitqueue_head(&prtd->buf_wait); diff --git a/sound/soc/tegra/tegra_sndfx.h b/sound/soc/tegra/tegra_sndfx.h index 2cc38e557290..00f58436e75e 100644 --- a/sound/soc/tegra/tegra_sndfx.h +++ b/sound/soc/tegra/tegra_sndfx.h @@ -40,6 +40,7 @@ extern "C" #endif #include "nvrm_module.h" +#include "nvrm_memmgr.h" #include "nvrm_transport.h" #include "nvrm_init.h" @@ -154,16 +155,17 @@ typedef NvS32 NvAudioFxProperty; #define NvAudioFxPinProperty_Format (0x2000) #define NvAudioFxDrcProperty_Drc (0x3000) #define NvAudioFxEqProperty_Eq (0x4000) -#define NvAudioFxI2sProperty_AllocChannel (0x4a01) -#define NvAudioFxI2sProperty_InputAvailable (0x4a02) -#define NvAudioFxI2sProperty_InputDisable (0x4a04) -#define NvAudioFxI2sProperty_InputEnable (0x4a03) -#define NvAudioFxI2sProperty_InputSelect (0x4a05) -#define NvAudioFxI2sProperty_OutputAvailable (0x4a06) -#define NvAudioFxI2sProperty_OutputDisable (0x4a08) -#define NvAudioFxI2sProperty_OutputEnable (0x4a07) -#define NvAudioFxI2sProperty_OutputSelect (0x4a09) -#define NvAudioFxI2sProperty_IoDeviceVolume (0x4a0a) +#define NvAudioFxIoProperty_AllocChannel (0x4a01) +#define NvAudioFxIoProperty_InputAvailable (0x4a02) +#define NvAudioFxIoProperty_InputEnable (0x4a03) +#define NvAudioFxIoProperty_InputDisable (0x4a04) +#define NvAudioFxIoProperty_InputSelect (0x4a05) +#define NvAudioFxIoProperty_OutputAvailable (0x4a06) +#define NvAudioFxIoProperty_OutputEnable (0x4a07) +#define NvAudioFxIoProperty_OutputDisable (0x4a08) +#define NvAudioFxIoProperty_OutputSelect (0x4a09) +#define NvAudioFxIoProperty_IoDeviceVolume (0x4a0a) +#define NvAudioFxIoProperty_GenericOdmConfig (0x4a0b) #define NvAudioFxIoProperty_AddEvent (0x5000) #define NvAudioFxIoProperty_Position (0x5010) #define NvAudioFxIoProperty_RemoveEvent (0x5020) @@ -281,29 +283,6 @@ typedef struct NvAudioFxSpreaderDescriptorRec NvU32 SpeakerWidth; } NvAudioFxSpreaderDescriptor; -// I2S inputs. - -typedef NvS32 NvAudioFxI2sInputSelect; - -// Default is configurable based on the device. -#define NvAudioFxI2sInputSelect_Default (0x0) -#define NvAudioFxI2sInputSelect_Bluetooth (0x1) -#define NvAudioFxI2sInputSelect_BuiltinMic (0x2) -#define NvAudioFxI2sInputSelect_LineIn (0x3) -#define NvAudioFxI2sInputSelect_Mic (0x4) -#define NvAudioFxI2sInputSelect_Phone (0x5) -#define NvAudioFxI2sInputSelect_Radio (0x6) - -// Description of the NvAudioFxI2sProperty_AllocChannel property. - -typedef struct NvAudioFxI2sChannelDescriptorRec -{ - NvAudioFxPin Pin; - NvU32 Id; -} NvAudioFxI2sChannelDescriptor; - -// Parameteric EQ Filter types. - typedef enum { NvAudioFxIirFilter_Undefined, @@ -418,6 +397,31 @@ typedef struct NvAudioFxNotifierConnectionDescriptorRec NvU8 PortName[16]; } NvAudioFxNotifierConnectionDescriptor; +// Description of the NvAudioFxI2sProperty_AllocChannel property. + +typedef struct NvAudioFxIoChannelDescriptorRec +{ + NvAudioFxPin Pin; + NvU32 Id; +} NvAudioFxIoChannelDescriptor; + +// Buffer has a header of type NvAudioFxOdmConfigHeader followed by the data buffer. + +typedef struct NvAudioFxOdmConfigHeaderRec +{ + NvU32 Size; + NvError Result; +} NvAudioFxOdmConfigHeader; + +// Description of the NvAudioFxIoProperty_GenericOdmConfig property. + +typedef struct NvAudioFxOdmConfigDescriptorRec +{ + NvU32 hRmMemId; + NvU32 Size; + void* hSemaphore; +} NvAudioFxOdmConfigDescriptor; + // Description of the NvAudioFxProperty_AddEvent and // NvAudioFxProperty_RemoveEvent properties. @@ -429,6 +433,7 @@ typedef NvS32 NvAudioFxEvent; #define NvAudioFxEventPowerStateChange (0x10) #define NvAudioFxEventIoChange (0x20) #define NvAudioFxEventControlChange (0x40) +#define NvAudioFxEventControlQuery (0x80) #define NvAudioFxEventAll (0xffffffff) typedef struct NvAudioFxMessageRec @@ -462,6 +467,12 @@ typedef struct NvAudioFxIoDeviceVolumeControlChangeMessageRec NvAudioFxIoDeviceVolumeDescriptor idv; } NvAudioFxIoDeviceVolumeControlChangeMessage; +typedef struct NvAudioFxOdmConfigChangeMessageRec +{ + NvAudioFxControlChangeMessage m; + NvAudioFxOdmConfigDescriptor OdmConfig; +} NvAudioFxOdmConfigChangeMessage; + typedef struct NvAudioFxModeControlChangeMessageRec { NvAudioFxControlChangeMessage m; diff --git a/sound/soc/tegra/tegra_transport.c b/sound/soc/tegra/tegra_transport.c index 161ed15f1e0b..157c6d7c3476 100644 --- a/sound/soc/tegra/tegra_transport.c +++ b/sound/soc/tegra/tegra_transport.c @@ -477,6 +477,91 @@ EXIT: return; } +int tegra_audiofx_init(struct tegra_audio_data* tegra_snd_cx) +{ + NvError e = NvSuccess; + int ret = 0; + + if (!tegra_snd_cx->mixer_handle) { + mutex_lock(&tegra_snd_cx->lock); + e = tegra_transport_init(&tegra_snd_cx->xrt_fxn); + mutex_unlock(&tegra_snd_cx->lock); + + if (e != NvSuccess) { + snd_printk(KERN_ERR "tegra_transport_init failed \n"); + return -EFAULT; + } + + tegra_snd_cx->mixer_handle = + tegra_snd_cx->xrt_fxn.MixerOpen(); + + if (!tegra_snd_cx->mixer_handle) { + ret = -EFAULT; + goto fail; + } + + e = tegra_audiofx_createfx(tegra_snd_cx); + if (e != NvSuccess) { + snd_printk(KERN_ERR "tegra_audiofx_createfx failed \n"); + ret = -EFAULT; + goto fail; + } + + tegra_snd_cx->mixer_buffer[0] = + tegra_snd_cx->xrt_fxn.MixerMapBuffer( + tegra_snd_cx->mixer_handle, + NvRmMemGetId(tegra_snd_cx->mem_handle[0]), + 0, + tegra_snd_cx->mapped_buf_size); + + if (!tegra_snd_cx->mixer_buffer[0]) { + snd_printk(KERN_ERR"TransportMixerMapBuffer failed!\n"); + ret = -EFAULT; + goto fail; + } + + tegra_snd_cx->mixer_buffer[1] = + tegra_snd_cx->xrt_fxn.MixerMapBuffer( + tegra_snd_cx->mixer_handle, + NvRmMemGetId(tegra_snd_cx->mem_handle[1]), + 0, + tegra_snd_cx->mapped_buf_size); + + if (!tegra_snd_cx->mixer_buffer[1]) { + snd_printk(KERN_ERR"TransportMixerMapBuffer failed!\n"); + ret = -EFAULT; + goto fail; + } + + tegra_snd_cx->mvolume = tegra_snd_cx->xrt_fxn.MixerCreateObject( + tegra_snd_cx->mixer_handle, + NvAudioFxI2s1VolumeId); + tegra_snd_cx->i2s1volume = NvAudioFxVolumeDefault; + + tegra_snd_cx->mroute = tegra_snd_cx->xrt_fxn.MixerCreateObject( + tegra_snd_cx->mixer_handle, + NvAudioFxSpdifId); + tegra_snd_cx->spdif_plugin = 0; + } + + return 0; +fail: + snd_printk(KERN_ERR "tegra_audiofx_init failed \n"); + if (tegra_snd_cx->mixer_handle) { + tegra_audiofx_destroyfx(tegra_snd_cx); + + if (tegra_snd_cx->mixer_handle) { + tegra_snd_cx->xrt_fxn.MixerClose( + tegra_snd_cx->mixer_handle); + } + } + mutex_lock(&tegra_snd_cx->lock); + tegra_transport_deinit(); + mutex_unlock(&tegra_snd_cx->lock); + + return ret; +} + static void tegra_audiofx_notifier_thread(void *arg) { struct tegra_audio_data *audio_context = (struct tegra_audio_data *)arg; diff --git a/sound/soc/tegra/tegra_transport.h b/sound/soc/tegra/tegra_transport.h index 40e4c9eaa11d..a93188fbb560 100644 --- a/sound/soc/tegra/tegra_transport.h +++ b/sound/soc/tegra/tegra_transport.h @@ -411,11 +411,13 @@ struct tegra_audio_data { NvAudioFxMixBufferHandle mixer_buffer[2]; NvRmMemHandle mem_handle[2]; NvAudioFxObjectHandle mvolume; + NvAudioFxObjectHandle mroute; + int spdif_plugin; int i2s1volume; struct mutex lock; }; - +int tegra_audiofx_init(struct tegra_audio_data* tegra_snd_cx); NvError tegra_audiofx_createfx(struct tegra_audio_data *audio_context); void tegra_audiofx_destroyfx(struct tegra_audio_data *audio_context); NvError tegra_audiofx_create_output(NvRmDeviceHandle, |