Lines Matching +full:8 +full:- +full:ch
1 // SPDX-License-Identifier: GPL-2.0
6 * Author: Sugar Zhang <sugar.zhang@rock-chips.com>
18 #include <linux/dma-mapping.h>
40 "2CH: 1 Loopback + 1 Mic",
41 "2CH: 1 Mic + 1 Loopback",
42 "2CH: 1 Mic + 1 Loopback-mixed",
43 "2CH: 2 Loopbacks",
44 "4CH: 2 Mics + 2 Loopbacks",
45 "4CH: 2 Mics + 1 Loopback-mixed",
46 "4CH: 4 Loopbacks",
47 "6CH: 4 Mics + 2 Loopbacks",
48 "6CH: 4 Mics + 1 Loopback-mixed",
49 "6CH: 6 Loopbacks",
50 "8CH: 6 Mics + 2 Loopbacks",
51 "8CH: 6 Mics + 1 Loopback-mixed",
52 "8CH: 8 Loopbacks",
53 "10CH: 8 Mics + 2 Loopbacks",
54 "10CH: 8 Mics + 1 Loopback-mixed",
55 "16CH: 8 Mics + 8 Loopbacks",
60 DLP_MODE_2CH_1LP_1MIC, /* replace cap-ch-0 with play-ch-0 */
61 DLP_MODE_2CH_1MIC_1LP, /* replace cap-ch-1 with play-ch-1 */
62 DLP_MODE_2CH_1MIC_1LP_MIX, /* replace cap-ch-1 with play-ch-all-mix */
63 DLP_MODE_2CH_2LP, /* replace cap-ch-0~1 with play-ch-0~1 */
64 DLP_MODE_4CH_2MIC_2LP, /* replace cap-ch-2~3 with play-ch-0~1 */
65 DLP_MODE_4CH_2MIC_1LP_MIX, /* replace cap-ch-3 with play-ch-all-mix */
66 DLP_MODE_4CH_4LP, /* replace cap-ch-0~3 with play-ch-0~3 */
67 DLP_MODE_6CH_4MIC_2LP, /* replace cap-ch-4~5 with play-ch-0~1 */
68 DLP_MODE_6CH_4MIC_1LP_MIX, /* replace cap-ch-4 with play-ch-all-mix */
69 DLP_MODE_6CH_6LP, /* replace cap-ch-0~5 with play-ch-0~5 */
70 DLP_MODE_8CH_6MIC_2LP, /* replace cap-ch-6~7 with play-ch-0~1 */
71 DLP_MODE_8CH_6MIC_1LP_MIX, /* replace cap-ch-6 with play-ch-all-mix */
72 DLP_MODE_8CH_8LP, /* replace cap-ch-0~7 with play-ch-0~7 */
73 DLP_MODE_10CH_8MIC_2LP, /* replace cap-ch-8~9 with play-ch-0~1 */
74 DLP_MODE_10CH_8MIC_1LP_MIX, /* replace cap-ch-8 with play-ch-all-mix */
75 DLP_MODE_16CH_8MIC_8LP, /* replace cap-ch-8~f with play-ch-8~f */
103 snd_pcm_sframes_t hw_ptr_delta; /* play-ptr - cap-ptr */
113 spin_lock(&dlp->lock); in dlp_activate()
114 dlp->component.active++; in dlp_activate()
115 spin_unlock(&dlp->lock); in dlp_activate()
120 spin_lock(&dlp->lock); in dlp_deactivate()
121 dlp->component.active--; in dlp_deactivate()
122 spin_unlock(&dlp->lock); in dlp_deactivate()
126 int ch, int *expected) in dlp_mode_channels_match() argument
130 switch (dlp->mode) { in dlp_mode_channels_match()
138 return (ch == 2); in dlp_mode_channels_match()
143 return (ch == 4); in dlp_mode_channels_match()
148 return (ch == 6); in dlp_mode_channels_match()
152 *expected = 8; in dlp_mode_channels_match()
153 return (ch == 8); in dlp_mode_channels_match()
157 return (ch == 10); in dlp_mode_channels_match()
160 return (ch == 16); in dlp_mode_channels_match()
169 return (prtd->frame_bytes / prtd->channels) * channels; in dlp_channels_to_bytes()
175 return size * prtd->frame_bytes; in dlp_frames_to_bytes()
181 return size / prtd->frame_bytes; in dlp_bytes_to_frames()
192 if (!substream->runtime) in substream_to_prtd()
195 return substream->runtime->private_data; in substream_to_prtd()
202 return prtd->dma_chan; in snd_dmaengine_dlp_get_chan()
208 if (!dlp->chan[substream->stream]) in dmaengine_dma_dev()
211 return dlp->chan[substream->stream]->device->dev; in dmaengine_dma_dev()
217 bool is_playback = prtd->stream == SNDRV_PCM_STREAM_PLAYBACK; in dlp_get_offset_size()
314 *size = dlp_channels_to_bytes(prtd, 8); in dlp_get_offset_size()
321 *ofs = dlp_channels_to_bytes(prtd, 8); in dlp_get_offset_size()
332 *ofs = dlp_channels_to_bytes(prtd, 8); in dlp_get_offset_size()
339 *size = dlp_channels_to_bytes(prtd, 8); in dlp_get_offset_size()
341 *ofs = dlp_channels_to_bytes(prtd, 8); in dlp_get_offset_size()
342 *size = dlp_channels_to_bytes(prtd, 8); in dlp_get_offset_size()
350 ret = -EINVAL; in dlp_get_offset_size()
365 for (i = 0; i < prtd->channels; i++) in dlp_mix_frame_buffer()
366 v16 += (p16[i] / prtd->channels); in dlp_mix_frame_buffer()
370 for (i = 0; i < prtd->channels; i++) in dlp_mix_frame_buffer()
371 v32 += (p32[i] / prtd->channels); in dlp_mix_frame_buffer()
375 return -EINVAL; in dlp_mix_frame_buffer()
389 bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; in dmaengine_dlp_hw_params()
395 dev_err(dlp->dev, in dmaengine_dlp_hw_params()
396 "capture %d ch, expected: %d ch for loopback mode-%d\n", in dmaengine_dlp_hw_params()
397 ch_req, ch_exp, dlp->mode); in dmaengine_dlp_hw_params()
398 return -EINVAL; in dmaengine_dlp_hw_params()
411 prtd->frame_bytes = snd_pcm_format_size(params_format(params), in dmaengine_dlp_hw_params()
413 prtd->period_sz = params_period_size(params); in dmaengine_dlp_hw_params()
414 prtd->buf_sz = params_buffer_size(params); in dmaengine_dlp_hw_params()
415 prtd->channels = params_channels(params); in dmaengine_dlp_hw_params()
418 prtd->buf_sz *= PBUF_CNT; in dmaengine_dlp_hw_params()
430 struct dma_chan *chan = dlp->chan[substream->stream]; in dmaengine_pcm_set_runtime_hwparams()
434 if (rtd->num_cpus > 1) { in dmaengine_pcm_set_runtime_hwparams()
435 dev_err(rtd->dev, in dmaengine_pcm_set_runtime_hwparams()
437 return -EINVAL; in dmaengine_pcm_set_runtime_hwparams()
450 hw.fifo_size = dma_data->fifo_size; in dmaengine_pcm_set_runtime_hwparams()
469 struct dma_chan *chan = dlp->chan[substream->stream]; in dmaengine_dlp_open()
474 return -ENXIO; in dmaengine_dlp_open()
480 ret = snd_pcm_hw_constraint_integer(substream->runtime, in dmaengine_dlp_open()
487 return -ENOMEM; in dmaengine_dlp_open()
489 dlp_info("PRTD-CREATE: 0x%px (%s)\n", in dmaengine_dlp_open()
490 prtd, substream->stream ? "C" : "P"); in dmaengine_dlp_open()
492 kref_init(&prtd->refcount); in dmaengine_dlp_open()
493 prtd->parent = dlp; in dmaengine_dlp_open()
494 prtd->stream = substream->stream; in dmaengine_dlp_open()
495 prtd->dma_chan = chan; in dmaengine_dlp_open()
497 substream->runtime->private_data = prtd; in dmaengine_dlp_open()
509 dlp_info("PRTD-FREE: 0x%px\n", prtd); in dmaengine_free_prtd()
511 kfree(prtd->buf); in dmaengine_free_prtd()
520 spin_lock(&dlp->lock); in free_ref_list()
521 list_for_each_entry_safe(prtd, _pt, &dlp->ref_list, node) { in free_ref_list()
522 list_del(&prtd->node); in free_ref_list()
523 kref_put(&prtd->refcount, dmaengine_free_prtd); in free_ref_list()
525 spin_unlock(&dlp->lock); in free_ref_list()
534 dmaengine_synchronize(prtd->dma_chan); in dmaengine_dlp_close()
538 * ops->trigger: SNDRV_PCM_TRIGGER_STOP -> ops->close in dmaengine_dlp_close()
541 kref_put(&prtd->refcount, dmaengine_free_prtd); in dmaengine_dlp_close()
557 dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state); in dmaengine_dlp_pointer()
560 pos = buf_size - state.residue; in dmaengine_dlp_pointer()
569 struct dmaengine_dlp *dlp = prtd->parent; in dmaengine_dlp_dma_complete()
571 if (!substream->runtime) in dmaengine_dlp_dma_complete()
574 spin_lock(&dlp->lock); in dmaengine_dlp_dma_complete()
575 prtd->period_elapsed++; in dmaengine_dlp_dma_complete()
576 prtd->hw_ptr = prtd->period_elapsed * prtd->period_sz; in dmaengine_dlp_dma_complete()
577 spin_unlock(&dlp->lock); in dmaengine_dlp_dma_complete()
584 struct dma_chan *chan = prtd->dma_chan; in dmaengine_dlp_prepare_and_submit()
591 if (!substream->runtime->no_period_wakeup) in dmaengine_dlp_prepare_and_submit()
595 substream->runtime->dma_addr, in dmaengine_dlp_prepare_and_submit()
600 return -ENOMEM; in dmaengine_dlp_prepare_and_submit()
602 desc->callback = dmaengine_dlp_dma_complete; in dmaengine_dlp_prepare_and_submit()
603 desc->callback_param = substream; in dmaengine_dlp_prepare_and_submit()
604 prtd->cookie = dmaengine_submit(desc); in dmaengine_dlp_prepare_and_submit()
613 int bstream = SNDRV_PCM_STREAM_LAST - substream->stream; in dmaengine_dlp_setup()
614 struct snd_pcm_str *bro = &substream->pcm->streams[bstream]; in dmaengine_dlp_setup()
615 struct snd_pcm_substream *bsubstream = bro->substream; in dmaengine_dlp_setup()
618 struct dmaengine_dlp_runtime_data *pref = dlp->pref; in dmaengine_dlp_setup()
619 bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; in dmaengine_dlp_setup()
623 if (dlp->mode == DLP_MODE_DISABLED) in dmaengine_dlp_setup()
624 return -EINVAL; in dmaengine_dlp_setup()
626 fifo_a = dlp->config->get_fifo_count(dlp->dev, substream->stream); in dmaengine_dlp_setup()
629 if (bsubstream->runtime && snd_pcm_running(bsubstream)) { in dmaengine_dlp_setup()
630 fifo_b = dlp->config->get_fifo_count(dlp->dev, bstream); in dmaengine_dlp_setup()
633 spin_lock(&dlp->lock); in dmaengine_dlp_setup()
635 spin_unlock(&dlp->lock); in dmaengine_dlp_setup()
636 return -EINVAL; in dmaengine_dlp_setup()
639 a = (prtd->period_elapsed * prtd->period_sz) + (a % prtd->period_sz); in dmaengine_dlp_setup()
640 b = (brtd->period_elapsed * brtd->period_sz) + (b % brtd->period_sz); in dmaengine_dlp_setup()
645 delta = is_playback ? (a - fifo_a) - (b + fifo_b) : (b - fifo_b) - (a + fifo_a); in dmaengine_dlp_setup()
647 pref->hw_ptr_delta = delta; in dmaengine_dlp_setup()
648 kref_get(&pref->refcount); in dmaengine_dlp_setup()
650 list_add_tail(&pref->node, &dlp->ref_list); in dmaengine_dlp_setup()
652 spin_unlock(&dlp->lock); in dmaengine_dlp_setup()
656 dlp_info("START-P: DMA-P: %lu, DMA-C: %lu, FIFO-P: %lu, FIFO-C: %lu, DELTA: %ld\n", in dmaengine_dlp_setup()
659 dlp_info("START-C: DMA-P: %lu, DMA-C: %lu, FIFO-P: %lu, FIFO-C: %lu, DELTA: %ld\n", in dmaengine_dlp_setup()
670 struct dmaengine_dlp_runtime_data *pref = dlp->pref; in dmaengine_dlp_release()
671 struct snd_pcm_runtime *runtime = substream->runtime; in dmaengine_dlp_release()
674 if (dlp->mode == DLP_MODE_DISABLED) in dmaengine_dlp_release()
678 appl_ptr = READ_ONCE(runtime->control->appl_ptr); in dmaengine_dlp_release()
680 spin_lock(&dlp->lock); in dmaengine_dlp_release()
681 hw_ptr = (prtd->period_elapsed * prtd->period_sz) + (hw_ptr % prtd->period_sz); in dmaengine_dlp_release()
682 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) in dmaengine_dlp_release()
683 pref->hw_ptr = min(hw_ptr, appl_ptr); in dmaengine_dlp_release()
684 prtd->period_elapsed = 0; in dmaengine_dlp_release()
685 prtd->hw_ptr = 0; in dmaengine_dlp_release()
686 spin_unlock(&dlp->lock); in dmaengine_dlp_release()
696 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { in dmaengine_dlp_release()
697 spin_lock(&dlp->pref_lock); in dmaengine_dlp_release()
698 kref_put(&pref->refcount, dmaengine_free_prtd); in dmaengine_dlp_release()
699 dlp->pref = NULL; in dmaengine_dlp_release()
700 spin_unlock(&dlp->pref_lock); in dmaengine_dlp_release()
701 dlp_info("STOP-P: applptr: %lu, hwptr: %lu\n", appl_ptr, hw_ptr); in dmaengine_dlp_release()
705 dlp_info("STOP-C: applptr: %lu, hwptr: %lu\n", appl_ptr, hw_ptr); in dmaengine_dlp_release()
713 struct snd_pcm_runtime *runtime = substream->runtime; in dmaengine_dlp_trigger()
721 dma_async_issue_pending(prtd->dma_chan); in dmaengine_dlp_trigger()
726 dmaengine_resume(prtd->dma_chan); in dmaengine_dlp_trigger()
729 if (runtime->info & SNDRV_PCM_INFO_PAUSE) { in dmaengine_dlp_trigger()
730 dmaengine_pause(prtd->dma_chan); in dmaengine_dlp_trigger()
733 dmaengine_terminate_async(prtd->dma_chan); in dmaengine_dlp_trigger()
737 dmaengine_pause(prtd->dma_chan); in dmaengine_dlp_trigger()
741 dmaengine_terminate_async(prtd->dma_chan); in dmaengine_dlp_trigger()
744 return -EINVAL; in dmaengine_dlp_trigger()
763 substream = rtd->pcm->streams[i].substream; in dmaengine_dlp_new()
767 if (!dlp->chan[i]) { in dmaengine_dlp_new()
768 dev_err(component->dev, in dmaengine_dlp_new()
770 return -EINVAL; in dmaengine_dlp_new()
779 if (rtd->pcm->streams[i].pcm->name[0] == '\0') { in dmaengine_dlp_new()
780 strscpy_pad(rtd->pcm->streams[i].pcm->name, in dmaengine_dlp_new()
781 rtd->pcm->streams[i].pcm->id, in dmaengine_dlp_new()
782 sizeof(rtd->pcm->streams[i].pcm->name)); in dmaengine_dlp_new()
794 spin_lock(&dlp->lock); in get_ref()
795 if (!list_empty(&dlp->ref_list)) { in get_ref()
796 pref = list_first_entry(&dlp->ref_list, struct dmaengine_dlp_runtime_data, node); in get_ref()
797 list_del(&pref->node); in get_ref()
799 spin_unlock(&dlp->lock); in get_ref()
810 struct snd_pcm_runtime *runtime = substream->runtime; in process_capture()
813 void *dma_ptr = runtime->dma_area + hwoff; in process_capture()
818 char *cbuf = prtd->buf, *pbuf = NULL; in process_capture()
823 appl_ptr = READ_ONCE(runtime->control->appl_ptr); in process_capture()
827 /* DBG: mark STUB in ch-REC for trace each read */ in process_capture()
830 ret = dlp_get_offset_size(prtd, dlp->mode, &ofs_cap, &size_cap, NULL); in process_capture()
833 return -EINVAL; in process_capture()
836 /* clear channel-LP_CHN */ in process_capture()
838 cbuf = prtd->buf + dlp_frames_to_bytes(prtd, i) + ofs_cap; in process_capture()
843 if (!prtd->ref) in process_capture()
844 prtd->ref = get_ref(component); in process_capture()
845 pref = prtd->ref; in process_capture()
851 ret = dlp_get_offset_size(pref, dlp->mode, &ofs_play, &size_play, &mix); in process_capture()
857 ofs = appl_ptr + pref->hw_ptr_delta; in process_capture()
861 * know if playback stopped, then free prtd->ref if data consumed. in process_capture()
864 if (kref_read(&pref->refcount) == 1) { in process_capture()
865 if (ofs >= pref->hw_ptr) { in process_capture()
866 kref_put(&pref->refcount, dmaengine_free_prtd); in process_capture()
867 prtd->ref = NULL; in process_capture()
869 } else if ((ofs + frames) > pref->hw_ptr) { in process_capture()
870 dlp_info("applptr: %8lu, ofs': %7ld, refhwptr: %lu, frames: %lu (*)\n", in process_capture()
871 appl_ptr, ofs, pref->hw_ptr, frames); in process_capture()
877 frames_tmp = pref->hw_ptr - ofs; in process_capture()
878 frames_residue = frames - frames_tmp; in process_capture()
888 * +---------------------------------------------+ in process_capture()
890 * +---------------------------------------------+ in process_capture()
899 dlp_info("applptr: %8lu, ofs: %8ld, frames: %lu (*)\n", in process_capture()
901 j = -ofs; in process_capture()
906 ofs %= pref->buf_sz; in process_capture()
908 dlp_info("applptr: %8lu, ofs: %8ld, frames: %lu\n", appl_ptr, ofs, frames); in process_capture()
911 cbuf = prtd->buf + dlp_frames_to_bytes(prtd, j + frames_consumed) + ofs_cap; in process_capture()
912 pbuf = pref->buf + dlp_frames_to_bytes(pref, ((i + ofs) % pref->buf_sz)) + ofs_play; in process_capture()
922 kref_put(&pref->refcount, dmaengine_free_prtd); in process_capture()
923 prtd->ref = NULL; in process_capture()
945 spin_lock(&dlp->pref_lock); in process_playback()
946 pref = dlp->pref; in process_playback()
948 ret = -EFAULT; in process_playback()
952 pbuf = pref->buf + pref->buf_ofs; in process_playback()
955 ret = -EFAULT; in process_playback()
959 pref->buf_ofs += bytes; in process_playback()
960 pref->buf_ofs %= dlp_frames_to_bytes(pref, pref->buf_sz); in process_playback()
963 spin_unlock(&dlp->pref_lock); in process_playback()
976 if (dlp->mode == DLP_MODE_DISABLED) in dmaengine_dlp_process()
977 return -EINVAL; in dmaengine_dlp_process()
979 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) in dmaengine_dlp_process()
993 struct snd_pcm_runtime *runtime = substream->runtime; in dmaengine_dlp_copy_user()
994 bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; in dmaengine_dlp_copy_user()
995 void *dma_ptr = runtime->dma_area + hwoff + in dmaengine_dlp_copy_user()
996 channel * (runtime->dma_bytes / runtime->channels); in dmaengine_dlp_copy_user()
1001 return -EFAULT; in dmaengine_dlp_copy_user()
1005 dma_ptr = prtd->buf; in dmaengine_dlp_copy_user()
1009 return -EFAULT; in dmaengine_dlp_copy_user()
1022 ucontrol->value.enumerated.item[0] = dlp->mode; in dmaengine_dlp_mode_get()
1032 unsigned int mode = ucontrol->value.enumerated.item[0]; in dmaengine_dlp_mode_put()
1036 return -EPERM; in dmaengine_dlp_mode_put()
1038 if (mode == dlp->mode) in dmaengine_dlp_mode_put()
1041 dlp->mode = mode; in dmaengine_dlp_mode_put()
1058 int buf_bytes = dlp_frames_to_bytes(prtd, prtd->buf_sz); in dmaengine_dlp_prepare()
1060 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { in dmaengine_dlp_prepare()
1063 return -ENOMEM; in dmaengine_dlp_prepare()
1065 kref_init(&pref->refcount); in dmaengine_dlp_prepare()
1066 pref->buf_ofs = 0; in dmaengine_dlp_prepare()
1067 pref->buf = kzalloc(buf_bytes, GFP_KERNEL); in dmaengine_dlp_prepare()
1068 if (!pref->buf) { in dmaengine_dlp_prepare()
1070 return -ENOMEM; in dmaengine_dlp_prepare()
1073 spin_lock(&dlp->pref_lock); in dmaengine_dlp_prepare()
1074 dlp->pref = pref; in dmaengine_dlp_prepare()
1075 spin_unlock(&dlp->pref_lock); in dmaengine_dlp_prepare()
1076 dlp_info("PREF-CREATE: 0x%px\n", pref); in dmaengine_dlp_prepare()
1078 prtd->buf = kzalloc(buf_bytes, GFP_KERNEL); in dmaengine_dlp_prepare()
1079 if (!prtd->buf) in dmaengine_dlp_prepare()
1080 return -ENOMEM; in dmaengine_dlp_prepare()
1121 if (PTR_ERR(chan) == -EPROBE_DEFER) in dmaengine_pcm_request_chan_of()
1122 return -EPROBE_DEFER; in dmaengine_pcm_request_chan_of()
1123 dlp->chan[i] = NULL; in dmaengine_pcm_request_chan_of()
1125 dlp->chan[i] = chan; in dmaengine_pcm_request_chan_of()
1137 if (!dlp->chan[i]) in dmaengine_pcm_release_chan()
1139 dma_release_channel(dlp->chan[i]); in dmaengine_pcm_release_chan()
1144 * snd_dmaengine_dlp_register - Register a dmaengine based DLP device
1157 return -ENOMEM; in snd_dmaengine_dlp_register()
1159 dlp->dev = dev; in snd_dmaengine_dlp_register()
1160 dlp->config = config; in snd_dmaengine_dlp_register()
1162 INIT_LIST_HEAD(&dlp->ref_list); in snd_dmaengine_dlp_register()
1163 spin_lock_init(&dlp->lock); in snd_dmaengine_dlp_register()
1164 spin_lock_init(&dlp->pref_lock); in snd_dmaengine_dlp_register()
1167 dlp->component.debugfs_prefix = "dma"; in snd_dmaengine_dlp_register()
1175 ret = snd_soc_component_initialize(&dlp->component, driver, dev); in snd_dmaengine_dlp_register()
1179 ret = snd_soc_add_component(&dlp->component, NULL, 0); in snd_dmaengine_dlp_register()
1192 * snd_dmaengine_dlp_unregister - Removes a dmaengine based DLP device
1209 snd_soc_unregister_component_by_driver(dev, component->driver); in snd_dmaengine_dlp_unregister()
1220 * devm_snd_dmaengine_dlp_register - resource managed dmaengine DLP registration
1235 return -ENOMEM; in devm_snd_dmaengine_dlp_register()