]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
b4b9e90131bf79abedd87b8d2ee10697b91f49c0
[linux.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         .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
16         .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
17         .rate_min = 8000,
18         .rate_max = 48000,
19         .channels_min = 1,
20         .channels_max = 2,
21         .buffer_bytes_max = 128 * 1024,
22         .period_bytes_min = 1 * 1024,
23         .period_bytes_max = 128 * 1024,
24         .periods_min = 1,
25         .periods_max = 128,
26 };
27
28 static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
29         .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
30         SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
31         .formats = SNDRV_PCM_FMTBIT_S16_LE,
32         .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
33         SNDRV_PCM_RATE_48000,
34         .rate_min = 44100,
35         .rate_max = 48000,
36         .channels_min = 2,
37         .channels_max = 2,
38         .buffer_bytes_max = 128 * 1024,
39         .period_bytes_min = 1 * 1024,
40         .period_bytes_max = 128 * 1024,
41         .periods_min = 1,
42         .periods_max = 128,
43 };
44
45 static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
46 {
47         audio_info("Freeing up alsa stream here ..\n");
48         kfree(runtime->private_data);
49         runtime->private_data = NULL;
50 }
51
52 void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream)
53 {
54         unsigned int consumed = 0;
55         int new_period = 0;
56
57         audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
58                 alsa_stream ? alsa_stream->substream : 0);
59
60         consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
61
62         /* We get called only if playback was triggered, So, the number of buffers we retrieve in
63          * each iteration are the buffers that have been played out already
64          */
65
66         if (alsa_stream->period_size) {
67                 if ((alsa_stream->pos / alsa_stream->period_size) !=
68                         ((alsa_stream->pos + consumed) / alsa_stream->period_size))
69                         new_period = 1;
70         }
71         audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
72                 alsa_stream->pos,
73                 consumed,
74                 alsa_stream->buffer_size,
75                 (int) (alsa_stream->period_size * alsa_stream->substream->runtime->periods),
76                 frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
77                 new_period);
78         if (alsa_stream->buffer_size) {
79                 alsa_stream->pos += consumed & ~(1 << 30);
80                 alsa_stream->pos %= alsa_stream->buffer_size;
81         }
82
83         if (alsa_stream->substream) {
84                 if (new_period)
85                         snd_pcm_period_elapsed(alsa_stream->substream);
86         } else {
87                 audio_warning(" unexpected NULL substream\n");
88         }
89 }
90
91 /* open callback */
92 static int snd_bcm2835_playback_open_generic(
93         struct snd_pcm_substream *substream, int spdif)
94 {
95         struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
96         struct snd_pcm_runtime *runtime = substream->runtime;
97         struct bcm2835_alsa_stream *alsa_stream;
98         int idx;
99         int err;
100
101         mutex_lock(&chip->audio_mutex);
102         audio_info("Alsa open (%d)\n", substream->number);
103         idx = substream->number;
104
105         if (spdif && chip->opened) {
106                 err = -EBUSY;
107                 goto out;
108         } else if (!spdif && (chip->opened & (1 << idx))) {
109                 err = -EBUSY;
110                 goto out;
111         }
112         if (idx >= MAX_SUBSTREAMS) {
113                 audio_error
114                         ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
115                         idx, MAX_SUBSTREAMS);
116                 err = -ENODEV;
117                 goto out;
118         }
119
120         alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL);
121         if (!alsa_stream) {
122                 err = -ENOMEM;
123                 goto out;
124         }
125
126         /* Initialise alsa_stream */
127         alsa_stream->chip = chip;
128         alsa_stream->substream = substream;
129         alsa_stream->idx = idx;
130
131         spin_lock_init(&alsa_stream->lock);
132
133         err = bcm2835_audio_open(alsa_stream);
134         if (err) {
135                 kfree(alsa_stream);
136                 goto out;
137         }
138         runtime->private_data = alsa_stream;
139         runtime->private_free = snd_bcm2835_playback_free;
140         if (spdif) {
141                 runtime->hw = snd_bcm2835_playback_spdif_hw;
142         } else {
143                 /* clear spdif status, as we are not in spdif mode */
144                 chip->spdif_status = 0;
145                 runtime->hw = snd_bcm2835_playback_hw;
146         }
147         /* minimum 16 bytes alignment (for vchiq bulk transfers) */
148         snd_pcm_hw_constraint_step(runtime,
149                                    0,
150                                    SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
151                                    16);
152
153         chip->alsa_stream[idx] = alsa_stream;
154
155         chip->opened |= (1 << idx);
156         alsa_stream->draining = 1;
157
158 out:
159         mutex_unlock(&chip->audio_mutex);
160
161         return err;
162 }
163
164 static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
165 {
166         return snd_bcm2835_playback_open_generic(substream, 0);
167 }
168
169 static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
170 {
171         return snd_bcm2835_playback_open_generic(substream, 1);
172 }
173
174 /* close callback */
175 static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
176 {
177         /* the hardware-specific codes will be here */
178
179         struct bcm2835_chip *chip;
180         struct snd_pcm_runtime *runtime;
181         struct bcm2835_alsa_stream *alsa_stream;
182
183         chip = snd_pcm_substream_chip(substream);
184         mutex_lock(&chip->audio_mutex);
185         runtime = substream->runtime;
186         alsa_stream = runtime->private_data;
187
188         audio_info("Alsa close\n");
189
190         alsa_stream->period_size = 0;
191         alsa_stream->buffer_size = 0;
192
193         bcm2835_audio_close(alsa_stream);
194         if (alsa_stream->chip)
195                 alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
196         /*
197          * Do not free up alsa_stream here, it will be freed up by
198          * runtime->private_free callback we registered in *_open above
199          */
200
201         chip->opened &= ~(1 << substream->number);
202
203         mutex_unlock(&chip->audio_mutex);
204
205         return 0;
206 }
207
208 /* hw_params callback */
209 static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
210         struct snd_pcm_hw_params *params)
211 {
212         struct snd_pcm_runtime *runtime = substream->runtime;
213         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
214         int err;
215
216         err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
217         if (err < 0) {
218                 audio_error
219                         (" pcm_lib_malloc failed to allocated pages for buffers\n");
220                 return err;
221         }
222
223         alsa_stream->channels = params_channels(params);
224         alsa_stream->params_rate = params_rate(params);
225         alsa_stream->pcm_format_width = snd_pcm_format_width(params_format(params));
226
227         return err;
228 }
229
230 /* hw_free callback */
231 static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
232 {
233         return snd_pcm_lib_free_pages(substream);
234 }
235
236 /* prepare callback */
237 static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
238 {
239         struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
240         struct snd_pcm_runtime *runtime = substream->runtime;
241         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
242         int channels;
243         int err;
244
245         mutex_lock(&chip->audio_mutex);
246
247         /* notify the vchiq that it should enter spdif passthrough mode by
248          * setting channels=0 (see
249          * https://github.com/raspberrypi/linux/issues/528)
250          */
251         if (chip->spdif_status & IEC958_AES0_NONAUDIO)
252                 channels = 0;
253         else
254                 channels = alsa_stream->channels;
255
256         err = bcm2835_audio_set_params(alsa_stream, channels,
257                 alsa_stream->params_rate,
258                 alsa_stream->pcm_format_width);
259         if (err < 0)
260                 audio_error(" error setting hw params\n");
261
262         memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
263
264         alsa_stream->pcm_indirect.hw_buffer_size =
265                 alsa_stream->pcm_indirect.sw_buffer_size =
266                 snd_pcm_lib_buffer_bytes(substream);
267
268         alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
269         alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
270         alsa_stream->pos = 0;
271
272         audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
273                 alsa_stream->buffer_size, alsa_stream->period_size,
274                 alsa_stream->pos, runtime->frame_bits);
275
276         mutex_unlock(&chip->audio_mutex);
277         return 0;
278 }
279
280 static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
281         struct snd_pcm_indirect *rec, size_t bytes)
282 {
283         struct snd_pcm_runtime *runtime = substream->runtime;
284         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
285         void *src = (void *) (substream->runtime->dma_area + rec->sw_data);
286         int err;
287
288         err = bcm2835_audio_write(alsa_stream, bytes, src);
289         if (err)
290                 audio_error(" Failed to transfer to alsa device (%d)\n", err);
291
292 }
293
294 static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
295 {
296         struct snd_pcm_runtime *runtime = substream->runtime;
297         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
298         struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
299
300         pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
301         return snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
302                                                   snd_bcm2835_pcm_transfer);
303 }
304
305 /* trigger callback */
306 static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
307 {
308         struct snd_pcm_runtime *runtime = substream->runtime;
309         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
310         int err = 0;
311
312         switch (cmd) {
313         case SNDRV_PCM_TRIGGER_START:
314                 err = bcm2835_audio_start(alsa_stream);
315                 if (!err)
316                         alsa_stream->draining = 1;
317                 else
318                         audio_error(" Failed to START alsa device (%d)\n", err);
319                 break;
320         case SNDRV_PCM_TRIGGER_STOP:
321                 if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
322                         audio_info("DRAINING\n");
323                         alsa_stream->draining = 1;
324                 } else {
325                         audio_info("DROPPING\n");
326                         alsa_stream->draining = 0;
327                 }
328                 err = bcm2835_audio_stop(alsa_stream);
329                 if (err != 0)
330                         audio_error(" Failed to STOP alsa device (%d)\n", err);
331                 break;
332         default:
333                 err = -EINVAL;
334         }
335
336         return err;
337 }
338
339 /* pointer callback */
340 static snd_pcm_uframes_t
341 snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
342 {
343         struct snd_pcm_runtime *runtime = substream->runtime;
344         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
345
346         audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
347                 frames_to_bytes(runtime, runtime->status->hw_ptr),
348                 frames_to_bytes(runtime, runtime->control->appl_ptr),
349                 alsa_stream->pos);
350
351         return snd_pcm_indirect_playback_pointer(substream,
352                 &alsa_stream->pcm_indirect,
353                 alsa_stream->pos);
354 }
355
356 static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
357         unsigned int cmd, void *arg)
358 {
359         int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
360
361         audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
362                 cmd, arg, arg ? *(unsigned int *)arg : 0, ret);
363         return ret;
364 }
365
366 /* operators */
367 static const struct snd_pcm_ops snd_bcm2835_playback_ops = {
368         .open = snd_bcm2835_playback_open,
369         .close = snd_bcm2835_playback_close,
370         .ioctl = snd_bcm2835_pcm_lib_ioctl,
371         .hw_params = snd_bcm2835_pcm_hw_params,
372         .hw_free = snd_bcm2835_pcm_hw_free,
373         .prepare = snd_bcm2835_pcm_prepare,
374         .trigger = snd_bcm2835_pcm_trigger,
375         .pointer = snd_bcm2835_pcm_pointer,
376         .ack = snd_bcm2835_pcm_ack,
377 };
378
379 static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
380         .open = snd_bcm2835_playback_spdif_open,
381         .close = snd_bcm2835_playback_close,
382         .ioctl = snd_bcm2835_pcm_lib_ioctl,
383         .hw_params = snd_bcm2835_pcm_hw_params,
384         .hw_free = snd_bcm2835_pcm_hw_free,
385         .prepare = snd_bcm2835_pcm_prepare,
386         .trigger = snd_bcm2835_pcm_trigger,
387         .pointer = snd_bcm2835_pcm_pointer,
388         .ack = snd_bcm2835_pcm_ack,
389 };
390
391 /* create a pcm device */
392 int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, u32 numchannels)
393 {
394         struct snd_pcm *pcm;
395         int err;
396
397         err = snd_pcm_new(chip->card, "bcm2835 ALSA", 0, numchannels, 0, &pcm);
398         if (err < 0)
399                 return err;
400         pcm->private_data = chip;
401         strcpy(pcm->name, "bcm2835 ALSA");
402         chip->pcm = pcm;
403         chip->dest = AUDIO_DEST_AUTO;
404         chip->volume = 0;
405         chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
406         /* set operators */
407         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
408                         &snd_bcm2835_playback_ops);
409
410         /* pre-allocation of buffers */
411         /* NOTE: this may fail */
412         snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
413                                               snd_dma_continuous_data(GFP_KERNEL),
414                                               snd_bcm2835_playback_hw.buffer_bytes_max,
415                                               snd_bcm2835_playback_hw.buffer_bytes_max);
416
417         return 0;
418 }
419
420 int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip)
421 {
422         struct snd_pcm *pcm;
423         int err;
424
425         err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
426         if (err < 0)
427                 return err;
428
429         pcm->private_data = chip;
430         strcpy(pcm->name, "bcm2835 IEC958/HDMI");
431         chip->pcm_spdif = pcm;
432         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
433                         &snd_bcm2835_playback_spdif_ops);
434
435         /* pre-allocation of buffers */
436         /* NOTE: this may fail */
437         snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
438                 snd_dma_continuous_data(GFP_KERNEL),
439                 snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max);
440
441         return 0;
442 }
443
444 int snd_bcm2835_new_simple_pcm(struct bcm2835_chip *chip,
445                                const char *name,
446                                enum snd_bcm2835_route route,
447                                u32 numchannels)
448 {
449         struct snd_pcm *pcm;
450         int err;
451
452         err = snd_pcm_new(chip->card, name, 0, numchannels,
453                           0, &pcm);
454         if (err)
455                 return err;
456
457         pcm->private_data = chip;
458         strcpy(pcm->name, name);
459         chip->pcm = pcm;
460         chip->dest = route;
461         chip->volume = 0;
462         chip->mute = CTRL_VOL_UNMUTE;
463
464         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
465                         &snd_bcm2835_playback_ops);
466
467         snd_pcm_lib_preallocate_pages_for_all(
468                 pcm,
469                 SNDRV_DMA_TYPE_CONTINUOUS,
470                 snd_dma_continuous_data(GFP_KERNEL),
471                 snd_bcm2835_playback_hw.buffer_bytes_max,
472                 snd_bcm2835_playback_hw.buffer_bytes_max);
473
474         return 0;
475 }
476