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 = cpu_to_be32(0x00000003);
128 
129 	snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
130 			   DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
131 			   &data, sizeof(data), 0);
132 }
133 
134 static int begin_session(struct snd_dg00x *dg00x)
135 {
136 	__be32 data;
137 	u32 curr;
138 	int err;
139 
140 	err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
141 				 DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
142 				 &data, sizeof(data), 0);
143 	if (err < 0)
144 		goto error;
145 	curr = be32_to_cpu(data);
146 
147 	if (curr == 0)
148 		curr = 2;
149 
150 	curr--;
151 	while (curr > 0) {
152 		data = cpu_to_be32(curr);
153 		err = snd_fw_transaction(dg00x->unit,
154 					 TCODE_WRITE_QUADLET_REQUEST,
155 					 DG00X_ADDR_BASE +
156 					 DG00X_OFFSET_STREAMING_SET,
157 					 &data, sizeof(data), 0);
158 		if (err < 0)
159 			goto error;
160 
161 		msleep(20);
162 		curr--;
163 	}
164 
165 	return 0;
166 error:
167 	finish_session(dg00x);
168 	return err;
169 }
170 
171 static void release_resources(struct snd_dg00x *dg00x)
172 {
173 	__be32 data = 0;
174 
175 	/* Unregister isochronous channels for both direction. */
176 	snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
177 			   DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
178 			   &data, sizeof(data), 0);
179 
180 	/* Release isochronous resources. */
181 	fw_iso_resources_free(&dg00x->tx_resources);
182 	fw_iso_resources_free(&dg00x->rx_resources);
183 }
184 
185 static int keep_resources(struct snd_dg00x *dg00x, unsigned int rate)
186 {
187 	unsigned int i;
188 	__be32 data;
189 	int err;
190 
191 	/* Check sampling rate. */
192 	for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
193 		if (snd_dg00x_stream_rates[i] == rate)
194 			break;
195 	}
196 	if (i == SND_DG00X_RATE_COUNT)
197 		return -EINVAL;
198 
199 	/* Keep resources for out-stream. */
200 	err = amdtp_dot_set_parameters(&dg00x->rx_stream, rate,
201 				       snd_dg00x_stream_pcm_channels[i]);
202 	if (err < 0)
203 		return err;
204 	err = fw_iso_resources_allocate(&dg00x->rx_resources,
205 				amdtp_stream_get_max_payload(&dg00x->rx_stream),
206 				fw_parent_device(dg00x->unit)->max_speed);
207 	if (err < 0)
208 		return err;
209 
210 	/* Keep resources for in-stream. */
211 	err = amdtp_dot_set_parameters(&dg00x->tx_stream, rate,
212 				       snd_dg00x_stream_pcm_channels[i]);
213 	if (err < 0)
214 		return err;
215 	err = fw_iso_resources_allocate(&dg00x->tx_resources,
216 				amdtp_stream_get_max_payload(&dg00x->tx_stream),
217 				fw_parent_device(dg00x->unit)->max_speed);
218 	if (err < 0)
219 		goto error;
220 
221 	/* Register isochronous channels for both direction. */
222 	data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
223 			   dg00x->rx_resources.channel);
224 	err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
225 				 DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
226 				 &data, sizeof(data), 0);
227 	if (err < 0)
228 		goto error;
229 
230 	return 0;
231 error:
232 	release_resources(dg00x);
233 	return err;
234 }
235 
236 int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
237 {
238 	int err;
239 
240 	/* For out-stream. */
241 	err = fw_iso_resources_init(&dg00x->rx_resources, dg00x->unit);
242 	if (err < 0)
243 		goto error;
244 	err = amdtp_dot_init(&dg00x->rx_stream, dg00x->unit, AMDTP_OUT_STREAM);
245 	if (err < 0)
246 		goto error;
247 
248 	/* For in-stream. */
249 	err = fw_iso_resources_init(&dg00x->tx_resources, dg00x->unit);
250 	if (err < 0)
251 		goto error;
252 	err = amdtp_dot_init(&dg00x->tx_stream, dg00x->unit, AMDTP_IN_STREAM);
253 	if (err < 0)
254 		goto error;
255 
256 	return 0;
257 error:
258 	snd_dg00x_stream_destroy_duplex(dg00x);
259 	return err;
260 }
261 
262 /*
263  * This function should be called before starting streams or after stopping
264  * streams.
265  */
266 void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
267 {
268 	amdtp_stream_destroy(&dg00x->rx_stream);
269 	fw_iso_resources_destroy(&dg00x->rx_resources);
270 
271 	amdtp_stream_destroy(&dg00x->tx_stream);
272 	fw_iso_resources_destroy(&dg00x->tx_resources);
273 }
274 
275 int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate)
276 {
277 	unsigned int curr_rate;
278 	int err = 0;
279 
280 	if (dg00x->substreams_counter == 0)
281 		goto end;
282 
283 	/* Check current sampling rate. */
284 	err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
285 	if (err < 0)
286 		goto error;
287 	if (rate == 0)
288 		rate = curr_rate;
289 	if (curr_rate != rate ||
290 	    amdtp_streaming_error(&dg00x->tx_stream) ||
291 	    amdtp_streaming_error(&dg00x->rx_stream)) {
292 		finish_session(dg00x);
293 
294 		amdtp_stream_stop(&dg00x->tx_stream);
295 		amdtp_stream_stop(&dg00x->rx_stream);
296 		release_resources(dg00x);
297 	}
298 
299 	/*
300 	 * No packets are transmitted without receiving packets, reagardless of
301 	 * which source of clock is used.
302 	 */
303 	if (!amdtp_stream_running(&dg00x->rx_stream)) {
304 		err = snd_dg00x_stream_set_local_rate(dg00x, rate);
305 		if (err < 0)
306 			goto error;
307 
308 		err = keep_resources(dg00x, rate);
309 		if (err < 0)
310 			goto error;
311 
312 		err = begin_session(dg00x);
313 		if (err < 0)
314 			goto error;
315 
316 		err = amdtp_stream_start(&dg00x->rx_stream,
317 				dg00x->rx_resources.channel,
318 				fw_parent_device(dg00x->unit)->max_speed);
319 		if (err < 0)
320 			goto error;
321 
322 		if (!amdtp_stream_wait_callback(&dg00x->rx_stream,
323 					      CALLBACK_TIMEOUT)) {
324 			err = -ETIMEDOUT;
325 			goto error;
326 		}
327 	}
328 
329 	/*
330 	 * The value of SYT field in transmitted packets is always 0x0000. Thus,
331 	 * duplex streams with timestamp synchronization cannot be built.
332 	 */
333 	if (!amdtp_stream_running(&dg00x->tx_stream)) {
334 		err = amdtp_stream_start(&dg00x->tx_stream,
335 				dg00x->tx_resources.channel,
336 				fw_parent_device(dg00x->unit)->max_speed);
337 		if (err < 0)
338 			goto error;
339 
340 		if (!amdtp_stream_wait_callback(&dg00x->tx_stream,
341 					      CALLBACK_TIMEOUT)) {
342 			err = -ETIMEDOUT;
343 			goto error;
344 		}
345 	}
346 end:
347 	return err;
348 error:
349 	finish_session(dg00x);
350 
351 	amdtp_stream_stop(&dg00x->tx_stream);
352 	amdtp_stream_stop(&dg00x->rx_stream);
353 	release_resources(dg00x);
354 
355 	return err;
356 }
357 
358 void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
359 {
360 	if (dg00x->substreams_counter > 0)
361 		return;
362 
363 	amdtp_stream_stop(&dg00x->tx_stream);
364 	amdtp_stream_stop(&dg00x->rx_stream);
365 	finish_session(dg00x);
366 	release_resources(dg00x);
367 
368 	/*
369 	 * Just after finishing the session, the device may lost transmitting
370 	 * functionality for a short time.
371 	 */
372 	msleep(50);
373 }
374 
375 void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
376 {
377 	fw_iso_resources_update(&dg00x->tx_resources);
378 	fw_iso_resources_update(&dg00x->rx_resources);
379 
380 	amdtp_stream_update(&dg00x->tx_stream);
381 	amdtp_stream_update(&dg00x->rx_stream);
382 }
383 
384 void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x)
385 {
386 	dg00x->dev_lock_changed = true;
387 	wake_up(&dg00x->hwdep_wait);
388 }
389 
390 int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x)
391 {
392 	int err;
393 
394 	spin_lock_irq(&dg00x->lock);
395 
396 	/* user land lock this */
397 	if (dg00x->dev_lock_count < 0) {
398 		err = -EBUSY;
399 		goto end;
400 	}
401 
402 	/* this is the first time */
403 	if (dg00x->dev_lock_count++ == 0)
404 		snd_dg00x_stream_lock_changed(dg00x);
405 	err = 0;
406 end:
407 	spin_unlock_irq(&dg00x->lock);
408 	return err;
409 }
410 
411 void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x)
412 {
413 	spin_lock_irq(&dg00x->lock);
414 
415 	if (WARN_ON(dg00x->dev_lock_count <= 0))
416 		goto end;
417 	if (--dg00x->dev_lock_count == 0)
418 		snd_dg00x_stream_lock_changed(dg00x);
419 end:
420 	spin_unlock_irq(&dg00x->lock);
421 }
422