diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 78 |
1 files changed, 54 insertions, 24 deletions
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 |