Lines Matching +full:q6apm +full:- +full:dais

1 // SPDX-License-Identifier: GPL-2.0
10 #include <sound/soc-dapm.h>
14 #include <linux/dma-mapping.h>
17 #include "q6apm.h"
19 #define DRV_NAME "q6apm-dai"
129 struct snd_pcm_substream *substream = prtd->substream; in event_handler()
134 prtd->state = Q6APM_STREAM_STOPPED; in event_handler()
137 spin_lock_irqsave(&prtd->lock, flags); in event_handler()
138 prtd->pos += prtd->pcm_count; in event_handler()
139 spin_unlock_irqrestore(&prtd->lock, flags); in event_handler()
141 if (prtd->state == Q6APM_STREAM_RUNNING) in event_handler()
142 q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0); in event_handler()
146 spin_lock_irqsave(&prtd->lock, flags); in event_handler()
147 prtd->pos += prtd->pcm_count; in event_handler()
148 spin_unlock_irqrestore(&prtd->lock, flags); in event_handler()
150 if (prtd->state == Q6APM_STREAM_RUNNING) in event_handler()
151 q6apm_read(prtd->graph); in event_handler()
163 struct snd_compr_stream *substream = prtd->cstream; in event_handler_compr()
172 spin_lock_irqsave(&prtd->lock, flags); in event_handler_compr()
173 if (prtd->notify_on_drain) { in event_handler_compr()
174 snd_compr_drain_notify(prtd->cstream); in event_handler_compr()
175 prtd->notify_on_drain = false; in event_handler_compr()
177 prtd->state = Q6APM_STREAM_STOPPED; in event_handler_compr()
179 spin_unlock_irqrestore(&prtd->lock, flags); in event_handler_compr()
182 spin_lock_irqsave(&prtd->lock, flags); in event_handler_compr()
184 prtd->copied_total += bytes_written; in event_handler_compr()
187 if (prtd->state != Q6APM_STREAM_RUNNING) { in event_handler_compr()
188 spin_unlock_irqrestore(&prtd->lock, flags); in event_handler_compr()
192 avail = prtd->bytes_received - prtd->bytes_sent; in event_handler_compr()
194 if (avail > prtd->pcm_count) { in event_handler_compr()
195 bytes_to_write = prtd->pcm_count; in event_handler_compr()
197 if (substream->partial_drain || prtd->notify_on_drain) in event_handler_compr()
203 if (substream->partial_drain && is_last_buffer) in event_handler_compr()
206 q6apm_write_async(prtd->graph, in event_handler_compr()
209 prtd->bytes_sent += bytes_to_write; in event_handler_compr()
211 if (prtd->notify_on_drain && is_last_buffer) in event_handler_compr()
212 audioreach_shared_memory_send_eos(prtd->graph); in event_handler_compr()
215 spin_unlock_irqrestore(&prtd->lock, flags); in event_handler_compr()
225 struct snd_pcm_runtime *runtime = substream->runtime; in q6apm_dai_prepare()
226 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_prepare()
228 struct device *dev = component->dev; in q6apm_dai_prepare()
234 return -EINVAL; in q6apm_dai_prepare()
236 if (!prtd || !prtd->graph) { in q6apm_dai_prepare()
238 return -EINVAL; in q6apm_dai_prepare()
241 cfg.direction = substream->stream; in q6apm_dai_prepare()
242 cfg.sample_rate = runtime->rate; in q6apm_dai_prepare()
243 cfg.num_channels = runtime->channels; in q6apm_dai_prepare()
244 cfg.bit_width = prtd->bits_per_sample; in q6apm_dai_prepare()
247 if (prtd->state) { in q6apm_dai_prepare()
249 q6apm_graph_stop(prtd->graph); in q6apm_dai_prepare()
250 q6apm_unmap_memory_regions(prtd->graph, substream->stream); in q6apm_dai_prepare()
253 prtd->pcm_count = snd_pcm_lib_period_bytes(substream); in q6apm_dai_prepare()
254 prtd->pos = 0; in q6apm_dai_prepare()
256 ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg); in q6apm_dai_prepare()
262 ret = q6apm_graph_media_format_pcm(prtd->graph, &cfg); in q6apm_dai_prepare()
266 ret = q6apm_map_memory_regions(prtd->graph, substream->stream, prtd->phys, in q6apm_dai_prepare()
267 (prtd->pcm_size / prtd->periods), prtd->periods); in q6apm_dai_prepare()
271 return -ENOMEM; in q6apm_dai_prepare()
274 ret = q6apm_graph_prepare(prtd->graph); in q6apm_dai_prepare()
280 ret = q6apm_graph_start(prtd->graph); in q6apm_dai_prepare()
286 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { in q6apm_dai_prepare()
289 for (i = 0; i < runtime->periods; i++) in q6apm_dai_prepare()
290 q6apm_read(prtd->graph); in q6apm_dai_prepare()
295 prtd->state = Q6APM_STREAM_RUNNING; in q6apm_dai_prepare()
303 struct snd_pcm_runtime *runtime = substream->runtime; in q6apm_dai_trigger()
304 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_trigger()
312 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) in q6apm_dai_trigger()
313 ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0); in q6apm_dai_trigger()
317 prtd->state = Q6APM_STREAM_STOPPED; in q6apm_dai_trigger()
323 ret = -EINVAL; in q6apm_dai_trigger()
333 struct snd_pcm_runtime *runtime = substream->runtime; in q6apm_dai_open()
334 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; in q6apm_dai_open()
336 struct device *dev = component->dev; in q6apm_dai_open()
341 graph_id = cpu_dai->driver->id; in q6apm_dai_open()
346 return -EINVAL; in q6apm_dai_open()
351 return -ENOMEM; in q6apm_dai_open()
353 spin_lock_init(&prtd->lock); in q6apm_dai_open()
354 prtd->substream = substream; in q6apm_dai_open()
355 prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler, prtd, graph_id); in q6apm_dai_open()
356 if (IS_ERR(prtd->graph)) { in q6apm_dai_open()
358 ret = PTR_ERR(prtd->graph); in q6apm_dai_open()
362 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) in q6apm_dai_open()
363 runtime->hw = q6apm_dai_hardware_playback; in q6apm_dai_open()
364 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) in q6apm_dai_open()
365 runtime->hw = q6apm_dai_hardware_capture; in q6apm_dai_open()
374 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { in q6apm_dai_open()
395 runtime->private_data = prtd; in q6apm_dai_open()
396 runtime->dma_bytes = BUFFER_BYTES_MAX; in q6apm_dai_open()
397 if (pdata->sid < 0) in q6apm_dai_open()
398 prtd->phys = substream->dma_buffer.addr; in q6apm_dai_open()
400 prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32); in q6apm_dai_open()
412 struct snd_pcm_runtime *runtime = substream->runtime; in q6apm_dai_close()
413 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_close()
415 if (prtd->state) { /* only stop graph that is started */ in q6apm_dai_close()
416 q6apm_graph_stop(prtd->graph); in q6apm_dai_close()
417 q6apm_unmap_memory_regions(prtd->graph, substream->stream); in q6apm_dai_close()
420 q6apm_graph_close(prtd->graph); in q6apm_dai_close()
421 prtd->graph = NULL; in q6apm_dai_close()
423 runtime->private_data = NULL; in q6apm_dai_close()
431 struct snd_pcm_runtime *runtime = substream->runtime; in q6apm_dai_pointer()
432 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_pointer()
436 spin_lock_irqsave(&prtd->lock, flags); in q6apm_dai_pointer()
437 if (prtd->pos == prtd->pcm_size) in q6apm_dai_pointer()
438 prtd->pos = 0; in q6apm_dai_pointer()
440 ptr = bytes_to_frames(runtime, prtd->pos); in q6apm_dai_pointer()
441 spin_unlock_irqrestore(&prtd->lock, flags); in q6apm_dai_pointer()
450 struct snd_pcm_runtime *runtime = substream->runtime; in q6apm_dai_hw_params()
451 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_hw_params()
453 prtd->pcm_size = params_buffer_bytes(params); in q6apm_dai_hw_params()
454 prtd->periods = params_periods(params); in q6apm_dai_hw_params()
458 prtd->bits_per_sample = 16; in q6apm_dai_hw_params()
461 prtd->bits_per_sample = 24; in q6apm_dai_hw_params()
464 return -EINVAL; in q6apm_dai_hw_params()
474 return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, component->dev, size); in q6apm_dai_pcm_new()
480 struct snd_soc_pcm_runtime *rtd = stream->private_data; in q6apm_dai_compr_open()
482 struct snd_compr_runtime *runtime = stream->runtime; in q6apm_dai_compr_open()
485 struct device *dev = component->dev; in q6apm_dai_compr_open()
489 graph_id = cpu_dai->driver->id; in q6apm_dai_compr_open()
492 return -EINVAL; in q6apm_dai_compr_open()
496 return -ENOMEM; in q6apm_dai_compr_open()
498 prtd->cstream = stream; in q6apm_dai_compr_open()
499 prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler_compr, prtd, graph_id); in q6apm_dai_compr_open()
500 if (IS_ERR(prtd->graph)) { in q6apm_dai_compr_open()
501 ret = PTR_ERR(prtd->graph); in q6apm_dai_compr_open()
506 runtime->private_data = prtd; in q6apm_dai_compr_open()
507 runtime->dma_bytes = BUFFER_BYTES_MAX; in q6apm_dai_compr_open()
509 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, &prtd->dma_buffer); in q6apm_dai_compr_open()
513 if (pdata->sid < 0) in q6apm_dai_compr_open()
514 prtd->phys = prtd->dma_buffer.addr; in q6apm_dai_compr_open()
516 prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32); in q6apm_dai_compr_open()
518 snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer); in q6apm_dai_compr_open()
519 spin_lock_init(&prtd->lock); in q6apm_dai_compr_open()
521 q6apm_enable_compress_module(dev, prtd->graph, true); in q6apm_dai_compr_open()
528 struct snd_compr_runtime *runtime = stream->runtime; in q6apm_dai_compr_free()
529 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_compr_free()
531 q6apm_graph_stop(prtd->graph); in q6apm_dai_compr_free()
532 q6apm_unmap_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK); in q6apm_dai_compr_free()
533 q6apm_graph_close(prtd->graph); in q6apm_dai_compr_free()
534 snd_dma_free_pages(&prtd->dma_buffer); in q6apm_dai_compr_free()
535 prtd->graph = NULL; in q6apm_dai_compr_free()
537 runtime->private_data = NULL; in q6apm_dai_compr_free()
546 caps->direction = SND_COMPRESS_PLAYBACK; in q6apm_dai_compr_get_caps()
547 caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE; in q6apm_dai_compr_get_caps()
548 caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE; in q6apm_dai_compr_get_caps()
549 caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS; in q6apm_dai_compr_get_caps()
550 caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS; in q6apm_dai_compr_get_caps()
551 caps->num_codecs = 3; in q6apm_dai_compr_get_caps()
552 caps->codecs[0] = SND_AUDIOCODEC_MP3; in q6apm_dai_compr_get_caps()
553 caps->codecs[1] = SND_AUDIOCODEC_AAC; in q6apm_dai_compr_get_caps()
554 caps->codecs[2] = SND_AUDIOCODEC_FLAC; in q6apm_dai_compr_get_caps()
563 switch (codec->codec) { in q6apm_dai_compr_get_codec_caps()
578 struct snd_compr_runtime *runtime = stream->runtime; in q6apm_dai_compr_pointer()
579 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_compr_pointer()
582 spin_lock_irqsave(&prtd->lock, flags); in q6apm_dai_compr_pointer()
583 tstamp->copied_total = prtd->copied_total; in q6apm_dai_compr_pointer()
584 tstamp->byte_offset = prtd->copied_total % prtd->pcm_size; in q6apm_dai_compr_pointer()
585 spin_unlock_irqrestore(&prtd->lock, flags); in q6apm_dai_compr_pointer()
593 struct snd_compr_runtime *runtime = stream->runtime; in q6apm_dai_compr_trigger()
594 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_compr_trigger()
601 ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP); in q6apm_dai_compr_trigger()
609 prtd->next_track = true; in q6apm_dai_compr_trigger()
613 prtd->notify_on_drain = true; in q6apm_dai_compr_trigger()
616 ret = -EINVAL; in q6apm_dai_compr_trigger()
626 struct snd_compr_runtime *runtime = stream->runtime; in q6apm_dai_compr_ack()
627 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_compr_ack()
630 spin_lock_irqsave(&prtd->lock, flags); in q6apm_dai_compr_ack()
631 prtd->bytes_received += count; in q6apm_dai_compr_ack()
632 spin_unlock_irqrestore(&prtd->lock, flags); in q6apm_dai_compr_ack()
641 struct snd_compr_runtime *runtime = stream->runtime; in q6apm_dai_compr_set_params()
642 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_compr_set_params()
645 struct snd_codec *codec = &params->codec; in q6apm_dai_compr_set_params()
646 int dir = stream->direction; in q6apm_dai_compr_set_params()
651 return -EINVAL; in q6apm_dai_compr_set_params()
653 prtd->periods = runtime->fragments; in q6apm_dai_compr_set_params()
654 prtd->pcm_count = runtime->fragment_size; in q6apm_dai_compr_set_params()
655 prtd->pcm_size = runtime->fragments * runtime->fragment_size; in q6apm_dai_compr_set_params()
656 prtd->bits_per_sample = 16; in q6apm_dai_compr_set_params()
658 prtd->pos = 0; in q6apm_dai_compr_set_params()
660 if (prtd->next_track != true) { in q6apm_dai_compr_set_params()
661 memcpy(&prtd->codec, codec, sizeof(*codec)); in q6apm_dai_compr_set_params()
663 ret = q6apm_set_real_module_id(component->dev, prtd->graph, codec->id); in q6apm_dai_compr_set_params()
668 cfg.sample_rate = codec->sample_rate; in q6apm_dai_compr_set_params()
670 cfg.bit_width = prtd->bits_per_sample; in q6apm_dai_compr_set_params()
671 cfg.fmt = codec->id; in q6apm_dai_compr_set_params()
674 ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg); in q6apm_dai_compr_set_params()
678 ret = q6apm_graph_media_format_pcm(prtd->graph, &cfg); in q6apm_dai_compr_set_params()
682 ret = q6apm_map_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK, in q6apm_dai_compr_set_params()
683 prtd->phys, (prtd->pcm_size / prtd->periods), in q6apm_dai_compr_set_params()
684 prtd->periods); in q6apm_dai_compr_set_params()
686 return -ENOMEM; in q6apm_dai_compr_set_params()
688 ret = q6apm_graph_prepare(prtd->graph); in q6apm_dai_compr_set_params()
692 ret = q6apm_graph_start(prtd->graph); in q6apm_dai_compr_set_params()
698 cfg.sample_rate = codec->sample_rate; in q6apm_dai_compr_set_params()
700 cfg.bit_width = prtd->bits_per_sample; in q6apm_dai_compr_set_params()
701 cfg.fmt = codec->id; in q6apm_dai_compr_set_params()
704 ret = audioreach_compr_set_param(prtd->graph, &cfg); in q6apm_dai_compr_set_params()
708 prtd->state = Q6APM_STREAM_RUNNING; in q6apm_dai_compr_set_params()
717 struct snd_compr_runtime *runtime = stream->runtime; in q6apm_dai_compr_set_metadata()
718 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_compr_set_metadata()
721 switch (metadata->key) { in q6apm_dai_compr_set_metadata()
723 prtd->trailing_samples_drop = metadata->value[0]; in q6apm_dai_compr_set_metadata()
724 q6apm_remove_trailing_silence(component->dev, prtd->graph, in q6apm_dai_compr_set_metadata()
725 prtd->trailing_samples_drop); in q6apm_dai_compr_set_metadata()
728 prtd->initial_samples_drop = metadata->value[0]; in q6apm_dai_compr_set_metadata()
729 q6apm_remove_initial_silence(component->dev, prtd->graph, in q6apm_dai_compr_set_metadata()
730 prtd->initial_samples_drop); in q6apm_dai_compr_set_metadata()
733 ret = -EINVAL; in q6apm_dai_compr_set_metadata()
744 struct snd_compr_runtime *runtime = stream->runtime; in q6apm_dai_compr_mmap()
745 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_dai_compr_mmap()
746 struct device *dev = component->dev; in q6apm_dai_compr_mmap()
748 return dma_mmap_coherent(dev, vma, prtd->dma_buffer.area, prtd->dma_buffer.addr, in q6apm_dai_compr_mmap()
749 prtd->dma_buffer.bytes); in q6apm_dai_compr_mmap()
756 struct snd_compr_runtime *runtime = stream->runtime; in q6apm_compr_copy()
757 struct q6apm_dai_rtd *prtd = runtime->private_data; in q6apm_compr_copy()
767 bytes_received = prtd->bytes_received; in q6apm_compr_copy()
773 if (prtd->next_track) in q6apm_compr_copy()
774 bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count); in q6apm_compr_copy()
776 app_pointer = bytes_received/prtd->pcm_size; in q6apm_compr_copy()
777 app_pointer = bytes_received - (app_pointer * prtd->pcm_size); in q6apm_compr_copy()
778 dstn = prtd->dma_buffer.area + app_pointer; in q6apm_compr_copy()
780 if (count < prtd->pcm_size - app_pointer) { in q6apm_compr_copy()
782 return -EFAULT; in q6apm_compr_copy()
784 copy = prtd->pcm_size - app_pointer; in q6apm_compr_copy()
786 return -EFAULT; in q6apm_compr_copy()
787 if (copy_from_user(prtd->dma_buffer.area, buf + copy, count - copy)) in q6apm_compr_copy()
788 return -EFAULT; in q6apm_compr_copy()
791 spin_lock_irqsave(&prtd->lock, flags); in q6apm_compr_copy()
792 bytes_in_flight = prtd->bytes_received - prtd->copied_total; in q6apm_compr_copy()
794 if (prtd->next_track) { in q6apm_compr_copy()
795 prtd->next_track = false; in q6apm_compr_copy()
796 prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count); in q6apm_compr_copy()
797 prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count); in q6apm_compr_copy()
800 prtd->bytes_received = bytes_received + count; in q6apm_compr_copy()
803 if (prtd->state == Q6APM_STREAM_RUNNING && (bytes_in_flight == 0)) { in q6apm_compr_copy()
804 bytes_to_write = prtd->pcm_count; in q6apm_compr_copy()
805 avail = prtd->bytes_received - prtd->bytes_sent; in q6apm_compr_copy()
807 if (avail < prtd->pcm_count) in q6apm_compr_copy()
810 q6apm_write_async(prtd->graph, bytes_to_write, 0, 0, wflags); in q6apm_compr_copy()
811 prtd->bytes_sent += bytes_to_write; in q6apm_compr_copy()
814 spin_unlock_irqrestore(&prtd->lock, flags); in q6apm_compr_copy()
848 struct device *dev = &pdev->dev; in q6apm_dai_probe()
849 struct device_node *node = dev->of_node; in q6apm_dai_probe()
856 return -ENOMEM; in q6apm_dai_probe()
860 pdata->sid = -1; in q6apm_dai_probe()
862 pdata->sid = args.args[0] & SID_MASK_DEFAULT; in q6apm_dai_probe()
871 { .compatible = "qcom,q6apm-dais" },
879 .name = "q6apm-dai",
886 MODULE_DESCRIPTION("Q6APM dai driver");