Linux 6.9-rc6
[sfrench/cifs-2.6.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 READY_TIMEOUT_MS        200
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                 return err;
265         }
266
267         err = amdtp_domain_init(&dg00x->domain);
268         if (err < 0) {
269                 destroy_stream(dg00x, &dg00x->rx_stream);
270                 destroy_stream(dg00x, &dg00x->tx_stream);
271         }
272
273         return err;
274 }
275
276 /*
277  * This function should be called before starting streams or after stopping
278  * streams.
279  */
280 void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
281 {
282         amdtp_domain_destroy(&dg00x->domain);
283
284         destroy_stream(dg00x, &dg00x->rx_stream);
285         destroy_stream(dg00x, &dg00x->tx_stream);
286 }
287
288 int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate,
289                                     unsigned int frames_per_period,
290                                     unsigned int frames_per_buffer)
291 {
292         unsigned int curr_rate;
293         int err;
294
295         err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
296         if (err < 0)
297                 return err;
298         if (rate == 0)
299                 rate = curr_rate;
300
301         if (dg00x->substreams_counter == 0 || curr_rate != rate) {
302                 amdtp_domain_stop(&dg00x->domain);
303
304                 finish_session(dg00x);
305
306                 fw_iso_resources_free(&dg00x->tx_resources);
307                 fw_iso_resources_free(&dg00x->rx_resources);
308
309                 err = snd_dg00x_stream_set_local_rate(dg00x, rate);
310                 if (err < 0)
311                         return err;
312
313                 err = keep_resources(dg00x, &dg00x->rx_stream, rate);
314                 if (err < 0)
315                         return err;
316
317                 err = keep_resources(dg00x, &dg00x->tx_stream, rate);
318                 if (err < 0) {
319                         fw_iso_resources_free(&dg00x->rx_resources);
320                         return err;
321                 }
322
323                 err = amdtp_domain_set_events_per_period(&dg00x->domain,
324                                         frames_per_period, frames_per_buffer);
325                 if (err < 0) {
326                         fw_iso_resources_free(&dg00x->rx_resources);
327                         fw_iso_resources_free(&dg00x->tx_resources);
328                         return err;
329                 }
330         }
331
332         return 0;
333 }
334
335 int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
336 {
337         unsigned int generation = dg00x->rx_resources.generation;
338         int err = 0;
339
340         if (dg00x->substreams_counter == 0)
341                 return 0;
342
343         if (amdtp_streaming_error(&dg00x->tx_stream) ||
344             amdtp_streaming_error(&dg00x->rx_stream)) {
345                 amdtp_domain_stop(&dg00x->domain);
346                 finish_session(dg00x);
347         }
348
349         if (generation != fw_parent_device(dg00x->unit)->card->generation) {
350                 err = fw_iso_resources_update(&dg00x->tx_resources);
351                 if (err < 0)
352                         goto error;
353
354                 err = fw_iso_resources_update(&dg00x->rx_resources);
355                 if (err < 0)
356                         goto error;
357         }
358
359         /*
360          * No packets are transmitted without receiving packets, reagardless of
361          * which source of clock is used.
362          */
363         if (!amdtp_stream_running(&dg00x->rx_stream)) {
364                 int spd = fw_parent_device(dg00x->unit)->max_speed;
365
366                 err = begin_session(dg00x);
367                 if (err < 0)
368                         goto error;
369
370                 err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->rx_stream,
371                                               dg00x->rx_resources.channel, spd);
372                 if (err < 0)
373                         goto error;
374
375                 err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->tx_stream,
376                                               dg00x->tx_resources.channel, spd);
377                 if (err < 0)
378                         goto error;
379
380                 // NOTE: The device doesn't start packet transmission till receiving any packet.
381                 // It ignores presentation time expressed by the value of syt field of CIP header
382                 // in received packets. The sequence of the number of data blocks per packet is
383                 // important for media clock recovery.
384                 err = amdtp_domain_start(&dg00x->domain, 0, true, true);
385                 if (err < 0)
386                         goto error;
387
388                 if (!amdtp_domain_wait_ready(&dg00x->domain, READY_TIMEOUT_MS)) {
389                         err = -ETIMEDOUT;
390                         goto error;
391                 }
392         }
393
394         return 0;
395 error:
396         amdtp_domain_stop(&dg00x->domain);
397         finish_session(dg00x);
398
399         return err;
400 }
401
402 void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
403 {
404         if (dg00x->substreams_counter == 0) {
405                 amdtp_domain_stop(&dg00x->domain);
406                 finish_session(dg00x);
407
408                 fw_iso_resources_free(&dg00x->tx_resources);
409                 fw_iso_resources_free(&dg00x->rx_resources);
410         }
411 }
412
413 void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
414 {
415         fw_iso_resources_update(&dg00x->tx_resources);
416         fw_iso_resources_update(&dg00x->rx_resources);
417
418         amdtp_stream_update(&dg00x->tx_stream);
419         amdtp_stream_update(&dg00x->rx_stream);
420 }
421
422 void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x)
423 {
424         dg00x->dev_lock_changed = true;
425         wake_up(&dg00x->hwdep_wait);
426 }
427
428 int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x)
429 {
430         int err;
431
432         spin_lock_irq(&dg00x->lock);
433
434         /* user land lock this */
435         if (dg00x->dev_lock_count < 0) {
436                 err = -EBUSY;
437                 goto end;
438         }
439
440         /* this is the first time */
441         if (dg00x->dev_lock_count++ == 0)
442                 snd_dg00x_stream_lock_changed(dg00x);
443         err = 0;
444 end:
445         spin_unlock_irq(&dg00x->lock);
446         return err;
447 }
448
449 void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x)
450 {
451         spin_lock_irq(&dg00x->lock);
452
453         if (WARN_ON(dg00x->dev_lock_count <= 0))
454                 goto end;
455         if (--dg00x->dev_lock_count == 0)
456                 snd_dg00x_stream_lock_changed(dg00x);
457 end:
458         spin_unlock_irq(&dg00x->lock);
459 }