diff options
author | Sumit Bhattacharya <sumitb@nvidia.com> | 2011-01-29 11:51:53 +0530 |
---|---|---|
committer | Niket Sirsi <nsirsi@nvidia.com> | 2011-02-07 18:15:11 -0800 |
commit | 36de5b7823f769116875b30f4bbef2aa8f31d747 (patch) | |
tree | 893d03a2163f369b6583da28f24400406888c4ba /sound | |
parent | a68d871f5b814aa935af353f130737a0a8f7510a (diff) |
tegra alsa: Implement generic codec interface
Change-Id: I210dea5af60e11326ad23bafa78e937d4932e58c
Reviewed-on: http://git-master/r/17564
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Tested-by: Sumit Bhattacharya <sumitb@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Reviewed-by: Scott Peterson <speterson@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/tegra/Kconfig | 3 | ||||
-rw-r--r-- | sound/soc/tegra/Makefile | 1 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_generic_codec.c | 192 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_i2s.c | 12 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_pcm.c | 2 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_soc.h | 4 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_soc_wm8903.c | 41 |
7 files changed, 241 insertions, 14 deletions
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 09d1d26450c8..4e0d9c251252 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -3,6 +3,7 @@ config TEGRA_ALSA select TEGRA_PCM select TEGRA_I2S select TEGRA_IEC + select TEGRA_GENERIC_CODEC help Say Y if you for ALSA SoC support @@ -15,3 +16,5 @@ config TEGRA_I2S config TEGRA_IEC tristate "Tegra IEC" +config TEGRA_GENERIC_CODEC + tristate "Tegra ALSA Generic Codec support" diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index d7fa52bc28f2..303abe5a088f 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -2,6 +2,7 @@ ccflags-y += -DNV_DEBUG=0 obj-$(CONFIG_TEGRA_PCM) += tegra_pcm.o obj-$(CONFIG_TEGRA_I2S) += tegra_i2s.o obj-$(CONFIG_TEGRA_ALSA) += tegra_soc_controls.o +obj-$(CONFIG_TEGRA_GENERIC_CODEC)+= tegra_generic_codec.o obj-${CONFIG_SND_SOC_WM8903} += tegra_soc_wm8903.o obj-${CONFIG_SND_SOC_WM8753} += tegra_soc_wm8753.o diff --git a/sound/soc/tegra/tegra_generic_codec.c b/sound/soc/tegra/tegra_generic_codec.c new file mode 100644 index 000000000000..5da9e8a6294f --- /dev/null +++ b/sound/soc/tegra/tegra_generic_codec.c @@ -0,0 +1,192 @@ + /* + * tegra_generic_codec.c -- Generic codec interface for tegra + * + * Copyright 2011 Nvidia Graphics Pvt. Ltd. + * + * Author: Sumit Bhattacharya + * sumitb@nvidia.com + * http://www.nvidia.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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "tegra_soc.h" + +static struct snd_soc_codec* tegra_generic_codec; +static struct platform_device* tegra_generic_codec_dev; + +// Stubbed implementations of generic codec ops +static int tegra_generic_codec_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return 0; +} + +static void tegra_generic_codec_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return; +} +static int tegra_generic_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return 0; +} + +static int tegra_generic_codec_mute(struct snd_soc_dai *dai, int mute) +{ + return 0; +} + + +static int tegra_generic_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + return 0; +} + +static int tegra_generic_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + return 0; +} + +static struct snd_soc_dai_ops tegra_generic_codec_stub_ops = { + .startup = tegra_generic_codec_startup, + .shutdown = tegra_generic_codec_shutdown, + .hw_params = tegra_generic_codec_hw_params, + .digital_mute = tegra_generic_codec_mute, + .set_fmt = tegra_generic_codec_set_dai_fmt, + .set_sysclk = tegra_generic_codec_set_dai_sysclk, +}; + +struct snd_soc_dai tegra_generic_codec_dai[] = { + { + .name = "tegra_generic_voice_codec", + .id = 0, + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 1, + .rates = TEGRA_VOICE_SAMPLE_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 1, + .rates = TEGRA_VOICE_SAMPLE_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &tegra_generic_codec_stub_ops, + } +}; +EXPORT_SYMBOL_GPL(tegra_generic_codec_dai); + +static int generic_codec_init(struct platform_device *pdev) +{ + int ret = 0; + + tegra_generic_codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (!tegra_generic_codec) + return -ENOMEM; + + mutex_init(&tegra_generic_codec->mutex); + + tegra_generic_codec->dev = &pdev->dev; + tegra_generic_codec->name = "tegra_generic_codec"; + tegra_generic_codec->owner = THIS_MODULE; + tegra_generic_codec->dai = tegra_generic_codec_dai; + tegra_generic_codec->num_dai = ARRAY_SIZE(tegra_generic_codec_dai); + tegra_generic_codec->write = NULL; + tegra_generic_codec->read = NULL; + tegra_generic_codec_dai[0].dev = &pdev->dev; + INIT_LIST_HEAD(&tegra_generic_codec->dapm_widgets); + INIT_LIST_HEAD(&tegra_generic_codec->dapm_paths); + + ret = snd_soc_register_codec(tegra_generic_codec); + if (ret != 0) { + pr_err("codec: failed to register tegra_generic_codec\n"); + goto codec_err; + } + + ret = snd_soc_register_dais(tegra_generic_codec_dai, ARRAY_SIZE(tegra_generic_codec_dai)); + if (ret != 0) { + pr_err("codec: failed to register dais\n"); + goto dai_err; + } + + return ret; +dai_err: + snd_soc_unregister_codec(tegra_generic_codec); +codec_err: + kfree(tegra_generic_codec); + tegra_generic_codec = NULL; + + return ret; +} + + +static int generic_codec_remove(struct platform_device *pdev) +{ + if (!tegra_generic_codec) + return 0; + + snd_soc_unregister_dais(tegra_generic_codec_dai, ARRAY_SIZE(tegra_generic_codec_dai)); + snd_soc_unregister_codec(tegra_generic_codec); + kfree(tegra_generic_codec); + tegra_generic_codec = NULL; + tegra_generic_codec_dai[0].dev = NULL; + + return 0; +} + +static int __init tegra_generic_codec_init(void) +{ + int ret = 0; + + tegra_generic_codec_dev = + platform_device_register_simple("tegra_generic_codec", -1, NULL, 0); + if (!tegra_generic_codec_dev) + return -ENOMEM; + + ret = generic_codec_init(tegra_generic_codec_dev); + if (ret != 0) + goto codec_err; + + return 0; + +codec_err: + platform_device_unregister(tegra_generic_codec_dev); + tegra_generic_codec_dev = 0; + return ret; +} + +static void __exit tegra_generic_codec_exit(void) +{ + generic_codec_remove(tegra_generic_codec_dev); + platform_device_unregister(tegra_generic_codec_dev); + tegra_generic_codec_dev = 0; +} + +module_init(tegra_generic_codec_init); +module_exit(tegra_generic_codec_exit); + +/* Module information */ +MODULE_DESCRIPTION("Tegra ALSA Generic Codec Interface"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index fe65aabb6f09..6f62d2ce36ef 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -437,15 +437,15 @@ struct snd_soc_dai tegra_i2s_dai[] = { .suspend = tegra_i2s_suspend, .resume = tegra_i2s_resume, .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = TEGRA_SAMPLE_RATES, + .channels_min = 1, + .channels_max = 1, + .rates = TEGRA_VOICE_SAMPLE_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = TEGRA_SAMPLE_RATES, + .channels_min = 1, + .channels_max = 1, + .rates = TEGRA_VOICE_SAMPLE_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .ops = &tegra_i2s_dai_ops, diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 1bddb5547c3c..2c13ea4fc7d5 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -125,7 +125,7 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = { .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (PAGE_SIZE * 8), - .period_bytes_min = 1024, + .period_bytes_min = 256, .period_bytes_max = (PAGE_SIZE), .periods_min = 2, .periods_max = 8, diff --git a/sound/soc/tegra/tegra_soc.h b/sound/soc/tegra/tegra_soc.h index 29f4fcf13651..d46fc9078c8a 100644 --- a/sound/soc/tegra/tegra_soc.h +++ b/sound/soc/tegra/tegra_soc.h @@ -66,12 +66,14 @@ #define I2S_I2S_FIFO_RX_BUSY I2S_I2S_STATUS_FIFO2_BSY #define I2S_I2S_FIFO_RX_QS I2S_I2S_STATUS_QS_FIFO2 -#define I2S_CLK 11289600 +#define I2S1_CLK 11289600 +#define I2S2_CLK 2000000 #define TEGRA_DEFAULT_SR 44100 #define TEGRA_SAMPLE_RATES \ (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) +#define TEGRA_VOICE_SAMPLE_RATES SNDRV_PCM_RATE_8000 struct tegra_dma_channel; diff --git a/sound/soc/tegra/tegra_soc_wm8903.c b/sound/soc/tegra/tegra_soc_wm8903.c index dc5103c36377..fd168e221404 100644 --- a/sound/soc/tegra/tegra_soc_wm8903.c +++ b/sound/soc/tegra/tegra_soc_wm8903.c @@ -21,6 +21,7 @@ static struct platform_device *tegra_snd_device; extern struct snd_soc_dai tegra_i2s_dai[]; +extern struct snd_soc_dai tegra_generic_codec_dai[]; extern struct snd_soc_platform tegra_soc_platform; /* codec register values */ @@ -86,13 +87,13 @@ static int tegra_hifi_hw_params(struct snd_pcm_substream *substream, return err; } - err = snd_soc_dai_set_sysclk(codec_dai, 0, I2S_CLK, SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(codec_dai, 0, I2S1_CLK, SND_SOC_CLOCK_IN); if (err < 0) { printk(KERN_ERR "codec_dai clock not set\n"); return err; } - err = snd_soc_dai_set_sysclk(cpu_dai, 0, I2S_CLK, SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(cpu_dai, 0, I2S1_CLK, SND_SOC_CLOCK_IN); if (err < 0) { printk(KERN_ERR "cpu_dai clock not set\n"); return err; @@ -153,10 +154,38 @@ static int tegra_hifi_hw_params(struct snd_pcm_substream *substream, return 0; } +static int tegra_voice_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int err; + + err = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_DSP_A | \ + SND_SOC_DAIFMT_NB_NF | \ + SND_SOC_DAIFMT_CBS_CFS); + if (err < 0) { + pr_err("cpu_dai fmt not set \n"); + return err; + } + + err = snd_soc_dai_set_sysclk(cpu_dai, 0, I2S2_CLK, SND_SOC_CLOCK_IN); + if (err < 0) { + pr_err("cpu_dai clock not set\n"); + return err; + } + return 0; +} + static struct snd_soc_ops tegra_hifi_ops = { .hw_params = tegra_hifi_hw_params, }; +static struct snd_soc_ops tegra_voice_ops = { + .hw_params = tegra_voice_hw_params, +}; + static int tegra_codec_init(struct snd_soc_codec *codec) { return tegra_controls_init(codec); @@ -172,12 +201,12 @@ static struct snd_soc_dai_link tegra_soc_dai[] = { .ops = &tegra_hifi_ops, }, { - .name = "WM8903", - .stream_name = "WM8903 Voice", + .name = "Tegra-generic", + .stream_name = "Tegra Generic Voice", .cpu_dai = &tegra_i2s_dai[1], - .codec_dai = &wm8903_dai, + .codec_dai = &tegra_generic_codec_dai[0], .init = tegra_codec_init, - .ops = &tegra_hifi_ops, + .ops = &tegra_voice_ops, }, }; |