summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-component.h4
-rw-r--r--sound/soc/soc-component.c28
-rw-r--r--sound/soc/soc-pcm.c2
3 files changed, 34 insertions, 0 deletions
diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h
index a4317144ab62..a52080407b98 100644
--- a/include/sound/soc-component.h
+++ b/include/sound/soc-component.h
@@ -148,6 +148,8 @@ struct snd_soc_component_driver {
struct vm_area_struct *vma);
int (*ack)(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
+ snd_pcm_sframes_t (*delay)(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream);
const struct snd_compress_ops *compress_ops;
@@ -505,5 +507,7 @@ int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd,
void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd,
void *stream, int rollback);
int snd_soc_pcm_component_ack(struct snd_pcm_substream *substream);
+void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream,
+ snd_pcm_sframes_t *cpu_delay, snd_pcm_sframes_t *codec_delay);
#endif /* __SOC_COMPONENT_H */
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index c76ff9c59dfb..c0664f94990c 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -932,6 +932,34 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream)
return 0;
}
+void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream,
+ snd_pcm_sframes_t *cpu_delay,
+ snd_pcm_sframes_t *codec_delay)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_component *component;
+ snd_pcm_sframes_t delay;
+ int i;
+
+ /*
+ * We're looking for the delay through the full audio path so it needs to
+ * be the maximum of the Components doing transmit and the maximum of the
+ * Components doing receive (ie, all CPUs and all CODECs) rather than
+ * just the maximum of all Components.
+ */
+ for_each_rtd_components(rtd, i, component) {
+ if (!component->driver->delay)
+ continue;
+
+ delay = component->driver->delay(component, substream);
+
+ if (snd_soc_component_is_codec(component))
+ *codec_delay = max(*codec_delay, delay);
+ else
+ *cpu_delay = max(*cpu_delay, delay);
+ }
+}
+
int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 82fd170e16af..493d231a2ffd 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1098,7 +1098,9 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
/* base delay if assigned in pointer callback */
delay = runtime->delay;
+ /* should be called *after* snd_soc_pcm_component_pointer() */
snd_soc_pcm_dai_delay(substream, &cpu_delay, &codec_delay);
+ snd_soc_pcm_component_delay(substream, &cpu_delay, &codec_delay);
runtime->delay = delay + cpu_delay + codec_delay;