diff options
author | Ankit Gupta <ankitgupta@nvidia.com> | 2012-07-11 20:50:01 +0530 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-07-27 15:36:22 -0700 |
commit | 4b70cc537cadc787b748c7c246d703a240b08985 (patch) | |
tree | 4190e7a78fda2f55f0c4c7bbfb2302394c740029 /sound | |
parent | 907bac80691c7df5b5b57cbf27f91e8bb1dcf434 (diff) |
asoc: tegra: integration of slave mode support.
Add master/slave configurability support interface for
all codecs. Currently, complete slave mode functionality
is added only for MAX98088 and WM8903 codec only. By
default, board parameters will set i2s master mode for
all codecs.
asoc: tegra: utils: add support for i2s master/slave mode.
Support for i2s in master or slave mode is made generic by
obtaining information from platform data.
Signed-off-by: Ankit Gupta <ankitgupta@nvidia.com>
Change-Id: Ided0fcefb6cdb124b78aab423bfd8c7dccd4bf6e
Reviewed-on: http://git-master/r/111553
(cherry picked from commit bb1ad7222f9c75424a45976d16de418bc927dc04)
asoc: tegra: wm8903 machine: add support for i2s in slave mode.
Add support for i2s as slave for playback and capture use cases.
Signed-off-by: Ankit Gupta <ankitgupta@nvidia.com>
Change-Id: I1f6b73a0a1b690ecd311b0ff4107aadbb1f037d8
Reviewed-on: http://git-master/r/111472
(cherry picked from commit 0434f8ba74adefe60597d95d30a455b9b2ece9b8)
asoc: tegra: wm8753 machine: add support for i2s in slave mode.
Add support for i2s as slave for playback and capture use cases.
Signed-off-by: Ankit Gupta <ankitgupta@nvidia.com>
Change-Id: Ib0596955cd0c6ac5ec57b0f3c6ecc9e4ed41268c
Reviewed-on: http://git-master/r/113208
(cherry picked from commit 0fc6b5e3a98d9f8866f73d7914b0c590334ce862)
asoc: tegra: aic326x machine: add support for i2s in slave mode.
Support for i2s in slave mode is added for playabck and capture
use cases.
Signed-off-by: Ankit Gupta <ankitgupta@nvidia.com>
Change-Id: I41f6459765f075703ad7f5f8dc9d4628dd853820
Reviewed-on: http://git-master/r/112874
(cherry picked from commit 9a89ede36a1dca6f53250444e819443fb6f28d09)
asoc: tegra: rt5640 machine: add support for i2s in slave mode.
Add support for i2s as slave for playback and capture use cases.
Signed-off-by: Ankit Gupta <ankitgupta@nvidia.com>
Change-Id: I850ec62149b8a8d244445b70658b632dbce06558
Reviewed-on: http://git-master/r/112878
(cherry picked from commit 1d51561c8edf47d8557a825450a48ee8743a185b)
asoc: tegra: max98088 machine: add support for codec i2s as slave.
Add support for codec i2s as slave during voice Call.
(Bug 998682)
Signed-off-by: Ankit Gupta <ankitgupta@nvidia.com>
Change-Id: I8fc54d367e9acd5417d270869cb5a9398b3b527f
Reviewed-on: http://git-master/r/110559
(cherry picked from commit 78a490867e131b1cc892094ddd844c2b892cafb6)
asoc: tegra: max98095 machine: add support for i2s in slave mode.
Add support for i2s as slave for playback and capture use cases.
Signed-off-by: Ankit Gupta <ankitgupta@nvidia.com>
Change-Id: I80944d403be94c55ad2ce31aea921d80ea7c088a
Reviewed-on: http://git-master/r/112875
Reviewed-on: http://git-master/r/118080
Reviewed-by: Scott Peterson <speterson@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Sumit Bhattacharya <sumitb@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/tegra/tegra_aic326x.c | 173 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_asoc_utils.c | 53 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_asoc_utils.h | 11 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_max98088.c | 193 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_max98095.c | 57 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_rt5640.c | 103 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_wm8753.c | 88 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_wm8903.c | 132 |
8 files changed, 570 insertions, 240 deletions
diff --git a/sound/soc/tegra/tegra_aic326x.c b/sound/soc/tegra/tegra_aic326x.c index 4cacb6758eb8..a809d4c74145 100644 --- a/sound/soc/tegra/tegra_aic326x.c +++ b/sound/soc/tegra/tegra_aic326x.c @@ -8,6 +8,7 @@ * * (c) 2010, 2011 Nvidia Graphics Pvt. Ltd. * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * 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. @@ -26,6 +27,7 @@ #include <asm/mach-types.h> +#include <linux/clk.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -274,8 +276,9 @@ static int tegra_aic326x_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); - int srate, mclk, sample_size, daifmt; - int err; + struct tegra_asoc_platform_data *pdata = machine->pdata; + int srate, mclk, sample_size, i2s_daifmt; + int err, rate; #ifndef CONFIG_ARCH_TEGRA_2x_SOC struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); #endif @@ -294,9 +297,30 @@ static int tegra_aic326x_hw_params(struct snd_pcm_substream *substream, if (mclk < 0) return mclk; - daifmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS; + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ? + SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; + + switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, "Can't configure i2s format\n"); + return -EINVAL; + } err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); if (err < 0) { @@ -310,20 +334,21 @@ static int tegra_aic326x_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - err = snd_soc_dai_set_fmt(codec_dai, daifmt); + rate = clk_get_rate(machine->util_data.clk_cdev1); + + 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; } - err = snd_soc_dai_set_fmt(cpu_dai, daifmt); + err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt); if (err < 0) { dev_err(card->dev, "cpu_dai fmt not set\n"); return err; } - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN); if (err < 0) { dev_err(card->dev, "codec_dai clock not set\n"); return err; @@ -390,7 +415,8 @@ static int tegra_aic326x_bt_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); - int err, srate, mclk, min_mclk, sample_size; + struct tegra_asoc_platform_data *pdata = machine->pdata; + int err, srate, mclk, min_mclk, sample_size, i2s_daifmt; #ifndef CONFIG_ARCH_TEGRA_2x_SOC struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(rtd->cpu_dai); #endif @@ -423,10 +449,32 @@ static int tegra_aic326x_bt_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - err = snd_soc_dai_set_fmt(rtd->cpu_dai, - SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= pdata->i2s_param[BT_SCO].is_i2s_master ? + SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; + + switch (pdata->i2s_param[BT_SCO].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, "Can't configure i2s format\n"); + return -EINVAL; + } + + err = snd_soc_dai_set_fmt(rtd->cpu_dai, i2s_daifmt); if (err < 0) { dev_err(rtd->codec->card->dev, "cpu_dai fmt not set\n"); @@ -624,7 +672,8 @@ static int tegra_aic326x_voice_call_hw_params( struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); - int srate, mclk; + struct tegra_asoc_platform_data *pdata = machine->pdata; + int srate, mclk, rate, i2s_daifmt; int err, pcmdiv, vxclkdiv;; srate = params_rate(params); @@ -632,6 +681,36 @@ static int tegra_aic326x_voice_call_hw_params( if (mclk < 0) return mclk; + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ? + SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; + + if (machine_is_tegra_enterprise()) { + switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, + "Can't configure i2s format\n"); + return -EINVAL; + } + } else { + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + } + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); if (err < 0) { if (!(machine->util_data.set_mclk % mclk)) @@ -644,25 +723,15 @@ static int tegra_aic326x_voice_call_hw_params( tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - if(machine_is_tegra_enterprise()) { - err = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); - } else { - err = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); - } + rate = clk_get_rate(machine->util_data.clk_cdev1); + 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; } - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN); if (err < 0) { dev_err(card->dev, "codec_dai clock not set\n"); return err; @@ -691,14 +760,6 @@ static int tegra_aic326x_voice_call_hw_params( /* codec configuration */ machine->codec_info[HIFI_CODEC].rate = params_rate(params); machine->codec_info[HIFI_CODEC].channels = params_channels(params); - machine->codec_info[HIFI_CODEC].bitsize = 16; - machine->codec_info[HIFI_CODEC].is_i2smaster = 1; - machine->codec_info[HIFI_CODEC].is_format_dsp = 0; - - /* baseband configuration */ - machine->codec_info[BASEBAND].bitsize = 16; - machine->codec_info[BASEBAND].is_i2smaster = 1; - machine->codec_info[BASEBAND].is_format_dsp = 1; #endif machine->is_device_bt = 0; @@ -754,14 +815,6 @@ static int tegra_aic326x_bt_voice_call_hw_params( /* codec configuration */ machine->codec_info[BT_SCO].rate = params_rate(params); machine->codec_info[BT_SCO].channels = params_channels(params); - machine->codec_info[BT_SCO].bitsize = 16; - machine->codec_info[BT_SCO].is_i2smaster = 1; - machine->codec_info[BT_SCO].is_format_dsp = 1; - - /* baseband configuration */ - machine->codec_info[BASEBAND].bitsize = 16; - machine->codec_info[BASEBAND].is_i2smaster = 1; - machine->codec_info[BASEBAND].is_format_dsp = 1; #endif machine->is_device_bt = 1; @@ -1183,11 +1236,23 @@ static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev) #endif #ifndef CONFIG_ARCH_TEGRA_2x_SOC - for (i = 0; i < NUM_I2S_DEVICES ; i++) - machine->codec_info[i].i2s_id = pdata->audio_port_id[i]; - - machine->codec_info[BASEBAND].rate = pdata->baseband_param.rate; - machine->codec_info[BASEBAND].channels = pdata->baseband_param.channels; + for (i = 0; i < NUM_I2S_DEVICES ; i++) { + machine->codec_info[i].i2s_id = + pdata->i2s_param[i].audio_port_id; + machine->codec_info[i].bitsize = + pdata->i2s_param[i].sample_size; + machine->codec_info[i].is_i2smaster = + pdata->i2s_param[i].is_i2s_master; + machine->codec_info[i].rate = + pdata->i2s_param[i].rate; + machine->codec_info[i].channels = + pdata->i2s_param[i].channels; + if ((pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_A) || + (pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_B)) + machine->codec_info[i].is_format_dsp = 1; + else + machine->codec_info[i].is_format_dsp = 0; + } tegra_aic326x_dai[DAI_LINK_HIFI].cpu_dai_name = tegra_i2s_dai_name[machine->codec_info[HIFI_CODEC].i2s_id]; @@ -1214,6 +1279,16 @@ static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev) goto err_unregister_card; } +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + ret = tegra_asoc_utils_set_parent(&machine->util_data, + pdata->i2s_param[HIFI_CODEC].is_i2s_master); + if (ret) { + dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n", + ret); + goto err_unregister_card; + } +#endif + return 0; err_unregister_card: diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c index 6ab5b2d46a1f..2c18a71b8b52 100644 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ b/sound/soc/tegra/tegra_asoc_utils.c @@ -2,8 +2,7 @@ * tegra_asoc_utils.c - Harmony machine ASoC driver * * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (C) 2010 - NVIDIA, Inc. - * + * Copyright (c) 2010-12, NVIDIA CORPORATION. All rights reserved. * 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. @@ -342,28 +341,6 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, } #endif -#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) -#if TEGRA30_I2S_MASTER_PLAYBACK - ret = clk_set_parent(data->clk_cdev1, data->clk_pll_a_out0); - if (ret) { - dev_err(data->dev, "Can't set clk cdev1/extern1 parent"); - goto err_put_out1; - } -#else - rate = clk_get_rate(data->clk_m); - - if(rate == 26000000) - clk_set_rate(data->clk_cdev1, 13000000); - - ret = clk_set_parent(data->clk_cdev1, data->clk_m); - if (ret) { - dev_err(data->dev, "Can't set clk cdev1/extern1 parent"); - goto err_put_out1; - } -#endif - -#endif - ret = clk_enable(data->clk_cdev1); if (ret) { dev_err(data->dev, "Can't enable clk cdev1/extern1"); @@ -402,6 +379,34 @@ err: } EXPORT_SYMBOL_GPL(tegra_asoc_utils_init); +#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) +int tegra_asoc_utils_set_parent (struct tegra_asoc_utils_data *data, + int is_i2s_master) +{ + int ret = -ENODEV; + + if (is_i2s_master) { + ret = clk_set_parent(data->clk_cdev1, data->clk_pll_a_out0); + if (ret) { + dev_err(data->dev, "Can't set clk cdev1/extern1 parent"); + return ret; + } + } else { + if(clk_get_rate(data->clk_m) == 26000000) + clk_set_rate(data->clk_cdev1, 13000000); + + ret = clk_set_parent(data->clk_cdev1, data->clk_m); + if (ret) { + dev_err(data->dev, "Can't set clk cdev1/extern1 parent"); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_parent); +#endif + void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data) { if (!IS_ERR(data->clk_out1)) diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h index 0423f02b76cc..ce379e3e513d 100644 --- a/sound/soc/tegra/tegra_asoc_utils.h +++ b/sound/soc/tegra/tegra_asoc_utils.h @@ -2,7 +2,7 @@ * tegra_asoc_utils.h - Definitions for Tegra DAS driver * * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (C) 2010 - NVIDIA, Inc. + * Copyright (c) 2010-12, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -24,7 +24,6 @@ #define __TEGRA_ASOC_UTILS_H_ -#define TEGRA30_I2S_MASTER_PLAYBACK 1 #define TEGRA_ALSA_MAX_DEVICES 6 #define TEGRA_DMA_MAX_CHANNELS 32 @@ -47,11 +46,13 @@ struct tegra_asoc_utils_data { }; int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, - int mclk); + int mclk); void tegra_asoc_utils_lock_clk_rate(struct tegra_asoc_utils_data *data, - int lock); + int lock); int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, - struct device *dev, struct snd_soc_card *card); + struct device *dev, struct snd_soc_card *card); +int tegra_asoc_utils_set_parent(struct tegra_asoc_utils_data *data, + int is_i2s_master); void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data); int tegra_asoc_utils_clk_enable(struct tegra_asoc_utils_data *data); int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data); diff --git a/sound/soc/tegra/tegra_max98088.c b/sound/soc/tegra/tegra_max98088.c index 82c2b930a39e..88098fcd99d9 100644 --- a/sound/soc/tegra/tegra_max98088.c +++ b/sound/soc/tegra/tegra_max98088.c @@ -12,6 +12,7 @@ * Author: Graeme Gregory * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * 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. @@ -213,14 +214,16 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); + struct tegra_asoc_platform_data *pdata = machine->pdata; #ifndef CONFIG_ARCH_TEGRA_2x_SOC struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); #endif - int srate, mclk, sample_size, i2s_daifmt; + int srate, mclk, sample_size, i2s_daifmt, i2s_master; int err; - struct clk *clk; int rate; + i2s_master = pdata->i2s_param[HIFI_CODEC].is_i2s_master; + switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: sample_size = 16; @@ -251,32 +254,31 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream, break; } + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= i2s_master ? SND_SOC_DAIFMT_CBS_CFS : + SND_SOC_DAIFMT_CBM_CFM; -#if defined(CONFIG_ARCH_TEGRA_2x_SOC) - clk = clk_get_sys(NULL, "cdev1"); -#else - clk = clk_get_sys("extern1", NULL); -#endif - if (IS_ERR(clk)) { - dev_err(card->dev, "Can't retrieve clk cdev1\n"); - err = PTR_ERR(clk); - return err; + switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, "Can't configure i2s format\n"); + return -EINVAL; } - rate = clk_get_rate(clk); - printk("extern1 rate=%d\n",rate); - -#if TEGRA30_I2S_MASTER_PLAYBACK - i2s_daifmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS; -#else - i2s_daifmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; - mclk = rate; -#endif - err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); if (err < 0) { if (!(machine->util_data.set_mclk % mclk)) @@ -289,7 +291,9 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - err = snd_soc_dai_set_fmt(codec_dai,i2s_daifmt); + rate = clk_get_rate(machine->util_data.clk_cdev1); + + 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; @@ -301,8 +305,17 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream, return err; } - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN); + + /* ULP specific use case for 44.1kHz stream. */ + if ((!i2s_master) && (srate == 44100) && + machine_is_tegra_enterprise()) { + clk_set_rate(machine->util_data.clk_cdev1, (256 * srate)); + rate = clk_get_rate(machine->util_data.clk_cdev1); + err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, + SND_SOC_CLOCK_IN); + } + if (err < 0) { dev_err(card->dev, "codec_dai clock not set\n"); return err; @@ -371,7 +384,9 @@ static int tegra_bt_hw_params(struct snd_pcm_substream *substream, #endif struct snd_soc_card *card = rtd->card; struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); + struct tegra_asoc_platform_data *pdata = machine->pdata; int err, srate, mclk, min_mclk, sample_size; + int i2s_daifmt; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -414,10 +429,32 @@ static int tegra_bt_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - err = snd_soc_dai_set_fmt(rtd->cpu_dai, - SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= pdata->i2s_param[BT_SCO].is_i2s_master ? + SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; + + switch (pdata->i2s_param[BT_SCO].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, "Can't configure i2s format\n"); + return -EINVAL; + } + + err = snd_soc_dai_set_fmt(rtd->cpu_dai, i2s_daifmt); if (err < 0) { dev_err(rtd->codec->card->dev, "cpu_dai fmt not set\n"); return err; @@ -598,8 +635,9 @@ static int tegra_voice_call_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); - int srate, mclk; - int err; + struct tegra_asoc_platform_data *pdata = machine->pdata; + int srate, mclk, i2s_daifmt; + int err, rate; srate = params_rate(params); switch (srate) { @@ -623,6 +661,31 @@ static int tegra_voice_call_hw_params(struct snd_pcm_substream *substream, break; } + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ? + SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; + + switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, "Can't configure i2s format\n"); + return -EINVAL; + } + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); if (err < 0) { if (!(machine->util_data.set_mclk % mclk)) @@ -635,17 +698,15 @@ static int tegra_voice_call_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - err = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + rate = clk_get_rate(machine->util_data.clk_cdev1); + + 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; } - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN); if (err < 0) { dev_err(card->dev, "codec_dai clock not set\n"); return err; @@ -655,14 +716,6 @@ static int tegra_voice_call_hw_params(struct snd_pcm_substream *substream, /* codec configuration */ machine->codec_info[HIFI_CODEC].rate = params_rate(params); machine->codec_info[HIFI_CODEC].channels = params_channels(params); - machine->codec_info[HIFI_CODEC].bitsize = 16; - machine->codec_info[HIFI_CODEC].is_i2smaster = 1; - machine->codec_info[HIFI_CODEC].is_format_dsp = 0; - - /* baseband configuration */ - machine->codec_info[BASEBAND].bitsize = 16; - machine->codec_info[BASEBAND].is_i2smaster = 1; - machine->codec_info[BASEBAND].is_format_dsp = 1; #endif machine->is_device_bt = 0; @@ -729,14 +782,6 @@ static int tegra_bt_voice_call_hw_params(struct snd_pcm_substream *substream, /* codec configuration */ machine->codec_info[BT_SCO].rate = params_rate(params); machine->codec_info[BT_SCO].channels = params_channels(params); - machine->codec_info[BT_SCO].bitsize = 16; - machine->codec_info[BT_SCO].is_i2smaster = 1; - machine->codec_info[BT_SCO].is_format_dsp = 1; - - /* baseband configuration */ - machine->codec_info[BASEBAND].bitsize = 16; - machine->codec_info[BASEBAND].is_i2smaster = 1; - machine->codec_info[BASEBAND].is_format_dsp = 1; #endif machine->is_device_bt = 1; @@ -1148,16 +1193,22 @@ static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev) #endif #ifndef CONFIG_ARCH_TEGRA_2x_SOC - for (i = 0; i < NUM_I2S_DEVICES ; i++) - machine->codec_info[i].i2s_id = pdata->audio_port_id[i]; - - machine->codec_info[BASEBAND].rate = pdata->baseband_param.rate; - machine->codec_info[BASEBAND].channels = pdata->baseband_param.channels; - machine->codec_info[BASEBAND].is_format_dsp = 0; - - if ((pdata->baseband_param.bit_format == TEGRA_DAIFMT_DSP_A) || - (pdata->baseband_param.bit_format == TEGRA_DAIFMT_DSP_B)) { - machine->codec_info[BASEBAND].is_format_dsp = 1; + for (i = 0; i < NUM_I2S_DEVICES ; i++) { + machine->codec_info[i].i2s_id = + pdata->i2s_param[i].audio_port_id; + machine->codec_info[i].bitsize = + pdata->i2s_param[i].sample_size; + machine->codec_info[i].is_i2smaster = + pdata->i2s_param[i].is_i2s_master; + machine->codec_info[i].rate = + pdata->i2s_param[i].rate; + machine->codec_info[i].channels = + pdata->i2s_param[i].channels; + if ((pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_A) || + (pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_B)) + machine->codec_info[i].is_format_dsp = 1; + else + machine->codec_info[i].is_format_dsp = 0; } tegra_max98088_dai[DAI_LINK_HIFI].cpu_dai_name = @@ -1180,6 +1231,16 @@ static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev) goto err_unregister_card; } +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + ret = tegra_asoc_utils_set_parent(&machine->util_data, + pdata->i2s_param[HIFI_CODEC].is_i2s_master); + if (ret) { + dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n", + ret); + goto err_unregister_card; + } +#endif + return 0; err_unregister_card: diff --git a/sound/soc/tegra/tegra_max98095.c b/sound/soc/tegra/tegra_max98095.c index d065b78164ac..f77c327b4b00 100644 --- a/sound/soc/tegra/tegra_max98095.c +++ b/sound/soc/tegra/tegra_max98095.c @@ -8,7 +8,7 @@ * * Based on code copyright/by: * - * (c) 2010, 2011, 2012 Nvidia Graphics Pvt. Ltd. + * Copyright (c) 2010-12, NVIDIA CORPORATION. All rights reserved. * * Copyright 2007 Wolfson Microelectronics PLC. * Author: Graeme Gregory @@ -32,6 +32,7 @@ #include <asm/mach-types.h> +#include <linux/clk.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -118,11 +119,12 @@ static int tegra_max98095_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); + struct tegra_asoc_platform_data *pdata = machine->pdata; #ifndef CONFIG_ARCH_TEGRA_2x_SOC struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); #endif - unsigned int srate, mclk, sample_size; - int err; + unsigned int srate, mclk, sample_size, i2s_daifmt; + int err, rate; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -154,6 +156,31 @@ static int tegra_max98095_hw_params(struct snd_pcm_substream *substream, break; } + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master; ? + SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; + + switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, "Can't configure i2s format\n"); + return -EINVAL; + } + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); if (err < 0) { if (!(machine->util_data.set_mclk % mclk)) @@ -166,26 +193,20 @@ static int tegra_max98095_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - err = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + rate = clk_get_rate(machine->util_data.clk_cdev1); + 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; } - err = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt); if (err < 0) { dev_err(card->dev, "cpu_dai fmt not set\n"); return err; } - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN); if (err < 0) { dev_err(card->dev, "codec_dai clock not set\n"); return err; @@ -667,6 +688,16 @@ static __devinit int tegra_max98095_driver_probe(struct platform_device *pdev) goto err_unregister_card; } +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + ret = tegra_asoc_utils_set_parent(&machine->util_data, + pdata->i2s_param[HIFI_CODEC].is_i2s_master); + if (ret) { + dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n", + ret); + goto err_switch_unregister; + } +#endif + return 0; err_unregister_card: diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index 765eb59fabae..a99711fb9234 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -10,6 +10,7 @@ * Author: Graeme Gregory * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * 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. @@ -28,6 +29,7 @@ #include <asm/mach-types.h> +#include <linux/clk.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -37,7 +39,7 @@ #include <linux/switch.h> #endif -#include <mach/tegra_rt5640_pdata.h> +#include <mach/tegra_asoc_pdata.h> #include <sound/core.h> #include <sound/jack.h> @@ -61,7 +63,7 @@ struct tegra_rt5640 { struct tegra_asoc_utils_data util_data; - struct tegra_rt5640_platform_data *pdata; + struct tegra_asoc_platform_data *pdata; struct regulator *spk_reg; struct regulator *dmic_reg; struct regulator *cdc_en; @@ -82,11 +84,38 @@ static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); + struct tegra_asoc_platform_data *pdata = machine->pdata; int srate, mclk, i2s_daifmt; - int err; + int err, rate; srate = params_rate(params); mclk = 256 * srate; + + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ? + SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; + + switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, "Can't configure i2s format\n"); + return -EINVAL; + } + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); if (err < 0) { if (!(machine->util_data.set_mclk % mclk)) { @@ -99,10 +128,7 @@ static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - i2s_daifmt = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS; - - i2s_daifmt |= SND_SOC_DAIFMT_I2S; + rate = clk_get_rate(machine->util_data.clk_cdev1); err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt); if (err < 0) { @@ -116,8 +142,7 @@ static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream, return err; } - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN); if (err < 0) { dev_err(card->dev, "codec_dai clock not set\n"); return err; @@ -130,10 +155,10 @@ static int tegra_bt_sco_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->cpu_dai; struct snd_soc_card *card = rtd->card; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); - int srate, mclk, min_mclk; + struct tegra_asoc_platform_data *pdata = machine->pdata; + int srate, mclk, min_mclk, i2s_daifmt; int err; srate = params_rate(params); @@ -169,10 +194,32 @@ static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - err = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= pdata->i2s_param[BT_SCO].is_i2s_master ? + SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; + + switch (pdata->i2s_param[BT_SCO].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, "Can't configure i2s format\n"); + return -EINVAL; + } + + err = snd_soc_dai_set_fmt(rtd->cpu_dai, i2s_daifmt); if (err < 0) { dev_err(card->dev, "cpu_dai fmt not set\n"); return err; @@ -279,7 +326,7 @@ static int tegra_rt5640_jack_notifier(struct notifier_block *self, struct snd_soc_codec *codec = jack->codec; struct snd_soc_card *card = codec->card; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); - struct tegra_rt5640_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; enum headset_state state = BIT_NO_HEADSET; unsigned char status_jack = 0; @@ -357,7 +404,7 @@ static int tegra_rt5640_event_int_spk(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); - struct tegra_rt5640_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; if (machine->spk_reg) { if (SND_SOC_DAPM_EVENT_ON(event)) @@ -381,7 +428,7 @@ static int tegra_rt5640_event_hp(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); - struct tegra_rt5640_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; if (!(machine->gpio_requested & GPIO_HP_MUTE)) return 0; @@ -398,7 +445,7 @@ static int tegra_rt5640_event_int_mic(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); - struct tegra_rt5640_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; if (machine->dmic_reg) { if (SND_SOC_DAPM_EVENT_ON(event)) @@ -422,7 +469,7 @@ static int tegra_rt5640_event_ext_mic(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); - struct tegra_rt5640_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; if (!(machine->gpio_requested & GPIO_EXT_MIC_EN)) return 0; @@ -467,7 +514,7 @@ static int tegra_rt5640_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_card *card = codec->card; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); - struct tegra_rt5640_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; int ret; if (gpio_is_valid(pdata->gpio_spkr_en)) { @@ -650,7 +697,7 @@ static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_tegra_rt5640; struct tegra_rt5640 *machine; - struct tegra_rt5640_platform_data *pdata; + struct tegra_asoc_platform_data *pdata; int ret; pdata = pdev->dev.platform_data; @@ -716,6 +763,16 @@ static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev) goto err_unregister_card; } +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + ret = tegra_asoc_utils_set_parent(&machine->util_data, + pdata->i2s_param[HIFI_CODEC].is_i2s_master); + if (ret) { + dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n", + ret); + goto err_unregister_card; + } +#endif + return 0; err_unregister_card: @@ -735,7 +792,7 @@ static int __devexit tegra_rt5640_driver_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); - struct tegra_rt5640_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; if (machine->gpio_requested & GPIO_HP_DET) snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index f7c7a4c6b5a1..f1b9335ab473 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -12,6 +12,7 @@ * Author: Graeme Gregory * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * 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. @@ -30,6 +31,7 @@ #include <asm/mach-types.h> +#include <linux/clk.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -83,8 +85,10 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); + struct tegra_asoc_platform_data *pdata = machine->pdata; int srate, mclk, i2s_daifmt; - int err; + int err, rate; + srate = params_rate(params); switch (srate) { case 8000: @@ -119,14 +123,38 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - i2s_daifmt = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS; + rate = clk_get_rate(machine->util_data.clk_cdev1); + + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ? + SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; /* Use DSP mode for mono on Tegra20 */ - if ((params_channels(params) != 2) && machine_is_whistler()) + if ((params_channels(params) != 2) && machine_is_whistler()) { i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; - else - i2s_daifmt |= SND_SOC_DAIFMT_I2S; + } else { + switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, + "Can't configure i2s format\n"); + return -EINVAL; + } + } err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt); if (err < 0) { @@ -140,8 +168,7 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream, return err; } - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN); if (err < 0) { dev_err(card->dev, "codec_dai clock not set\n"); return err; @@ -173,7 +200,8 @@ static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream, 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, min_mclk; + struct tegra_asoc_platform_data *pdata = machine->pdata; + int srate, mclk, min_mclk, i2s_daifmt; int err; srate = params_rate(params); @@ -209,10 +237,32 @@ static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - err = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= pdata->i2s_param[BT_SCO].is_i2s_master ? + SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; + + switch (pdata->i2s_param[BT_SCO].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, "Can't configure i2s format\n"); + return -EINVAL; + } + + err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt); if (err < 0) { dev_err(card->dev, "cpu_dai fmt not set\n"); return err; @@ -873,8 +923,6 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev) return -ENOMEM; } - machine->pdata = pdata; - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); if (ret) goto err_free_machine; @@ -904,6 +952,16 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev) } #endif +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + ret = tegra_asoc_utils_set_parent(&machine->util_data, + pdata->i2s_param[HIFI_CODEC].is_i2s_master); + if (ret) { + dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n", + ret); + goto err_unregister_card; + } +#endif + return 0; err_unregister_card: diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 063aefe50507..dcd031209172 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -12,6 +12,8 @@ * Author: Graeme Gregory * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * * 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. @@ -40,7 +42,7 @@ #include <linux/switch.h> #endif -#include <mach/tegra_wm8903_pdata.h> +#include <mach/tegra_asoc_pdata.h> #include <sound/core.h> #include <sound/jack.h> @@ -67,7 +69,7 @@ struct tegra_wm8903 { struct tegra_asoc_utils_data util_data; - struct tegra_wm8903_platform_data *pdata; + struct tegra_asoc_platform_data *pdata; struct regulator *spk_reg; struct regulator *dmic_reg; int gpio_requested; @@ -86,9 +88,9 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); + struct tegra_asoc_platform_data *pdata = machine->pdata; int srate, mclk, i2s_daifmt; int err; - struct clk *clk_m; int rate; srate = params_rate(params); @@ -103,31 +105,17 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, break; } + if(pdata->i2s_param[HIFI_CODEC].is_i2s_master) { + /* FIXME: Codec only requires >= 3MHz if OSR==0 */ + while (mclk < 6000000) + mclk *= 2; - - clk_m = clk_get_sys(NULL, "clk_m"); - if (IS_ERR(clk_m)) { - dev_err(card->dev, "Can't retrieve clk clk_m\n"); - err = PTR_ERR(clk_m); - return err; + i2s_daifmt = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; + } else { + i2s_daifmt = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; } - rate = clk_get_rate(clk_m); - printk("extern1 rate=%d\n",rate); - -#if TEGRA30_I2S_MASTER_PLAYBACK - /* FIXME: Codec only requires >= 3MHz if OSR==0 */ - while (mclk < 6000000) - mclk *= 2; - - i2s_daifmt = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS; -#else - mclk = rate; - - i2s_daifmt = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; -#endif - err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); if (err < 0) { @@ -141,13 +129,36 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); + rate = clk_get_rate(machine->util_data.clk_cdev1); + /* Use DSP mode for mono on Tegra20 */ if ((params_channels(params) != 2) && - (machine_is_ventana() || machine_is_harmony() || - machine_is_kaen() || machine_is_aebl())) + (machine_is_ventana() || machine_is_harmony() || + machine_is_kaen() || machine_is_aebl())) { i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; - else - i2s_daifmt |= SND_SOC_DAIFMT_I2S; + } else { + switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, + "Can't configure i2s format\n"); + return -EINVAL; + } + } err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt); if (err < 0) { @@ -161,8 +172,7 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, return err; } - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN); if (err < 0) { dev_err(card->dev, "codec_dai clock not set\n"); return err; @@ -190,10 +200,10 @@ static int tegra_bt_sco_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->cpu_dai; struct snd_soc_card *card = rtd->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - int srate, mclk, min_mclk; + struct tegra_asoc_platform_data *pdata = machine->pdata; + int srate, mclk, min_mclk, i2s_daifmt; int err; srate = params_rate(params); @@ -229,10 +239,32 @@ static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream, tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); - err = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + i2s_daifmt = SND_SOC_DAIFMT_NB_NF; + i2s_daifmt |= pdata->i2s_param[BT_SCO].is_i2s_master ? + SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; + + switch (pdata->i2s_param[BT_SCO].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, "Can't configure i2s format\n"); + return -EINVAL; + } + + err = snd_soc_dai_set_fmt(rtd->cpu_dai, i2s_daifmt); if (err < 0) { dev_err(card->dev, "cpu_dai fmt not set\n"); return err; @@ -408,7 +440,7 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; if (machine->spk_reg) { if (SND_SOC_DAPM_EVENT_ON(event)) @@ -432,7 +464,7 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; if (!(machine->gpio_requested & GPIO_HP_MUTE)) return 0; @@ -449,7 +481,7 @@ static int tegra_wm8903_event_int_mic(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; if (machine->dmic_reg) { if (SND_SOC_DAPM_EVENT_ON(event)) @@ -473,7 +505,7 @@ static int tegra_wm8903_event_ext_mic(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; if (!(machine->gpio_requested & GPIO_EXT_MIC_EN)) return 0; @@ -578,7 +610,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_card *card = codec->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; int ret; machine->bias_level = SND_SOC_BIAS_STANDBY; @@ -792,7 +824,7 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_tegra_wm8903; struct tegra_wm8903 *machine; - struct tegra_wm8903_platform_data *pdata; + struct tegra_asoc_platform_data *pdata; int ret; pdata = pdev->dev.platform_data; @@ -895,6 +927,16 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) goto err_unregister_card; } +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + ret = tegra_asoc_utils_set_parent(&machine->util_data, + pdata->i2s_param[HIFI_CODEC].is_i2s_master); + if (ret) { + dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n", + ret); + goto err_unregister_card; + } +#endif + return 0; err_unregister_card: @@ -914,7 +956,7 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_asoc_platform_data *pdata = machine->pdata; if (machine->gpio_requested & GPIO_HP_DET) snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, |