digi00x-stream.c 10.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
/*
 * digi00x-stream.c - a part of driver for Digidesign Digi 002/003 family
 *
 * Copyright (c) 2014-2015 Takashi Sakamoto
 */

#include "digi00x.h"

#define CALLBACK_TIMEOUT 500

const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = {
	[SND_DG00X_RATE_44100] = 44100,
	[SND_DG00X_RATE_48000] = 48000,
	[SND_DG00X_RATE_88200] = 88200,
	[SND_DG00X_RATE_96000] = 96000,
};

/* Multi Bit Linear Audio data channels for each sampling transfer frequency. */
const unsigned int
snd_dg00x_stream_pcm_channels[SND_DG00X_RATE_COUNT] = {
	/* Analog/ADAT/SPDIF */
	[SND_DG00X_RATE_44100] = (8 + 8 + 2),
	[SND_DG00X_RATE_48000] = (8 + 8 + 2),
	/* Analog/SPDIF */
	[SND_DG00X_RATE_88200] = (8 + 2),
	[SND_DG00X_RATE_96000] = (8 + 2),
};

int snd_dg00x_stream_get_local_rate(struct snd_dg00x *dg00x, unsigned int *rate)
{
	u32 data;
	__be32 reg;
	int err;

	err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
				 DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
				 &reg, sizeof(reg), 0);
	if (err < 0)
		return err;

	data = be32_to_cpu(reg) & 0x0f;
	if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
		*rate = snd_dg00x_stream_rates[data];
	else
		err = -EIO;

	return err;
}

int snd_dg00x_stream_set_local_rate(struct snd_dg00x *dg00x, unsigned int rate)
{
	__be32 reg;
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(snd_dg00x_stream_rates); i++) {
		if (rate == snd_dg00x_stream_rates[i])
			break;
	}
	if (i == ARRAY_SIZE(snd_dg00x_stream_rates))
		return -EINVAL;

	reg = cpu_to_be32(i);
	return snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
				  DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
				  &reg, sizeof(reg), 0);
}

int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
			       enum snd_dg00x_clock *clock)
{
	__be32 reg;
	int err;

	err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
				 DG00X_ADDR_BASE + DG00X_OFFSET_CLOCK_SOURCE,
				 &reg, sizeof(reg), 0);
	if (err < 0)
		return err;

	*clock = be32_to_cpu(reg) & 0x0f;
	if (*clock >= SND_DG00X_CLOCK_COUNT)
		err = -EIO;

	return err;
}

int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x, bool *detect)
{
	__be32 reg;
	int err;

	err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
				 DG00X_ADDR_BASE + DG00X_OFFSET_DETECT_EXTERNAL,
				 &reg, sizeof(reg), 0);
	if (err >= 0)
		*detect = be32_to_cpu(reg) > 0;

	return err;
}

int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,
				       unsigned int *rate)
{
	u32 data;
	__be32 reg;
	int err;

	err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
				 DG00X_ADDR_BASE + DG00X_OFFSET_EXTERNAL_RATE,
				 &reg, sizeof(reg), 0);
	if (err < 0)
		return err;

	data = be32_to_cpu(reg) & 0x0f;
	if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
		*rate = snd_dg00x_stream_rates[data];
	/* This means desync. */
	else
		err = -EBUSY;

	return err;
}

static void finish_session(struct snd_dg00x *dg00x)
{
127 128 129
	__be32 data;

	data = cpu_to_be32(0x00000003);
130 131 132
	snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
			   DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
			   &data, sizeof(data), 0);
133 134 135 136 137 138

	// Unregister isochronous channels for both direction.
	data = 0;
	snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
			   DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
			   &data, sizeof(data), 0);
139 140 141 142

	// Just after finishing the session, the device may lost transmitting
	// functionality for a short time.
	msleep(50);
143 144 145 146 147 148 149 150
}

static int begin_session(struct snd_dg00x *dg00x)
{
	__be32 data;
	u32 curr;
	int err;

151 152 153 154 155 156 157
	// Register isochronous channels for both direction.
	data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
			   dg00x->rx_resources.channel);
	err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
				 DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
				 &data, sizeof(data), 0);
	if (err < 0)
158
		return err;
159

160 161 162 163
	err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
				 DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
				 &data, sizeof(data), 0);
	if (err < 0)
