aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-component.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-component.c')
-rw-r--r--sound/soc/soc-component.c75
1 files changed, 72 insertions, 3 deletions
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index f0b4f4bc44a4..728e93f35ffb 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -9,6 +9,7 @@
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
//
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <sound/soc.h>
#define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret)
@@ -33,6 +34,14 @@ static inline int _soc_component_ret(struct snd_soc_component *component,
return ret;
}
+/*
+ * We might want to check substream by using list.
+ * In such case, we can update these macros.
+ */
+#define soc_component_mark_push(component, substream, tgt) ((component)->mark_##tgt = substream)
+#define soc_component_mark_pop(component, substream, tgt) ((component)->mark_##tgt = NULL)
+#define soc_component_mark_match(component, substream, tgt) ((component)->mark_##tgt == substream)
+
void snd_soc_component_set_aux(struct snd_soc_component *component,
struct snd_soc_aux_dev *aux)
{
@@ -238,6 +247,7 @@ int snd_soc_component_set_jack(struct snd_soc_component *component,
EXPORT_SYMBOL_GPL(snd_soc_component_set_jack);
int snd_soc_component_module_get(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
int upon_open)
{
int ret = 0;
@@ -246,14 +256,25 @@ int snd_soc_component_module_get(struct snd_soc_component *component,
!try_module_get(component->dev->driver->owner))
ret = -ENODEV;
+ /* mark substream if succeeded */
+ if (ret == 0)
+ soc_component_mark_push(component, substream, module);
+
return soc_component_ret(component, ret);
}
void snd_soc_component_module_put(struct snd_soc_component *component,
- int upon_open)
+ struct snd_pcm_substream *substream,
+ int upon_open, int rollback)
{
+ if (rollback && !soc_component_mark_match(component, substream, module))
+ return;
+
if (component->driver->module_get_upon_open == !!upon_open)
module_put(component->dev->driver->owner);
+
+ /* remove marked substream */
+ soc_component_mark_pop(component, substream, module);
}
int snd_soc_component_open(struct snd_soc_component *component,
@@ -264,17 +285,28 @@ int snd_soc_component_open(struct snd_soc_component *component,
if (component->driver->open)
ret = component->driver->open(component, substream);
+ /* mark substream if succeeded */
+ if (ret == 0)
+ soc_component_mark_push(component, substream, open);
+
return soc_component_ret(component, ret);
}
int snd_soc_component_close(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
+ struct snd_pcm_substream *substream,
+ int rollback)
{
int ret = 0;
+ if (rollback && !soc_component_mark_match(component, substream, open))
+ return 0;
+
if (component->driver->close)
ret = component->driver->close(component, substream);
+ /* remove marked substream */
+ soc_component_mark_pop(component, substream, open);
+
return soc_component_ret(component, ret);
}
@@ -406,7 +438,7 @@ static unsigned int soc_component_read_no_lock(
ret = -EIO;
if (ret < 0)
- soc_component_ret(component, ret);
+ return soc_component_ret(component, ret);
return val;
}
@@ -805,3 +837,40 @@ int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream,
return 0;
}
+
+int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd,
+ void *stream)
+{
+ struct snd_soc_component *component;
+ int i, ret;
+
+ for_each_rtd_components(rtd, i, component) {
+ ret = pm_runtime_get_sync(component->dev);
+ if (ret < 0 && ret != -EACCES) {
+ pm_runtime_put_noidle(component->dev);
+ return soc_component_ret(component, ret);
+ }
+ /* mark stream if succeeded */
+ soc_component_mark_push(component, stream, pm);
+ }
+
+ return 0;
+}
+
+void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd,
+ void *stream, int rollback)
+{
+ struct snd_soc_component *component;
+ int i;
+
+ for_each_rtd_components(rtd, i, component) {
+ if (rollback && !soc_component_mark_match(component, stream, pm))
+ continue;
+
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
+
+ /* remove marked stream */
+ soc_component_mark_pop(component, stream, pm);
+ }
+}