^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Rockchip DLP (Digital Loopback) Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2022 Rockchip Electronics Co. Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Sugar Zhang <sugar.zhang@rock-chips.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kref.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/dmaengine.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <sound/dmaengine_pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "rockchip_dlp.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #ifdef DLP_DBG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define dlp_info(args...) pr_info(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define dlp_info(args...) no_printk(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define SND_DMAENGINE_DLP_DRV_NAME "snd_dmaengine_dlp"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define PBUF_CNT 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static unsigned int prealloc_buffer_size_kbytes = 512;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) module_param(prealloc_buffer_size_kbytes, uint, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) MODULE_PARM_DESC(prealloc_buffer_size_kbytes, "Preallocate DMA buffer size (KB).");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* MUST: dlp_text should be match to enum dlp_mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static const char *const dlp_text[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) "Disabled",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) "2CH: 1 Loopback + 1 Mic",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) "2CH: 1 Mic + 1 Loopback",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) "2CH: 1 Mic + 1 Loopback-mixed",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) "2CH: 2 Loopbacks",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) "4CH: 2 Mics + 2 Loopbacks",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) "4CH: 2 Mics + 1 Loopback-mixed",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) enum dlp_mode {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) DLP_MODE_DISABLED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) DLP_MODE_2CH_1LP_1MIC, /* replace cap-ch-0 with play-ch-0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) DLP_MODE_2CH_1MIC_1LP, /* replace cap-ch-1 with play-ch-1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) DLP_MODE_2CH_1MIC_1LP_MIX, /* replace cap-ch-1 with play-ch-all-mix */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) DLP_MODE_2CH_2LP, /* replace cap-ch-01 with play-ch-01 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) DLP_MODE_4CH_2MIC_2LP, /* replace cap-ch-34 with play-ch-01 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) DLP_MODE_4CH_2MIC_1LP_MIX, /* replace cap-ch-3 with play-ch-all-mix */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct dmaengine_dlp {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) const struct snd_dlp_config *config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct snd_soc_component component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct list_head ref_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) enum dlp_mode mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct dmaengine_dlp_runtime_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct dmaengine_dlp *parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct dmaengine_dlp_runtime_data *ref;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct dma_chan *dma_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct kref refcount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct list_head node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) dma_cookie_t cookie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) snd_pcm_uframes_t buf_sz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) snd_pcm_uframes_t period_sz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) snd_pcm_uframes_t hw_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) snd_pcm_sframes_t hw_ptr_delta; /* play-ptr - cap-ptr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) unsigned long period_elapsed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) unsigned int frame_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) unsigned int channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) unsigned int buf_ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) int stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static inline void dlp_activate(struct dmaengine_dlp *dlp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) spin_lock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) dlp->component.active++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) spin_unlock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static inline void dlp_deactivate(struct dmaengine_dlp *dlp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) spin_lock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) dlp->component.active--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) spin_unlock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static inline bool dlp_mode_channels_match(struct dmaengine_dlp *dlp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) int ch, int *expected)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) *expected = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) switch (dlp->mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) case DLP_MODE_DISABLED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) case DLP_MODE_2CH_1LP_1MIC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) case DLP_MODE_2CH_1MIC_1LP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) case DLP_MODE_2CH_1MIC_1LP_MIX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) case DLP_MODE_2CH_2LP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) *expected = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return (ch == 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) case DLP_MODE_4CH_2MIC_2LP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) case DLP_MODE_4CH_2MIC_1LP_MIX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) *expected = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return (ch == 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static inline ssize_t dlp_channels_to_bytes(struct dmaengine_dlp_runtime_data *prtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) int channels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return (prtd->frame_bytes / prtd->channels) * channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) static inline ssize_t dlp_frames_to_bytes(struct dmaengine_dlp_runtime_data *prtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) snd_pcm_sframes_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return size * prtd->frame_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static inline snd_pcm_sframes_t dlp_bytes_to_frames(struct dmaengine_dlp_runtime_data *prtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ssize_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return size / prtd->frame_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static inline struct dmaengine_dlp *soc_component_to_dlp(struct snd_soc_component *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return container_of(p, struct dmaengine_dlp, component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static inline struct dmaengine_dlp_runtime_data *substream_to_prtd(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) const struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (!substream->runtime)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return substream->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static struct dma_chan *snd_dmaengine_dlp_get_chan(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return prtd->dma_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static struct device *dmaengine_dma_dev(struct dmaengine_dlp *dlp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (!dlp->chan[substream->stream])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return dlp->chan[substream->stream]->device->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static int dlp_get_offset_size(struct dmaengine_dlp_runtime_data *prtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) enum dlp_mode mode, int *ofs, int *size, bool *mix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) bool is_playback = prtd->stream == SNDRV_PCM_STREAM_PLAYBACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) switch (mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) case DLP_MODE_2CH_1LP_1MIC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) *ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) *size = dlp_channels_to_bytes(prtd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) case DLP_MODE_2CH_1MIC_1LP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) *ofs = dlp_channels_to_bytes(prtd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) *size = dlp_channels_to_bytes(prtd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) case DLP_MODE_2CH_1MIC_1LP_MIX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (is_playback) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) *ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) *size = dlp_frames_to_bytes(prtd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (mix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) *mix = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) *ofs = dlp_channels_to_bytes(prtd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) *size = dlp_channels_to_bytes(prtd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) case DLP_MODE_2CH_2LP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) *ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) *size = dlp_channels_to_bytes(prtd, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) case DLP_MODE_4CH_2MIC_2LP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (is_playback) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) *ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) *size = dlp_channels_to_bytes(prtd, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) *ofs = dlp_channels_to_bytes(prtd, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) *size = dlp_channels_to_bytes(prtd, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) case DLP_MODE_4CH_2MIC_1LP_MIX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (is_playback) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) *ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) *size = dlp_frames_to_bytes(prtd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (mix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) *mix = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) *ofs = dlp_channels_to_bytes(prtd, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) *size = dlp_channels_to_bytes(prtd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) *ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) *size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (mix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) *mix = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) static int dlp_mix_frame_buffer(struct dmaengine_dlp_runtime_data *prtd, void *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) int sample_bytes = dlp_channels_to_bytes(prtd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) int16_t *p16 = (int16_t *)buf, v16 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) int32_t *p32 = (int32_t *)buf, v32 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) switch (sample_bytes) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) for (i = 0; i < prtd->channels; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) v16 += (p16[i] / prtd->channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) p16[0] = v16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) for (i = 0; i < prtd->channels; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) v32 += (p32[i] / prtd->channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) p32[0] = v32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static int dmaengine_dlp_hw_params(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) struct snd_pcm_hw_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct dma_chan *chan = snd_dmaengine_dlp_get_chan(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct dma_slave_config slave_config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) unsigned int buf_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) int ch_req = params_channels(params), ch_exp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /* mode should match to channels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (!is_playback && !dlp_mode_channels_match(dlp, ch_req, &ch_exp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) dev_err(dlp->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) "capture %d ch, expected: %d ch for loopback mode-%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) ch_req, ch_exp, dlp->mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) memset(&slave_config, 0, sizeof(slave_config));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) ret = snd_dmaengine_pcm_prepare_slave_config(substream, params, &slave_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) ret = dmaengine_slave_config(chan, &slave_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) prtd->frame_bytes = snd_pcm_format_size(params_format(params),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) params_channels(params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) prtd->period_sz = params_period_size(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) prtd->buf_sz = params_buffer_size(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) prtd->channels = params_channels(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) buf_bytes = prtd->frame_bytes * params_buffer_size(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (is_playback) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) buf_bytes *= PBUF_CNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) prtd->buf_sz *= PBUF_CNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) prtd->buf = kzalloc(buf_bytes, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (!prtd->buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) struct device *dma_dev = dmaengine_dma_dev(dlp, substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) struct dma_chan *chan = dlp->chan[substream->stream];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) struct snd_dmaengine_dai_dma_data *dma_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) struct snd_pcm_hardware hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (rtd->num_cpus > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) dev_err(rtd->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) "%s doesn't support Multi CPU yet\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) memset(&hw, 0, sizeof(hw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) SNDRV_PCM_INFO_INTERLEAVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) hw.periods_min = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) hw.periods_max = UINT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) hw.period_bytes_min = 256;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) hw.period_bytes_max = dma_get_max_seg_size(dma_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) hw.buffer_bytes_max = SIZE_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) hw.fifo_size = dma_data->fifo_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * FIXME: Remove the return value check to align with the code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * before adding snd_dmaengine_pcm_refine_runtime_hwparams
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) snd_dmaengine_pcm_refine_runtime_hwparams(substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) dma_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) &hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return snd_soc_set_runtime_hwparams(substream, &hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) static int dmaengine_dlp_open(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) struct dma_chan *chan = dlp->chan[substream->stream];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) struct dmaengine_dlp_runtime_data *prtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (!chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) ret = dmaengine_pcm_set_runtime_hwparams(component, substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) ret = snd_pcm_hw_constraint_integer(substream->runtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) SNDRV_PCM_HW_PARAM_PERIODS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (!prtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) dlp_info("PRTD-CREATE: 0x%px (%s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) prtd, substream->stream ? "C" : "P");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) kref_init(&prtd->refcount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) prtd->parent = dlp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) prtd->stream = substream->stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) prtd->dma_chan = chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) substream->runtime->private_data = prtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) dlp_activate(dlp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) static void dmaengine_free_prtd(struct kref *ref)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) struct dmaengine_dlp_runtime_data *prtd =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) container_of(ref, struct dmaengine_dlp_runtime_data, refcount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) dlp_info("PRTD-FREE: 0x%px\n", prtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) kfree(prtd->buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) kfree(prtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) static void free_ref_list(struct snd_soc_component *component)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) struct dmaengine_dlp_runtime_data *prtd, *_pt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) spin_lock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) list_for_each_entry_safe(prtd, _pt, &dlp->ref_list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) list_del(&prtd->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) kref_put(&prtd->refcount, dmaengine_free_prtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) spin_unlock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) static int dmaengine_dlp_close(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) dmaengine_synchronize(prtd->dma_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) * free residue playback ref list for capture when close
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) free_ref_list(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) * kref put should be after hw_ptr updated when stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * ops->trigger: SNDRV_PCM_TRIGGER_STOP -> ops->close
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) * obviously, it is!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) kref_put(&prtd->refcount, dmaengine_free_prtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) dlp_deactivate(dlp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static snd_pcm_uframes_t dmaengine_dlp_pointer(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) struct dma_tx_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) unsigned int buf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) unsigned int pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) buf_size = snd_pcm_lib_buffer_bytes(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if (state.residue > 0 && state.residue <= buf_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) pos = buf_size - state.residue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return dlp_bytes_to_frames(prtd, pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) static void dmaengine_dlp_dma_complete(void *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) struct snd_pcm_substream *substream = arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) struct dmaengine_dlp *dlp = prtd->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) if (!substream->runtime)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) spin_lock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) prtd->period_elapsed++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) prtd->hw_ptr = prtd->period_elapsed * prtd->period_sz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) spin_unlock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) snd_pcm_period_elapsed(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) static int dmaengine_dlp_prepare_and_submit(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) struct dma_chan *chan = prtd->dma_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) struct dma_async_tx_descriptor *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) enum dma_transfer_direction direction;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) unsigned long flags = DMA_CTRL_ACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) direction = snd_pcm_substream_to_dma_direction(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (!substream->runtime->no_period_wakeup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) flags |= DMA_PREP_INTERRUPT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) desc = dmaengine_prep_dma_cyclic(chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) substream->runtime->dma_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) snd_pcm_lib_buffer_bytes(substream),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) snd_pcm_lib_period_bytes(substream), direction, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (!desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) desc->callback = dmaengine_dlp_dma_complete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) desc->callback_param = substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) prtd->cookie = dmaengine_submit(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) static int dmaengine_pcm_lp_setup(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) int bstream = SNDRV_PCM_STREAM_LAST - substream->stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) struct snd_pcm_str *bro = &substream->pcm->streams[bstream];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) struct snd_pcm_substream *bsubstream = bro->substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) struct dmaengine_dlp_runtime_data *brtd = substream_to_prtd(bsubstream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) snd_pcm_uframes_t a = 0, b = 0, fifo_a = 0, fifo_b = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) snd_pcm_sframes_t delta = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (dlp->mode == DLP_MODE_DISABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) fifo_a = dlp->config->get_fifo_count(dlp->dev, substream->stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) a = dmaengine_dlp_pointer(component, substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) if (bsubstream->runtime && snd_pcm_running(bsubstream)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) fifo_b = dlp->config->get_fifo_count(dlp->dev, bstream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) b = dmaengine_dlp_pointer(component, bsubstream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) a = (prtd->period_elapsed * prtd->period_sz) + (a % prtd->period_sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) b = (brtd->period_elapsed * brtd->period_sz) + (b % brtd->period_sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) fifo_a = dlp_bytes_to_frames(prtd, fifo_a * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) fifo_b = dlp_bytes_to_frames(brtd, fifo_b * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) delta = is_playback ? (a - fifo_a) - (b + fifo_b) : (b - fifo_b) - (a + fifo_a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) /* push valid playback into ref list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) spin_lock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (is_playback) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) prtd->hw_ptr_delta = delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) kref_get(&prtd->refcount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) list_add_tail(&prtd->node, &dlp->ref_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) brtd->hw_ptr_delta = delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) kref_get(&brtd->refcount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) list_add_tail(&brtd->node, &dlp->ref_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) spin_unlock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (is_playback)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) dlp_info("START-P: DMA-P: %lu, DMA-C: %lu, FIFO-P: %lu, FIFO-C: %lu, DELTA: %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) a, b, fifo_a, fifo_b, delta);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) dlp_info("START-C: DMA-P: %lu, DMA-C: %lu, FIFO-P: %lu, FIFO-C: %lu, DELTA: %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) b, a, fifo_b, fifo_a, delta);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) static void dmaengine_pcm_lp_release(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) snd_pcm_uframes_t appl_ptr, hw_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) if (dlp->mode == DLP_MODE_DISABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) /* any data in FIFOs will be gone ,so don't care */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) appl_ptr = READ_ONCE(runtime->control->appl_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) hw_ptr = dmaengine_dlp_pointer(component, substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) spin_lock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) hw_ptr = (prtd->period_elapsed * prtd->period_sz) + (hw_ptr % prtd->period_sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) prtd->hw_ptr = hw_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) spin_unlock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) * playback:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) * snd_pcm_drop: hw_ptr will be smaller than appl_ptr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) * snd_pcm_drain, hw_ptr will be equal to appl_ptr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) * anyway, we should use the smaller one, obviously, it's hw_ptr.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) dlp_info("STOP-P: applptr: %lu, hwptr: %lu\n", appl_ptr, hw_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) dlp_info("STOP-C: applptr: %lu, hwptr: %lu\n", appl_ptr, hw_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) static int dmaengine_dlp_trigger(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) struct snd_pcm_substream *substream, int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) ret = dmaengine_dlp_prepare_and_submit(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) dma_async_issue_pending(prtd->dma_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) dmaengine_pcm_lp_setup(component, substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) case SNDRV_PCM_TRIGGER_RESUME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) dmaengine_resume(prtd->dma_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) case SNDRV_PCM_TRIGGER_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) if (runtime->info & SNDRV_PCM_INFO_PAUSE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) dmaengine_pause(prtd->dma_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) dmaengine_pcm_lp_release(component, substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) dmaengine_terminate_async(prtd->dma_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) dmaengine_pause(prtd->dma_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) dmaengine_pcm_lp_release(component, substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) dmaengine_terminate_async(prtd->dma_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) static int dmaengine_dlp_new(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) struct snd_soc_pcm_runtime *rtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) struct snd_pcm_substream *substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) size_t prealloc_buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) size_t max_buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) prealloc_buffer_size = prealloc_buffer_size_kbytes * 1024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) max_buffer_size = SIZE_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) for_each_pcm_streams(i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) substream = rtd->pcm->streams[i].substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) if (!substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (!dlp->chan[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) dev_err(component->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) "Missing dma channel for stream: %d\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) snd_pcm_set_managed_buffer(substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) SNDRV_DMA_TYPE_DEV_IRAM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) dmaengine_dma_dev(dlp, substream),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) prealloc_buffer_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) max_buffer_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (rtd->pcm->streams[i].pcm->name[0] == '\0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) strscpy_pad(rtd->pcm->streams[i].pcm->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) rtd->pcm->streams[i].pcm->id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) sizeof(rtd->pcm->streams[i].pcm->name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) static struct dmaengine_dlp_runtime_data *get_ref(struct snd_soc_component *component)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) struct dmaengine_dlp_runtime_data *pref = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) spin_lock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (!list_empty(&dlp->ref_list)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) pref = list_first_entry(&dlp->ref_list, struct dmaengine_dlp_runtime_data, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) list_del(&pref->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) spin_unlock(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) return pref;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) static int process_capture(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) unsigned long hwoff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) void __user *buf, unsigned long bytes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) struct dmaengine_dlp_runtime_data *pref = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) void *dma_ptr = runtime->dma_area + hwoff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) snd_pcm_sframes_t frames = dlp_bytes_to_frames(prtd, bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) snd_pcm_sframes_t frames_consumed = 0, frames_residue = 0, frames_tmp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) snd_pcm_sframes_t ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) snd_pcm_uframes_t appl_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) char *cbuf = prtd->buf, *pbuf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) int ofs_cap, ofs_play, size_cap, size_play;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) int i = 0, j = 0, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) bool free_ref = false, mix = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) appl_ptr = READ_ONCE(runtime->control->appl_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) memcpy(cbuf, dma_ptr, bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) #ifdef DLP_DBG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) /* DBG: mark STUB in ch-REC for trace each read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) memset(cbuf, 0x22, dlp_channels_to_bytes(prtd, 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) ret = dlp_get_offset_size(prtd, dlp->mode, &ofs_cap, &size_cap, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) dlp_info("fail to get dlp cap offset\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) /* clear channel-LP_CHN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) for (i = 0; i < frames; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) cbuf = prtd->buf + dlp_frames_to_bytes(prtd, i) + ofs_cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) memset(cbuf, 0x0, size_cap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) start:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) if (!prtd->ref)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) prtd->ref = get_ref(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) pref = prtd->ref;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) /* do nothing if play stop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (!pref)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) ret = dlp_get_offset_size(pref, dlp->mode, &ofs_play, &size_play, &mix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) dlp_info("fail to get dlp play offset\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) ofs = appl_ptr + pref->hw_ptr_delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) * if playback stop, kref_put ref, and we can check this to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) * know if playback stopped, then free prtd->ref if data consumed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (kref_read(&pref->refcount) == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) if (ofs >= pref->hw_ptr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) kref_put(&pref->refcount, dmaengine_free_prtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) prtd->ref = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) } else if ((ofs + frames) > pref->hw_ptr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) dlp_info("applptr: %8lu, ofs': %7ld, refhwptr: %lu, frames: %lu (*)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) appl_ptr, ofs, pref->hw_ptr, frames);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) * should ignore the data that after play stop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) * and care about if the next ref start in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) * same window
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) frames_tmp = pref->hw_ptr - ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) frames_residue = frames - frames_tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) frames = frames_tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) free_ref = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) * should ignore the data that before play start:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) * frames:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) * +---------------------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) * | ofs<0 | ofs>0 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) * +---------------------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) if ((ofs + frames) <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) /* skip if ofs < 0 and fixup ofs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) j = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) if (ofs < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) dlp_info("applptr: %8lu, ofs: %8ld, frames: %lu (*)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) appl_ptr, ofs, frames);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) j = -ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) frames += ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) ofs %= pref->buf_sz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) dlp_info("applptr: %8lu, ofs: %8ld, frames: %lu\n", appl_ptr, ofs, frames);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) for (i = 0; i < frames; i++, j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) cbuf = prtd->buf + dlp_frames_to_bytes(prtd, j + frames_consumed) + ofs_cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) pbuf = pref->buf + dlp_frames_to_bytes(pref, ((i + ofs) % pref->buf_sz)) + ofs_play;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) if (mix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) dlp_mix_frame_buffer(pref, pbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) memcpy(cbuf, pbuf, size_cap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) appl_ptr += frames;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) frames_consumed += frames;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) if (free_ref) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) kref_put(&pref->refcount, dmaengine_free_prtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) prtd->ref = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) free_ref = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) if (frames_residue) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) frames = frames_residue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) frames_residue = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) goto start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) static int process_playback(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) unsigned long hwoff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) void __user *buf, unsigned long bytes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) char *pbuf = prtd->buf + prtd->buf_ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) if (copy_from_user(pbuf, buf, bytes))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) prtd->buf_ofs += bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) prtd->buf_ofs %= dlp_frames_to_bytes(prtd, prtd->buf_sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) static int dmaengine_process(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) unsigned long hwoff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) void __user *buf, unsigned long bytes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) if (dlp->mode == DLP_MODE_DISABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) ret = process_playback(component, substream, hwoff, buf, bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) ret = process_capture(component, substream, hwoff, buf, bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) static int dmaengine_copy_user(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) int channel, unsigned long hwoff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) void __user *buf, unsigned long bytes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) struct dmaengine_dlp_runtime_data *prtd = substream_to_prtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) void *dma_ptr = runtime->dma_area + hwoff +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) channel * (runtime->dma_bytes / runtime->channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (is_playback)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) if (copy_from_user(dma_ptr, buf, bytes))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) ret = dmaengine_process(component, substream, hwoff, buf, bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) dma_ptr = prtd->buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) if (!is_playback)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) if (copy_to_user(buf, dma_ptr, bytes))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) static SOC_ENUM_SINGLE_EXT_DECL(dlp_mode, dlp_text);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) static int dmaengine_dlp_mode_get(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) ucontrol->value.enumerated.item[0] = dlp->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) static int dmaengine_dlp_mode_put(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) struct dmaengine_dlp *dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) unsigned int mode = ucontrol->value.enumerated.item[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) /* MUST: do not update mode while stream is running */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) if (snd_soc_component_active(component))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) if (mode == dlp->mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) dlp->mode = mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) static const struct snd_kcontrol_new dmaengine_dlp_controls[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) SOC_ENUM_EXT("Software Digital Loopback Mode", dlp_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) dmaengine_dlp_mode_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) dmaengine_dlp_mode_put),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) static const struct snd_soc_component_driver dmaengine_dlp_component = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) .name = SND_DMAENGINE_DLP_DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) .probe_order = SND_SOC_COMP_ORDER_LATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) .open = dmaengine_dlp_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) .close = dmaengine_dlp_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) .hw_params = dmaengine_dlp_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) .trigger = dmaengine_dlp_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) .pointer = dmaengine_dlp_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) .copy_user = dmaengine_copy_user,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) .pcm_construct = dmaengine_dlp_new,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) .controls = dmaengine_dlp_controls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) .num_controls = ARRAY_SIZE(dmaengine_dlp_controls),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) static const char * const dmaengine_pcm_dma_channel_names[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) [SNDRV_PCM_STREAM_PLAYBACK] = "tx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) [SNDRV_PCM_STREAM_CAPTURE] = "rx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) static int dmaengine_pcm_request_chan_of(struct dmaengine_dlp *dlp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) struct device *dev, const struct snd_dmaengine_pcm_config *config)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) struct dma_chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) for_each_pcm_streams(i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) name = dmaengine_pcm_dma_channel_names[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) chan = dma_request_chan(dev, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) if (IS_ERR(chan)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) * Only report probe deferral errors, channels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) * might not be present for devices that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) * support only TX or only RX.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) if (PTR_ERR(chan) == -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) dlp->chan[i] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) dlp->chan[i] = chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) static void dmaengine_pcm_release_chan(struct dmaengine_dlp *dlp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) for_each_pcm_streams(i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) if (!dlp->chan[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) dma_release_channel(dlp->chan[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) * snd_dmaengine_dlp_register - Register a dmaengine based DLP device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) * @dev: The parent device for the DLP device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) * @config: Platform specific DLP configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) static int snd_dmaengine_dlp_register(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) const struct snd_dlp_config *config)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) const struct snd_soc_component_driver *driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) struct dmaengine_dlp *dlp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) dlp = kzalloc(sizeof(*dlp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) if (!dlp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) dlp->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) dlp->config = config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) INIT_LIST_HEAD(&dlp->ref_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) spin_lock_init(&dlp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) #ifdef CONFIG_DEBUG_FS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) dlp->component.debugfs_prefix = "dma";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) ret = dmaengine_pcm_request_chan_of(dlp, dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) goto err_free_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) driver = &dmaengine_dlp_component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) ret = snd_soc_component_initialize(&dlp->component, driver, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) goto err_free_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) ret = snd_soc_add_component(&dlp->component, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) goto err_free_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) err_free_dma:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) dmaengine_pcm_release_chan(dlp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) kfree(dlp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) * snd_dmaengine_dlp_unregister - Removes a dmaengine based DLP device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) * @dev: Parent device the DLP was register with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) * Removes a dmaengine based DLP device previously registered with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) * snd_dmaengine_pcm_register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) static void snd_dmaengine_dlp_unregister(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) struct snd_soc_component *component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) struct dmaengine_dlp *dlp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) component = snd_soc_lookup_component(dev, SND_DMAENGINE_DLP_DRV_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) if (!component)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) dlp = soc_component_to_dlp(component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) snd_soc_unregister_component_by_driver(dev, component->driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) dmaengine_pcm_release_chan(dlp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) kfree(dlp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) static void devm_dmaengine_dlp_release(struct device *dev, void *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) snd_dmaengine_dlp_unregister(*(struct device **)res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) * devm_snd_dmaengine_dlp_register - resource managed dmaengine DLP registration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) * @dev: The parent device for the DLP device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) * @config: Platform specific DLP configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) * Register a dmaengine based DLP device with automatic unregistration when the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) * device is unregistered.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) int devm_snd_dmaengine_dlp_register(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) const struct snd_dlp_config *config)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) struct device **ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) ptr = devres_alloc(devm_dmaengine_dlp_release, sizeof(*ptr), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) if (!ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) ret = snd_dmaengine_dlp_register(dev, config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) *ptr = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) devres_add(dev, ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) devres_free(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) EXPORT_SYMBOL_GPL(devm_snd_dmaengine_dlp_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) MODULE_LICENSE("GPL");