diff options
author | Scott Peterson <speterson@nvidia.com> | 2012-12-27 19:11:42 -0800 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2013-01-03 15:15:47 -0800 |
commit | 501983d17947d25a18ac527d020563b959942528 (patch) | |
tree | 1f015545b0eaf30d22422ed3813adb33acd89d33 /sound | |
parent | 2be11457a857263ee83263484af6294542230076 (diff) |
asoc: tegra: Roth headphone detection
Fixed clocking issues when doing headphone detection
on roth. The NXP device requires an active I2S interface
in order to supply clocks for programming.
Bug 1210696
Change-Id: I6e18daa349448d14e7ea2c98df2917213d24d82a
Signed-off-by: Scott Peterson <speterson@nvidia.com>
(cherry picked from commit 5d386c3275f38c84686f9b7f2181b5ecb08e0391)
Reviewed-on: http://git-master/r/188063
Tested-by: Vinod Subbarayalu <vsubbarayalu@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/tegra/tegra_rt5640.c | 83 |
1 files changed, 51 insertions, 32 deletions
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index 3e606415aaec..d1280d3d4427 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -81,32 +81,8 @@ struct tegra_rt5640 { volatile int clock_enabled; }; -void enable_clks(struct tegra30_i2s *i2s) -{ - tegra30_ahub_enable_clocks(); - clk_enable(i2s->clk_i2s); - tegra30_ahub_enable_tx_fifo(i2s->txcif); - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; - #ifdef CONFIG_PM - i2s->reg_cache[TEGRA30_I2S_CTRL >> 2] = i2s->reg_ctrl; - #endif - __raw_writel(i2s->reg_ctrl, i2s->regs + TEGRA30_I2S_CTRL); -} - -void disable_clks(struct tegra30_i2s *i2s) -{ - int dcnt = 10; - i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; - #ifdef CONFIG_PM - i2s->reg_cache[TEGRA30_I2S_CTRL >> 2] = i2s->reg_ctrl; - #endif - __raw_writel(i2s->reg_ctrl, i2s->regs + TEGRA30_I2S_CTRL); - while (tegra30_ahub_tx_fifo_is_enabled(i2s->id) && dcnt--) - udelay(100); - clk_disable(i2s->clk_i2s); - tegra30_ahub_disable_clocks(); - tegra30_ahub_disable_tx_fifo(i2s->txcif); -} +void tegra_asoc_enable_clocks(void); +void tegra_asoc_disable_clocks(void); static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -185,10 +161,10 @@ static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream, if(machine_is_roth()) { if(initTfa == 1) { i2s_tfa = i2s; - enable_clks(i2s); + tegra_asoc_enable_clocks(); pr_info("INIT TFA\n"); Tfa9887_Init(srate); - disable_clks(i2s); + tegra_asoc_disable_clocks(); } initTfa++; } @@ -461,9 +437,9 @@ static int tegra_rt5640_event_int_spk(struct snd_soc_dapm_widget *w, if(machine_is_roth()) { if (SND_SOC_DAPM_EVENT_ON(event)) { if(i2s_tfa) { - enable_clks(i2s_tfa); + tegra_asoc_enable_clocks(); Tfa9887_Powerdown(0); - disable_clks(i2s_tfa); + tegra_asoc_disable_clocks(); } } else { @@ -474,7 +450,7 @@ static int tegra_rt5640_event_int_spk(struct snd_soc_dapm_widget *w, return 0; gpio_set_value_cansleep(pdata->gpio_spkr_en, - SND_SOC_DAPM_EVENT_ON(event)); + !!SND_SOC_DAPM_EVENT_ON(event)); return 0; } @@ -515,7 +491,7 @@ static int tegra_rt5640_event_int_mic(struct snd_soc_dapm_widget *w, return 0; gpio_set_value_cansleep(pdata->gpio_int_mic_en, - SND_SOC_DAPM_EVENT_ON(event)); + !!SND_SOC_DAPM_EVENT_ON(event)); return 0; } @@ -748,6 +724,49 @@ static struct snd_soc_card snd_soc_tegra_rt5640 = { .fully_routed = true, }; +void tegra_asoc_enable_clocks() +{ + struct snd_soc_card *card = &snd_soc_tegra_rt5640; + struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); + int reg; + struct tegra30_i2s *i2s = i2s_tfa; + if (!i2s || !machine) + return; + + reg = i2s->reg_ctrl | TEGRA30_I2S_CTRL_XFER_EN_TX; + if (!(i2s->reg_ctrl & TEGRA30_I2S_CTRL_XFER_EN_TX)) { + tegra_asoc_utils_clk_enable(&machine->util_data); + clk_enable(i2s->clk_i2s); + tegra30_ahub_enable_clocks(); + tegra30_ahub_enable_tx_fifo(i2s->txcif); + __raw_writel(reg, i2s->regs + TEGRA30_I2S_CTRL); + } +} +EXPORT_SYMBOL_GPL(tegra_asoc_enable_clocks); + +void tegra_asoc_disable_clocks() +{ + struct snd_soc_card *card = &snd_soc_tegra_rt5640; + struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); + int dcnt = 10; + struct tegra30_i2s *i2s = i2s_tfa; + if (!i2s || !machine) + return; + + if (!(i2s->reg_ctrl & TEGRA30_I2S_CTRL_XFER_EN_TX)) { + __raw_writel(i2s->reg_ctrl, i2s->regs + TEGRA30_I2S_CTRL); + while (!tegra30_ahub_tx_fifo_is_empty(i2s->id) && dcnt--) + udelay(100); + + tegra30_ahub_disable_tx_fifo(i2s->txcif); + tegra30_ahub_disable_clocks(); + clk_disable(i2s->clk_i2s); + tegra_asoc_utils_clk_disable(&machine->util_data); + } +} +EXPORT_SYMBOL_GPL(tegra_asoc_disable_clocks); + + static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_tegra_rt5640; |