diff options
author | Vinod G <vinodg@nvidia.com> | 2011-04-21 15:16:40 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-04-26 15:56:17 -0700 |
commit | 5047a0f6d0b6c1c44d0f692531396f1c5b541c74 (patch) | |
tree | ffcd806160112f222d96be7ccae0c45fe460a333 /sound | |
parent | 23e69c4ccebadc2b1152a5b3973780cd797c939a (diff) |
arm: tegra: Fix suspend/resume issue for spdif.
bug 793875
bug 818490
Merge spdif soc code from dev_hc.
Add clock and power mode calls to spdif
Fix the system suspend/resume issue caused by audio modules.
Original-Change-Id: Ie6d9c1e52596fa744dff893fd7340c1fa2f0f058
Reviewed-on: http://git-master/r/28520
Reviewed-by: Vinod Gopalakrishnakurup <vinodg@nvidia.com>
Tested-by: Vinod Gopalakrishnakurup <vinodg@nvidia.com>
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Change-Id: I367a048727b5fbe1a8db70a140b6ed1d752cd3a5
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/tegra/tegra_generic_codec.c | 10 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_i2s.c | 14 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_pcm.c | 20 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_soc.h | 12 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_soc_wm8753.c | 14 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_soc_wm8903.c | 12 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_spdif.c | 111 |
7 files changed, 110 insertions, 83 deletions
diff --git a/sound/soc/tegra/tegra_generic_codec.c b/sound/soc/tegra/tegra_generic_codec.c index 9afb910b5162..bccfc51909e9 100644 --- a/sound/soc/tegra/tegra_generic_codec.c +++ b/sound/soc/tegra/tegra_generic_codec.c @@ -97,16 +97,16 @@ static struct snd_soc_dai_ops tegra_generic_codec_stub_ops = { } struct snd_soc_dai tegra_generic_codec_dai[] = { + TEGRA_CREATE_GENERIC_CODEC_DAI("tegra_generic_spdif_codec", + 0, 2, 2, TEGRA_SAMPLE_RATES), #if defined(CONFIG_ARCH_TEGRA_2x_SOC) TEGRA_CREATE_GENERIC_CODEC_DAI("tegra_generic_voice_codec", - 0, 1, 1, TEGRA_VOICE_SAMPLE_RATES), - TEGRA_CREATE_GENERIC_CODEC_DAI("tegra_generic_spdif_codec", - 1, 1, 1, TEGRA_SAMPLE_RATES), + 1, 1, 1, TEGRA_VOICE_SAMPLE_RATES), #else TEGRA_CREATE_GENERIC_CODEC_DAI("tegra_generic_BB_codec", - 0, 1, 1, TEGRA_VOICE_SAMPLE_RATES), - TEGRA_CREATE_GENERIC_CODEC_DAI("tegra_generic_BT_codec", 1, 1, 1, TEGRA_VOICE_SAMPLE_RATES), + TEGRA_CREATE_GENERIC_CODEC_DAI("tegra_generic_BT_codec", + 2, 1, 1, TEGRA_VOICE_SAMPLE_RATES), #endif }; diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 53fb0c00e5b2..7ad1af85bc2c 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -26,14 +26,13 @@ struct tegra_i2s_info { struct platform_device *pdev; struct tegra_audio_platform_data *pdata; - /* Control for whole I2S (Data format, etc.) */ unsigned int bit_format; bool i2s_master; int ref_count; struct das_regs_cache das_regs; }; -void free_dma_request(struct snd_pcm_substream *substream) +void free_i2s_dma_request(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -92,7 +91,7 @@ void setup_i2s_dma_request(struct snd_pcm_substream *substream, return; } -void set_fifo_attention(struct snd_pcm_substream *substream, +void set_i2s_fifo_attention(struct snd_pcm_substream *substream, int buffersize) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -226,6 +225,7 @@ static int tegra_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, default: return -EINVAL; } + i2s_set_bit_format(i2s_id, val1); i2s_set_left_right_control_polarity(i2s_id, val2); @@ -271,7 +271,6 @@ static int i2s_configure(struct tegra_i2s_info *info ) { struct platform_device *pdev = info->pdev; struct tegra_audio_platform_data *pdata = pdev->dev.platform_data; - unsigned int i2s_id = pdev->id; struct tegra_i2s_property i2sprop; memset(&i2sprop, 0, sizeof(i2sprop)); @@ -279,12 +278,11 @@ static int i2s_configure(struct tegra_i2s_info *info ) i2sprop.master_mode = pdata->i2s_master; i2sprop.audio_mode = pdata->mode; i2sprop.bit_size = pdata->bit_size; - i2sprop.clk_rate = pdata->i2s_clk_rate; + i2sprop.clk_rate = pdata->dev_clk_rate; i2sprop.sample_rate = pdata->i2s_master_clk; i2sprop.fifo_fmt = pdata->fifo_fmt; - i2s_init(i2s_id, &i2sprop); - i2s_set_samplerate(i2s_id, i2sprop.sample_rate); + i2s_init(pdev->id, &i2sprop); return 0; } @@ -316,6 +314,8 @@ int tegra_i2s_resume(struct snd_soc_dai *cpu_dai) i2s_clock_disable(cpu_dai->id); + /* disabled clock as it is being enabled back on startup */ + i2s_clock_disable(cpu_dai->id); return 0; } diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 25a8c553e5ed..d75848741038 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -115,8 +115,16 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = { static int tegra_pcm_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 buffersize = params_period_bytes(params); + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - set_fifo_attention(substream, params_period_bytes(params)); + + if (strcmp(cpu_dai->name, "tegra-spdif") == 0) + set_spdif_fifo_attention(substream, buffersize); + else + set_i2s_fifo_attention(substream, buffersize); return 0; } @@ -234,7 +242,6 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) goto fail; } - /* prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL); if (prtd == NULL) return -ENOMEM; @@ -293,9 +300,11 @@ end: static int tegra_pcm_close(struct snd_pcm_substream *substream) { + int i; struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; - int i; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; if (!prtd) { printk(KERN_ERR "tegra_pcm_close called with prtd == NULL\n"); @@ -306,7 +315,10 @@ static int tegra_pcm_close(struct snd_pcm_substream *substream) prtd->dma_state = STATE_EXIT; for (i = 0; i < DMA_REQ_QCOUNT; i++) { tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[i]); - free_dma_request(substream); + if (strcmp(cpu_dai->name, "tegra-spdif") == 0) + free_spdif_dma_request(substream); + else + free_i2s_dma_request(substream); } tegra_dma_flush(prtd->dma_chan); tegra_dma_free_channel(prtd->dma_chan); diff --git a/sound/soc/tegra/tegra_soc.h b/sound/soc/tegra/tegra_soc.h index 5815f3d33fa5..bfaf998f973e 100644 --- a/sound/soc/tegra/tegra_soc.h +++ b/sound/soc/tegra/tegra_soc.h @@ -41,6 +41,7 @@ #include <mach/iomap.h> #include <mach/spdif.h> #include <mach/tegra_i2s.h> +#include <mach/spdif.h> #include <mach/irqs.h> #include <mach/pinmux.h> #include <mach/audio.h> @@ -132,12 +133,11 @@ int tegra_controls_init(struct snd_soc_codec *codec); int tegra_jack_init(struct snd_soc_codec *codec); void tegra_jack_exit(void); void tegra_jack_resume(void); -void setup_dma_request(struct snd_pcm_substream *substream, - struct tegra_dma_req *req, - void (*dma_callback)(struct tegra_dma_req *req), - void *dma_data); -void free_dma_request(struct snd_pcm_substream *substream); -void set_fifo_attention(struct snd_pcm_substream *substream, +void free_i2s_dma_request(struct snd_pcm_substream *substream); +void set_i2s_fifo_attention(struct snd_pcm_substream *substream, + int buffersize); +void free_spdif_dma_request(struct snd_pcm_substream *substream); +void set_spdif_fifo_attention(struct snd_pcm_substream *substream, int buffersize); void tegra_switch_set_state(int state); diff --git a/sound/soc/tegra/tegra_soc_wm8753.c b/sound/soc/tegra/tegra_soc_wm8753.c index 613a7fb78f86..87b1b0655ad7 100644 --- a/sound/soc/tegra/tegra_soc_wm8753.c +++ b/sound/soc/tegra/tegra_soc_wm8753.c @@ -368,6 +368,11 @@ static int tegra_voice_hw_free(struct snd_pcm_substream *substream) { return 0; } +static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return 0; +} static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -526,6 +531,10 @@ static const struct snd_soc_dapm_route audio_map[] = { {"LINE2", NULL, "Linein"}, }; +static struct snd_soc_ops tegra_spdif_ops = { + .hw_params = tegra_spdif_hw_params, +}; + static void wm8753_intr_work(struct work_struct *work) { unsigned int value; @@ -703,8 +712,11 @@ static struct snd_soc_dai_link tegra_soc_dai[] = { TEGRA_CREATE_SOC_DAI_LINK("WM8753", "WM8753 HiFi", &tegra_i2s_dai[0], &wm8753_dai[WM8753_DAI_HIFI], &tegra_hifi_ops), + TEGRA_CREATE_SOC_DAI_LINK("Tegra-spdif", "Tegra Spdif", + &tegra_spdif_dai, &tegra_generic_codec_dai[0], + &tegra_spdif_ops), TEGRA_CREATE_SOC_DAI_LINK("Tegra-generic", "Tegra Generic Voice", - &tegra_i2s_dai[1], &tegra_generic_codec_dai[0], + &tegra_i2s_dai[1], &tegra_generic_codec_dai[1], &tegra_voice_ops), TEGRA_CREATE_SOC_DAI_LINK("Tegra-spdif", "Tegra Spdif", &tegra_spdif_dai, &tegra_generic_codec_dai[1], diff --git a/sound/soc/tegra/tegra_soc_wm8903.c b/sound/soc/tegra/tegra_soc_wm8903.c index 4d6569c22f09..057f78b28cde 100644 --- a/sound/soc/tegra/tegra_soc_wm8903.c +++ b/sound/soc/tegra/tegra_soc_wm8903.c @@ -468,7 +468,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"IN3R", NULL, "Linein"}, }; - static int tegra_codec_init(struct snd_soc_codec *codec) { struct tegra_audio_data* audio_data = codec->socdev->codec_data; @@ -530,9 +529,14 @@ static struct snd_soc_dai_link tegra_soc_dai[] = { TEGRA_CREATE_SOC_DAI_LINK("WM8903", "WM8903 HiFi", &tegra_i2s_dai[0], &wm8903_dai, &tegra_hifi_ops), + TEGRA_CREATE_SOC_DAI_LINK("Tegra-spdif", "Tegra Spdif", + &tegra_spdif_dai, &tegra_generic_codec_dai[0], + &tegra_spdif_ops), + + #if defined(CONFIG_ARCH_TEGRA_2x_SOC) TEGRA_CREATE_SOC_DAI_LINK("Tegra-generic", "Tegra Generic Voice", - &tegra_i2s_dai[1], &tegra_generic_codec_dai[0], + &tegra_i2s_dai[1], &tegra_generic_codec_dai[1], &tegra_voice_ops), TEGRA_CREATE_SOC_DAI_LINK("Tegra-spdif", "Tegra Spdif", &tegra_spdif_dai, &tegra_generic_codec_dai[1], @@ -540,10 +544,10 @@ static struct snd_soc_dai_link tegra_soc_dai[] = { #else /* FIXME: enabled once these device are enumerated TEGRA_CREATE_SOC_DAI_LINK("Tegra-generic-0", "Tegra BB Voice", - &tegra_i2s_dai[2], &tegra_generic_codec_dai[0], + &tegra_i2s_dai[1], &tegra_generic_codec_dai[1], &tegra_voice_ops), TEGRA_CREATE_SOC_DAI_LINK("Tegra-generic-1", "Tegra BT Voice", - &tegra_i2s_dai[3], &tegra_generic_codec_dai[1], + &tegra_i2s_dai[2], &tegra_generic_codec_dai[2], &tegra_voice_ops), */ #endif diff --git a/sound/soc/tegra/tegra_spdif.c b/sound/soc/tegra/tegra_spdif.c index 99e275db8d3e..7243efd22044 100644 --- a/sound/soc/tegra/tegra_spdif.c +++ b/sound/soc/tegra/tegra_spdif.c @@ -28,13 +28,19 @@ struct tegra_spdif_info { unsigned long spdif_phys; unsigned long spdif_base; - unsigned long dma_req_sel; int irq; - - int ref_count; - struct spdif_regs_cache spdif_regs; }; +void free_spdif_dma_request(struct snd_pcm_substream *substream) +{ + int fifo_mode = AUDIO_RX_MODE; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + fifo_mode = AUDIO_TX_MODE; + + spdif_free_dma_requestor(fifo_mode); +} + void setup_spdif_dma_request(struct snd_pcm_substream *substream, struct tegra_dma_req *req, void (*dma_callback)(struct tegra_dma_req *req), @@ -44,10 +50,15 @@ void setup_spdif_dma_request(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct tegra_spdif_info *info = cpu_dai->private_data; + int fifo_mode = AUDIO_RX_MODE; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + fifo_mode = AUDIO_TX_MODE; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { req->to_memory = false; req->dest_addr = spdif_get_fifo_phy_base(info->spdif_phys, - AUDIO_TX_MODE); + fifo_mode); req->dest_wrap = 4; req->source_wrap = 0; req->dest_bus_width = 32; @@ -55,7 +66,7 @@ void setup_spdif_dma_request(struct snd_pcm_substream *substream, } else { req->to_memory = true; req->dest_addr = spdif_get_fifo_phy_base(info->spdif_phys, - AUDIO_RX_MODE); + fifo_mode); req->dest_wrap = 0; req->source_wrap = 4; req->dest_bus_width = 32; @@ -63,18 +74,25 @@ void setup_spdif_dma_request(struct snd_pcm_substream *substream, } req->complete = dma_callback; req->dev = dma_data; - req->req_sel = info->dma_req_sel; + req->req_sel = spdif_get_dma_requestor(fifo_mode); return; } +void set_spdif_fifo_attention(struct snd_pcm_substream *substream, + int buffersize) +{ + spdif_set_fifo_attention( + buffersize, + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)? + AUDIO_TX_MODE: AUDIO_RX_MODE); +} + /* playback */ static inline void start_spdif_playback(struct snd_soc_dai *dai) { struct tegra_spdif_info *info = dai->private_data; - spdif_fifo_set_attention_level(info->spdif_base, AUDIO_TX_MODE, - SPDIF_FIFO_ATN_LVL_FOUR_SLOTS); spdif_fifo_enable(info->spdif_base, AUDIO_TX_MODE, true); } @@ -83,7 +101,8 @@ static inline void stop_spdif_playback(struct snd_soc_dai *dai) struct tegra_spdif_info *info = dai->private_data; spdif_fifo_enable(info->spdif_base, AUDIO_TX_MODE, false); - while (spdif_get_status(info->spdif_base, AUDIO_TX_MODE) & SPDIF_STATUS_0_TX_BSY); + while (spdif_get_status(info->spdif_base, AUDIO_TX_MODE) & + SPDIF_STATUS_0_TX_BSY); } /* capture */ @@ -91,8 +110,6 @@ static inline void start_spdif_capture(struct snd_soc_dai *dai) { struct tegra_spdif_info *info = dai->private_data; - spdif_fifo_set_attention_level(info->spdif_base, AUDIO_RX_MODE, - SPDIF_FIFO_ATN_LVL_FOUR_SLOTS); spdif_fifo_enable(info->spdif_base, AUDIO_RX_MODE, true); } @@ -101,7 +118,8 @@ static inline void stop_spdif_capture(struct snd_soc_dai *dai) struct tegra_spdif_info *info = dai->private_data; spdif_fifo_enable(info->spdif_base, AUDIO_RX_MODE, false); - while (spdif_get_status(info->spdif_base, AUDIO_RX_MODE) & SPDIF_STATUS_0_RX_BSY); + while (spdif_get_status(info->spdif_base, AUDIO_RX_MODE) & + SPDIF_STATUS_0_RX_BSY); } static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, @@ -111,6 +129,10 @@ static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, struct tegra_spdif_info *info = dai->private_data; int val; unsigned int rate, sample_size; + int fifo_mode = AUDIO_RX_MODE; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + fifo_mode = AUDIO_TX_MODE; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -145,15 +167,7 @@ static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - /* Min BCLK = samplerate * channel * bits per sample * 4 */ - rate = val * params_channels(params) * sample_size * 4; - - /* Ensure Spdif clk rate is atleast greater than min BCLK */ - clk_set_rate(info->spdif_clk, rate); - if (clk_get_rate(info->spdif_clk) < rate) - clk_set_rate(info->spdif_clk, rate << 1); - - spdif_set_sample_rate(info->spdif_base, val); + spdif_set_sample_rate(fifo_mode, val); return 0; } @@ -203,17 +217,16 @@ static int tegra_spdif_trigger(struct snd_pcm_substream *substream, int cmd, #ifdef CONFIG_PM int tegra_spdif_suspend(struct snd_soc_dai *cpu_dai) { - struct tegra_spdif_info* info = cpu_dai->private_data; - - spdif_get_all_regs(info->spdif_base, &info->spdif_regs); + spdif_suspend(); return 0; } int tegra_spdif_resume(struct snd_soc_dai *cpu_dai) { - struct tegra_spdif_info* info = cpu_dai->private_data; + spdif_resume(); - spdif_set_all_regs(info->spdif_base, &info->spdif_regs); + /* disabled clock as startup code enable the clock */ + spdif_clock_disable(AUDIO_TX_MODE); return 0; } @@ -225,25 +238,25 @@ int tegra_spdif_resume(struct snd_soc_dai *cpu_dai) static int tegra_spdif_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct tegra_spdif_info *info = dai->private_data; + int fifo_mode = AUDIO_RX_MODE; - if (!info->ref_count) - clk_enable(info->spdif_clk); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + fifo_mode = AUDIO_TX_MODE; + + spdif_clock_enable(fifo_mode); - info->ref_count++; return 0; } static void tegra_spdif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct tegra_spdif_info *info = dai->private_data; + int fifo_mode = AUDIO_RX_MODE; - if (info->ref_count > 0) - info->ref_count--; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + fifo_mode = AUDIO_TX_MODE; - if (!info->ref_count) - clk_disable(info->spdif_clk); + spdif_clock_disable(fifo_mode); return; } @@ -290,6 +303,7 @@ static int tegra_spdif_driver_probe(struct platform_device *pdev) int err = 0; struct resource *res, *mem; struct tegra_spdif_info *info; + struct tegra_spdif_property sp_prop; pr_info("%s\n", __func__); @@ -317,21 +331,14 @@ static int tegra_spdif_driver_probe(struct platform_device *pdev) } info->spdif_phys = res->start; - info->spdif_base = (unsigned long)ioremap(res->start, res->end - res->start + 1); + info->spdif_base = (unsigned long)ioremap(res->start, + res->end - res->start + 1); if (!info->spdif_base) { dev_err(&pdev->dev, "cannot remap iomem!\n"); err = -ENOMEM; goto fail_release_mem; } - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!res) { - dev_err(&pdev->dev, "no dma resource!\n"); - err = -ENODEV; - goto fail_unmap_mem; - } - info->dma_req_sel = res->start; - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(&pdev->dev, "no irq resource!\n"); @@ -340,16 +347,10 @@ static int tegra_spdif_driver_probe(struct platform_device *pdev) } info->irq = res->start; - info->spdif_clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(info->spdif_clk)) { - err = PTR_ERR(info->spdif_clk); - goto fail_unmap_mem; - } - clk_enable(info->spdif_clk); - clk_set_rate(info->spdif_clk, info->pdata->spdif_clk_rate); + sp_prop.clk_rate = info->pdata->dev_clk_rate; - spdif_initialize(info->spdif_base, AUDIO_TX_MODE); - spdif_initialize(info->spdif_base, AUDIO_RX_MODE); + spdif_init(info->spdif_base, AUDIO_TX_MODE, &sp_prop); + spdif_init(info->spdif_base, AUDIO_RX_MODE, &sp_prop); tegra_spdif_dai.dev = &pdev->dev; tegra_spdif_dai.private_data = info; @@ -357,8 +358,6 @@ static int tegra_spdif_driver_probe(struct platform_device *pdev) if (err) goto fail_unmap_mem; - /* Disable SPDIF clock to save power */ - clk_disable(info->spdif_clk); return 0; fail_unmap_mem: |