aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2020-06-23 10:17:16 +0100
committerSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2020-06-29 17:15:44 +0100
commit5c3d2360fa50eb8bb9407ff106e1ac056ab827e6 (patch)
treeaf3a94899bb34fd8a5d9116f168c113cccdfd727
parent2ded1144b93ec9ef3a3e3584ad1a766d45bf0a8d (diff)
ASoC: qdsp6-dai: add gapless support
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c349
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.c15
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.h2
3 files changed, 275 insertions, 91 deletions
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 4d642bb657cd..e637fe958c23 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -53,7 +53,7 @@ enum stream_state {
struct q6asm_dai_rtd {
struct snd_pcm_substream *substream;
struct snd_compr_stream *cstream;
- struct snd_compr_params codec_param;
+ struct snd_codec codec;
struct snd_dma_buffer dma_buffer;
spinlock_t lock;
phys_addr_t phys;
@@ -67,12 +67,15 @@ struct q6asm_dai_rtd {
uint16_t bits_per_sample;
uint16_t source; /* Encoding source bit mask */
struct audio_client *audio_client;
+ uint32_t next_track_stream_id;
+ bool next_track;
/* Active */
uint32_t stream_id;
uint16_t session_id;
enum stream_state state;
uint32_t initial_samples_drop;
uint32_t trailing_samples_drop;
+ bool notify_on_drain;
};
struct q6asm_dai_data {
@@ -189,7 +192,7 @@ static void event_handler(uint32_t opcode, uint32_t token,
case ASM_CLIENT_EVENT_CMD_RUN_DONE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
q6asm_write_async(prtd->audio_client, prtd->stream_id,
- prtd->pcm_count, 0, 0, 0);
+ prtd->pcm_count, 0, 0, 0);
break;
case ASM_CLIENT_EVENT_CMD_EOS_DONE:
prtd->state = Q6ASM_STREAM_STOPPED;
@@ -199,7 +202,7 @@ static void event_handler(uint32_t opcode, uint32_t token,
snd_pcm_period_elapsed(substream);
if (prtd->state == Q6ASM_STREAM_RUNNING)
q6asm_write_async(prtd->audio_client, prtd->stream_id,
- prtd->pcm_count, 0, 0, 0);
+ prtd->pcm_count, 0, 0, 0);
break;
}
@@ -509,15 +512,22 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
void *payload, void *priv)
{
struct q6asm_dai_rtd *prtd = priv;
- struct snd_compr_stream *substream = prtd->cstream;
- unsigned long flags;
+ struct snd_compr_stream *stream = prtd->cstream;
+ unsigned long flags = 0;
+ u32 wflags = 0;
uint64_t avail;
- uint32_t bytes_written;
+ uint32_t bytes_written, bytes_to_write;
+ bool is_last_buffer = false;
switch (opcode) {
case ASM_CLIENT_EVENT_CMD_RUN_DONE:
spin_lock_irqsave(&prtd->lock, flags);
if (!prtd->bytes_sent) {
+ q6asm_stream_remove_initial_silence(prtd->audio_client,
+ prtd->stream_id,
+ prtd->initial_samples_drop);
+ avail = prtd->bytes_received - prtd->bytes_sent;
+
q6asm_write_async(prtd->audio_client, prtd->stream_id,
prtd->pcm_count, 0, 0, 0);
prtd->bytes_sent += prtd->pcm_count;
@@ -527,7 +537,23 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
break;
case ASM_CLIENT_EVENT_CMD_EOS_DONE:
- prtd->state = Q6ASM_STREAM_STOPPED;
+ if (prtd->notify_on_drain) {
+ if (stream->partial_drain && prtd->next_track_stream_id) {
+ /* Close old stream and make it stale, switch
+ * the active stream now! */
+ q6asm_cmd_nowait(prtd->audio_client,
+ prtd->stream_id,
+ CMD_CLOSE);
+ prtd->stream_id = prtd->next_track_stream_id;
+ prtd->next_track_stream_id = 0;
+ }
+
+ snd_compr_drain_notify(prtd->cstream);
+ prtd->notify_on_drain = false;
+
+ } else {
+ prtd->state = Q6ASM_STREAM_STOPPED;
+ }
break;
case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
@@ -535,20 +561,41 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
bytes_written = token >> ASM_WRITE_TOKEN_LEN_SHIFT;
prtd->copied_total += bytes_written;
- snd_compr_fragment_elapsed(substream);
- avail = prtd->bytes_received - prtd->bytes_sent;
- if (prtd->state != Q6ASM_STREAM_RUNNING || avail <= 0) {
+ snd_compr_fragment_elapsed(stream);
+
+ if (prtd->state != Q6ASM_STREAM_RUNNING) {
spin_unlock_irqrestore(&prtd->lock, flags);
break;
}
- if (avail >= prtd->pcm_count) {
+ avail = prtd->bytes_received - prtd->bytes_sent;
+ if (avail > prtd->pcm_count) {
+ bytes_to_write = prtd->pcm_count;
+ } else {
+ if (stream->partial_drain || prtd->notify_on_drain)
+ is_last_buffer = true;
+ bytes_to_write = avail;
+ }
+
+ if (bytes_to_write) {
+ if (stream->partial_drain && is_last_buffer) {
+ wflags |= ASM_LAST_BUFFER_FLAG;
+ q6asm_stream_remove_trailing_silence(prtd->audio_client,
+ prtd->stream_id,
+ prtd->trailing_samples_drop);
+ }
+
q6asm_write_async(prtd->audio_client, prtd->stream_id,
- prtd->pcm_count, 0, 0, 0);
- prtd->bytes_sent += prtd->pcm_count;
+ bytes_to_write, 0, 0, wflags);
+
+ prtd->bytes_sent += bytes_to_write;
}
+ if (prtd->notify_on_drain && is_last_buffer)
+ q6asm_cmd_nowait(prtd->audio_client,
+ prtd->stream_id, CMD_EOS);
+
spin_unlock_irqrestore(&prtd->lock, flags);
break;
@@ -606,7 +653,6 @@ static int q6asm_dai_compr_open(struct snd_soc_component *component,
else
prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
- snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
spin_lock_init(&prtd->lock);
runtime->private_data = prtd;
@@ -628,9 +674,15 @@ static int q6asm_dai_compr_free(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd = stream->private_data;
if (prtd->audio_client) {
- if (prtd->state)
+ if (prtd->state) {
q6asm_cmd(prtd->audio_client, prtd->stream_id,
CMD_CLOSE);
+ if (prtd->next_track_stream_id) {
+ q6asm_cmd(prtd->audio_client,
+ prtd->next_track_stream_id,
+ CMD_CLOSE);
+ }
+ }
snd_dma_free_pages(&prtd->dma_buffer);
q6asm_unmap_memory_regions(stream->direction,
@@ -644,21 +696,20 @@ static int q6asm_dai_compr_free(struct snd_soc_component *component,
return 0;
}
-static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
- struct snd_compr_stream *stream,
- struct snd_compr_params *params)
+static int __q6asm_dai_compr_set_codec_params(struct snd_compr_stream *stream,
+ struct snd_codec *codec,
+ int stream_id)
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- int dir = stream->direction;
- struct q6asm_dai_data *pdata;
+ struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct q6asm_flac_cfg flac_cfg;
struct q6asm_wma_cfg wma_cfg;
struct q6asm_alac_cfg alac_cfg;
struct q6asm_ape_cfg ape_cfg;
unsigned int wma_v9 = 0;
- struct device *dev = component->dev;
+ struct device *dev = c->dev;
int ret;
union snd_codec_options *codec_options;
struct snd_dec_flac *flac;
@@ -666,53 +717,18 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
struct snd_dec_alac *alac;
struct snd_dec_ape *ape;
- codec_options = &(prtd->codec_param.codec.options);
-
-
- memcpy(&prtd->codec_param, params, sizeof(*params));
-
- pdata = snd_soc_component_get_drvdata(component);
- if (!pdata)
- return -EINVAL;
-
- if (!prtd || !prtd->audio_client) {
- dev_err(dev, "private data null or audio client freed\n");
- return -EINVAL;
- }
-
- prtd->periods = runtime->fragments;
- prtd->pcm_count = runtime->fragment_size;
- prtd->pcm_size = runtime->fragments * runtime->fragment_size;
- prtd->bits_per_sample = 16;
- if (dir == SND_COMPRESS_PLAYBACK) {
- ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
- params->codec.id, params->codec.profile,
- prtd->bits_per_sample, true);
+ codec_options = &(prtd->codec.options);
- if (ret < 0) {
- dev_err(dev, "q6asm_open_write failed\n");
- q6asm_audio_client_free(prtd->audio_client);
- prtd->audio_client = NULL;
- return ret;
- }
- }
+ memcpy(&prtd->codec, codec, sizeof(*codec));
- prtd->session_id = q6asm_get_session_id(prtd->audio_client);
- ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
- prtd->session_id, dir);
- if (ret) {
- dev_err(dev, "Stream reg failed ret:%d\n", ret);
- return ret;
- }
-
- switch (params->codec.id) {
+ switch (codec->id) {
case SND_AUDIOCODEC_FLAC:
memset(&flac_cfg, 0x0, sizeof(struct q6asm_flac_cfg));
flac = &codec_options->flac_d;
- flac_cfg.ch_cfg = params->codec.ch_in;
- flac_cfg.sample_rate = params->codec.sample_rate;
+ flac_cfg.ch_cfg = codec->ch_in;
+ flac_cfg.sample_rate = codec->sample_rate;
flac_cfg.stream_info_present = 1;
flac_cfg.sample_size = flac->sample_size;
flac_cfg.min_blk_size = flac->min_blk_size;
@@ -721,7 +737,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
flac_cfg.min_frame_size = flac->min_frame_size;
ret = q6asm_stream_media_format_block_flac(prtd->audio_client,
- prtd->stream_id,
+ stream_id,
&flac_cfg);
if (ret < 0) {
dev_err(dev, "FLAC CMD Format block failed:%d\n", ret);
@@ -734,10 +750,10 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
memset(&wma_cfg, 0x0, sizeof(struct q6asm_wma_cfg));
- wma_cfg.sample_rate = params->codec.sample_rate;
- wma_cfg.num_channels = params->codec.ch_in;
- wma_cfg.bytes_per_sec = params->codec.bit_rate / 8;
- wma_cfg.block_align = params->codec.align;
+ wma_cfg.sample_rate = codec->sample_rate;
+ wma_cfg.num_channels = codec->ch_in;
+ wma_cfg.bytes_per_sec = codec->bit_rate / 8;
+ wma_cfg.block_align = codec->align;
wma_cfg.bits_per_sample = prtd->bits_per_sample;
wma_cfg.enc_options = wma->encoder_option;
wma_cfg.adv_enc_options = wma->adv_encoder_option;
@@ -751,7 +767,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
return -EINVAL;
/* check the codec profile */
- switch (params->codec.profile) {
+ switch (codec->profile) {
case SND_AUDIOPROFILE_WMA9:
wma_cfg.fmtag = 0x161;
wma_v9 = 1;
@@ -775,17 +791,17 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
default:
dev_err(dev, "Unknown WMA profile:%x\n",
- params->codec.profile);
+ codec->profile);
return -EIO;
}
if (wma_v9)
ret = q6asm_stream_media_format_block_wma_v9(
- prtd->audio_client, prtd->stream_id,
+ prtd->audio_client, stream_id,
&wma_cfg);
else
ret = q6asm_stream_media_format_block_wma_v10(
- prtd->audio_client, prtd->stream_id,
+ prtd->audio_client, stream_id,
&wma_cfg);
if (ret < 0) {
dev_err(dev, "WMA9 CMD failed:%d\n", ret);
@@ -797,10 +813,10 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
memset(&alac_cfg, 0x0, sizeof(alac_cfg));
alac = &codec_options->alac_d;
- alac_cfg.sample_rate = params->codec.sample_rate;
- alac_cfg.avg_bit_rate = params->codec.bit_rate;
+ alac_cfg.sample_rate = codec->sample_rate;
+ alac_cfg.avg_bit_rate = codec->bit_rate;
alac_cfg.bit_depth = prtd->bits_per_sample;
- alac_cfg.num_channels = params->codec.ch_in;
+ alac_cfg.num_channels = codec->ch_in;
alac_cfg.frame_length = alac->frame_length;
alac_cfg.pb = alac->pb;
@@ -810,7 +826,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
alac_cfg.compatible_version = alac->compatible_version;
alac_cfg.max_frame_bytes = alac->max_frame_bytes;
- switch (params->codec.ch_in) {
+ switch (codec->ch_in) {
case 1:
alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_MONO;
break;
@@ -819,7 +835,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
break;
}
ret = q6asm_stream_media_format_block_alac(prtd->audio_client,
- prtd->stream_id,
+ stream_id,
&alac_cfg);
if (ret < 0) {
dev_err(dev, "ALAC CMD Format block failed:%d\n", ret);
@@ -831,8 +847,8 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
memset(&ape_cfg, 0x0, sizeof(ape_cfg));
ape = &codec_options->ape_d;
- ape_cfg.sample_rate = params->codec.sample_rate;
- ape_cfg.num_channels = params->codec.ch_in;
+ ape_cfg.sample_rate = codec->sample_rate;
+ ape_cfg.num_channels = codec->ch_in;
ape_cfg.bits_per_sample = prtd->bits_per_sample;
ape_cfg.compatible_version = ape->compatible_version;
@@ -844,7 +860,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
ape_cfg.seek_table_present = ape->seek_table_present;
ret = q6asm_stream_media_format_block_ape(prtd->audio_client,
- prtd->stream_id,
+ stream_id,
&ape_cfg);
if (ret < 0) {
dev_err(dev, "APE CMD Format block failed:%d\n", ret);
@@ -856,6 +872,98 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
break;
}
+ return 0;
+}
+
+static int q6asm_dai_compr_set_codec_params(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_codec *codec)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ int ret;
+
+ ret = q6asm_open_write(prtd->audio_client, prtd->next_track_stream_id,
+ codec->id, codec->profile, prtd->bits_per_sample,
+ true);
+ if (ret < 0) {
+ dev_err(component->dev, "q6asm_open_write failed\n");
+ return ret;
+ }
+
+ ret = __q6asm_dai_compr_set_codec_params(stream, codec,
+ prtd->next_track_stream_id);
+ if (ret < 0) {
+ dev_err(component->dev, "q6asm_open_write failed\n");
+ return ret;
+ }
+
+ return q6asm_stream_remove_initial_silence(prtd->audio_client,
+ prtd->next_track_stream_id,
+ prtd->initial_samples_drop);
+}
+
+static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_params *params)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ int dir = stream->direction;
+ struct q6asm_dai_data *pdata;
+ struct device *dev = c->dev;
+ int ret;
+ union snd_codec_options *codec_options;
+
+ codec_options = &(prtd->codec.options);
+
+
+ memcpy(&prtd->codec, &params->codec, sizeof(params->codec));
+
+ pdata = snd_soc_component_get_drvdata(c);
+ if (!pdata)
+ return -EINVAL;
+
+ if (!prtd || !prtd->audio_client) {
+ dev_err(dev, "private data null or audio client freed\n");
+ return -EINVAL;
+ }
+
+ prtd->periods = runtime->fragments;
+ prtd->pcm_count = runtime->fragment_size;
+ prtd->pcm_size = runtime->fragments * runtime->fragment_size;
+ prtd->bits_per_sample = 16;
+
+ if (dir == SND_COMPRESS_PLAYBACK) {
+ ret = q6asm_open_write(prtd->audio_client, prtd->stream_id, params->codec.id,
+ params->codec.profile, prtd->bits_per_sample,
+ true);
+
+ if (ret < 0) {
+ dev_err(dev, "q6asm_open_write failed\n");
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return ret;
+ }
+ }
+
+ prtd->session_id = q6asm_get_session_id(prtd->audio_client);
+ ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
+ prtd->session_id, dir);
+ if (ret) {
+ dev_err(dev, "Stream reg failed ret:%d\n", ret);
+ return ret;
+ }
+
+ ret = __q6asm_dai_compr_set_codec_params(stream, &prtd->codec,
+ prtd->stream_id);
+ if (ret) {
+ dev_err(dev, "codec param setup failed ret:%d\n", ret);
+ return ret;
+ }
+
ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
(prtd->pcm_size / prtd->periods),
prtd->periods);
@@ -870,7 +978,8 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
return 0;
}
-static int q6asm_dai_compr_set_metadata(struct snd_compr_stream *stream,
+static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
struct snd_compr_metadata *metadata)
{
struct snd_compr_runtime *runtime = stream->runtime;
@@ -916,6 +1025,17 @@ static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
CMD_PAUSE);
break;
+ case SND_COMPR_TRIGGER_NEXT_TRACK:
+ /* Get Next stream id
+ open it
+ */
+ prtd->next_track = true;
+ prtd->next_track_stream_id = (prtd->stream_id == 1 ? 2 : 1);
+ break;
+ case SND_COMPR_TRIGGER_DRAIN:
+ case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
+ prtd->notify_on_drain = true;
+ break;
default:
ret = -EINVAL;
break;
@@ -942,16 +1062,76 @@ static int q6asm_dai_compr_pointer(struct snd_soc_component *component,
return 0;
}
-static int q6asm_dai_compr_ack(struct snd_soc_component *component,
- struct snd_compr_stream *stream,
- size_t count)
+static int q6asm_compr_copy(struct snd_soc_component *component,
+ struct snd_compr_stream *stream, char __user *buf,
+ size_t count)
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
unsigned long flags;
+ u32 wflags = 0;
+ int avail, bytes_in_flight = 0;
+ void *dstn;
+ size_t copy;
+ u32 app_pointer;
+ u32 bytes_received;
+
+
+ bytes_received = prtd->bytes_received;
+
+ /**
+ * Make sure that next track data pointer is aligned at 32 bit boundary
+ * This is a Mandatory requirement from DSP data buffers alignment
+ */
+ if (prtd->next_track)
+ bytes_received= ALIGN(prtd->bytes_received, prtd->pcm_count);
+
+ app_pointer = bytes_received/prtd->pcm_size;
+ app_pointer = bytes_received - (app_pointer * prtd->pcm_size);
+ dstn = prtd->dma_buffer.area + app_pointer;
+
+ if (count < prtd->pcm_size - app_pointer) {
+ if (copy_from_user(dstn, buf, count))
+ return -EFAULT;
+ } else {
+ copy = prtd->pcm_size - app_pointer;
+ if (copy_from_user(dstn, buf, copy))
+ return -EFAULT;
+ if (copy_from_user(prtd->dma_buffer.area, buf + copy,
+ count - copy))
+ return -EFAULT;
+ }
spin_lock_irqsave(&prtd->lock, flags);
+
+ bytes_in_flight = prtd->bytes_received - prtd->copied_total;
+
+ if (prtd->next_track) {
+ /* Adjust the bytes sent and copied as per new aligment */
+ prtd->next_track = false;
+ prtd->bytes_received= ALIGN(prtd->bytes_received, prtd->pcm_count);
+ prtd->copied_total= ALIGN(prtd->copied_total, prtd->pcm_count);
+ prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
+ }
prtd->bytes_received += count;
+
+ /* Kick off the data to dsp if its starving!! */
+ if (prtd->state == Q6ASM_STREAM_RUNNING && (bytes_in_flight == 0)) {
+ uint32_t bytes_to_write = prtd->pcm_count;
+
+ avail = prtd->bytes_received - prtd->bytes_sent;
+
+ if (avail > prtd->pcm_count) {
+ bytes_to_write = prtd->pcm_count;
+ } else {
+ bytes_to_write = avail;
+ }
+
+ q6asm_write_async(prtd->audio_client, prtd->stream_id,
+ bytes_to_write, 0, 0, wflags);
+ prtd->bytes_sent += bytes_to_write;
+ }
+
spin_unlock_irqrestore(&prtd->lock, flags);
return count;
@@ -1008,13 +1188,14 @@ static struct snd_compress_ops q6asm_dai_compress_ops = {
.open = q6asm_dai_compr_open,
.free = q6asm_dai_compr_free,
.set_params = q6asm_dai_compr_set_params,
+ .set_codec_params = q6asm_dai_compr_set_codec_params,
.set_metadata = q6asm_dai_compr_set_metadata,
.pointer = q6asm_dai_compr_pointer,
.trigger = q6asm_dai_compr_trigger,
.get_caps = q6asm_dai_compr_get_caps,
.get_codec_caps = q6asm_dai_compr_get_codec_caps,
.mmap = q6asm_dai_compr_mmap,
- .ack = q6asm_dai_compr_ack,
+ .copy = q6asm_compr_copy,
};
static int q6asm_dai_pcm_new(struct snd_soc_component *component,
@@ -1079,7 +1260,7 @@ static const struct snd_soc_component_driver q6asm_fe_dai_component = {
.mmap = q6asm_dai_mmap,
.pcm_construct = q6asm_dai_pcm_new,
.pcm_destruct = q6asm_dai_pcm_free,
- .compress_ops = &q6asm_dai_compress_ops,
+ .compress_ops =&q6asm_dai_compress_ops,
};
static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index 891bfeb74451..c663b9308144 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -654,8 +654,8 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
}
break;
default:
- dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
- result->opcode);
+ dev_err(ac->dev, "command[0x%x] not expecting rsp status [0x%x]\n",
+ result->opcode, result->status);
break;
}
@@ -675,6 +675,7 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
phys_addr_t phys;
unsigned long flags;
int token = hdr->token & ASM_WRITE_TOKEN_MASK;
+ struct audio_buffer *ab;
spin_lock_irqsave(&ac->lock, flags);
@@ -686,12 +687,13 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
goto done;
}
- phys = port->buf[token].phys;
+ ab = &port->buf[token];
+ phys = ab->phys;
- if (lower_32_bits(phys) != result->opcode ||
+ if (lower_32_bits(phys) != (result->opcode) ||
upper_32_bits(phys) != result->status) {
dev_err(ac->dev, "Expected addr %pa\n",
- &port->buf[token].phys);
+ &phys);
spin_unlock_irqrestore(&ac->lock, flags);
ret = -EINVAL;
goto done;
@@ -1604,7 +1606,8 @@ int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
write->flags = wflags;
- port->dsp_buf++;
+ if (len)
+ port->dsp_buf++;
if (port->dsp_buf >= port->num_periods)
port->dsp_buf = 0;
diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
index 287143454a52..34e01826e549 100644
--- a/sound/soc/qcom/qdsp6/q6asm.h
+++ b/sound/soc/qcom/qdsp6/q6asm.h
@@ -32,7 +32,7 @@ enum {
};
#define MAX_SESSIONS 8
-#define NO_TIMESTAMP 0xFF00
+#define ASM_LAST_BUFFER_FLAG BIT(30)
#define FORMAT_LINEAR_PCM 0x0000
struct q6asm_flac_cfg {