@@ -43,7 +43,8 @@ static const struct snd_pcm_hardware azx_pcm_hw = {
SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */
SNDRV_PCM_INFO_HAS_LINK_ATIME |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+ SNDRV_PCM_INFO_SYNC_APPLPTR),
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_S24_LE,
@@ -145,6 +146,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
unsigned int format_val;
struct hdac_stream *hstream;
struct hdac_ext_stream *stream;
+ struct snd_pcm_runtime *runtime;
int err;
hstream = snd_hdac_get_stream(bus, params->stream,
@@ -170,6 +172,11 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
if (err < 0)
return err;
+ /* Enable SPIB if no_rewinds flag is set */
+ runtime = hdac_stream(stream)->substream->runtime;
+ if (runtime->no_rewinds)
+ snd_hdac_ext_stream_spbcap_enable(ebus, true, hstream->index);
+
hdac_stream(stream)->prepared = 1;
return 0;
@@ -366,9 +373,14 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
{
struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hdac_stream *hstream = hdac_stream(stream);
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
+ if (runtime->no_rewinds)
+ snd_hdac_ext_stream_spbcap_enable(ebus, false, hstream->index);
+
snd_hdac_stream_cleanup(hdac_stream(stream));
hdac_stream(stream)->prepared = 0;
@@ -444,6 +456,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct skl_module_cfg *mconfig;
struct hdac_ext_bus *ebus = get_bus_ctx(substream);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_dapm_widget *w;
int ret;
@@ -469,6 +482,10 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
snd_hdac_ext_stream_set_dpibr(ebus, stream,
stream->lpib);
snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
+
+ if (runtime->no_rewinds)
+ snd_hdac_ext_stream_set_spib(ebus,
+ stream, stream->spib);
}
case SNDRV_PCM_TRIGGER_START:
@@ -1095,6 +1112,29 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
return 0;
}
+/* Update SPIB register with application position */
+static int skl_platform_ack(struct snd_pcm_substream *substream)
+{
+ struct hdac_ext_stream *estream = get_hdac_ext_stream(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ ssize_t appl_pos, buf_size;
+ u32 spib;
+
+ /* Use spib mode only if no_rewind mode is set */
+ if (!runtime->no_rewinds)
+ return 0;
+
+ appl_pos = frames_to_bytes(runtime, runtime->control->appl_ptr);
+ buf_size = frames_to_bytes(runtime, runtime->buffer_size);
+
+ spib = appl_pos % buf_size;
+
+ /* Allowable value for SPIB is 1 byte to max buffer size */
+ spib = (spib == 0) ? buf_size : spib;
+ return snd_hdac_ext_stream_set_spib(ebus, estream, spib);
+}
+
static snd_pcm_uframes_t skl_platform_pcm_pointer
(struct snd_pcm_substream *substream)
{
@@ -1202,6 +1242,7 @@ static const struct snd_pcm_ops skl_platform_ops = {
.get_time_info = skl_get_time_info,
.mmap = snd_pcm_lib_default_mmap,
.page = snd_pcm_sgbuf_ops_page,
+ .ack = skl_platform_ack,
};
static void skl_pcm_free(struct snd_pcm *pcm)