1 // SPDX-License-Identifier: GPL-2.0
3 // Freescale ASRC ALSA SoC Platform (DMA) driver
5 // Copyright (C) 2014 Freescale Semiconductor, Inc.
7 // Author: Nicolin Chen <nicoleotsuka@gmail.com>
9 #include <linux/dma-mapping.h>
10 #include <linux/module.h>
11 #include <linux/platform_data/dma-imx.h>
12 #include <sound/dmaengine_pcm.h>
13 #include <sound/pcm_params.h>
17 #define FSL_ASRC_DMABUF_SIZE (256 * 1024)
19 static const struct snd_pcm_hardware snd_imx_hardware
= {
20 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
21 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
23 SNDRV_PCM_INFO_MMAP_VALID
|
24 SNDRV_PCM_INFO_PAUSE
|
25 SNDRV_PCM_INFO_RESUME
,
26 .buffer_bytes_max
= FSL_ASRC_DMABUF_SIZE
,
27 .period_bytes_min
= 128,
28 .period_bytes_max
= 65535, /* Limited by SDMA engine */
34 static bool filter(struct dma_chan
*chan
, void *param
)
36 if (!imx_dma_is_general_purpose(chan
))
39 chan
->private = param
;
44 static void fsl_asrc_dma_complete(void *arg
)
46 struct snd_pcm_substream
*substream
= arg
;
47 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
48 struct fsl_asrc_pair
*pair
= runtime
->private_data
;
50 pair
->pos
+= snd_pcm_lib_period_bytes(substream
);
51 if (pair
->pos
>= snd_pcm_lib_buffer_bytes(substream
))
54 snd_pcm_period_elapsed(substream
);
57 static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream
*substream
)
59 u8 dir
= substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
? OUT
: IN
;
60 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
61 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
62 struct fsl_asrc_pair
*pair
= runtime
->private_data
;
63 struct snd_soc_component
*component
= snd_soc_rtdcom_lookup(rtd
, DRV_NAME
);
64 struct device
*dev
= component
->dev
;
65 unsigned long flags
= DMA_CTRL_ACK
;
67 /* Prepare and submit Front-End DMA channel */
68 if (!substream
->runtime
->no_period_wakeup
)
69 flags
|= DMA_PREP_INTERRUPT
;
72 pair
->desc
[!dir
] = dmaengine_prep_dma_cyclic(
73 pair
->dma_chan
[!dir
], runtime
->dma_addr
,
74 snd_pcm_lib_buffer_bytes(substream
),
75 snd_pcm_lib_period_bytes(substream
),
76 dir
== OUT
? DMA_MEM_TO_DEV
: DMA_DEV_TO_MEM
, flags
);
77 if (!pair
->desc
[!dir
]) {
78 dev_err(dev
, "failed to prepare slave DMA for Front-End\n");
82 pair
->desc
[!dir
]->callback
= fsl_asrc_dma_complete
;
83 pair
->desc
[!dir
]->callback_param
= substream
;
85 dmaengine_submit(pair
->desc
[!dir
]);
87 /* Prepare and submit Back-End DMA channel */
88 pair
->desc
[dir
] = dmaengine_prep_dma_cyclic(
89 pair
->dma_chan
[dir
], 0xffff, 64, 64, DMA_DEV_TO_DEV
, 0);
90 if (!pair
->desc
[dir
]) {
91 dev_err(dev
, "failed to prepare slave DMA for Back-End\n");
95 dmaengine_submit(pair
->desc
[dir
]);
100 static int fsl_asrc_dma_trigger(struct snd_pcm_substream
*substream
, int cmd
)
102 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
103 struct fsl_asrc_pair
*pair
= runtime
->private_data
;
107 case SNDRV_PCM_TRIGGER_START
:
108 case SNDRV_PCM_TRIGGER_RESUME
:
109 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
110 ret
= fsl_asrc_dma_prepare_and_submit(substream
);
113 dma_async_issue_pending(pair
->dma_chan
[IN
]);
114 dma_async_issue_pending(pair
->dma_chan
[OUT
]);
116 case SNDRV_PCM_TRIGGER_STOP
:
117 case SNDRV_PCM_TRIGGER_SUSPEND
:
118 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
119 dmaengine_terminate_all(pair
->dma_chan
[OUT
]);
120 dmaengine_terminate_all(pair
->dma_chan
[IN
]);
129 static int fsl_asrc_dma_hw_params(struct snd_pcm_substream
*substream
,
130 struct snd_pcm_hw_params
*params
)
132 enum dma_slave_buswidth buswidth
= DMA_SLAVE_BUSWIDTH_2_BYTES
;
133 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
134 bool tx
= substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
;
135 struct snd_dmaengine_dai_dma_data
*dma_params_fe
= NULL
;
136 struct snd_dmaengine_dai_dma_data
*dma_params_be
= NULL
;
137 struct snd_soc_component
*component
= snd_soc_rtdcom_lookup(rtd
, DRV_NAME
);
138 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
139 struct fsl_asrc_pair
*pair
= runtime
->private_data
;
140 struct fsl_asrc
*asrc_priv
= pair
->asrc_priv
;
141 struct dma_slave_config config_fe
, config_be
;
142 enum asrc_pair_index index
= pair
->index
;
143 struct device
*dev
= component
->dev
;
144 int stream
= substream
->stream
;
145 struct imx_dma_data
*tmp_data
;
146 struct snd_soc_dpcm
*dpcm
;
147 struct dma_chan
*tmp_chan
;
148 struct device
*dev_be
;
149 u8 dir
= tx
? OUT
: IN
;
153 /* Fetch the Back-End dma_data from DPCM */
154 list_for_each_entry(dpcm
, &rtd
->dpcm
[stream
].be_clients
, list_be
) {
155 struct snd_soc_pcm_runtime
*be
= dpcm
->be
;
156 struct snd_pcm_substream
*substream_be
;
157 struct snd_soc_dai
*dai
= be
->cpu_dai
;
162 substream_be
= snd_soc_dpcm_get_substream(be
, stream
);
163 dma_params_be
= snd_soc_dai_get_dma_data(dai
, substream_be
);
168 if (!dma_params_be
) {
169 dev_err(dev
, "failed to get the substream of Back-End\n");
173 /* Override dma_data of the Front-End and config its dmaengine */
174 dma_params_fe
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, substream
);
175 dma_params_fe
->addr
= asrc_priv
->paddr
+ REG_ASRDx(!dir
, index
);
176 dma_params_fe
->maxburst
= dma_params_be
->maxburst
;
178 pair
->dma_chan
[!dir
] = fsl_asrc_get_dma_channel(pair
, !dir
);
179 if (!pair
->dma_chan
[!dir
]) {
180 dev_err(dev
, "failed to request DMA channel\n");
184 memset(&config_fe
, 0, sizeof(config_fe
));
185 ret
= snd_dmaengine_pcm_prepare_slave_config(substream
, params
, &config_fe
);
187 dev_err(dev
, "failed to prepare DMA config for Front-End\n");
191 ret
= dmaengine_slave_config(pair
->dma_chan
[!dir
], &config_fe
);
193 dev_err(dev
, "failed to config DMA channel for Front-End\n");
197 /* Request and config DMA channel for Back-End */
199 dma_cap_set(DMA_SLAVE
, mask
);
200 dma_cap_set(DMA_CYCLIC
, mask
);
202 /* Get DMA request of Back-End */
203 tmp_chan
= dma_request_slave_channel(dev_be
, tx
? "tx" : "rx");
204 tmp_data
= tmp_chan
->private;
205 pair
->dma_data
.dma_request
= tmp_data
->dma_request
;
206 dma_release_channel(tmp_chan
);
208 /* Get DMA request of Front-End */
209 tmp_chan
= fsl_asrc_get_dma_channel(pair
, dir
);
210 tmp_data
= tmp_chan
->private;
211 pair
->dma_data
.dma_request2
= tmp_data
->dma_request
;
212 pair
->dma_data
.peripheral_type
= tmp_data
->peripheral_type
;
213 pair
->dma_data
.priority
= tmp_data
->priority
;
214 dma_release_channel(tmp_chan
);
216 pair
->dma_chan
[dir
] = dma_request_channel(mask
, filter
, &pair
->dma_data
);
217 if (!pair
->dma_chan
[dir
]) {
218 dev_err(dev
, "failed to request DMA channel for Back-End\n");
222 if (asrc_priv
->asrc_width
== 16)
223 buswidth
= DMA_SLAVE_BUSWIDTH_2_BYTES
;
225 buswidth
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
227 config_be
.direction
= DMA_DEV_TO_DEV
;
228 config_be
.src_addr_width
= buswidth
;
229 config_be
.src_maxburst
= dma_params_be
->maxburst
;
230 config_be
.dst_addr_width
= buswidth
;
231 config_be
.dst_maxburst
= dma_params_be
->maxburst
;
234 config_be
.src_addr
= asrc_priv
->paddr
+ REG_ASRDO(index
);
235 config_be
.dst_addr
= dma_params_be
->addr
;
237 config_be
.dst_addr
= asrc_priv
->paddr
+ REG_ASRDI(index
);
238 config_be
.src_addr
= dma_params_be
->addr
;
241 ret
= dmaengine_slave_config(pair
->dma_chan
[dir
], &config_be
);
243 dev_err(dev
, "failed to config DMA channel for Back-End\n");
247 snd_pcm_set_runtime_buffer(substream
, &substream
->dma_buffer
);
252 static int fsl_asrc_dma_hw_free(struct snd_pcm_substream
*substream
)
254 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
255 struct fsl_asrc_pair
*pair
= runtime
->private_data
;
257 snd_pcm_set_runtime_buffer(substream
, NULL
);
259 if (pair
->dma_chan
[IN
])
260 dma_release_channel(pair
->dma_chan
[IN
]);
262 if (pair
->dma_chan
[OUT
])
263 dma_release_channel(pair
->dma_chan
[OUT
]);
265 pair
->dma_chan
[IN
] = NULL
;
266 pair
->dma_chan
[OUT
] = NULL
;
271 static int fsl_asrc_dma_startup(struct snd_pcm_substream
*substream
)
273 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
274 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
275 struct snd_soc_component
*component
= snd_soc_rtdcom_lookup(rtd
, DRV_NAME
);
276 struct device
*dev
= component
->dev
;
277 struct fsl_asrc
*asrc_priv
= dev_get_drvdata(dev
);
278 struct fsl_asrc_pair
*pair
;
280 pair
= kzalloc(sizeof(struct fsl_asrc_pair
), GFP_KERNEL
);
284 pair
->asrc_priv
= asrc_priv
;
286 runtime
->private_data
= pair
;
288 snd_pcm_hw_constraint_integer(substream
->runtime
,
289 SNDRV_PCM_HW_PARAM_PERIODS
);
290 snd_soc_set_runtime_hwparams(substream
, &snd_imx_hardware
);
295 static int fsl_asrc_dma_shutdown(struct snd_pcm_substream
*substream
)
297 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
298 struct fsl_asrc_pair
*pair
= runtime
->private_data
;
299 struct fsl_asrc
*asrc_priv
;
304 asrc_priv
= pair
->asrc_priv
;
306 if (asrc_priv
->pair
[pair
->index
] == pair
)
307 asrc_priv
->pair
[pair
->index
] = NULL
;
314 static snd_pcm_uframes_t
fsl_asrc_dma_pcm_pointer(struct snd_pcm_substream
*substream
)
316 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
317 struct fsl_asrc_pair
*pair
= runtime
->private_data
;
319 return bytes_to_frames(substream
->runtime
, pair
->pos
);
322 static const struct snd_pcm_ops fsl_asrc_dma_pcm_ops
= {
323 .ioctl
= snd_pcm_lib_ioctl
,
324 .hw_params
= fsl_asrc_dma_hw_params
,
325 .hw_free
= fsl_asrc_dma_hw_free
,
326 .trigger
= fsl_asrc_dma_trigger
,
327 .open
= fsl_asrc_dma_startup
,
328 .close
= fsl_asrc_dma_shutdown
,
329 .pointer
= fsl_asrc_dma_pcm_pointer
,
332 static int fsl_asrc_dma_pcm_new(struct snd_soc_pcm_runtime
*rtd
)
334 struct snd_card
*card
= rtd
->card
->snd_card
;
335 struct snd_pcm_substream
*substream
;
336 struct snd_pcm
*pcm
= rtd
->pcm
;
339 ret
= dma_coerce_mask_and_coherent(card
->dev
, DMA_BIT_MASK(32));
341 dev_err(card
->dev
, "failed to set DMA mask\n");
345 for (i
= SNDRV_PCM_STREAM_PLAYBACK
; i
<= SNDRV_PCM_STREAM_LAST
; i
++) {
346 substream
= pcm
->streams
[i
].substream
;
350 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
, pcm
->card
->dev
,
351 FSL_ASRC_DMABUF_SIZE
, &substream
->dma_buffer
);
353 dev_err(card
->dev
, "failed to allocate DMA buffer\n");
361 if (--i
== 0 && pcm
->streams
[i
].substream
)
362 snd_dma_free_pages(&pcm
->streams
[i
].substream
->dma_buffer
);
367 static void fsl_asrc_dma_pcm_free(struct snd_pcm
*pcm
)
369 struct snd_pcm_substream
*substream
;
372 for (i
= SNDRV_PCM_STREAM_PLAYBACK
; i
<= SNDRV_PCM_STREAM_LAST
; i
++) {
373 substream
= pcm
->streams
[i
].substream
;
377 snd_dma_free_pages(&substream
->dma_buffer
);
378 substream
->dma_buffer
.area
= NULL
;
379 substream
->dma_buffer
.addr
= 0;
383 struct snd_soc_component_driver fsl_asrc_component
= {
385 .ops
= &fsl_asrc_dma_pcm_ops
,
386 .pcm_new
= fsl_asrc_dma_pcm_new
,
387 .pcm_free
= fsl_asrc_dma_pcm_free
,
389 EXPORT_SYMBOL_GPL(fsl_asrc_component
);