1
2
3
4#include <linux/interrupt.h>
5#include <linux/slab.h>
6
7#include <sound/asoundef.h>
8
9#include "bcm2835.h"
10
11
12static 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 | SNDRV_PCM_INFO_BATCH),
16 .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
17 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
18 .rate_min = 8000,
19 .rate_max = 192000,
20 .channels_min = 1,
21 .channels_max = 8,
22 .buffer_bytes_max = 512 * 1024,
23 .period_bytes_min = 1 * 1024,
24 .period_bytes_max = 512 * 1024,
25 .periods_min = 1,
26 .periods_max = 128,
27};
28
29static 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 | SNDRV_PCM_INFO_BATCH),
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
47static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
48{
49 kfree(runtime->private_data);
50}
51
52void 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
85static 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
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
134 chip->spdif_status = 0;
135 runtime->hw = snd_bcm2835_playback_hw;
136 }
137
138 snd_pcm_hw_constraint_step(runtime,
139 0,
140 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
141 16);
142
143
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
152out:
153 mutex_unlock(&chip->audio_mutex);
154
155 return err;
156}
157
158static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
159{
160 return snd_bcm2835_playback_open_generic(substream, 0);
161}
162
163static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
164{
165 return snd_bcm2835_playback_open_generic(substream, 1);
166}
167
168static 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
186
187
188
189 chip->opened &= ~(1 << substream->number);
190
191 mutex_unlock(&chip->audio_mutex);
192
193 return 0;
194}
195
196static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
197{
198 struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
199 struct snd_pcm_runtime *runtime = substream->runtime;
200 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
201 int channels;
202 int err;
203
204
205
206
207
208 if (chip->spdif_status & IEC958_AES0_NONAUDIO)
209 channels = 0;
210 else
211 channels = runtime->channels;
212
213 err = bcm2835_audio_set_params(alsa_stream, channels,
214 runtime->rate,
215 snd_pcm_format_width(runtime->format));
216 if (err < 0)
217 return err;
218
219 memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
220
221 alsa_stream->pcm_indirect.hw_buffer_size =
222 alsa_stream->pcm_indirect.sw_buffer_size =
223 snd_pcm_lib_buffer_bytes(substream);
224
225 alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
226 alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
227 atomic_set(&alsa_stream->pos, 0);
228 alsa_stream->period_offset = 0;
229 alsa_stream->draining = false;
230 alsa_stream->interpolate_start = ktime_get();
231
232 return 0;
233}
234
235static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
236 struct snd_pcm_indirect *rec, size_t bytes)
237{
238 struct snd_pcm_runtime *runtime = substream->runtime;
239 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
240 void *src = (void *) (substream->runtime->dma_area + rec->sw_data);
241
242 bcm2835_audio_write(alsa_stream, bytes, src);
243}
244
245static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
246{
247 struct snd_pcm_runtime *runtime = substream->runtime;
248 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
249 struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
250
251 return snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
252 snd_bcm2835_pcm_transfer);
253}
254
255
256static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
257{
258 struct snd_pcm_runtime *runtime = substream->runtime;
259 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
260
261 switch (cmd) {
262 case SNDRV_PCM_TRIGGER_START:
263 return bcm2835_audio_start(alsa_stream);
264 case SNDRV_PCM_TRIGGER_DRAIN:
265 alsa_stream->draining = true;
266 return bcm2835_audio_drain(alsa_stream);
267 case SNDRV_PCM_TRIGGER_STOP:
268 return bcm2835_audio_stop(alsa_stream);
269 default:
270 return -EINVAL;
271 }
272}
273
274
275static snd_pcm_uframes_t
276snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
277{
278 struct snd_pcm_runtime *runtime = substream->runtime;
279 struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
280 ktime_t now = ktime_get();
281
282
283
284
285
286
287 if ((ktime_to_ns(alsa_stream->interpolate_start)) &&
288 (ktime_compare(alsa_stream->interpolate_start, now) < 0)) {
289 u64 interval =
290 (ktime_to_ns(ktime_sub(now,
291 alsa_stream->interpolate_start)));
292 u64 frames_output_in_interval =
293 div_u64((interval * runtime->rate), 1000000000);
294 snd_pcm_sframes_t frames_output_in_interval_sized =
295 -frames_output_in_interval;
296 runtime->delay = frames_output_in_interval_sized;
297 }
298
299 return snd_pcm_indirect_playback_pointer(substream,
300 &alsa_stream->pcm_indirect,
301 atomic_read(&alsa_stream->pos));
302}
303
304
305static const struct snd_pcm_ops snd_bcm2835_playback_ops = {
306 .open = snd_bcm2835_playback_open,
307 .close = snd_bcm2835_playback_close,
308 .prepare = snd_bcm2835_pcm_prepare,
309 .trigger = snd_bcm2835_pcm_trigger,
310 .pointer = snd_bcm2835_pcm_pointer,
311 .ack = snd_bcm2835_pcm_ack,
312};
313
314static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
315 .open = snd_bcm2835_playback_spdif_open,
316 .close = snd_bcm2835_playback_close,
317 .prepare = snd_bcm2835_pcm_prepare,
318 .trigger = snd_bcm2835_pcm_trigger,
319 .pointer = snd_bcm2835_pcm_pointer,
320 .ack = snd_bcm2835_pcm_ack,
321};
322
323
324int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name,
325 int idx, enum snd_bcm2835_route route,
326 u32 numchannels, bool spdif)
327{
328 struct snd_pcm *pcm;
329 int err;
330
331 err = snd_pcm_new(chip->card, name, idx, numchannels, 0, &pcm);
332 if (err)
333 return err;
334
335 pcm->private_data = chip;
336 pcm->nonatomic = true;
337 strscpy(pcm->name, name, sizeof(pcm->name));
338 if (!spdif) {
339 chip->dest = route;
340 chip->volume = 0;
341 chip->mute = CTRL_VOL_UNMUTE;
342 }
343
344 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
345 spdif ? &snd_bcm2835_playback_spdif_ops :
346 &snd_bcm2835_playback_ops);
347
348 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
349 chip->card->dev, 128 * 1024, 128 * 1024);
350
351 if (spdif)
352 chip->pcm_spdif = pcm;
353 else
354 chip->pcm = pcm;
355 return 0;
356}
357