diff options
-rw-r--r-- | include/sound/soc-dapm.h | 2 | ||||
-rw-r--r-- | include/sound/soc.h | 1 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 61 | ||||
-rw-r--r-- | sound/soc/soc-dapm.c | 78 |
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 */ |
280 | int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, | 280 | int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, |
281 | int event); | 281 | int event); |
282 | int 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 */ |
286 | int snd_soc_dapm_sys_add(struct device *dev); | 284 | int 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 | ||
501 | out: | 459 | out: |
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 | */ | ||
106 | static 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 */ |
98 | static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | 122 | static 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 | */ |
708 | static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | 732 | static 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, | |||
1721 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | 1775 | EXPORT_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 | */ | ||
1732 | int 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 |