164
		return err;
165 166 167 168 169 170 171 172 173 174 175 176 177 178
	curr = be32_to_cpu(data);

	if (curr == 0)
		curr = 2;

	curr--;
	while (curr > 0) {
		data = cpu_to_be32(curr);
		err = snd_fw_transaction(dg00x->unit,
					 TCODE_WRITE_QUADLET_REQUEST,
					 DG00X_ADDR_BASE +
					 DG00X_OFFSET_STREAMING_SET,
					 &data, sizeof(data), 0);
		if (err < 0)
179
			break;
180 181 182 183 184 185 186 187

		msleep(20);
		curr--;
	}

	return err;
}

188 189
static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream,
			  unsigned int rate)
190
{
191 192
	struct fw_iso_resources *resources;
	int i;
193 194
	int err;

195
	// Check sampling rate.
196 197 198 199 200 201 202
	for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
		if (snd_dg00x_stream_rates[i] == rate)
			break;
	}
	if (i == SND_DG00X_RATE_COUNT)
		return -EINVAL;

203 204 205 206
	if (stream == &dg00x->tx_stream)
		resources = &dg00x->tx_resources;
	else
		resources = &dg00x->rx_resources;
207

208
	err = amdtp_dot_set_parameters(stream, rate,
209
				       snd_dg00x_stream_pcm_channels[i]);
210 211 212
	if (err < 0)
		return err;

213 214 215
	return fw_iso_resources_allocate(resources,
				amdtp_stream_get_max_payload(stream),
				fw_parent_device(dg00x->unit)->max_speed);
216 217
}

218
static int init_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s)
219
{
220 221
	struct fw_iso_resources *resources;
	enum amdtp_stream_direction dir;
222 223
	int err;

224 225 226 227 228 229 230 231 232
	if (s == &dg00x->tx_stream) {
		resources = &dg00x->tx_resources;
		dir = AMDTP_IN_STREAM;
	} else {
		resources = &dg00x->rx_resources;
		dir = AMDTP_OUT_STREAM;
	}

	err = fw_iso_resources_init(resources, dg00x->unit);
233
	if (err < 0)
234 235 236
		return err;

	err = amdtp_dot_init(s, dg00x->unit, dir);
237
	if (err < 0)
238 239 240 241 242 243 244 245
		fw_iso_resources_destroy(resources);

	return err;
}

static void destroy_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s)
{
	amdtp_stream_destroy(s);
246

247 248 249 250 251 252 253 254 255 256 257
	if (s == &dg00x->tx_stream)
		fw_iso_resources_destroy(&dg00x->tx_resources);
	else
		fw_iso_resources_destroy(&dg00x->rx_resources);
}

