summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h2
-rw-r--r--sound/soc/soc-core.c32
-rw-r--r--sound/soc/soc-dapm.c31
3 files changed, 60 insertions, 5 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 55c6d3d1894f..66ff4c124dbd 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -341,6 +341,7 @@ int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin);
int snd_soc_dapm_sync(struct snd_soc_codec *codec);
int snd_soc_dapm_force_enable_pin(struct snd_soc_codec *codec,
const char *pin);
+int snd_soc_dapm_ignore_suspend(struct snd_soc_codec *codec, const char *pin);
/* dapm widget types */
enum snd_soc_dapm_type {
@@ -428,6 +429,7 @@ struct snd_soc_dapm_widget {
unsigned char new:1; /* cnew complete */
unsigned char ext:1; /* has external widgets */
unsigned char force:1; /* force state */
+ unsigned char ignore_suspend:1; /* kept enabled over suspend */
int (*power_check)(struct snd_soc_dapm_widget *w);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 95739767ec45..8661e5b4adb1 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -927,8 +927,19 @@ static int soc_suspend(struct device *dev)
SND_SOC_DAPM_STREAM_SUSPEND);
}
- if (codec_dev->suspend)
- codec_dev->suspend(pdev, PMSG_SUSPEND);
+ /* If there are paths active then the CODEC will be held with
+ * bias _ON and should not be suspended. */
+ if (codec_dev->suspend) {
+ switch (codec->bias_level) {
+ case SND_SOC_BIAS_STANDBY:
+ case SND_SOC_BIAS_OFF:
+ codec_dev->suspend(pdev, PMSG_SUSPEND);
+ break;
+ default:
+ dev_dbg(socdev->dev, "CODEC is on over suspend\n");
+ break;
+ }
+ }
for (i = 0; i < card->num_links; i++) {
struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
@@ -975,8 +986,21 @@ static void soc_resume_deferred(struct work_struct *work)
cpu_dai->resume(cpu_dai);
}
- if (codec_dev->resume)
- codec_dev->resume(pdev);
+ /* If the CODEC was idle over suspend then it will have been
+ * left with bias OFF or STANDBY and suspended so we must now
+ * resume. Otherwise the suspend was suppressed.
+ */
+ if (codec_dev->resume) {
+ switch (codec->bias_level) {
+ case SND_SOC_BIAS_STANDBY:
+ case SND_SOC_BIAS_OFF:
+ codec_dev->resume(pdev);
+ break;
+ default:
+ dev_dbg(socdev->dev, "CODEC was on over suspend\n");
+ break;
+ }
+ }
for (i = 0; i < codec->num_dai; i++) {
char *stream = codec->dai[i].playback.stream_name;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 8c8b291320a8..fefb6c44fc81 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -441,7 +441,9 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
switch (snd_power_get_state(codec->card)) {
case SNDRV_CTL_POWER_D3hot:
case SNDRV_CTL_POWER_D3cold:
- return 0;
+ if (widget->ignore_suspend)
+ pr_debug("%s ignoring suspend\n", widget->name);
+ return widget->ignore_suspend;
default:
return 1;
}
@@ -2137,6 +2139,33 @@ int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin)
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
/**
+ * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
+ * @codec: audio codec
+ * @pin: audio signal pin endpoint (or start point)
+ *
+ * Mark the given endpoint or pin as ignoring suspend. When the
+ * system is disabled a path between two endpoints flagged as ignoring
+ * suspend will not be disabled. The path must already be enabled via
+ * normal means at suspend time, it will not be turned on if it was not
+ * already enabled.
+ */
+int snd_soc_dapm_ignore_suspend(struct snd_soc_codec *codec, const char *pin)
+{
+ struct snd_soc_dapm_widget *w;
+
+ list_for_each_entry(w, &codec->dapm_widgets, list) {
+ if (!strcmp(w->name, pin)) {
+ w->ignore_suspend = 1;
+ return 0;
+ }
+ }
+
+ pr_err("Unknown DAPM pin: %s\n", pin);
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
+
+/**
* snd_soc_dapm_free - free dapm resources
* @socdev: SoC device
*