Merge tag 'iommu-updates-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / sound / firewire / digi00x / digi00x-stream.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * digi00x-stream.c - a part of driver for Digidesign Digi 002/003 family
4  *
5  * Copyright (c) 2014-2015 Takashi Sakamoto
6  */
7
8 #include "digi00x.h"
9
10 #define CALLBACK_TIMEOUT 500
11
12 const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = {
13         [SND_DG00X_RATE_44100] = 44100,
14         [SND_DG00X_RATE_48000] = 48000,
15         [SND_DG00X_RATE_88200] = 88200,
16         [SND_DG00X_RATE_96000] = 96000,
17 };
18
19 /* Multi Bit Linear Audio data channels for each sampling transfer frequency. */
20 const unsigned int
21 snd_dg00x_stream_pcm_channels[SND_DG00X_RATE_COUNT] = {
22         /* Analog/ADAT/SPDIF */
23         [SND_DG00X_RATE_44100] = (8 + 8 + 2),
24         [SND_DG00X_RATE_48000] = (8 + 8 + 2),
25         /* Analog/SPDIF */
26         [SND_DG00X_RATE_88200] = (8 + 2),
27         [SND_DG00X_RATE_96000] = (8 + 2),
28 };
29
30 int snd_dg00x_stream_get_local_rate(struct snd_dg00x *dg00x, unsigned int *rate)
31 {
32         u32 data;
33         __be32 reg;
34         int err;
35
36         err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
37                                  DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
38                                  &reg, sizeof(reg), 0);
39         if (err < 0)
40                 return err;
41
42         data = be32_to_cpu(reg) & 0x0f;
43         if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
44                 *rate = snd_dg00x_stream_rates[data];
45         else
46                 err = -EIO;
47
48         return err;
49 }
50
51 int snd_dg00x_stream_set_local_rate(struct snd_dg00x *dg00x, unsigned int rate)
52 {
53         __be32 reg;
54         unsigned int i;
55
56         for (i = 0; i < ARRAY_SIZE(snd_dg00x_stream_rates); i++) {
57                 if (rate == snd_dg00x_stream_rates[i])
58                         break;
59         }
60         if (i == ARRAY_SIZE(snd_dg00x_stream_rates))
61                 return -EINVAL;
62
63         reg = cpu_to_be32(i);
64         return snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
65                                   DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
66                                   &reg, sizeof(reg), 0);
67 }
68
69 int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
70                                enum snd_dg00x_clock *clock)
71 {
72         __be32 reg;
73         int err;
74
75         err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
76                                  DG00X_ADDR_BASE + DG00X_OFFSET_CLOCK_SOURCE,
77                                  &reg, sizeof(reg), 0);
78         if (err < 0)
79                 return err;
80
81         *clock = be32_to_cpu(reg) & 0x0f;
82         if (*clock >= SND_DG00X_CLOCK_COUNT)
83                 err = -EIO;
84
85         return err;
86 }
87
88 int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x, bool *detect)
89 {
90         __be32 reg;
91         int err;
92
93         err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
94                                  DG00X_ADDR_BASE + DG00X_OFFSET_DETECT_EXTERNAL,
95                                  &reg, sizeof(reg), 0);
96         if (err >= 0)
97                 *detect = be32_to_cpu(reg) > 0;
98
99         return err;
100 }
101
102 int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,
103                                        unsigned int *rate)
104 {
105         u32 data;
106         __be32 reg;
107         int err;
108
109         err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
110                                  DG00X_ADDR_BASE + DG00X_OFFSET_EXTERNAL_RATE,
111                                  &reg, sizeof(reg), 0);
112         if (err < 0)
113                 return err;
114
115         data = be32_to_cpu(reg) & 0x0f;
116         if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
117                 *rate = snd_dg00x_stream_rates[data];
118         /* This means desync. */
119         else
120                 err = -EBUSY;
121
122         return err;
123 }
124
125 static void finish_session(struct snd_dg00x *dg00x)
126 {
127         __be32 data;
128
129         data = cpu_to_be32(0x00000003);
130         snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
131                            DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
132                            &data, sizeof(data), 0);
133
134         // Unregister isochronous channels for both direction.
135         data = 0;
136         snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
137                            DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
138                            &data, sizeof(data), 0);
139
140         // Just after finishing the session, the device may lost transmitting
141         // functionality for a short time.
142         msleep(50);
143 }
144
145 static int begin_session(struct snd_dg00x *dg00x)
146 {
147         __be32 data;
148         u32 curr;
149         int err;
150
151         // Register isochronous channels for both direction.
152         data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
153                            dg00x->rx_resources.channel);
154         err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
155                                  DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
156                                  &data, sizeof(data), 0);
157         if (err < 0)
158                 return err;
159
160         err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
161                                  DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
162                                  &data, sizeof(data), 0);
163         if (err < 0)
164                 return err;
165         curr = be32_to_cpu(data);
166
167         if (curr == 0)
168                 curr = 2;
169
170         curr--;
171         while (curr > 0) {
172                 data = cpu_to_be32(curr);
173                 err = snd_fw_transaction(dg00x->unit,
174                                          TCODE_WRITE_QUADLET_REQUEST,
175                                          DG00X_ADDR_BASE +
176                                          DG00X_OFFSET_STREAMING_SET,
177                                          &data, sizeof(data), 0);
178                 if (err < 0)
179                         break;
180
181                 msleep(20);
182                 curr--;
183         }
184
185         return err;
186 }
187
188 static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream,
189                           unsigned int rate)
190 {
191         struct fw_iso_resources *resources;
192         int i;
193         int err;
194
195         // Check sampling rate.
196         for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
197                 if (snd_dg00x_stream_rates[i] == rate)
198                         break;
199         }
200         if (i == SND_DG00X_RATE_COUNT)
201                 return -EINVAL;
202
203         if (stream == &dg00x->tx_stream)
204                 resources = &dg00x->tx_resources;
205         else
206                 resources = &dg00x->rx_resources;
207
208         err = amdtp_dot_set_parameters(stream, rate,
209                                        snd_dg00x_stream_pcm_channels[i]);
210         if (err < 0)
211                 return err;
212
213         return fw_iso_resources_allocate(resources,
214                                 amdtp_stream_get_max_payload(stream),
215                                 fw_parent_device(dg00x->unit)->max_speed);
216 }
217
218 static int init_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s)
219 {
220         struct fw_iso_resources *resources;
221         enum amdtp_stream_direction dir;
222         int err;
223
224         if (s == &dg00x->tx_stream) {
225                 resources = &dg00x->tx_resources;
226                 dir = AMDTP_IN_STREAM;
227         } else {
228                 resources = &dg00x->rx_resources;
229                 dir = AMDTP_OUT_STREAM;
230         }
231
232         err = fw_iso_resources_init(resources, dg00x->unit);
233         if (err < 0)
234                 return err;
235
236         err = amdtp_dot_init(s, dg00x->unit, dir);
237         if (err < 0)
238                 fw_iso_resources_destroy(resources);
239
240         return err;
241 }
242
243 static void destroy_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s)
244 {
245         amdtp_stream_destroy(s);
246
247         if (s == &dg00x->tx_stream)
248                 fw_iso_resources_destroy(&dg00x->tx_resources);
249         else
250                 fw_iso_resources_destroy(&dg00x->rx_resources);
251 }
252
253 int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
254 {
255         int err;
256
257         err = init_stream(dg00x, &dg00x->rx_stream);
258         if (err < 0)
259                 return err;
260
261         err = init_stream(dg00x, &dg00x->tx_stream);
262         if (err < 0)
263                 destroy_stream(dg00x, &dg00x->rx_stream);
264
265         err = amdtp_domain_init(&dg00x->domain);
266         if (err < 0) {
267                 destroy_stream(dg00x, &dg00x->rx_stream);
268                 destroy_stream(dg00x, &dg00x->tx_stream);
269         }
270
271         return err;
272 }
273
274 /*
275  * This function should be called before starting streams or after stopping
276  * streams.
277  */
278 void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
279 {
280         amdtp_domain_destroy(&dg00x->domain);
281
282         destroy_stream(dg00x, &dg00x->rx_stream);
283         destroy_stream(dg00x, &dg00x->tx_stream);
284 }
285
286 int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate,
287                                     unsigned int frames_per_period,
288                                     unsigned int frames_per_buffer)
289 {
290         unsigned int curr_rate;
291         int err;
292
293         err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
294         if (err < 0)
295                 return err;
296         if (rate == 0)
297                 rate = curr_rate;
298
299         if (dg00x->substreams_counter == 0 || curr_rate != rate) {
300                 amdtp_domain_stop(&dg00x->domain);
301
302                 finish_session(dg00x);
303
304                 fw_iso_resources_free(&dg00x->tx_resources);
305                 fw_iso_resources_free(&dg00x->rx_resources);
306
307                 err = snd_dg00x_stream_set_local_rate(dg00x, rate);
308                 if (err < 0)
309                         return err;
310
311                 err = keep_resources(dg00x, &dg00x->rx_stream, rate);
312                 if (err < 0)
313                         return err;
314
315                 err = keep_resources(dg00x, &dg00x->tx_stream, rate);
316                 if (err < 0) {
317                         fw_iso_resources_free(&dg00x->rx_resources);
318                         return err;
319                 }
320
321                 err = amdtp_domain_set_events_per_period(&dg00x->domain,
322                                         frames_per_period, frames_per_buffer);
323                 if (err < 0) {
324                         fw_iso_resources_free(&dg00x->rx_resources);
325                         fw_iso_resources_free(&dg00x->tx_resources);
326                         return err;
327                 }
328         }
329
330         return 0;
331 }
332
333 int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
334 {
335         unsigned int generation = dg00x->rx_resources.generation;
336         int err = 0;
337
338         if (dg00x->substreams_counter == 0)
339                 return 0;
340
341         if (amdtp_streaming_error(&dg00x->tx_stream) ||
342             amdtp_streaming_error(&dg00x->rx_stream)) {
343                 amdtp_domain_stop(&dg00x->domain);
344                 finish_session(dg00x);
345         }
346
347         if (generation != fw_parent_device(dg00x->unit)->card->generation) {
348                 err = fw_iso_resources_update(&dg00x->tx_resources);
349                 if (err < 0)
350                         goto error;
351
352                 err = fw_iso_resources_update(&dg00x->rx_resources);
353                 if (err < 0)
354                         goto error;
355         }
356
357         /*
358          * No packets are transmitted without receiving packets, reagardless of
359          * which source of clock is used.
360          */
361         if (!amdtp_stream_running(&dg00x->rx_stream)) {
362                 int spd = fw_parent_device(dg00x->unit)->max_speed;
363
364                 err = begin_session(dg00x);
365                 if (err < 0)
366                         goto error;
367
368                 err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->rx_stream,
369                                               dg00x->rx_resources.channel, spd);
370                 if (err < 0)
371                         goto error;
372
373                 err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->tx_stream,
374                                               dg00x->tx_resources.channel, spd);
375                 if (err < 0)
376                         goto error;
377
378                 err = amdtp_domain_start(&dg00x->domain, 0);
379                 if (err < 0)
380                         goto error;
381
382                 if (!amdtp_stream_wait_callback(&dg00x->rx_stream,
383                                                 CALLBACK_TIMEOUT) ||
384                     !amdtp_stream_wait_callback(&dg00x->tx_stream,
385                                                 CALLBACK_TIMEOUT)) {
386                         err = -ETIMEDOUT;
387                         goto error;
388                 }
389         }
390
391         return 0;
392 error:
393         amdtp_domain_stop(&dg00x->domain);
394         finish_session(dg00x);
395
396         return err;
397 }
398
399 void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
400 {
401         if (dg00x->substreams_counter == 0) {
402                 amdtp_domain_stop(&dg00x->domain);
403                 finish_session(dg00x);
404
405                 fw_iso_resources_free(&dg00x->tx_resources);
406                 fw_iso_resources_free(&dg00x->rx_resources);
407         }
408 }
409
410 void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
411 {
412         fw_iso_resources_update(&dg00x->tx_resources);
413         fw_iso_resources_update(&dg00x->rx_resources);
414
415         amdtp_stream_update(&dg00x->tx_stream);
416         amdtp_stream_update(&dg00x->rx_stream);
417 }
418
419 void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x)
420 {
421         dg00x->dev_lock_changed = true;
422         wake_up(&dg00x->hwdep_wait);
423 }
424
425 int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x)
426 {
427         int err;
428
429         spin_lock_irq(&dg00x->lock);
430
431         /* user land lock this */
432         if (dg00x->dev_lock_count < 0) {
433                 err = -EBUSY;
434                 goto end;
435         }
436
437         /* this is the first time */
438         if (dg00x->dev_lock_count++ == 0)
439                 snd_dg00x_stream_lock_changed(dg00x);
440         err = 0;
441 end:
442         spin_unlock_irq(&dg00x->lock);
443         return err;
444 }
445
446 void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x)
447 {
448         spin_lock_irq(&dg00x->lock);
449
450         if (WARN_ON(dg00x->dev_lock_count <= 0))
451                 goto end;
452         if (--dg00x->dev_lock_count == 0)
453                 snd_dg00x_stream_lock_changed(dg00x);
454 end:
455         spin_unlock_irq(&dg00x->lock);
456 }