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 CALLBACK_TIMEOUT 500 12 13 static 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 27 static 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 /* Base rate. */ 42 if ((rate % 44100) == 0) { 43 data |= 0x00000100; 44 /* Multiplier. */ 45 if (rate / 44100 == 2) 46 data |= 0x00008000; 47 } else if ((rate % 48000) == 0) { 48 data |= 0x00000200; 49 /* Multiplier. */ 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 80 int 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 /* Check base rate. */ 95 if ((data & 0x0f) == 0x01) 96 *rate = 44100; 97 else if ((data & 0x0f) == 0x02) 98 *rate = 48000; 99 else 100 return -EAGAIN; 101 102 /* Check multiplier. */ 103 if ((data & 0xf0) == 0x80) 104 *rate *= 2; 105 else if ((data & 0xf0) != 0x00) 106 return -EAGAIN; 107 108 return err; 109 } 110 111 int 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 127 static 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 163 static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate) 164 { 165 __be32 reg; 166 int err; 167 168 /* Set an option for unknown purpose. */ 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 err = enable_data_channels(tscm); 177 if (err < 0) 178 return err; 179 180 return set_clock(tscm, rate, INT_MAX); 181 } 182 183 static void finish_session(struct snd_tscm *tscm) 184 { 185 __be32 reg; 186 187 reg = 0; 188 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, 189 TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING, 190 ®, sizeof(reg), 0); 191 192 reg = 0; 193 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, 194 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON, 195 ®, sizeof(reg), 0); 196 197 } 198 199 static int begin_session(struct snd_tscm *tscm) 200 { 201 __be32 reg; 202 int err; 203 204 reg = cpu_to_be32(0x00000001); 205 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, 206 TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING, 207 ®, sizeof(reg), 0); 208 if (err < 0) 209 return err; 210 211 reg = cpu_to_be32(0x00000001); 212 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, 213 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON, 214 ®, sizeof(reg), 0); 215 if (err < 0) 216 return err; 217 218 /* Set an option for unknown purpose. */ 219 reg = cpu_to_be32(0x00002000); 220 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, 221 TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION, 222 ®, sizeof(reg), 0); 223 if (err < 0) 224 return err; 225 226 /* Start multiplexing PCM samples on packets. */ 227 reg = cpu_to_be32(0x00000001); 228 return snd_fw_transaction(tscm->unit, 229 TCODE_WRITE_QUADLET_REQUEST, 230 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_ON, 231 ®, sizeof(reg), 0); 232 } 233 234 static void release_resources(struct snd_tscm *tscm) 235 { 236 __be32 reg; 237 238 /* Unregister channels. */ 239 reg = cpu_to_be32(0x00000000); 240 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, 241 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH, 242 ®, sizeof(reg), 0); 243 reg = cpu_to_be32(0x00000000); 244 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, 245 TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN, 246 ®, sizeof(reg), 0); 247 reg = cpu_to_be32(0x00000000); 248 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, 249 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH, 250 ®, sizeof(reg), 0); 251 252 /* Release isochronous resources. */ 253 fw_iso_resources_free(&tscm->tx_resources); 254 fw_iso_resources_free(&tscm->rx_resources); 255 } 256 257 static int keep_resources(struct snd_tscm *tscm, unsigned int rate) 258 { 259 __be32 reg; 260 int err; 261 262 /* Keep resources for in-stream. */ 263 err = amdtp_tscm_set_parameters(&tscm->tx_stream, rate); 264 if (err < 0) 265 return err; 266 err = fw_iso_resources_allocate(&tscm->tx_resources, 267 amdtp_stream_get_max_payload(&tscm->tx_stream), 268 fw_parent_device(tscm->unit)->max_speed); 269 if (err < 0) 270 goto error; 271 272 /* Keep resources for out-stream. */ 273 err = amdtp_tscm_set_parameters(&tscm->rx_stream, rate); 274 if (err < 0) 275 return err; 276 err = fw_iso_resources_allocate(&tscm->rx_resources, 277 amdtp_stream_get_max_payload(&tscm->rx_stream), 278 fw_parent_device(tscm->unit)->max_speed); 279 if (err < 0) 280 return err; 281 282 /* Register the isochronous channel for transmitting stream. */ 283 reg = cpu_to_be32(tscm->tx_resources.channel); 284 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, 285 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH, 286 ®, sizeof(reg), 0); 287 if (err < 0) 288 goto error; 289 290 /* Unknown */ 291 reg = cpu_to_be32(0x00000002); 292 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, 293 TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN, 294 ®, sizeof(reg), 0); 295 if (err < 0) 296 goto error; 297 298 /* Register the isochronous channel for receiving stream. */ 299 reg = cpu_to_be32(tscm->rx_resources.channel); 300 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, 301 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH, 302 ®, sizeof(reg), 0); 303 if (err < 0) 304 goto error; 305 306 return 0; 307 error: 308 release_resources(tscm); 309 return err; 310 } 311 312 int snd_tscm_stream_init_duplex(struct snd_tscm *tscm) 313 { 314 unsigned int pcm_channels; 315 int err; 316 317 /* For out-stream. */ 318 err = fw_iso_resources_init(&tscm->rx_resources, tscm->unit); 319 if (err < 0) 320 return err; 321 pcm_channels = tscm->spec->pcm_playback_analog_channels; 322 if (tscm->spec->has_adat) 323 pcm_channels += 8; 324 if (tscm->spec->has_spdif) 325 pcm_channels += 2; 326 err = amdtp_tscm_init(&tscm->rx_stream, tscm->unit, AMDTP_OUT_STREAM, 327 pcm_channels); 328 if (err < 0) 329 return err; 330 331 /* For in-stream. */ 332 err = fw_iso_resources_init(&tscm->tx_resources, tscm->unit); 333 if (err < 0) 334 return err; 335 pcm_channels = tscm->spec->pcm_capture_analog_channels; 336 if (tscm->spec->has_adat) 337 pcm_channels += 8; 338 if (tscm->spec->has_spdif) 339 pcm_channels += 2; 340 err = amdtp_tscm_init(&tscm->tx_stream, tscm->unit, AMDTP_IN_STREAM, 341 pcm_channels); 342 if (err < 0) 343 amdtp_stream_destroy(&tscm->rx_stream); 344 345 return err; 346 } 347 348 /* At bus reset, streaming is stopped and some registers are clear. */ 349 void snd_tscm_stream_update_duplex(struct snd_tscm *tscm) 350 { 351 amdtp_stream_pcm_abort(&tscm->tx_stream); 352 amdtp_stream_stop(&tscm->tx_stream); 353 354 amdtp_stream_pcm_abort(&tscm->rx_stream); 355 amdtp_stream_stop(&tscm->rx_stream); 356 } 357 358 /* 359 * This function should be called before starting streams or after stopping 360 * streams. 361 */ 362 void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm) 363 { 364 amdtp_stream_destroy(&tscm->rx_stream); 365 amdtp_stream_destroy(&tscm->tx_stream); 366 367 fw_iso_resources_destroy(&tscm->rx_resources); 368 fw_iso_resources_destroy(&tscm->tx_resources); 369 } 370 371 int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) 372 { 373 unsigned int curr_rate; 374 int err; 375 376 if (tscm->substreams_counter == 0) 377 return 0; 378 379 err = snd_tscm_stream_get_rate(tscm, &curr_rate); 380 if (err < 0) 381 return err; 382 if (curr_rate != rate || 383 amdtp_streaming_error(&tscm->rx_stream) || 384 amdtp_streaming_error(&tscm->tx_stream)) { 385 finish_session(tscm); 386 387 amdtp_stream_stop(&tscm->rx_stream); 388 amdtp_stream_stop(&tscm->tx_stream); 389 390 release_resources(tscm); 391 } 392 393 if (!amdtp_stream_running(&tscm->rx_stream)) { 394 err = keep_resources(tscm, rate); 395 if (err < 0) 396 goto error; 397 398 err = set_stream_formats(tscm, rate); 399 if (err < 0) 400 goto error; 401 402 err = begin_session(tscm); 403 if (err < 0) 404 goto error; 405 406 err = amdtp_stream_start(&tscm->rx_stream, 407 tscm->rx_resources.channel, 408 fw_parent_device(tscm->unit)->max_speed); 409 if (err < 0) 410 goto error; 411 412 if (!amdtp_stream_wait_callback(&tscm->rx_stream, 413 CALLBACK_TIMEOUT)) { 414 err = -ETIMEDOUT; 415 goto error; 416 } 417 } 418 419 if (!amdtp_stream_running(&tscm->tx_stream)) { 420 err = amdtp_stream_start(&tscm->tx_stream, 421 tscm->tx_resources.channel, 422 fw_parent_device(tscm->unit)->max_speed); 423 if (err < 0) 424 goto error; 425 426 if (!amdtp_stream_wait_callback(&tscm->tx_stream, 427 CALLBACK_TIMEOUT)) { 428 err = -ETIMEDOUT; 429 goto error; 430 } 431 } 432 433 return 0; 434 error: 435 amdtp_stream_stop(&tscm->rx_stream); 436 amdtp_stream_stop(&tscm->tx_stream); 437 438 finish_session(tscm); 439 release_resources(tscm); 440 441 return err; 442 } 443 444 void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm) 445 { 446 if (tscm->substreams_counter > 0) 447 return; 448 449 amdtp_stream_stop(&tscm->tx_stream); 450 amdtp_stream_stop(&tscm->rx_stream); 451 452 finish_session(tscm); 453 release_resources(tscm); 454 } 455 456 void snd_tscm_stream_lock_changed(struct snd_tscm *tscm) 457 { 458 tscm->dev_lock_changed = true; 459 wake_up(&tscm->hwdep_wait); 460 } 461 462 int snd_tscm_stream_lock_try(struct snd_tscm *tscm) 463 { 464 int err; 465 466 spin_lock_irq(&tscm->lock); 467 468 /* user land lock this */ 469 if (tscm->dev_lock_count < 0) { 470 err = -EBUSY; 471 goto end; 472 } 473 474 /* this is the first time */ 475 if (tscm->dev_lock_count++ == 0) 476 snd_tscm_stream_lock_changed(tscm); 477 err = 0; 478 end: 479 spin_unlock_irq(&tscm->lock); 480 return err; 481 } 482 483 void snd_tscm_stream_lock_release(struct snd_tscm *tscm) 484 { 485 spin_lock_irq(&tscm->lock); 486 487 if (WARN_ON(tscm->dev_lock_count <= 0)) 488 goto end; 489 if (--tscm->dev_lock_count == 0) 490 snd_tscm_stream_lock_changed(tscm); 491 end: 492 spin_unlock_irq(&tscm->lock); 493 } 494