int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
{
	int err;

	err = init_stream(dg00x, &dg00x->rx_stream);
258
	if (err < 0)
259 260 261
		return err;

	err = init_stream(dg00x, &dg00x->tx_stream);
262
	if (err < 0)
263
		destroy_stream(dg00x, &dg00x->rx_stream);
264

265 266 267 268 269 270
	err = amdtp_domain_init(&dg00x->domain);
	if (err < 0) {
		destroy_stream(dg00x, &dg00x->rx_stream);
		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
 * streams.
 */
278 279
void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
{
280 281
	amdtp_domain_destroy(&dg00x->domain);

282 283
	destroy_stream(dg00x, &dg00x->rx_stream);
	destroy_stream(dg00x, &dg00x->tx_stream);
284 285
}

286
int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate,
287 288
				    unsigned int frames_per_period,
				    unsigned int frames_per_buffer)
289 290
{
	unsigned int curr_rate;
291
	int err;
292 293 294

	err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
	if (err < 0)
295
		return err;
296 297
	if (rate == 0)
		rate = curr_rate;
298 299

	if (dg00x->substreams_counter == 0 || curr_rate != rate) {
300 301
		amdtp_domain_stop(&dg00x->domain);

302 303
		finish_session(dg00x);

304 305
		fw_iso_resources_free(&dg00x->tx_resources);
		fw_iso_resources_free(&dg00x->rx_resources);
306 307 308

		err = snd_dg00x_stream_set_local_rate(dg00x, rate);
		if (err < 0)
309
			return err;
310

311 312
		err = keep_resources(dg00x, &dg00x->rx_stream, rate);
		if (err < 0)
313
			return err;
314 315

		err = keep_resources(dg00x, &dg00x->tx_stream, rate);
316 317 318 319
		if (err < 0) {
			fw_iso_resources_free(&dg00x->rx_resources);
			return err;
		}
320 321

		err = amdtp_domain_set_events_per_period(&dg00x->domain,
322
					frames_per_period, frames_per_buffer);
323 324 325 326 327
		if (err < 0) {
			fw_iso_resources_free(&dg00x->rx_resources);
			fw_iso_resources_free(&dg00x->tx_resources);
			return err;
		}
328 329 330 331
	}

	return 0;
}
332

333 334
int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
{
335
	unsigned int generation = dg00x->rx_resources.generation;
336 337 338 339 340 341
	int err = 0;

	if (dg00x->substreams_counter == 0)
		return 0;

	if (amdtp_streaming_error(&dg00x->tx_stream) ||
342 343
	    amdtp_streaming_error(&dg00x->rx_stream)) {
		amdtp_domain_stop(&dg00x->domain);
344
		finish_session(dg00x);
345
	}
346

347 348 349 350 351 352 353 354 355 356
	if (generation != fw_parent_device(dg00x->unit)->card->generation) {
		err = fw_iso_resources_update(&dg00x->tx_resources);
		if (err < 0)
			goto error;

		err = fw_iso_resources_update(&dg00x->rx_resources);
		if (err < 0)
			goto error;
	}

357 358 359 360 361
	/*
	 * No packets are transmitted without receiving packets, reagardless of
	 * which source of clock is used.
	 */
	if (!amdtp_stream_running(&dg00x->rx_stream)) {
362 363
		int spd = fw_parent_device(dg00x->unit)->max_speed;

364 365 366 367
		err = begin_session(dg00x);
		if (err < 0)
			goto error;

368 369
		err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->rx_stream,
					      dg00x->rx_resources.channel, spd);
370 371 372
		if (err < 0)
			goto error;

373 374 375
		err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->tx_stream,
					      dg00x->tx_resources.channel, spd);
		if (err < 0)
376 377
			goto error;

378
		err = amdtp_domain_start(&dg00x->domain, 0);
379 380 381
		if (err < 0)
			goto error;

382 383 384 385
		if (!amdtp_stream_wait_callback(&dg00x->rx_stream,
						CALLBACK_TIMEOUT) ||
		    !amdtp_stream_wait_callback(&dg00x->tx_stream,
						CALLBACK_TIMEOUT)) {
386 387 388 389
			err = -ETIMEDOUT;
			goto error;
		}
	}
390 391

	return 0;
392
error:
393
	amdtp_domain_stop(&dg00x->domain);
394 395 396 397 398 399 400
	finish_session(dg00x);

	return err;
}

void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
{
401
	if (dg00x->substreams_counter == 0) {
402
		amdtp_domain_stop(&dg00x->domain);
403
		finish_session(dg00x);
404 405 406 407

		fw_iso_resources_free(&dg00x->tx_resources);
		fw_iso_resources_free(&dg00x->rx_resources);
	}
408 409 410 411 412 413 414 415 416 417
}

void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
{
	fw_iso_resources_update(&dg00x->tx_resources);
	fw_iso_resources_update(&dg00x->rx_resources);

	amdtp_stream_update(&dg00x->tx_stream);
	amdtp_stream_update(&dg00x->rx_stream);
}
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456

void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x)
{
	dg00x->dev_lock_changed = true;
	wake_up(&dg00x->hwdep_wait);
}

int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x)
{
	int err;

	spin_lock_irq(&dg00x->lock);

	/* user land lock this */
	if (dg00x->dev_lock_count < 0) {
		err = -EBUSY;
		goto end;
	}

	/* this is the first time */
	if (dg00x->dev_lock_count++ == 0)
		snd_dg00x_stream_lock_changed(dg00x);
	err = 0;
end:
	spin_unlock_irq(&dg00x->lock);
	return err;
}

void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x)
{
	spin_lock_irq(&dg00x->lock);

	if (WARN_ON(dg00x->dev_lock_count <= 0))
		goto end;
	if (--dg00x->dev_lock_count == 0)
		snd_dg00x_stream_lock_changed(dg00x);
end:
	spin_unlock_irq(&dg00x->lock);
}