summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorScottPeterson <speterson@nvidia.com>2012-01-17 17:32:11 -0800
committerVarun Colbert <vcolbert@nvidia.com>2012-01-30 13:28:18 -0800
commit2e3c724c167ec5da8b1ed5ab07cda55232ecdf13 (patch)
treed82c4c6da45dd46de1aa0c75393869470fe033e3 /sound
parent6814bf677b18c10cee192e813d3d468b01229a25 (diff)
asoc:tegra: Support I2S slave mode
Support I2S slave mode. Disable pll_p_out1 and pll_a to reduce power when in slave mode. Slave mode disabled by default. Reviewed-on: http://git-master/r/76046 Change-Id: I873a11d54f1e037d99c86ff4cec06ee83064902a Signed-off-by: ScottPeterson <speterson@nvidia.com> Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-on: http://git-master/r/77765 Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/tegra/tegra30_ahub.c6
-rw-r--r--sound/soc/tegra/tegra30_dam.c6
-rw-r--r--sound/soc/tegra/tegra30_i2s.c8
-rw-r--r--sound/soc/tegra/tegra_aic326x.c29
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c107
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h5
-rw-r--r--sound/soc/tegra/tegra_max98088.c41
-rw-r--r--sound/soc/tegra/tegra_wm8903.c60
8 files changed, 192 insertions, 70 deletions
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index 3fceda143da8..710d9465b4b0 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -487,6 +487,7 @@ static int __devinit tegra30_ahub_probe(struct platform_device *pdev)
#ifdef CONFIG_PM
int i = 0, cache_idx_rsvd;
#endif
+ int clkm_rate;
if (ahub)
return -ENODEV;
@@ -505,6 +506,11 @@ static int __devinit tegra30_ahub_probe(struct platform_device *pdev)
ret = PTR_ERR(ahub->clk_d_audio);
goto err_free;
}
+ clkm_rate = clk_get_rate(clk_get_parent(ahub->clk_d_audio));
+ while (clkm_rate > 12000000)
+ clkm_rate >>= 1;
+
+ clk_set_rate(ahub->clk_d_audio,clkm_rate);
ahub->clk_apbif = clk_get(&pdev->dev, "apbif");
if (IS_ERR(ahub->clk_apbif)) {
diff --git a/sound/soc/tegra/tegra30_dam.c b/sound/soc/tegra/tegra30_dam.c
index 4ac81266e7cf..d308179110c9 100644
--- a/sound/soc/tegra/tegra30_dam.c
+++ b/sound/soc/tegra/tegra30_dam.c
@@ -529,6 +529,7 @@ static int __devinit tegra30_dam_probe(struct platform_device *pdev)
#ifdef CONFIG_PM
int i;
#endif
+ int clkm_rate;
if ((pdev->id < 0) ||
(pdev->id >= TEGRA30_NR_DAM_IFC)) {
@@ -552,6 +553,11 @@ static int __devinit tegra30_dam_probe(struct platform_device *pdev)
ret = PTR_ERR(dam->dam_clk);
goto err_free;
}
+ clkm_rate = clk_get_rate(clk_get_parent(dam->dam_clk));
+ while (clkm_rate > 12000000)
+ clkm_rate >>= 1;
+
+ clk_set_rate(dam->dam_clk,clkm_rate);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index c1de635765a5..9a0ed5a762ed 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -303,13 +303,11 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
srate = params_rate(params);
if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) {
- /* Final "* 2" required by Tegra hardware */
- i2sclock = srate * params_channels(params) * sample_size * 2;
+ i2sclock = srate * params_channels(params) * sample_size;
- /* Additional "* 2" is needed for FSYNC mode */
+ /* Additional "* 4" is needed for FSYNC mode */
if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC)
- i2sclock *= 2;
-
+ i2sclock *= 4;
ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0);
if (ret) {
dev_err(dev, "Can't set parent of I2S clock\n");
diff --git a/sound/soc/tegra/tegra_aic326x.c b/sound/soc/tegra/tegra_aic326x.c
index a7297a54233a..31afb907a653 100644
--- a/sound/soc/tegra/tegra_aic326x.c
+++ b/sound/soc/tegra/tegra_aic326x.c
@@ -237,6 +237,32 @@ static int tegra_aic326x_hw_params(struct snd_pcm_substream *substream,
if (mclk < 0)
return mclk;
+
+#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;
+ }
+
+ rate = clk_get_rate(clk);
+ printk("extern1 rate=%d\n",rate);
+
+#if TEGRA30_I2S_MASTER_PLAYBACK
+ daifmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS;
+#else
+ 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))
@@ -249,9 +275,6 @@ static int tegra_aic326x_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
-
err = snd_soc_dai_set_fmt(codec_dai, daifmt);
if (err < 0) {
dev_err(card->dev, "codec_dai fmt not set\n");
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index c517bd04e2da..1f336d82bfe3 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -25,6 +25,8 @@
#include <linux/err.h>
#include <linux/kernel.h>
+#include <mach/clk.h>
+
#include "tegra_asoc_utils.h"
int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
@@ -33,6 +35,7 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
int new_baseclock;
bool clk_change;
int err;
+ bool reenable_clock;
switch (srate) {
case 11025:
@@ -73,41 +76,32 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
data->set_baseclock = 0;
data->set_mclk = 0;
- clk_disable(data->clk_cdev1);
- clk_disable(data->clk_pll_a_out0);
- clk_disable(data->clk_pll_a);
-
+ reenable_clock = false;
+ if(tegra_is_clk_enabled(data->clk_pll_a)) {
+ clk_disable(data->clk_pll_a);
+ reenable_clock = true;
+ }
err = clk_set_rate(data->clk_pll_a, new_baseclock);
if (err) {
dev_err(data->dev, "Can't set pll_a rate: %d\n", err);
return err;
}
+ if(reenable_clock)
+ clk_enable(data->clk_pll_a);
- err = clk_set_rate(data->clk_pll_a_out0, mclk);
- if (err) {
- dev_err(data->dev, "Can't set pll_a_out0 rate: %d\n", err);
- return err;
+ reenable_clock = false;
+ if(tegra_is_clk_enabled(data->clk_pll_a_out0)) {
+ clk_disable(data->clk_pll_a_out0);
+ reenable_clock = true;
}
-
- /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
-
- err = clk_enable(data->clk_pll_a);
- if (err) {
- dev_err(data->dev, "Can't enable pll_a: %d\n", err);
- return err;
- }
-
- err = clk_enable(data->clk_pll_a_out0);
+ err = clk_set_rate(data->clk_pll_a_out0, mclk);
if (err) {
- dev_err(data->dev, "Can't enable pll_a_out0: %d\n", err);
+ dev_err(data->dev, "Can't set clk_pll_a_out0 rate: %d\n", err);
return err;
}
+ if(reenable_clock)
+ clk_enable(data->clk_pll_a_out0);
- err = clk_enable(data->clk_cdev1);
- if (err) {
- dev_err(data->dev, "Can't enable cdev1: %d\n", err);
- return err;
- }
data->set_baseclock = new_baseclock;
data->set_mclk = mclk;
@@ -130,18 +124,6 @@ int tegra_asoc_utils_clk_enable(struct tegra_asoc_utils_data *data)
{
int err;
- err = clk_enable(data->clk_pll_a);
- if (err) {
- dev_err(data->dev, "Can't enable pll_a: %d\n", err);
- return err;
- }
-
- err = clk_enable(data->clk_pll_a_out0);
- if (err) {
- dev_err(data->dev, "Can't enable pll_a_out0: %d\n", err);
- return err;
- }
-
err = clk_enable(data->clk_cdev1);
if (err) {
dev_err(data->dev, "Can't enable cdev1: %d\n", err);
@@ -155,8 +137,6 @@ EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_enable);
int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data)
{
clk_disable(data->clk_cdev1);
- clk_disable(data->clk_pll_a_out0);
- clk_disable(data->clk_pll_a);
return 0;
}
EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_disable);
@@ -165,14 +145,22 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
struct device *dev)
{
int ret;
+ int rate;
data->dev = dev;
+ data->clk_pll_p_out1 = clk_get_sys(NULL, "pll_p_out1");
+ if (IS_ERR(data->clk_pll_p_out1)) {
+ dev_err(data->dev, "Can't retrieve clk pll_p_out1\n");
+ ret = PTR_ERR(data->clk_pll_p_out1);
+ goto err;
+ }
+
data->clk_pll_a = clk_get_sys(NULL, "pll_a");
if (IS_ERR(data->clk_pll_a)) {
dev_err(data->dev, "Can't retrieve clk pll_a\n");
ret = PTR_ERR(data->clk_pll_a);
- goto err;
+ goto err_put_pll_p_out1;
}
data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
@@ -182,6 +170,13 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
goto err_put_pll_a;
}
+ data->clk_m = clk_get_sys(NULL, "clk_m");
+ if (IS_ERR(data->clk_m)) {
+ dev_err(data->dev, "Can't retrieve clk clk_m\n");
+ ret = PTR_ERR(data->clk_m);
+ goto err;
+ }
+
#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
#else
@@ -204,26 +199,28 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
}
#endif
- ret = clk_enable(data->clk_pll_a);
+#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 enable clk pll_a");
+ dev_err(data->dev, "Can't set clk cdev1/extern1 parent");
goto err_put_out1;
}
+#else
+ rate = clk_get_rate(data->clk_m);
- ret = clk_enable(data->clk_pll_a_out0);
- if (ret) {
- dev_err(data->dev, "Can't enable clk pll_a_out0");
- goto err_put_out1;
- }
+ if(rate == 26000000)
+ clk_set_rate(data->clk_cdev1, 13000000);
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
- ret = clk_set_parent(data->clk_cdev1, data->clk_pll_a_out0);
+ 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");
@@ -255,6 +252,8 @@ err_put_pll_a_out0:
clk_put(data->clk_pll_a_out0);
err_put_pll_a:
clk_put(data->clk_pll_a);
+err_put_pll_p_out1:
+ clk_put(data->clk_pll_p_out1);
err:
return ret;
}
@@ -264,9 +263,17 @@ void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data)
{
if (!IS_ERR(data->clk_out1))
clk_put(data->clk_out1);
+
clk_put(data->clk_cdev1);
- clk_put(data->clk_pll_a_out0);
- clk_put(data->clk_pll_a);
+
+ if (!IS_ERR(data->clk_pll_a_out0))
+ clk_put(data->clk_pll_a_out0);
+
+ if (!IS_ERR(data->clk_pll_a))
+ clk_put(data->clk_pll_a);
+
+ if (!IS_ERR(data->clk_pll_p_out1))
+ clk_put(data->clk_pll_p_out1);
}
EXPORT_SYMBOL_GPL(tegra_asoc_utils_fini);
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
index 72d3994a935f..1c4e521cb4ba 100644
--- a/sound/soc/tegra/tegra_asoc_utils.h
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -23,6 +23,9 @@
#ifndef __TEGRA_ASOC_UTILS_H__
#define __TEGRA_ASOC_UTILS_H_
+
+#define TEGRA30_I2S_MASTER_PLAYBACK 1
+
struct clk;
struct device;
@@ -32,6 +35,8 @@ struct tegra_asoc_utils_data {
struct clk *clk_pll_a_out0;
struct clk *clk_cdev1;
struct clk *clk_out1;
+ struct clk *clk_m;
+ struct clk *clk_pll_p_out1;
int set_baseclock;
int set_mclk;
int lock_count;
diff --git a/sound/soc/tegra/tegra_max98088.c b/sound/soc/tegra/tegra_max98088.c
index d666a953a394..61f45936e440 100644
--- a/sound/soc/tegra/tegra_max98088.c
+++ b/sound/soc/tegra/tegra_max98088.c
@@ -30,6 +30,7 @@
#include <asm/mach-types.h>
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -223,8 +224,10 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream,
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai);
#endif
- int srate, mclk, sample_size;
+ int srate, mclk, sample_size, i2s_daifmt;
int err;
+ struct clk *clk;
+ int rate;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -256,6 +259,32 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream,
break;
}
+
+#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;
+ }
+
+ 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))
@@ -268,19 +297,13 @@ 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,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
+ 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;
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index bdd355574066..80b05dcd654c 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -30,6 +30,7 @@
#include <asm/mach-types.h>
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -73,6 +74,7 @@ struct tegra_wm8903 {
#ifdef CONFIG_SWITCH
int jack_status;
#endif
+ enum snd_soc_bias_level bias_level;
};
static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
@@ -86,6 +88,8 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
int srate, mclk, i2s_daifmt;
int err;
+ struct clk *clk_m;
+ int rate;
srate = params_rate(params);
switch (srate) {
@@ -98,10 +102,33 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
mclk = 256 * srate;
break;
}
+
+
+
+ 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;
+ }
+ 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) {
if (!(machine->util_data.set_mclk % mclk))
@@ -114,9 +141,6 @@ static int tegra_wm8903_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;
-
/* Use DSP mode for mono on Tegra20 */
if ((params_channels(params) != 2) &&
(machine_is_ventana() || machine_is_harmony() ||
@@ -557,6 +581,8 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
struct tegra_wm8903_platform_data *pdata = machine->pdata;
int ret;
+ machine->bias_level = SND_SOC_BIAS_STANDBY;
+
if (gpio_is_valid(pdata->gpio_spkr_en)) {
ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
if (ret) {
@@ -664,6 +690,32 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static int tegra30_soc_set_bias_level(struct snd_soc_card *card,
+ enum snd_soc_bias_level level)
+{
+ struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+
+ if (machine->bias_level == SND_SOC_BIAS_OFF &&
+ level != SND_SOC_BIAS_OFF)
+ tegra_asoc_utils_clk_enable(&machine->util_data);
+
+ return 0;
+}
+
+static int tegra30_soc_set_bias_level_post(struct snd_soc_card *card,
+ enum snd_soc_bias_level level)
+{
+ struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+
+ if (machine->bias_level != SND_SOC_BIAS_OFF &&
+ level == SND_SOC_BIAS_OFF)
+ tegra_asoc_utils_clk_disable(&machine->util_data);
+
+ machine->bias_level = level;
+
+ return 0 ;
+}
+
static struct snd_soc_dai_link tegra_wm8903_dai[] = {
{
.name = "WM8903",
@@ -699,6 +751,8 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = {
.name = "tegra-wm8903",
.dai_link = tegra_wm8903_dai,
.num_links = ARRAY_SIZE(tegra_wm8903_dai),
+ //.set_bias_level = tegra30_soc_set_bias_level,
+ //.set_bias_level_post = tegra30_soc_set_bias_level_post,
};
static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)