aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h2
-rw-r--r--include/sound/soc.h1
-rw-r--r--sound/soc/soc-core.c61
-rw-r--r--sound/soc/soc-dapm.c78
4 files changed, 65 insertions, 77 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index b3f789d0cee8..ec8a45f9a069 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -279,8 +279,6 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
279/* dapm events */ 279/* dapm events */
280int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, 280int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
281 int event); 281 int event);
282int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
283 enum snd_soc_bias_level level);
284 282
285/* dapm sys fs - used by the core */ 283/* dapm sys fs - used by the core */
286int snd_soc_dapm_sys_add(struct device *dev); 284int snd_soc_dapm_sys_add(struct device *dev);
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 8309ce81cf3b..2af3213df90c 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -339,6 +339,7 @@ struct snd_soc_codec {
339 struct module *owner; 339 struct module *owner;
340 struct mutex mutex; 340 struct mutex mutex;
341 struct device *dev; 341 struct device *dev;
342 struct snd_soc_device *socdev;
342 343
343 struct list_head list; 344 struct list_head list;
344 345
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