1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2011 Broadcom Corporation. All rights reserved. */
4 #include <linux/interrupt.h>
5 #include <linux/slab.h>
7 #include <sound/asoundef.h>
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,
22 .buffer_bytes_max = 128 * 1024,
23 .period_bytes_min = 1 * 1024,
24 .period_bytes_max = 128 * 1024,
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 |
40 .buffer_bytes_max = 128 * 1024,
41 .period_bytes_min = 1 * 1024,
42 .period_bytes_max = 128 * 1024,
47 static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
49 kfree(runtime->private_data);
52 void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream,
55 struct snd_pcm_substream *substream = alsa_stream->substream;
58 if (!alsa_stream->period_size)
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);
71 pos = atomic_read(&alsa_stream->pos);
73 pos %= alsa_stream->buffer_size;
74 atomic_set(&alsa_stream->pos, pos);
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);
85 static int snd_bcm2835_playback_open_generic(
86 struct snd_pcm_substream *substream, int spdif)
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;
94 mutex_lock(&chip->audio_mutex);
95 idx = substream->number;
97 if (spdif && chip->opened) {
100 } else if (!spdif && (chip->opened & (1 << idx))) {
104 if (idx >= MAX_SUBSTREAMS) {
106 "substream(%d) device doesn't exist max(%d) substreams allowed\n",
107 idx, MAX_SUBSTREAMS);
112 alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL);
118 /* Initialise alsa_stream */
119 alsa_stream->chip = chip;
120 alsa_stream->substream = substream;
121 alsa_stream->idx = idx;
123 err = bcm2835_audio_open(alsa_stream);
128 runtime->private_data = alsa_stream;
129 runtime->private_free = snd_bcm2835_playback_free;
131 runtime->hw = snd_bcm2835_playback_spdif_hw;
133 /* clear spdif status, as we are not in spdif mode */
134 chip->spdif_status = 0;
135 runtime->hw = snd_bcm2835_playback_hw;
137 /* minimum 16 bytes alignment (for vchiq bulk transfers) */
138 snd_pcm_hw_constraint_step(runtime,
140 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
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);
148 chip->alsa_stream[idx] = alsa_stream;
150 chip->opened |= (1 << idx);
153 mutex_unlock(&chip->audio_mutex);
158 static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
160 return snd_bcm2835_playback_open_generic(substream, 0);
163 static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
165 return snd_bcm2835_playback_open_generic(substream, 1);
168 static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
170 struct bcm2835_alsa_stream *alsa_stream;
171 struct snd_pcm_runtime *runtime;
172 struct bcm2835_chip *chip;
174 chip = snd_pcm_substream_chip(substream);
175 mutex_lock(&chip->audio_mutex);
176 runtime = substream->runtime;
177 alsa_stream = runtime->private_data;
179 alsa_stream->period_size = 0;
180 alsa_stream->buffer_size = 0;
182 bcm2835_audio_close(alsa_stream);
183 alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
185 * Do not free up alsa_stream here, it will be freed up by
186 * runtime->private_free callback we registered in *_open above
189 chip->opened &= ~(1 << substream->number);
191 mutex_unlock(&chip->audio_mutex);
196 static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
197 struct snd_pcm_hw_params *params)
199 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
202 static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
204 return snd_pcm_lib_free_pages(substream);
207 static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
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;
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)
219 if (chip->spdif_status & IEC958_AES0_NONAUDIO)
222 channels = runtime->channels;
224 err = bcm2835_audio_set_params(alsa_stream, channels,
226 snd_pcm_format_width(runtime->format));
230 memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
232 alsa_stream->pcm_indirect.hw_buffer_size =
233 alsa_stream->pcm_indirect.sw_buffer_size =
234 snd_pcm_lib_buffer_bytes(substream);
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();
246 static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
247 struct snd_pcm_indirect *rec, size_t bytes)
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);
253 bcm2835_audio_write(alsa_stream, bytes, src);
256 static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
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;
262 return snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
263 snd_bcm2835_pcm_transfer);
266 /* trigger callback */
267 static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
269 struct snd_pcm_runtime *runtime = substream->runtime;
270 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
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);
285 /* pointer callback */
286 static snd_pcm_uframes_t
287 snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
289 struct snd_pcm_runtime *runtime = substream->runtime;
290 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
291 ktime_t now = ktime_get();
293 /* Give userspace better delay reporting by interpolating between GPU
294 * notifications, assuming audio speed is close enough to the clock
298 if ((ktime_to_ns(alsa_stream->interpolate_start)) &&
299 (ktime_compare(alsa_stream->interpolate_start, now) < 0)) {
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;
310 return snd_pcm_indirect_playback_pointer(substream,
311 &alsa_stream->pcm_indirect,
312 atomic_read(&alsa_stream->pos));
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,
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,
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)
348 err = snd_pcm_new(chip->card, name, idx, numchannels, 0, &pcm);
352 pcm->private_data = chip;
353 pcm->nonatomic = true;
354 strcpy(pcm->name, name);
358 chip->mute = CTRL_VOL_UNMUTE;
361 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
362 spdif ? &snd_bcm2835_playback_spdif_ops :
363 &snd_bcm2835_playback_ops);
365 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
366 chip->card->dev, 128 * 1024, 128 * 1024);
369 chip->pcm_spdif = pcm;