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);
|
||||
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 */
|
||||
|
@ -208,8 +208,6 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream);
|
||||
void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
|
||||
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_resume(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 snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
|
||||
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,
|
||||
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 audio_substream_data *rtd = runtime->private_data;
|
||||
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
|
||||
|
||||
if (!rtd)
|
||||
return -EINVAL;
|
||||
@ -1023,7 +1024,7 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component,
|
||||
}
|
||||
if (bytescount > 0) {
|
||||
delay = do_div(bytescount, period_bytes);
|
||||
runtime->delay = bytes_to_frames(runtime, delay);
|
||||
adata->delay += bytes_to_frames(runtime, delay);
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
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,
|
||||
.trigger = acp_dma_trigger,
|
||||
.pointer = acp_dma_pointer,
|
||||
.delay = acp_dma_delay,
|
||||
.prepare = acp_dma_prepare,
|
||||
.pcm_construct = acp_dma_new,
|
||||
};
|
||||
|
@ -151,6 +151,7 @@ struct audio_drv_data {
|
||||
struct snd_pcm_substream *capture_i2sbt_stream;
|
||||
void __iomem *acp_mmio;
|
||||
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);
|
||||
return ret_val;
|
||||
}
|
||||
substream->runtime->delay = str_info->pcm_delay;
|
||||
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,
|
||||
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,
|
||||
.trigger = sst_soc_trigger,
|
||||
.pointer = sst_soc_pointer,
|
||||
.delay = sst_soc_delay,
|
||||
.compress_ops = &sst_platform_compress_ops,
|
||||
.pcm_construct = sst_soc_pcm_new,
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -453,18 +453,6 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
struct snd_compr_stream *cstream)
|
||||
{
|
||||
|
@ -1080,41 +1080,22 @@ start_err:
|
||||
/*
|
||||
* soc level wrapper for pointer callback
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
snd_pcm_uframes_t offset = 0;
|
||||
snd_pcm_sframes_t delay = 0;
|
||||
snd_pcm_sframes_t codec_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);
|
||||
|
||||
/* 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);
|
||||
|
||||
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
|
||||
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;
|
||||
runtime->delay = cpu_delay + codec_delay;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user