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