Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / drivers / staging / vc04_services / bcm2835-audio / bcm2835-pcm.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2011 Broadcom Corporation.  All rights reserved. */
3
4 #include <linux/interrupt.h>
5 #include <linux/slab.h>
6
7 #include <sound/asoundef.h>
8
9 #include "bcm2835.h"
10
11 /* hardware definition */
12 static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
13         .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
14                  SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
15                  SNDRV_PCM_INFO_SYNC_APPLPTR),
16         .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
17         .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
18         .rate_min = 8000,
19         .rate_max = 48000,
20         .channels_min = 1,
21         .channels_max = 2,
22         .buffer_bytes_max = 128 * 1024,
23         .period_bytes_min = 1 * 1024,
24         .period_bytes_max = 128 * 1024,
25         .periods_min = 1,
26         .periods_max = 128,
27 };
28
29 static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
30         .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
31                  SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
32                  SNDRV_PCM_INFO_SYNC_APPLPTR),
33         .formats = SNDRV_PCM_FMTBIT_S16_LE,
34         .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
35         SNDRV_PCM_RATE_48000,
36         .rate_min = 44100,
37         .rate_max = 48000,
38         .channels_min = 2,
39         .channels_max = 2,
40         .buffer_bytes_max = 128 * 1024,
41         .period_bytes_min = 1 * 1024,
42         .period_bytes_max = 128 * 1024,
43         .periods_min = 1,
44         .periods_max = 128,
45 };
46
47 static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
48 {
49         kfree(runtime->private_data);
50 }
51
52 void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream,
53                            unsigned int bytes)
54 {
55         struct snd_pcm_substream *substream = alsa_stream->substream;
56         unsigned int pos;
57
58         if (!alsa_stream->period_size)
59                 return;
60
61         if (bytes >= alsa_stream->buffer_size) {
62                 snd_pcm_stream_lock(substream);
63                 snd_pcm_stop(substream,
64                              alsa_stream->draining ?
65                              SNDRV_PCM_STATE_SETUP :
66                              SNDRV_PCM_STATE_XRUN);
67                 snd_pcm_stream_unlock(substream);
68                 return;
69         }
70
71         pos = atomic_read(&alsa_stream->pos);
72         pos += bytes;
73         pos %= alsa_stream->buffer_size;
74         atomic_set(&alsa_stream->pos, pos);
75
76         alsa_stream->period_offset += bytes;
77         alsa_stream->interpolate_start = ktime_get();
78         if (alsa_stream->period_offset >= alsa_stream->period_size) {
79                 alsa_stream->period_offset %= alsa_stream->period_size;
80                 snd_pcm_period_elapsed(substream);
81         }
82 }
83
84 /* open callback */
85 static int snd_bcm2835_playback_open_generic(
86         struct snd_pcm_substream *substream, int spdif)
87 {
88         struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
89         struct snd_pcm_runtime *runtime = substream->runtime;
90         struct bcm2835_alsa_stream *alsa_stream;
91         int idx;
92         int err;
93
94         mutex_lock(&chip->audio_mutex);
95         idx = substream->number;
96
97         if (spdif && chip->opened) {
98                 err = -EBUSY;
99                 goto out;
100         } else if (!spdif && (chip->opened & (1 << idx))) {
101                 err = -EBUSY;
102                 goto out;
103         }
104         if (idx >= MAX_SUBSTREAMS) {
105                 dev_err(chip->dev,
106                         "substream(%d) device doesn't exist max(%d) substreams allowed\n",
107                         idx, MAX_SUBSTREAMS);
108                 err = -ENODEV;
109                 goto out;
110         }
111
112         alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL);
113         if (!alsa_stream) {
114                 err = -ENOMEM;
115                 goto out;
116         }
117
118         /* Initialise alsa_stream */
119         alsa_stream->chip = chip;
120         alsa_stream->substream = substream;
121         alsa_stream->idx = idx;
122
123         err = bcm2835_audio_open(alsa_stream);
124         if (err) {
125                 kfree(alsa_stream);
126                 goto out;
127         }
128         runtime->private_data = alsa_stream;
129         runtime->private_free = snd_bcm2835_playback_free;
130         if (spdif) {
131                 runtime->hw = snd_bcm2835_playback_spdif_hw;
132         } else {
133                 /* clear spdif status, as we are not in spdif mode */
134                 chip->spdif_status = 0;
135                 runtime->hw = snd_bcm2835_playback_hw;
136         }
137         /* minimum 16 bytes alignment (for vchiq bulk transfers) */
138         snd_pcm_hw_constraint_step(runtime,
139                                    0,
140                                    SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
141                                    16);
142
143         /* position update is in 10ms order */
144         snd_pcm_hw_constraint_minmax(runtime,
145                                      SNDRV_PCM_HW_PARAM_PERIOD_TIME,
146                                      10 * 1000, UINT_MAX);
147
148         chip->alsa_stream[idx] = alsa_stream;
149
150         chip->opened |= (1 << idx);
151
152 out:
153         mutex_unlock(&chip->audio_mutex);
154
155         return err;
156 }
157
158 static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
159 {
160         return snd_bcm2835_playback_open_generic(substream, 0);
161 }
162
163 static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
164 {
165         return snd_bcm2835_playback_open_generic(substream, 1);
166 }
167
168 static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
169 {
170         struct bcm2835_alsa_stream *alsa_stream;
171         struct snd_pcm_runtime *runtime;
172         struct bcm2835_chip *chip;
173
174         chip = snd_pcm_substream_chip(substream);
175         mutex_lock(&chip->audio_mutex);
176         runtime = substream->runtime;
177         alsa_stream = runtime->private_data;
178
179         alsa_stream->period_size = 0;
180         alsa_stream->buffer_size = 0;
181
182         bcm2835_audio_close(alsa_stream);
183         alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
184         /*
185          * Do not free up alsa_stream here, it will be freed up by
186          * runtime->private_free callback we registered in *_open above
187          */
188
189         chip->opened &= ~(1 << substream->number);
190
191         mutex_unlock(&chip->audio_mutex);
192
193         return 0;
194 }
195
196 static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
197         struct snd_pcm_hw_params *params)
198 {
199         return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
200 }
201
202 static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
203 {
204         return snd_pcm_lib_free_pages(substream);
205 }
206
207 static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
208 {
209         struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
210         struct snd_pcm_runtime *runtime = substream->runtime;
211         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
212         int channels;
213         int err;
214
215         /* notify the vchiq that it should enter spdif passthrough mode by
216          * setting channels=0 (see
217          * https://github.com/raspberrypi/linux/issues/528)
218          */
219         if (chip->spdif_status & IEC958_AES0_NONAUDIO)
220                 channels = 0;
221         else
222                 channels = runtime->channels;
223
224         err = bcm2835_audio_set_params(alsa_stream, channels,
225                                        runtime->rate,
226                                        snd_pcm_format_width(runtime->format));
227         if (err < 0)
228                 return err;
229
230         memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
231
232         alsa_stream->pcm_indirect.hw_buffer_size =
233                 alsa_stream->pcm_indirect.sw_buffer_size =
234                 snd_pcm_lib_buffer_bytes(substream);
235
236         alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
237         alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
238         atomic_set(&alsa_stream->pos, 0);
239         alsa_stream->period_offset = 0;
240         alsa_stream->draining = false;
241         alsa_stream->interpolate_start = ktime_get();
242
243         return 0;
244 }
245
246 static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
247         struct snd_pcm_indirect *rec, size_t bytes)
248 {
249         struct snd_pcm_runtime *runtime = substream->runtime;
250         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
251         void *src = (void *) (substream->runtime->dma_area + rec->sw_data);
252
253         bcm2835_audio_write(alsa_stream, bytes, src);
254 }
255
256 static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
257 {
258         struct snd_pcm_runtime *runtime = substream->runtime;
259         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
260         struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
261
262         return snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
263                                                   snd_bcm2835_pcm_transfer);
264 }
265
266 /* trigger callback */
267 static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
268 {
269         struct snd_pcm_runtime *runtime = substream->runtime;
270         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
271
272         switch (cmd) {
273         case SNDRV_PCM_TRIGGER_START:
274                 return bcm2835_audio_start(alsa_stream);
275         case SNDRV_PCM_TRIGGER_DRAIN:
276                 alsa_stream->draining = true;
277                 return bcm2835_audio_drain(alsa_stream);
278         case SNDRV_PCM_TRIGGER_STOP:
279                 return bcm2835_audio_stop(alsa_stream);
280         default:
281                 return -EINVAL;
282         }
283 }
284
285 /* pointer callback */
286 static snd_pcm_uframes_t
287 snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
288 {
289         struct snd_pcm_runtime *runtime = substream->runtime;
290         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
291         ktime_t now = ktime_get();
292
293         /* Give userspace better delay reporting by interpolating between GPU
294          * notifications, assuming audio speed is close enough to the clock
295          * used for ktime
296          */
297
298         if ((ktime_to_ns(alsa_stream->interpolate_start)) &&
299             (ktime_compare(alsa_stream->interpolate_start, now) < 0)) {
300                 u64 interval =
301                         (ktime_to_ns(ktime_sub(now,
302                                 alsa_stream->interpolate_start)));
303                 u64 frames_output_in_interval =
304                         div_u64((interval * runtime->rate), 1000000000);
305                 snd_pcm_sframes_t frames_output_in_interval_sized =
306                         -frames_output_in_interval;
307                 runtime->delay = frames_output_in_interval_sized;
308         }
309
310         return snd_pcm_indirect_playback_pointer(substream,
311                 &alsa_stream->pcm_indirect,
312                 atomic_read(&alsa_stream->pos));
313 }
314
315 /* operators */
316 static const struct snd_pcm_ops snd_bcm2835_playback_ops = {
317         .open = snd_bcm2835_playback_open,
318         .close = snd_bcm2835_playback_close,
319         .ioctl = snd_pcm_lib_ioctl,
320         .hw_params = snd_bcm2835_pcm_hw_params,
321         .hw_free = snd_bcm2835_pcm_hw_free,
322         .prepare = snd_bcm2835_pcm_prepare,
323         .trigger = snd_bcm2835_pcm_trigger,
324         .pointer = snd_bcm2835_pcm_pointer,
325         .ack = snd_bcm2835_pcm_ack,
326 };
327
328 static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
329         .open = snd_bcm2835_playback_spdif_open,
330         .close = snd_bcm2835_playback_close,
331         .ioctl = snd_pcm_lib_ioctl,
332         .hw_params = snd_bcm2835_pcm_hw_params,
333         .hw_free = snd_bcm2835_pcm_hw_free,
334         .prepare = snd_bcm2835_pcm_prepare,
335         .trigger = snd_bcm2835_pcm_trigger,
336         .pointer = snd_bcm2835_pcm_pointer,
337         .ack = snd_bcm2835_pcm_ack,
338 };
339
340 /* create a pcm device */
341 int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name,
342                         int idx, enum snd_bcm2835_route route,
343                         u32 numchannels, bool spdif)
344 {
345         struct snd_pcm *pcm;
346         int err;
347
348         err = snd_pcm_new(chip->card, name, idx, numchannels, 0, &pcm);
349         if (err)
350                 return err;
351
352         pcm->private_data = chip;
353         pcm->nonatomic = true;
354         strcpy(pcm->name, name);
355         if (!spdif) {
356                 chip->dest = route;
357                 chip->volume = 0;
358                 chip->mute = CTRL_VOL_UNMUTE;
359         }
360
361         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
362                         spdif ? &snd_bcm2835_playback_spdif_ops :
363                         &snd_bcm2835_playback_ops);
364
365         snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
366                 chip->card->dev, 128 * 1024, 128 * 1024);
367
368         if (spdif)
369                 chip->pcm_spdif = pcm;
370         else
371                 chip->pcm = pcm;
372         return 0;
373 }