aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-05-17 16:41:23 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-05-18 10:53:16 -0400
commit452c5eaa0d5162e02ffee742ea17540887bc2904 (patch)
tree7dbac625d69e3ff01445d7f1b1fa321aa35fcae5 /sound/soc
parentaef908434cd24dd5529065bf5d781773fad21125 (diff)
ASoC: Integrate bias management with DAPM power management
Rather than managing the bias level of the system based on if there is an active audio stream manage it based on there being an active DAPM widget. This simplifies the code a little, moving the power handling into one place, and improves audio performance for bypass paths when no playbacks or captures are active. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/soc-core.c61
-rw-r--r--sound/soc/soc-dapm.c78
2 files changed, 64 insertions, 75 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c0e706645ec4..4aa8e2d35061 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -299,7 +299,6 @@ static void close_delayed_work(struct work_struct *work)
299{ 299{
300 struct snd_soc_card *card = container_of(work, struct snd_soc_card, 300 struct snd_soc_card *card = container_of(work, struct snd_soc_card,
301 delayed_work.work); 301 delayed_work.work);
302 struct snd_soc_device *socdev = card->socdev;
303 struct snd_soc_codec *codec = card->codec; 302 struct snd_soc_codec *codec = card->codec;
304 struct snd_soc_dai *codec_dai; 303 struct snd_soc_dai *codec_dai;
305 int i; 304 int i;
@@ -315,27 +314,10 @@ static void close_delayed_work(struct work_struct *work)
315 314
316 /* are we waiting on this codec DAI stream */ 315 /* are we waiting on this codec DAI stream */
317 if (codec_dai->pop_wait == 1) { 316 if (codec_dai->pop_wait == 1) {
318
319 /* Reduce power if no longer active */
320 if (codec->active == 0) {
321 pr_debug("pop wq D1 %s %s\n", codec->name,
322 codec_dai->playback.stream_name);
323 snd_soc_dapm_set_bias_level(socdev,
324 SND_SOC_BIAS_PREPARE);
325 }
326
327 codec_dai->pop_wait = 0; 317 codec_dai->pop_wait = 0;
328 snd_soc_dapm_stream_event(codec, 318 snd_soc_dapm_stream_event(codec,
329 codec_dai->playback.stream_name, 319 codec_dai->playback.stream_name,
330 SND_SOC_DAPM_STREAM_STOP); 320 SND_SOC_DAPM_STREAM_STOP);
331
332 /* Fall into standby if no longer active */
333 if (codec->active == 0) {
334 pr_debug("pop wq D3 %s %s\n", codec->name,
335 codec_dai->playback.stream_name);
336 snd_soc_dapm_set_bias_level(socdev,
337 SND_SOC_BIAS_STANDBY);
338 }
339 } 321 }
340 } 322 }
341 mutex_unlock(&pcm_mutex); 323 mutex_unlock(&pcm_mutex);
@@ -399,10 +381,6 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
399 snd_soc_dapm_stream_event(codec, 381 snd_soc_dapm_stream_event(codec,
400 codec_dai->capture.stream_name, 382 codec_dai->capture.stream_name,
401 SND_SOC_DAPM_STREAM_STOP); 383 SND_SOC_DAPM_STREAM_STOP);
402
403 if (codec->active == 0 && codec_dai->pop_wait == 0)
404 snd_soc_dapm_set_bias_level(socdev,
405 SND_SOC_BIAS_STANDBY);
406 } 384 }
407 385
408 mutex_unlock(&pcm_mutex); 386 mutex_unlock(&pcm_mutex);
@@ -467,36 +445,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
467 cancel_delayed_work(&card->delayed_work); 445 cancel_delayed_work(&card->delayed_work);
468 } 446 }
469 447
470 /* do we need to power up codec */ 448 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
471 if (codec->bias_level != SND_SOC_BIAS_ON) { 449 snd_soc_dapm_stream_event(codec,
472 snd_soc_dapm_set_bias_level(socdev, 450 codec_dai->playback.stream_name,
473 SND_SOC_BIAS_PREPARE); 451 SND_SOC_DAPM_STREAM_START);
474 452 else
475 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 453 snd_soc_dapm_stream_event(codec,
476 snd_soc_dapm_stream_event(codec, 454 codec_dai->capture.stream_name,
477 codec_dai->playback.stream_name, 455 SND_SOC_DAPM_STREAM_START);
478 SND_SOC_DAPM_STREAM_START);
479 else
480 snd_soc_dapm_stream_event(codec,
481 codec_dai->capture.stream_name,
482 SND_SOC_DAPM_STREAM_START);
483
484 snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON);
485 snd_soc_dai_digital_mute(codec_dai, 0);
486
487 } else {
488 /* codec already powered - power on widgets */
489 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
490 snd_soc_dapm_stream_event(codec,
491 codec_dai->playback.stream_name,
492 SND_SOC_DAPM_STREAM_START);
493 else
494 snd_soc_dapm_stream_event(codec,
495 codec_dai->capture.stream_name,
496 SND_SOC_DAPM_STREAM_START);
497 456
498 snd_soc_dai_digital_mute(codec_dai, 0); 457 snd_soc_dai_digital_mute(codec_dai, 0);
499 }
500 458
501out: 459out:
502 mutex_unlock(&pcm_mutex); 460 mutex_unlock(&pcm_mutex);
@@ -1372,6 +1330,7 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
1372 return ret; 1330 return ret;
1373 } 1331 }
1374 1332
1333 codec->socdev = socdev;
1375 codec->card->dev = socdev->dev; 1334 codec->card->dev = socdev->dev;
1376 codec->card->private_data = codec; 1335 codec->card->private_data = codec;
1377 strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); 1336 strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d130602b3072..4ca5e56388a3 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -94,6 +94,30 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
94 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); 94 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
95} 95}
96 96
97/**
98 * snd_soc_dapm_set_bias_level - set the bias level for the system
99 * @socdev: audio device
100 * @level: level to configure
101 *
102 * Configure the bias (power) levels for the SoC audio device.
103 *
104 * Returns 0 for success else error.
105 */
106static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
107 enum snd_soc_bias_level level)
108{
109 struct snd_soc_card *card = socdev->card;
110 struct snd_soc_codec *codec = socdev->card->codec;
111 int ret = 0;
112
113 if (card->set_bias_level)
114 ret = card->set_bias_level(card, level);
115 if (ret == 0 && codec->set_bias_level)
116 ret = codec->set_bias_level(codec, level);
117
118 return ret;
119}
120
97/* set up initial codec paths */ 121/* set up initial codec paths */
98static void dapm_set_path_status(struct snd_soc_dapm_widget *w, 122static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
99 struct snd_soc_dapm_path *p, int i) 123 struct snd_soc_dapm_path *p, int i)
@@ -707,9 +731,11 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event,
707 */ 731 */
708static int dapm_power_widgets(struct snd_soc_codec *codec, int event) 732static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
709{ 733{
734 struct snd_soc_device *socdev = codec->socdev;
710 struct snd_soc_dapm_widget *w; 735 struct snd_soc_dapm_widget *w;
711 int ret = 0; 736 int ret = 0;
712 int i, power; 737 int i, power;
738 int sys_power = 0;
713 739
714 INIT_LIST_HEAD(&codec->up_list); 740 INIT_LIST_HEAD(&codec->up_list);
715 INIT_LIST_HEAD(&codec->down_list); 741 INIT_LIST_HEAD(&codec->down_list);
@@ -731,6 +757,9 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
731 continue; 757 continue;
732 758
733 power = w->power_check(w); 759 power = w->power_check(w);
760 if (power)
761 sys_power = 1;
762
734 if (w->power == power) 763 if (w->power == power)
735 continue; 764 continue;
736 765
@@ -745,6 +774,15 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
745 } 774 }
746 } 775 }
747 776
777 /* If we're changing to all on or all off then prepare */
778 if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) ||
779 (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) {
780 ret = snd_soc_dapm_set_bias_level(socdev,
781 SND_SOC_BIAS_PREPARE);
782 if (ret != 0)
783 pr_err("Failed to prepare bias: %d\n", ret);
784 }
785
748 /* Power down widgets first; try to avoid amplifying pops. */ 786 /* Power down widgets first; try to avoid amplifying pops. */
749 for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) { 787 for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) {
750 list_for_each_entry(w, &codec->down_list, power_list) { 788 list_for_each_entry(w, &codec->down_list, power_list) {
@@ -773,6 +811,22 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
773 } 811 }
774 } 812 }
775 813
814 /* If we just powered the last thing off drop to standby bias */
815 if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
816 ret = snd_soc_dapm_set_bias_level(socdev,
817 SND_SOC_BIAS_STANDBY);
818 if (ret != 0)
819 pr_err("Failed to apply standby bias: %d\n", ret);
820 }
821
822 /* If we just powered up then move to active bias */
823 if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
824 ret = snd_soc_dapm_set_bias_level(socdev,
825 SND_SOC_BIAS_ON);
826 if (ret != 0)
827 pr_err("Failed to apply active bias: %d\n", ret);
828 }
829
776 return 0; 830 return 0;
777} 831}
778 832
@@ -1721,30 +1775,6 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
1721EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); 1775EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
1722 1776
1723/** 1777/**
1724 * snd_soc_dapm_set_bias_level - set the bias level for the system
1725 * @socdev: audio device
1726 * @level: level to configure
1727 *
1728 * Configure the bias (power) levels for the SoC audio device.
1729 *
1730 * Returns 0 for success else error.
1731 */
1732int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
1733 enum snd_soc_bias_level level)
1734{
1735 struct snd_soc_card *card = socdev->card;
1736 struct snd_soc_codec *codec = socdev->card->codec;
1737 int ret = 0;
1738
1739 if (card->set_bias_level)
1740 ret = card->set_bias_level(card, level);
1741 if (ret == 0 && codec->set_bias_level)
1742 ret = codec->set_bias_level(codec, level);
1743
1744 return ret;
1745}
1746
1747/**
1748 * snd_soc_dapm_enable_pin - enable pin. 1778 * snd_soc_dapm_enable_pin - enable pin.
1749 * @codec: SoC codec 1779 * @codec: SoC codec
1750 * @pin: pin name 1780 * @pin: pin name