File Index
Files and directories
Sign in
FILE

tascam-stream.c

File preview with syntax highlighting.

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