summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
authorNikesh Oswal <noswal@nvidia.com>2012-01-24 12:19:32 +0530
committerVarun Colbert <vcolbert@nvidia.com>2012-01-30 11:56:52 -0800
commitc8b140cfc9db43d43e9513df55e6d6813d0aaead (patch)
tree0274c09a4c109cef1a9fa74328526dd8065fe975 /sound/soc
parent965e071849da10e150d68693e20396d120e83168 (diff)
asoc: tegra: wm8753: add support for voice call
Bug: 919350 Reviewed-on: http://git-master/r/76953 Change-Id: I95611af5e6c12e03cc22fc30c8147e3ef6852615 Signed-off-by: Nikesh Oswal <noswal@nvidia.com> Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-on: http://git-master/r/77731 Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/tegra/tegra_wm8753.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
index 0b2a431d500e..1388a8d664bb 100644
--- a/sound/soc/tegra/tegra_wm8753.c
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -68,6 +68,7 @@ struct tegra_wm8753 {
struct tegra_wm8753_platform_data *pdata;
struct regulator *audio_reg;
int gpio_requested;
+ int is_call_mode;
};
static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream,
@@ -277,6 +278,98 @@ static int tegra_spdif_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static int tegra_wm8753_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 *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *card = codec->card;
+ struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
+ int srate, mclk, i2s_daifmt, sys_clk;
+ int err, pcmdiv, vxclkdiv;
+
+ srate = params_rate(params);
+ switch (srate) {
+ case 8000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ case 64000:
+ case 96000:
+ mclk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ mclk = 11289600;
+ break;
+ default:
+ mclk = 12000000;
+ break;
+ }
+
+ err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+ if (err < 0) {
+ if (!(machine->util_data.set_mclk % mclk))
+ mclk = machine->util_data.set_mclk;
+ else {
+ dev_err(card->dev, "Can't configure clocks\n");
+ return err;
+ }
+ }
+
+ tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
+
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
+
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+
+ err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
+ if (err < 0) {
+ dev_err(card->dev, "codec_dai fmt not set\n");
+ return err;
+ }
+
+ sys_clk = machine->util_data.set_mclk;
+
+ err = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, sys_clk,
+ SND_SOC_CLOCK_IN);
+ if (err < 0) {
+ dev_err(card->dev, "codec_dai clock not set\n");
+ return err;
+ }
+
+ err = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
+ sys_clk, 12288000);
+
+ if (err < 0) {
+ dev_err(card->dev, "codec_dai pll not set\n");
+ return err;
+ }
+
+ if (params_rate(params) == 8000) {
+ pcmdiv = WM8753_PCM_DIV_6;
+ /* BB expecting 2048Khz bclk */
+ vxclkdiv = WM8753_VXCLK_DIV_1;
+ } else if (params_rate(params) == 16000) {
+ pcmdiv = WM8753_PCM_DIV_3;
+ /* BB expecting 2048Khz bclk */
+ vxclkdiv = WM8753_VXCLK_DIV_2;
+ } else {
+ dev_err(card->dev, "codec_dai unsupported voice rate\n");
+ return -EINVAL;
+ }
+
+ snd_soc_dai_set_clkdiv(codec_dai, WM8753_VXCLKDIV, vxclkdiv);
+ snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
+
+ return 0;
+}
+
static int tegra_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -287,11 +380,94 @@ static int tegra_hw_free(struct snd_pcm_substream *substream)
return 0;
}
+static int tegra_wm8753_voice_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(rtd->card);
+
+ tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0);
+
+ return 0;
+}
+
+static int tegra_call_mode_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_call_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_wm8753 *machine = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = machine->is_call_mode;
+
+ return 0;
+}
+
+static int tegra_call_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_wm8753 *machine = snd_kcontrol_chip(kcontrol);
+ int is_call_mode_new = ucontrol->value.integer.value[0];
+
+ if (machine->is_call_mode == is_call_mode_new)
+ return 0;
+
+ if (is_call_mode_new) {
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ tegra20_das_set_tristate(TEGRA20_DAS_DAP_ID_2, 1);
+ tegra20_das_set_tristate(TEGRA20_DAS_DAP_ID_3, 1);
+ tegra20_das_connect_dap_to_dap(TEGRA20_DAS_DAP_ID_2,
+ TEGRA20_DAS_DAP_SEL_DAP3, 1, 0, 0);
+ tegra20_das_connect_dap_to_dap(TEGRA20_DAS_DAP_ID_3,
+ TEGRA20_DAS_DAP_SEL_DAP2, 0, 0, 0);
+ tegra20_das_set_tristate(TEGRA20_DAS_DAP_ID_2, 0);
+ tegra20_das_set_tristate(TEGRA20_DAS_DAP_ID_3, 0);
+#endif
+ } else {
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ tegra20_das_set_tristate(TEGRA20_DAS_DAP_ID_2, 1);
+ tegra20_das_set_tristate(TEGRA20_DAS_DAP_ID_3, 1);
+ tegra20_das_connect_dap_to_dap(TEGRA20_DAS_DAP_ID_3,
+ TEGRA20_DAS_DAP_SEL_DAP3, 0, 0, 0);
+ tegra20_das_connect_dap_to_dap(TEGRA20_DAS_DAP_ID_2,
+ TEGRA20_DAS_DAP_SEL_DAP2, 0, 0, 0);
+ tegra20_das_set_tristate(TEGRA20_DAS_DAP_ID_2, 0);
+ tegra20_das_set_tristate(TEGRA20_DAS_DAP_ID_3, 0);
+#endif
+ }
+
+ machine->is_call_mode = is_call_mode_new;
+
+ return 1;
+}
+
+struct snd_kcontrol_new tegra_call_mode_control = {
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Call Mode Switch",
+ .private_value = 0xffff,
+ .info = tegra_call_mode_info,
+ .get = tegra_call_mode_get,
+ .put = tegra_call_mode_put
+};
+
static struct snd_soc_ops tegra_wm8753_ops = {
.hw_params = tegra_wm8753_hw_params,
.hw_free = tegra_hw_free,
};
+static struct snd_soc_ops tegra_wm8753_voice_ops = {
+ .hw_params = tegra_wm8753_voice_hw_params,
+ .hw_free = tegra_wm8753_voice_hw_free,
+};
+
static struct snd_soc_ops tegra_bt_sco_ops = {
.hw_params = tegra_bt_sco_hw_params,
.hw_free = tegra_hw_free,
@@ -514,6 +690,12 @@ static int tegra_wm8753_init(struct snd_soc_pcm_runtime *rtd)
tegra_wm8753_hp_jack_pins);
#endif
+ /* Add call mode switch control */
+ ret = snd_ctl_add(codec->card->snd_card,
+ snd_ctl_new1(&tegra_call_mode_control, machine));
+ if (ret < 0)
+ return ret;
+
snd_soc_dapm_nc_pin(dapm, "ACIN");
snd_soc_dapm_nc_pin(dapm, "ACOP");
snd_soc_dapm_nc_pin(dapm, "OUT3");
@@ -555,6 +737,15 @@ static struct snd_soc_dai_link tegra_wm8753_dai[] = {
.ops = &tegra_bt_sco_ops,
},
#endif
+ {
+ .name = "VOICE CALL",
+ .stream_name = "VOICE CALL PCM",
+ .codec_name = "wm8753-codec.4-001a",
+ .platform_name = "tegra-pcm-audio",
+ .cpu_dai_name = "dit-hifi",
+ .codec_dai_name = "wm8753-voice",
+ .ops = &tegra_wm8753_voice_ops,
+ },
};
static struct snd_soc_card snd_soc_tegra_wm8753 = {