aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-12-13 08:54:53 -0500
committerTakashi Iwai <tiwai@suse.de>2013-12-13 08:54:53 -0500
commitafdcd431cebe3498db9aa963c780fdd5099917ec (patch)
tree16d9155e136f0df56689eead95cf44935aab2a0c /sound
parentc29cb5eb8157a0049c882672a7f941261f23ea34 (diff)
parente20ab019e28dcf09c2727aa69e2a073ed66718b3 (diff)
Merge tag 'asoc-v3.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Fixes for v3.13 A few driver and error handling fixes plus a fix to ensure that we mute streams when we should. The Atmel trigger addition is a fix to ensure that we do the correct sequence of interactions with the hardware.
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c30
-rw-r--r--sound/soc/atmel/sam9x5_wm8731.c2
-rw-r--r--sound/soc/codecs/wm8962.c13
-rw-r--r--sound/soc/fsl/imx-wm8962.c2
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c38
-rw-r--r--sound/soc/soc-pcm.c5
-rw-r--r--sound/soc/tegra/tegra20_i2s.c6
-rw-r--r--sound/soc/tegra/tegra20_spdif.c10
-rw-r--r--sound/soc/tegra/tegra30_i2s.c6
9 files changed, 84 insertions, 28 deletions
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 8697cedccd21..1ead3c977a51 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -648,7 +648,7 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
648 648
649 dma_params = ssc_p->dma_params[dir]; 649 dma_params = ssc_p->dma_params[dir];
650 650
651 ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable); 651 ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);
652 ssc_writel(ssc_p->ssc->regs, IDR, dma_params->mask->ssc_error); 652 ssc_writel(ssc_p->ssc->regs, IDR, dma_params->mask->ssc_error);
653 653
654 pr_debug("%s enabled SSC_SR=0x%08x\n", 654 pr_debug("%s enabled SSC_SR=0x%08x\n",
@@ -657,6 +657,33 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
657 return 0; 657 return 0;
658} 658}
659 659
660static int atmel_ssc_trigger(struct snd_pcm_substream *substream,
661 int cmd, struct snd_soc_dai *dai)
662{
663 struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
664 struct atmel_pcm_dma_params *dma_params;
665 int dir;
666
667 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
668 dir = 0;
669 else
670 dir = 1;
671
672 dma_params = ssc_p->dma_params[dir];
673
674 switch (cmd) {
675 case SNDRV_PCM_TRIGGER_START:
676 case SNDRV_PCM_TRIGGER_RESUME:
677 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
678 ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);
679 break;
680 default:
681 ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);
682 break;
683 }
684
685 return 0;
686}
660 687
661#ifdef CONFIG_PM 688#ifdef CONFIG_PM
662static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) 689static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
@@ -731,6 +758,7 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
731 .startup = atmel_ssc_startup, 758 .startup = atmel_ssc_startup,
732 .shutdown = atmel_ssc_shutdown, 759 .shutdown = atmel_ssc_shutdown,
733 .prepare = atmel_ssc_prepare, 760 .prepare = atmel_ssc_prepare,
761 .trigger = atmel_ssc_trigger,
734 .hw_params = atmel_ssc_hw_params, 762 .hw_params = atmel_ssc_hw_params,
735 .set_fmt = atmel_ssc_set_dai_fmt, 763 .set_fmt = atmel_ssc_set_dai_fmt,
736 .set_clkdiv = atmel_ssc_set_dai_clkdiv, 764 .set_clkdiv = atmel_ssc_set_dai_clkdiv,
diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c
index 1b372283bd01..7d6a9055874b 100644
--- a/sound/soc/atmel/sam9x5_wm8731.c
+++ b/sound/soc/atmel/sam9x5_wm8731.c
@@ -109,7 +109,7 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
109 dai->stream_name = "WM8731 PCM"; 109 dai->stream_name = "WM8731 PCM";
110 dai->codec_dai_name = "wm8731-hifi"; 110 dai->codec_dai_name = "wm8731-hifi";
111 dai->init = sam9x5_wm8731_init; 111 dai->init = sam9x5_wm8731_init;
112 dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 112 dai->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF
113 | SND_SOC_DAIFMT_CBM_CFM; 113 | SND_SOC_DAIFMT_CBM_CFM;
114 114
115 ret = snd_soc_of_parse_card_name(card, "atmel,model"); 115 ret = snd_soc_of_parse_card_name(card, "atmel,model");
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 543c5c2631b6..0f17ed3e29f4 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2439,7 +2439,20 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
2439 snd_soc_update_bits(codec, WM8962_CLOCKING_4, 2439 snd_soc_update_bits(codec, WM8962_CLOCKING_4,
2440 WM8962_SYSCLK_RATE_MASK, clocking4); 2440 WM8962_SYSCLK_RATE_MASK, clocking4);
2441 2441
2442 /* DSPCLK_DIV can be only generated correctly after enabling SYSCLK.
2443 * So we here provisionally enable it and then disable it afterward
2444 * if current bias_level hasn't reached SND_SOC_BIAS_ON.
2445 */
2446 if (codec->dapm.bias_level != SND_SOC_BIAS_ON)
2447 snd_soc_update_bits(codec, WM8962_CLOCKING2,
2448 WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA);
2449
2442 dspclk = snd_soc_read(codec, WM8962_CLOCKING1); 2450 dspclk = snd_soc_read(codec, WM8962_CLOCKING1);
2451
2452 if (codec->dapm.bias_level != SND_SOC_BIAS_ON)
2453 snd_soc_update_bits(codec, WM8962_CLOCKING2,
2454 WM8962_SYSCLK_ENA_MASK, 0);
2455
2443 if (dspclk < 0) { 2456 if (dspclk < 0) {
2444 dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk); 2457 dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk);
2445 return; 2458 return;
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c
index 61e48852b9e8..3fd76bc391de 100644
--- a/sound/soc/fsl/imx-wm8962.c
+++ b/sound/soc/fsl/imx-wm8962.c
@@ -130,8 +130,6 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
130 break; 130 break;
131 } 131 }
132 132
133 dapm->bias_level = level;
134
135 return 0; 133 return 0;
136} 134}
137 135
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index cbc9c96ce1f4..41949af3baae 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -305,6 +305,20 @@ static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,
305 } 305 }
306} 306}
307 307
308static void dmaengine_pcm_release_chan(struct dmaengine_pcm *pcm)
309{
310 unsigned int i;
311
312 for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE;
313 i++) {
314 if (!pcm->chan[i])
315 continue;
316 dma_release_channel(pcm->chan[i]);
317 if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
318 break;
319 }
320}
321
308/** 322/**
309 * snd_dmaengine_pcm_register - Register a dmaengine based PCM device 323 * snd_dmaengine_pcm_register - Register a dmaengine based PCM device
310 * @dev: The parent device for the PCM device 324 * @dev: The parent device for the PCM device
@@ -315,6 +329,7 @@ int snd_dmaengine_pcm_register(struct device *dev,
315 const struct snd_dmaengine_pcm_config *config, unsigned int flags) 329 const struct snd_dmaengine_pcm_config *config, unsigned int flags)
316{ 330{
317 struct dmaengine_pcm *pcm; 331 struct dmaengine_pcm *pcm;
332 int ret;
318 333
319 pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); 334 pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
320 if (!pcm) 335 if (!pcm)
@@ -326,11 +341,20 @@ int snd_dmaengine_pcm_register(struct device *dev,
326 dmaengine_pcm_request_chan_of(pcm, dev); 341 dmaengine_pcm_request_chan_of(pcm, dev);
327 342
328 if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) 343 if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
329 return snd_soc_add_platform(dev, &pcm->platform, 344 ret = snd_soc_add_platform(dev, &pcm->platform,
330 &dmaengine_no_residue_pcm_platform); 345 &dmaengine_no_residue_pcm_platform);
331 else 346 else
332 return snd_soc_add_platform(dev, &pcm->platform, 347 ret = snd_soc_add_platform(dev, &pcm->platform,
333 &dmaengine_pcm_platform); 348 &dmaengine_pcm_platform);
349 if (ret)
350 goto err_free_dma;
351
352 return 0;
353
354err_free_dma:
355 dmaengine_pcm_release_chan(pcm);
356 kfree(pcm);
357 return ret;
334} 358}
335EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register); 359EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register);
336 360
@@ -345,7 +369,6 @@ void snd_dmaengine_pcm_unregister(struct device *dev)
345{ 369{
346 struct snd_soc_platform *platform; 370 struct snd_soc_platform *platform;
347 struct dmaengine_pcm *pcm; 371 struct dmaengine_pcm *pcm;
348 unsigned int i;
349 372
350 platform = snd_soc_lookup_platform(dev); 373 platform = snd_soc_lookup_platform(dev);
351 if (!platform) 374 if (!platform)
@@ -353,15 +376,8 @@ void snd_dmaengine_pcm_unregister(struct device *dev)
353 376
354 pcm = soc_platform_to_pcm(platform); 377 pcm = soc_platform_to_pcm(platform);
355 378
356 for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
357 if (pcm->chan[i]) {
358 dma_release_channel(pcm->chan[i]);
359 if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
360 break;
361 }
362 }
363
364 snd_soc_remove_platform(platform); 379 snd_soc_remove_platform(platform);
380 dmaengine_pcm_release_chan(pcm);
365 kfree(pcm); 381 kfree(pcm);
366} 382}
367EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister); 383EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 11a90cd027fa..891b9a9bcbf8 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -600,12 +600,13 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
600 struct snd_soc_platform *platform = rtd->platform; 600 struct snd_soc_platform *platform = rtd->platform;
601 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 601 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
602 struct snd_soc_dai *codec_dai = rtd->codec_dai; 602 struct snd_soc_dai *codec_dai = rtd->codec_dai;
603 struct snd_soc_codec *codec = rtd->codec; 603 bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
604 604
605 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 605 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
606 606
607 /* apply codec digital mute */ 607 /* apply codec digital mute */
608 if (!codec->active) 608 if ((playback && codec_dai->playback_active == 1) ||
609 (!playback && codec_dai->capture_active == 1))
609 snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); 610 snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
610 611
611 /* free any machine hw params */ 612 /* free any machine hw params */
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 364bf6a907e1..8c819f811470 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -74,7 +74,7 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
74 unsigned int fmt) 74 unsigned int fmt)
75{ 75{
76 struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai); 76 struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
77 unsigned int mask, val; 77 unsigned int mask = 0, val = 0;
78 78
79 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 79 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
80 case SND_SOC_DAIFMT_NB_NF: 80 case SND_SOC_DAIFMT_NB_NF:
@@ -83,10 +83,10 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
83 return -EINVAL; 83 return -EINVAL;
84 } 84 }
85 85
86 mask = TEGRA20_I2S_CTRL_MASTER_ENABLE; 86 mask |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
87 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 87 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
88 case SND_SOC_DAIFMT_CBS_CFS: 88 case SND_SOC_DAIFMT_CBS_CFS:
89 val = TEGRA20_I2S_CTRL_MASTER_ENABLE; 89 val |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
90 break; 90 break;
91 case SND_SOC_DAIFMT_CBM_CFM: 91 case SND_SOC_DAIFMT_CBM_CFM:
92 break; 92 break;
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index 08bc6931c7c7..8c7c1028e579 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -67,15 +67,15 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
67{ 67{
68 struct device *dev = dai->dev; 68 struct device *dev = dai->dev;
69 struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); 69 struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
70 unsigned int mask, val; 70 unsigned int mask = 0, val = 0;
71 int ret, spdifclock; 71 int ret, spdifclock;
72 72
73 mask = TEGRA20_SPDIF_CTRL_PACK | 73 mask |= TEGRA20_SPDIF_CTRL_PACK |
74 TEGRA20_SPDIF_CTRL_BIT_MODE_MASK; 74 TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
75 switch (params_format(params)) { 75 switch (params_format(params)) {
76 case SNDRV_PCM_FORMAT_S16_LE: 76 case SNDRV_PCM_FORMAT_S16_LE:
77 val = TEGRA20_SPDIF_CTRL_PACK | 77 val |= TEGRA20_SPDIF_CTRL_PACK |
78 TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT; 78 TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT;
79 break; 79 break;
80 default: 80 default:
81 return -EINVAL; 81 return -EINVAL;
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 231a785b3921..02247fee1cf7 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -118,7 +118,7 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
118 unsigned int fmt) 118 unsigned int fmt)
119{ 119{
120 struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); 120 struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
121 unsigned int mask, val; 121 unsigned int mask = 0, val = 0;
122 122
123 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 123 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
124 case SND_SOC_DAIFMT_NB_NF: 124 case SND_SOC_DAIFMT_NB_NF:
@@ -127,10 +127,10 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
127 return -EINVAL; 127 return -EINVAL;
128 } 128 }
129 129
130 mask = TEGRA30_I2S_CTRL_MASTER_ENABLE; 130 mask |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
131 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 131 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
132 case SND_SOC_DAIFMT_CBS_CFS: 132 case SND_SOC_DAIFMT_CBS_CFS:
133 val = TEGRA30_I2S_CTRL_MASTER_ENABLE; 133 val |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
134 break; 134 break;
135 case SND_SOC_DAIFMT_CBM_CFM: 135 case SND_SOC_DAIFMT_CBM_CFM:
136 break; 136 break;