Merge tag 'selinux-pr-20201214' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / sound / soc / atmel / atmel-pcm-pdc.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * atmel-pcm.c  --  ALSA PCM interface for the Atmel atmel SoC.
4  *
5  *  Copyright (C) 2005 SAN People
6  *  Copyright (C) 2008 Atmel
7  *
8  * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
9  *
10  * Based on at91-pcm. by:
11  * Frank Mandarino <fmandarino@endrelia.com>
12  * Copyright 2006 Endrelia Technologies Inc.
13  *
14  * Based on pxa2xx-pcm.c by:
15  *
16  * Author:      Nicolas Pitre
17  * Created:     Nov 30, 2004
18  * Copyright:   (C) 2004 MontaVista Software, Inc.
19  */
20
21 #include <linux/module.h>
22 #include <linux/init.h>
23 #include <linux/platform_device.h>
24 #include <linux/slab.h>
25 #include <linux/dma-mapping.h>
26 #include <linux/atmel_pdc.h>
27 #include <linux/atmel-ssc.h>
28
29 #include <sound/core.h>
30 #include <sound/pcm.h>
31 #include <sound/pcm_params.h>
32 #include <sound/soc.h>
33
34 #include "atmel-pcm.h"
35
36
37 static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
38         int stream)
39 {
40         struct snd_pcm_substream *substream = pcm->streams[stream].substream;
41         struct snd_dma_buffer *buf = &substream->dma_buffer;
42         size_t size = ATMEL_SSC_DMABUF_SIZE;
43
44         buf->dev.type = SNDRV_DMA_TYPE_DEV;
45         buf->dev.dev = pcm->card->dev;
46         buf->private_data = NULL;
47         buf->area = dma_alloc_coherent(pcm->card->dev, size,
48                         &buf->addr, GFP_KERNEL);
49         pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n",
50                         (void *)buf->area, (void *)(long)buf->addr, size);
51
52         if (!buf->area)
53                 return -ENOMEM;
54
55         buf->bytes = size;
56         return 0;
57 }
58
59 static int atmel_pcm_mmap(struct snd_soc_component *component,
60                           struct snd_pcm_substream *substream,
61                           struct vm_area_struct *vma)
62 {
63         return remap_pfn_range(vma, vma->vm_start,
64                        substream->dma_buffer.addr >> PAGE_SHIFT,
65                        vma->vm_end - vma->vm_start, vma->vm_page_prot);
66 }
67
68 static int atmel_pcm_new(struct snd_soc_component *component,
69                          struct snd_soc_pcm_runtime *rtd)
70 {
71         struct snd_card *card = rtd->card->snd_card;
72         struct snd_pcm *pcm = rtd->pcm;
73         int ret;
74
75         ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
76         if (ret)
77                 return ret;
78
79         if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
80                 pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n");
81                 ret = atmel_pcm_preallocate_dma_buffer(pcm,
82                         SNDRV_PCM_STREAM_PLAYBACK);
83                 if (ret)
84                         goto out;
85         }
86
87         if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
88                 pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n");
89                 ret = atmel_pcm_preallocate_dma_buffer(pcm,
90                         SNDRV_PCM_STREAM_CAPTURE);
91                 if (ret)
92                         goto out;
93         }
94  out:
95         return ret;
96 }
97
98 static void atmel_pcm_free(struct snd_soc_component *component,
99                            struct snd_pcm *pcm)
100 {
101         struct snd_pcm_substream *substream;
102         struct snd_dma_buffer *buf;
103         int stream;
104
105         for (stream = 0; stream < 2; stream++) {
106                 substream = pcm->streams[stream].substream;
107                 if (!substream)
108                         continue;
109
110                 buf = &substream->dma_buffer;
111                 if (!buf->area)
112                         continue;
113                 dma_free_coherent(pcm->card->dev, buf->bytes,
114                                   buf->area, buf->addr);
115                 buf->area = NULL;
116         }
117 }
118
119 /*--------------------------------------------------------------------------*\
120  * Hardware definition
121 \*--------------------------------------------------------------------------*/
122 /* TODO: These values were taken from the AT91 platform driver, check
123  *       them against real values for AT32
124  */
125 static const struct snd_pcm_hardware atmel_pcm_hardware = {
126         .info                   = SNDRV_PCM_INFO_MMAP |
127                                   SNDRV_PCM_INFO_MMAP_VALID |
128                                   SNDRV_PCM_INFO_INTERLEAVED |
129                                   SNDRV_PCM_INFO_PAUSE,
130         .period_bytes_min       = 32,
131         .period_bytes_max       = 8192,
132         .periods_min            = 2,
133         .periods_max            = 1024,
134         .buffer_bytes_max       = ATMEL_SSC_DMABUF_SIZE,
135 };
136
137
138 /*--------------------------------------------------------------------------*\
139  * Data types
140 \*--------------------------------------------------------------------------*/
141 struct atmel_runtime_data {
142         struct atmel_pcm_dma_params *params;
143         dma_addr_t dma_buffer;          /* physical address of dma buffer */
144         dma_addr_t dma_buffer_end;      /* first address beyond DMA buffer */
145         size_t period_size;
146
147         dma_addr_t period_ptr;          /* physical address of next period */
148 };
149
150 /*--------------------------------------------------------------------------*\
151  * ISR
152 \*--------------------------------------------------------------------------*/
153 static void atmel_pcm_dma_irq(u32 ssc_sr,
154         struct snd_pcm_substream *substream)
155 {
156         struct atmel_runtime_data *prtd = substream->runtime->private_data;
157         struct atmel_pcm_dma_params *params = prtd->params;
158         static int count;
159
160         count++;
161
162         if (ssc_sr & params->mask->ssc_endbuf) {
163                 pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
164                                 substream->stream == SNDRV_PCM_STREAM_PLAYBACK
165                                 ? "underrun" : "overrun",
166                                 params->name, ssc_sr, count);
167
168                 /* re-start the PDC */
169                 ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
170                            params->mask->pdc_disable);
171                 prtd->period_ptr += prtd->period_size;
172                 if (prtd->period_ptr >= prtd->dma_buffer_end)
173                         prtd->period_ptr = prtd->dma_buffer;
174
175                 ssc_writex(params->ssc->regs, params->pdc->xpr,
176                            prtd->period_ptr);
177                 ssc_writex(params->ssc->regs, params->pdc->xcr,
178                            prtd->period_size / params->pdc_xfer_size);
179                 ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
180                            params->mask->pdc_enable);
181         }
182
183         if (ssc_sr & params->mask->ssc_endx) {
184                 /* Load the PDC next pointer and counter registers */
185                 prtd->period_ptr += prtd->period_size;
186                 if (prtd->period_ptr >= prtd->dma_buffer_end)
187                         prtd->period_ptr = prtd->dma_buffer;
188
189                 ssc_writex(params->ssc->regs, params->pdc->xnpr,
190                            prtd->period_ptr);
191                 ssc_writex(params->ssc->regs, params->pdc->xncr,
192                            prtd->period_size / params->pdc_xfer_size);
193         }
194
195         snd_pcm_period_elapsed(substream);
196 }
197
198
199 /*--------------------------------------------------------------------------*\
200  * PCM operations
201 \*--------------------------------------------------------------------------*/
202 static int atmel_pcm_hw_params(struct snd_soc_component *component,
203                                struct snd_pcm_substream *substream,
204                                struct snd_pcm_hw_params *params)
205 {
206         struct snd_pcm_runtime *runtime = substream->runtime;
207         struct atmel_runtime_data *prtd = runtime->private_data;
208         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
209
210         /* this may get called several times by oss emulation
211          * with different params */
212
213         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
214         runtime->dma_bytes = params_buffer_bytes(params);
215
216         prtd->params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
217         prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
218
219         prtd->dma_buffer = runtime->dma_addr;
220         prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
221         prtd->period_size = params_period_bytes(params);
222
223         pr_debug("atmel-pcm: "
224                 "hw_params: DMA for %s initialized "
225                 "(dma_bytes=%zu, period_size=%zu)\n",
226                 prtd->params->name,
227                 runtime->dma_bytes,
228                 prtd->period_size);
229         return 0;
230 }
231
232 static int atmel_pcm_hw_free(struct snd_soc_component *component,
233                              struct snd_pcm_substream *substream)
234 {
235         struct atmel_runtime_data *prtd = substream->runtime->private_data;
236         struct atmel_pcm_dma_params *params = prtd->params;
237
238         if (params != NULL) {
239                 ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
240                            params->mask->pdc_disable);
241                 prtd->params->dma_intr_handler = NULL;
242         }
243
244         return 0;
245 }
246
247 static int atmel_pcm_prepare(struct snd_soc_component *component,
248                              struct snd_pcm_substream *substream)
249 {
250         struct atmel_runtime_data *prtd = substream->runtime->private_data;
251         struct atmel_pcm_dma_params *params = prtd->params;
252
253         ssc_writex(params->ssc->regs, SSC_IDR,
254                    params->mask->ssc_endx | params->mask->ssc_endbuf);
255         ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
256                    params->mask->pdc_disable);
257         return 0;
258 }
259
260 static int atmel_pcm_trigger(struct snd_soc_component *component,
261                              struct snd_pcm_substream *substream, int cmd)
262 {
263         struct snd_pcm_runtime *rtd = substream->runtime;
264         struct atmel_runtime_data *prtd = rtd->private_data;
265         struct atmel_pcm_dma_params *params = prtd->params;
266         int ret = 0;
267
268         pr_debug("atmel-pcm:buffer_size = %ld,"
269                 "dma_area = %p, dma_bytes = %zu\n",
270                 rtd->buffer_size, rtd->dma_area, rtd->dma_bytes);
271
272         switch (cmd) {
273         case SNDRV_PCM_TRIGGER_START:
274                 prtd->period_ptr = prtd->dma_buffer;
275
276                 ssc_writex(params->ssc->regs, params->pdc->xpr,
277                            prtd->period_ptr);
278                 ssc_writex(params->ssc->regs, params->pdc->xcr,
279                            prtd->period_size / params->pdc_xfer_size);
280
281                 prtd->period_ptr += prtd->period_size;
282                 ssc_writex(params->ssc->regs, params->pdc->xnpr,
283                            prtd->period_ptr);
284                 ssc_writex(params->ssc->regs, params->pdc->xncr,
285                            prtd->period_size / params->pdc_xfer_size);
286
287                 pr_debug("atmel-pcm: trigger: "
288                         "period_ptr=%lx, xpr=%u, "
289                         "xcr=%u, xnpr=%u, xncr=%u\n",
290                         (unsigned long)prtd->period_ptr,
291                         ssc_readx(params->ssc->regs, params->pdc->xpr),
292                         ssc_readx(params->ssc->regs, params->pdc->xcr),
293                         ssc_readx(params->ssc->regs, params->pdc->xnpr),
294                         ssc_readx(params->ssc->regs, params->pdc->xncr));
295
296                 ssc_writex(params->ssc->regs, SSC_IER,
297                            params->mask->ssc_endx | params->mask->ssc_endbuf);
298                 ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
299                            params->mask->pdc_enable);
300
301                 pr_debug("sr=%u imr=%u\n",
302                         ssc_readx(params->ssc->regs, SSC_SR),
303                         ssc_readx(params->ssc->regs, SSC_IER));
304                 break;          /* SNDRV_PCM_TRIGGER_START */
305
306         case SNDRV_PCM_TRIGGER_STOP:
307         case SNDRV_PCM_TRIGGER_SUSPEND:
308         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
309                 ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
310                            params->mask->pdc_disable);
311                 break;
312
313         case SNDRV_PCM_TRIGGER_RESUME:
314         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
315                 ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
316                            params->mask->pdc_enable);
317                 break;
318
319         default:
320                 ret = -EINVAL;
321         }
322
323         return ret;
324 }
325
326 static snd_pcm_uframes_t atmel_pcm_pointer(struct snd_soc_component *component,
327                                            struct snd_pcm_substream *substream)
328 {
329         struct snd_pcm_runtime *runtime = substream->runtime;
330         struct atmel_runtime_data *prtd = runtime->private_data;
331         struct atmel_pcm_dma_params *params = prtd->params;
332         dma_addr_t ptr;
333         snd_pcm_uframes_t x;
334
335         ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr);
336         x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
337
338         if (x == runtime->buffer_size)
339                 x = 0;
340
341         return x;
342 }
343
344 static int atmel_pcm_open(struct snd_soc_component *component,
345                           struct snd_pcm_substream *substream)
346 {
347         struct snd_pcm_runtime *runtime = substream->runtime;
348         struct atmel_runtime_data *prtd;
349         int ret = 0;
350
351         snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware);
352
353         /* ensure that buffer size is a multiple of period size */
354         ret = snd_pcm_hw_constraint_integer(runtime,
355                                                 SNDRV_PCM_HW_PARAM_PERIODS);
356         if (ret < 0)
357                 goto out;
358
359         prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL);
360         if (prtd == NULL) {
361                 ret = -ENOMEM;
362                 goto out;
363         }
364         runtime->private_data = prtd;
365
366  out:
367         return ret;
368 }
369
370 static int atmel_pcm_close(struct snd_soc_component *component,
371                            struct snd_pcm_substream *substream)
372 {
373         struct atmel_runtime_data *prtd = substream->runtime->private_data;
374
375         kfree(prtd);
376         return 0;
377 }
378
379 static const struct snd_soc_component_driver atmel_soc_platform = {
380         .open           = atmel_pcm_open,
381         .close          = atmel_pcm_close,
382         .hw_params      = atmel_pcm_hw_params,
383         .hw_free        = atmel_pcm_hw_free,
384         .prepare        = atmel_pcm_prepare,
385         .trigger        = atmel_pcm_trigger,
386         .pointer        = atmel_pcm_pointer,
387         .mmap           = atmel_pcm_mmap,
388         .pcm_construct  = atmel_pcm_new,
389         .pcm_destruct   = atmel_pcm_free,
390 };
391
392 int atmel_pcm_pdc_platform_register(struct device *dev)
393 {
394         return devm_snd_soc_register_component(dev, &atmel_soc_platform,
395                                                NULL, 0);
396 }
397 EXPORT_SYMBOL(atmel_pcm_pdc_platform_register);
398
399 MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
400 MODULE_DESCRIPTION("Atmel PCM module");
401 MODULE_LICENSE("GPL");