1
2
3
4
5
6
7
8#include <linux/delay.h>
9#include "tascam.h"
10
11#define CALLBACK_TIMEOUT 500
12
13static int get_clock(struct snd_tscm *tscm, u32 *data)
14{
15 __be32 reg;
16 int err;
17
18 err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST,
19 TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS,
20 ®, sizeof(reg), 0);
21 if (err >= 0)
22 *data = be32_to_cpu(reg);
23
24 return err;
25}
26
27static int set_clock(struct snd_tscm *tscm, unsigned int rate,
28 enum snd_tscm_clock clock)
29{
30 u32 data;
31 __be32 reg;
32 int err;
33
34 err = get_clock(tscm, &data);
35 if (err < 0)
36 return err;
37 data &= 0x0000ffff;
38
39 if (rate > 0) {
40 data &= 0x000000ff;
41
42 if ((rate % 44100) == 0) {
43 data |= 0x00000100;
44
45 if (rate / 44100 == 2)
46 data |= 0x00008000;
47 } else if ((rate % 48000) == 0) {
48 data |= 0x00000200;
49
50 if (rate / 48000 == 2)
51 data |= 0x00008000;
52 } else {
53 return -EAGAIN;
54 }
55 }
56
57 if (clock != INT_MAX) {
58 data &= 0x0000ff00;
59 data |= clock + 1;
60 }
61
62 reg = cpu_to_be32(data);
63
64 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
65 TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS,
66 ®, sizeof(reg), 0);
67 if (err < 0)
68 return err;
69
70 if (data & 0x00008000)
71 reg = cpu_to_be32(0x0000001a);
72 else
73 reg = cpu_to_be32(0x0000000d);
74
75 return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
76 TSCM_ADDR_BASE + TSCM_OFFSET_MULTIPLEX_MODE,
77 ®, sizeof(reg), 0);
78}
79
80int snd_tscm_stream_get_rate(struct snd_tscm *tscm, unsigned int *rate)
81{
82 u32 data = 0x0;
83 unsigned int trials = 0;
84 int err;
85
86 while (data == 0x0 || trials++ < 5) {
87 err = get_clock(tscm, &data);
88 if (err < 0)
89 return err;
90
91 data = (data & 0xff000000) >> 24;
92 }
93
94
95 if ((data & 0x0f) == 0x01)
96 *rate = 44100;
97 else if ((data & 0x0f) == 0x02)
98 *rate = 48000;
99 else
100 return -EAGAIN;
101
102
103 if ((data & 0xf0) == 0x80)
104 *rate *= 2;
105 else if ((data & 0xf0) != 0x00)
106 return -EAGAIN;
107
108 return err;
109}
110
111int snd_tscm_stream_get_clock(struct snd_tscm *tscm, enum snd_tscm_clock *clock)
112{
113 u32 data;
114 int err;
115
116 err = get_clock(tscm, &data);
117 if (err < 0)
118 return err;
119
120 *clock = ((data & 0x00ff0000) >> 16) - 1;
121 if (*clock < 0 || *clock > SND_TSCM_CLOCK_ADAT)
122 return -EIO;
123
124 return 0;
125}
126
127static int enable_data_channels(struct snd_tscm *tscm)
128{
129 __be32 reg;
130 u32 data;
131 unsigned int i;
132 int err;
133
134 data = 0;
135 for (i = 0; i < tscm->spec->pcm_capture_analog_channels; ++i)
136 data |= BIT(i);
137 if (tscm->spec->has_adat)
138 data |= 0x0000ff00;
139 if (tscm->spec->has_spdif)
140 data |= 0x00030000;
141
142 reg = cpu_to_be32(data);
143 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
144 TSCM_ADDR_BASE + TSCM_OFFSET_TX_PCM_CHANNELS,
145 ®, sizeof(reg), 0);
146 if (err < 0)
147 return err;
148
149 data = 0;
150 for (i = 0; i < tscm->spec->pcm_playback_analog_channels; ++i)
151 data |= BIT(i);
152 if (tscm->spec->has_adat)
153 data |= 0x0000ff00;
154 if (tscm->spec->has_spdif)
155 data |= 0x00030000;
156
157 reg = cpu_to_be32(data);
158 return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
159 TSCM_ADDR_BASE + TSCM_OFFSET_RX_PCM_CHANNELS,
160 ®, sizeof(reg), 0);
161}
162
163static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate)
164{
165 __be32 reg;
166 int err;
167
168
169 reg = cpu_to_be32(0x00200000);
170 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
171 TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
172 ®, sizeof(reg), 0);
173 if (err < 0)
174 return err;
175
176 return enable_data_channels(tscm);
177}
178
179static void finish_session(struct snd_tscm *tscm)
180{
181 __be32 reg;
182
183 amdtp_stream_stop(&tscm->rx_stream);
184 amdtp_stream_stop(&tscm->tx_stream);
185
186 reg = 0;
187 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
188 TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,
189 ®, sizeof(reg), 0);
190
191 reg = 0;
192 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
193 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON,
194 ®, sizeof(reg), 0);
195
196
197 reg = cpu_to_be32(0x00000000);
198 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
199 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
200 ®, sizeof(reg), 0);
201 reg = cpu_to_be32(0x00000000);
202 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
203 TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
204 ®, sizeof(reg), 0);
205 reg = cpu_to_be32(0x00000000);
206 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
207 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
208 ®, sizeof(reg), 0);
209}
210
211static int begin_session(struct snd_tscm *tscm)
212{
213 __be32 reg;
214 int err;
215
216
217 reg = cpu_to_be32(tscm->tx_resources.channel);
218 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
219 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
220 ®, sizeof(reg), 0);
221 if (err < 0)
222 return err;
223
224
225 reg = cpu_to_be32(0x00000002);
226 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
227 TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
228 ®, sizeof(reg), 0);
229 if (err < 0)
230 return err;
231
232
233 reg = cpu_to_be32(tscm->rx_resources.channel);
234 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
235 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
236 ®, sizeof(reg), 0);
237 if (err < 0)
238 return err;
239
240 reg = cpu_to_be32(0x00000001);
241 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
242 TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,
243 ®, sizeof(reg), 0);
244 if (err < 0)
245 return err;
246
247 reg = cpu_to_be32(0x00000001);
248 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
249 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON,
250 ®, sizeof(reg), 0);
251 if (err < 0)
252 return err;
253
254
255 reg = cpu_to_be32(0x00002000);
256 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
257 TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
258 ®, sizeof(reg), 0);
259 if (err < 0)
260 return err;
261
262
263 reg = cpu_to_be32(0x00000001);
264 return snd_fw_transaction(tscm->unit,
265 TCODE_WRITE_QUADLET_REQUEST,
266 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_ON,
267 ®, sizeof(reg), 0);
268}
269
270static int keep_resources(struct snd_tscm *tscm, unsigned int rate,
271 struct amdtp_stream *stream)
272{
273 struct fw_iso_resources *resources;
274 int err;
275
276 if (stream == &tscm->tx_stream)
277 resources = &tscm->tx_resources;
278 else
279 resources = &tscm->rx_resources;
280
281 err = amdtp_tscm_set_parameters(stream, rate);
282 if (err < 0)
283 return err;
284
285 return fw_iso_resources_allocate(resources,
286 amdtp_stream_get_max_payload(stream),
287 fw_parent_device(tscm->unit)->max_speed);
288}
289
290int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
291{
292 unsigned int pcm_channels;
293 int err;
294
295
296 err = fw_iso_resources_init(&tscm->rx_resources, tscm->unit);
297 if (err < 0)
298 return err;
299 pcm_channels = tscm->spec->pcm_playback_analog_channels;
300 if (tscm->spec->has_adat)
301 pcm_channels += 8;
302 if (tscm->spec->has_spdif)
303 pcm_channels += 2;
304 err = amdtp_tscm_init(&tscm->rx_stream, tscm->unit, AMDTP_OUT_STREAM,
305 pcm_channels);
306 if (err < 0)
307 return err;
308
309
310 err = fw_iso_resources_init(&tscm->tx_resources, tscm->unit);
311 if (err < 0)
312 return err;
313 pcm_channels = tscm->spec->pcm_capture_analog_channels;
314 if (tscm->spec->has_adat)
315 pcm_channels += 8;
316 if (tscm->spec->has_spdif)
317 pcm_channels += 2;
318 err = amdtp_tscm_init(&tscm->tx_stream, tscm->unit, AMDTP_IN_STREAM,
319 pcm_channels);
320 if (err < 0)
321 amdtp_stream_destroy(&tscm->rx_stream);
322
323 return err;
324}
325
326
327void snd_tscm_stream_update_duplex(struct snd_tscm *tscm)
328{
329 amdtp_stream_pcm_abort(&tscm->tx_stream);
330 amdtp_stream_stop(&tscm->tx_stream);
331
332 amdtp_stream_pcm_abort(&tscm->rx_stream);
333 amdtp_stream_stop(&tscm->rx_stream);
334}
335
336
337
338
339
340void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm)
341{
342 amdtp_stream_destroy(&tscm->rx_stream);
343 amdtp_stream_destroy(&tscm->tx_stream);
344
345 fw_iso_resources_destroy(&tscm->rx_resources);
346 fw_iso_resources_destroy(&tscm->tx_resources);
347}
348
349int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate)
350{
351 unsigned int curr_rate;
352 int err;
353
354 err = snd_tscm_stream_get_rate(tscm, &curr_rate);
355 if (err < 0)
356 return err;
357
358 if (tscm->substreams_counter == 0 || rate != curr_rate) {
359 finish_session(tscm);
360
361 fw_iso_resources_free(&tscm->tx_resources);
362 fw_iso_resources_free(&tscm->rx_resources);
363
364 err = set_clock(tscm, rate, INT_MAX);
365 if (err < 0)
366 return err;
367
368 err = keep_resources(tscm, rate, &tscm->tx_stream);
369 if (err < 0)
370 return err;
371
372 err = keep_resources(tscm, rate, &tscm->rx_stream);
373 if (err < 0) {
374 fw_iso_resources_free(&tscm->tx_resources);
375 return err;
376 }
377 }
378
379 return 0;
380}
381
382int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
383{
384 unsigned int generation = tscm->rx_resources.generation;
385 int err;
386
387 if (tscm->substreams_counter == 0)
388 return 0;
389
390 if (amdtp_streaming_error(&tscm->rx_stream) ||
391 amdtp_streaming_error(&tscm->tx_stream))
392 finish_session(tscm);
393
394 if (generation != fw_parent_device(tscm->unit)->card->generation) {
395 err = fw_iso_resources_update(&tscm->tx_resources);
396 if (err < 0)
397 goto error;
398
399 err = fw_iso_resources_update(&tscm->rx_resources);
400 if (err < 0)
401 goto error;
402 }
403
404 if (!amdtp_stream_running(&tscm->rx_stream)) {
405 err = set_stream_formats(tscm, rate);
406 if (err < 0)
407 goto error;
408
409 err = begin_session(tscm);
410 if (err < 0)
411 goto error;
412
413 err = amdtp_stream_start(&tscm->rx_stream,
414 tscm->rx_resources.channel,
415 fw_parent_device(tscm->unit)->max_speed);
416 if (err < 0)
417 goto error;
418
419 if (!amdtp_stream_wait_callback(&tscm->rx_stream,
420 CALLBACK_TIMEOUT)) {
421 err = -ETIMEDOUT;
422 goto error;
423 }
424 }
425
426 if (!amdtp_stream_running(&tscm->tx_stream)) {
427 err = amdtp_stream_start(&tscm->tx_stream,
428 tscm->tx_resources.channel,
429 fw_parent_device(tscm->unit)->max_speed);
430 if (err < 0)
431 goto error;
432
433 if (!amdtp_stream_wait_callback(&tscm->tx_stream,
434 CALLBACK_TIMEOUT)) {
435 err = -ETIMEDOUT;
436 goto error;
437 }
438 }
439
440 return 0;
441error:
442 finish_session(tscm);
443
444 return err;
445}
446
447void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm)
448{
449 if (tscm->substreams_counter == 0) {
450 finish_session(tscm);
451
452 fw_iso_resources_free(&tscm->tx_resources);
453 fw_iso_resources_free(&tscm->rx_resources);
454 }
455}
456
457void snd_tscm_stream_lock_changed(struct snd_tscm *tscm)
458{
459 tscm->dev_lock_changed = true;
460 wake_up(&tscm->hwdep_wait);
461}
462
463int snd_tscm_stream_lock_try(struct snd_tscm *tscm)
464{
465 int err;
466
467 spin_lock_irq(&tscm->lock);
468
469
470 if (tscm->dev_lock_count < 0) {
471 err = -EBUSY;
472 goto end;
473 }
474
475
476 if (tscm->dev_lock_count++ == 0)
477 snd_tscm_stream_lock_changed(tscm);
478 err = 0;
479end:
480 spin_unlock_irq(&tscm->lock);
481 return err;
482}
483
484void snd_tscm_stream_lock_release(struct snd_tscm *tscm)
485{
486 spin_lock_irq(&tscm->lock);
487
488 if (WARN_ON(tscm->dev_lock_count <= 0))
489 goto end;
490 if (--tscm->dev_lock_count == 0)
491 snd_tscm_stream_lock_changed(tscm);
492end:
493 spin_unlock_irq(&tscm->lock);
494}
495