forked from Minki/linux
ASoC: soc-pcm: tidyup soc_pcm_pointer()'s delay update method
Merge series from Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>: Current soc_pcm_pointer() is checking runtime->delay, but it might be updated silently by component's .point callback. It is strange and difficult to find/know the issue. This patch adds .delay callback for component, and solve the issue.
This commit is contained in:
commit
7be10cef0f
@ -148,6 +148,8 @@ struct snd_soc_component_driver {
|
|||||||
struct vm_area_struct *vma);
|
struct vm_area_struct *vma);
|
||||||
int (*ack)(struct snd_soc_component *component,
|
int (*ack)(struct snd_soc_component *component,
|
||||||
struct snd_pcm_substream *substream);
|
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;
|
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 snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd,
|
||||||
void *stream, int rollback);
|
void *stream, int rollback);
|
||||||
int snd_soc_pcm_component_ack(struct snd_pcm_substream *substream);
|
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 */
|
#endif /* __SOC_COMPONENT_H */
|
||||||
|
@ -208,8 +208,6 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
|
|||||||
struct snd_pcm_substream *substream);
|
struct snd_pcm_substream *substream);
|
||||||
void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
|
void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
|
||||||
struct snd_pcm_substream *substream, int rollback);
|
struct snd_pcm_substream *substream, int rollback);
|
||||||
snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
|
|
||||||
struct snd_pcm_substream *substream);
|
|
||||||
void snd_soc_dai_suspend(struct snd_soc_dai *dai);
|
void snd_soc_dai_suspend(struct snd_soc_dai *dai);
|
||||||
void snd_soc_dai_resume(struct snd_soc_dai *dai);
|
void snd_soc_dai_resume(struct snd_soc_dai *dai);
|
||||||
int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
|
int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
|
||||||
@ -238,6 +236,8 @@ int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||||||
int rollback);
|
int rollback);
|
||||||
int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
|
int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
|
||||||
int cmd);
|
int cmd);
|
||||||
|
void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream,
|
||||||
|
snd_pcm_sframes_t *cpu_delay, snd_pcm_sframes_t *codec_delay);
|
||||||
|
|
||||||
int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
|
int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
|
||||||
struct snd_compr_stream *cstream);
|
struct snd_compr_stream *cstream);
|
||||||
|
@ -1003,6 +1003,7 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component,
|
|||||||
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
struct audio_substream_data *rtd = runtime->private_data;
|
struct audio_substream_data *rtd = runtime->private_data;
|
||||||
|
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
|
||||||
|
|
||||||
if (!rtd)
|
if (!rtd)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -1023,7 +1024,7 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component,
|
|||||||
}
|
}
|
||||||
if (bytescount > 0) {
|
if (bytescount > 0) {
|
||||||
delay = do_div(bytescount, period_bytes);
|
delay = do_div(bytescount, period_bytes);
|
||||||
runtime->delay = bytes_to_frames(runtime, delay);
|
adata->delay += bytes_to_frames(runtime, delay);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buffersize = frames_to_bytes(runtime, runtime->buffer_size);
|
buffersize = frames_to_bytes(runtime, runtime->buffer_size);
|
||||||
@ -1035,6 +1036,17 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component,
|
|||||||
return bytes_to_frames(runtime, pos);
|
return bytes_to_frames(runtime, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static snd_pcm_sframes_t acp_dma_delay(struct snd_soc_component *component,
|
||||||
|
struct snd_pcm_substream *substream)
|
||||||
|
{
|
||||||
|
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
|
||||||
|
snd_pcm_sframes_t delay = adata->delay;
|
||||||
|
|
||||||
|
adata->delay = 0;
|
||||||
|
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
static int acp_dma_prepare(struct snd_soc_component *component,
|
static int acp_dma_prepare(struct snd_soc_component *component,
|
||||||
struct snd_pcm_substream *substream)
|
struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
@ -1198,6 +1210,7 @@ static const struct snd_soc_component_driver acp_asoc_platform = {
|
|||||||
.hw_params = acp_dma_hw_params,
|
.hw_params = acp_dma_hw_params,
|
||||||
.trigger = acp_dma_trigger,
|
.trigger = acp_dma_trigger,
|
||||||
.pointer = acp_dma_pointer,
|
.pointer = acp_dma_pointer,
|
||||||
|
.delay = acp_dma_delay,
|
||||||
.prepare = acp_dma_prepare,
|
.prepare = acp_dma_prepare,
|
||||||
.pcm_construct = acp_dma_new,
|
.pcm_construct = acp_dma_new,
|
||||||
};
|
};
|
||||||
|
@ -151,6 +151,7 @@ struct audio_drv_data {
|
|||||||
struct snd_pcm_substream *capture_i2sbt_stream;
|
struct snd_pcm_substream *capture_i2sbt_stream;
|
||||||
void __iomem *acp_mmio;
|
void __iomem *acp_mmio;
|
||||||
u32 asic_type;
|
u32 asic_type;
|
||||||
|
snd_pcm_sframes_t delay;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -653,10 +653,21 @@ static snd_pcm_uframes_t sst_soc_pointer(struct snd_soc_component *component,
|
|||||||
dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
|
dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
|
||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
substream->runtime->delay = str_info->pcm_delay;
|
|
||||||
return str_info->buffer_ptr;
|
return str_info->buffer_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static snd_pcm_sframes_t sst_soc_delay(struct snd_soc_component *component,
|
||||||
|
struct snd_pcm_substream *substream)
|
||||||
|
{
|
||||||
|
struct sst_runtime_stream *stream = substream->runtime->private_data;
|
||||||
|
struct pcm_stream_info *str_info = &stream->stream_info;
|
||||||
|
|
||||||
|
if (sst_get_stream_status(stream) == SST_PLATFORM_INIT)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return str_info->pcm_delay;
|
||||||
|
}
|
||||||
|
|
||||||
static int sst_soc_pcm_new(struct snd_soc_component *component,
|
static int sst_soc_pcm_new(struct snd_soc_component *component,
|
||||||
struct snd_soc_pcm_runtime *rtd)
|
struct snd_soc_pcm_runtime *rtd)
|
||||||
{
|
{
|
||||||
@ -695,6 +706,7 @@ static const struct snd_soc_component_driver sst_soc_platform_drv = {
|
|||||||
.open = sst_soc_open,
|
.open = sst_soc_open,
|
||||||
.trigger = sst_soc_trigger,
|
.trigger = sst_soc_trigger,
|
||||||
.pointer = sst_soc_pointer,
|
.pointer = sst_soc_pointer,
|
||||||
|
.delay = sst_soc_delay,
|
||||||
.compress_ops = &sst_platform_compress_ops,
|
.compress_ops = &sst_platform_compress_ops,
|
||||||
.pcm_construct = sst_soc_pcm_new,
|
.pcm_construct = sst_soc_pcm_new,
|
||||||
};
|
};
|
||||||
|
@ -932,6 +932,34 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream)
|
|||||||
return 0;
|
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,
|
int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream,
|
||||||
unsigned int cmd, void *arg)
|
unsigned int cmd, void *arg)
|
||||||
{
|
{
|
||||||
|
@ -453,18 +453,6 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
|
|||||||
soc_dai_mark_pop(dai, substream, startup);
|
soc_dai_mark_pop(dai, substream, startup);
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
|
|
||||||
struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
int delay = 0;
|
|
||||||
|
|
||||||
if (dai->driver->ops &&
|
|
||||||
dai->driver->ops->delay)
|
|
||||||
delay = dai->driver->ops->delay(substream, dai);
|
|
||||||
|
|
||||||
return delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
|
int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
|
||||||
struct snd_soc_pcm_runtime *rtd, int num)
|
struct snd_soc_pcm_runtime *rtd, int num)
|
||||||
{
|
{
|
||||||
@ -693,6 +681,34 @@ int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void snd_soc_pcm_dai_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_dai *dai;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We're looking for the delay through the full audio path so it needs to
|
||||||
|
* be the maximum of the DAIs doing transmit and the maximum of the DAIs
|
||||||
|
* doing receive (ie, all CPUs and all CODECs) rather than just the maximum
|
||||||
|
* of all DAIs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* for CPU */
|
||||||
|
for_each_rtd_cpu_dais(rtd, i, dai)
|
||||||
|
if (dai->driver->ops &&
|
||||||
|
dai->driver->ops->delay)
|
||||||
|
*cpu_delay = max(*cpu_delay, dai->driver->ops->delay(substream, dai));
|
||||||
|
|
||||||
|
/* for Codec */
|
||||||
|
for_each_rtd_codec_dais(rtd, i, dai)
|
||||||
|
if (dai->driver->ops &&
|
||||||
|
dai->driver->ops->delay)
|
||||||
|
*codec_delay = max(*codec_delay, dai->driver->ops->delay(substream, dai));
|
||||||
|
}
|
||||||
|
|
||||||
int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
|
int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
|
||||||
struct snd_compr_stream *cstream)
|
struct snd_compr_stream *cstream)
|
||||||
{
|
{
|
||||||
|
@ -1080,41 +1080,22 @@ start_err:
|
|||||||
/*
|
/*
|
||||||
* soc level wrapper for pointer callback
|
* soc level wrapper for pointer callback
|
||||||
* If cpu_dai, codec_dai, component driver has the delay callback, then
|
* If cpu_dai, codec_dai, component driver has the delay callback, then
|
||||||
* the runtime->delay will be updated accordingly.
|
* the runtime->delay will be updated via snd_soc_pcm_component/dai_delay().
|
||||||
*/
|
*/
|
||||||
static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
|
static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
|
||||||
struct snd_soc_dai *cpu_dai;
|
|
||||||
struct snd_soc_dai *codec_dai;
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
snd_pcm_uframes_t offset = 0;
|
snd_pcm_uframes_t offset = 0;
|
||||||
snd_pcm_sframes_t delay = 0;
|
|
||||||
snd_pcm_sframes_t codec_delay = 0;
|
snd_pcm_sframes_t codec_delay = 0;
|
||||||
snd_pcm_sframes_t cpu_delay = 0;
|
snd_pcm_sframes_t cpu_delay = 0;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* clearing the previous total delay */
|
|
||||||
runtime->delay = 0;
|
|
||||||
|
|
||||||
offset = snd_soc_pcm_component_pointer(substream);
|
offset = snd_soc_pcm_component_pointer(substream);
|
||||||
|
|
||||||
/* base delay if assigned in pointer callback */
|
/* should be called *after* snd_soc_pcm_component_pointer() */
|
||||||
delay = runtime->delay;
|
snd_soc_pcm_dai_delay(substream, &cpu_delay, &codec_delay);
|
||||||
|
snd_soc_pcm_component_delay(substream, &cpu_delay, &codec_delay);
|
||||||
|
|
||||||
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
|
runtime->delay = cpu_delay + codec_delay;
|
||||||
cpu_delay = max(cpu_delay,
|
|
||||||
snd_soc_dai_delay(cpu_dai, substream));
|
|
||||||
}
|
|
||||||
delay += cpu_delay;
|
|
||||||
|
|
||||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
|
||||||
codec_delay = max(codec_delay,
|
|
||||||
snd_soc_dai_delay(codec_dai, substream));
|
|
||||||
}
|
|
||||||
delay += codec_delay;
|
|
||||||
|
|
||||||
runtime->delay = delay;
|
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user