diff options
Diffstat (limited to 'sound/firewire/dice/dice-stream.c')
-rw-r--r-- | sound/firewire/dice/dice-stream.c | 120 |
1 files changed, 56 insertions, 64 deletions
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index a6a39f7..df035b1 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -10,6 +10,7 @@ #include "dice.h" #define CALLBACK_TIMEOUT 200 +#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC) const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { /* mode 0 */ @@ -24,21 +25,44 @@ const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { [6] = 192000, }; -int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate, - unsigned int *mode) +/* + * This operation has an effect to synchronize GLOBAL_STATUS/GLOBAL_SAMPLE_RATE + * to GLOBAL_STATUS. Especially, just after powering on, these are different. + */ +static int ensure_phase_lock(struct snd_dice *dice) { - int i; + __be32 reg, nominal; + int err; + + err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT, + ®, sizeof(reg)); + if (err < 0) + return err; - for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) { - if (!(dice->clock_caps & BIT(i))) - continue; - if (snd_dice_rates[i] != rate) - continue; + if (completion_done(&dice->clock_accepted)) + reinit_completion(&dice->clock_accepted); - *mode = (i - 1) / 2; - return 0; + err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT, + ®, sizeof(reg)); + if (err < 0) + return err; + + if (wait_for_completion_timeout(&dice->clock_accepted, + msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) { + /* + * Old versions of Dice firmware transfer no notification when + * the same clock status as current one is set. In this case, + * just check current clock status. + */ + err = snd_dice_transaction_read_global(dice, GLOBAL_STATUS, + &nominal, sizeof(nominal)); + if (err < 0) + return err; + if (!(be32_to_cpu(nominal) & STATUS_SOURCE_LOCKED)) + return -ETIMEDOUT; } - return -EINVAL; + + return 0; } static void release_resources(struct snd_dice *dice, @@ -99,23 +123,27 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream, unsigned int rate) { struct fw_iso_resources *resources; - unsigned int i, mode, pcm_chs, midi_ports; + __be32 reg[2]; + unsigned int i, pcm_chs, midi_ports; bool double_pcm_frames; int err; - err = snd_dice_stream_get_rate_mode(dice, rate, &mode); - if (err < 0) - goto end; if (stream == &dice->tx_stream) { resources = &dice->tx_resources; - pcm_chs = dice->tx_channels[mode]; - midi_ports = dice->tx_midi_ports[mode]; + err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO, + reg, sizeof(reg)); } else { resources = &dice->rx_resources; - pcm_chs = dice->rx_channels[mode]; - midi_ports = dice->rx_midi_ports[mode]; + err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO, + reg, sizeof(reg)); } + if (err < 0) + goto end; + + pcm_chs = be32_to_cpu(reg[0]); + midi_ports = be32_to_cpu(reg[1]); + /* * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in * one data block of AMDTP packet. Thus sampling transfer frequency is @@ -126,7 +154,7 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream, * For this quirk, blocking mode is required and PCM buffer size should * be aligned to SYT_INTERVAL. */ - double_pcm_frames = mode > 1; + double_pcm_frames = rate > 96000; if (double_pcm_frames) { rate /= 2; pcm_chs *= 2; @@ -163,53 +191,17 @@ end: return err; } -static int get_sync_mode(struct snd_dice *dice, enum cip_flags *sync_mode) -{ - u32 source; - int err; - - err = snd_dice_transaction_get_clock_source(dice, &source); - if (err < 0) - goto end; - - switch (source) { - /* So-called 'SYT Match' modes, sync_to_syt value of packets received */ - case CLOCK_SOURCE_ARX4: /* in 4th stream */ - case CLOCK_SOURCE_ARX3: /* in 3rd stream */ - case CLOCK_SOURCE_ARX2: /* in 2nd stream */ - err = -ENOSYS; - break; - case CLOCK_SOURCE_ARX1: /* in 1st stream, which this driver uses */ - *sync_mode = 0; - break; - default: - *sync_mode = CIP_SYNC_TO_DEVICE; - break; - } -end: - return err; -} - int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate) { struct amdtp_stream *master, *slave; unsigned int curr_rate; - enum cip_flags sync_mode; int err = 0; if (dice->substreams_counter == 0) goto end; - err = get_sync_mode(dice, &sync_mode); - if (err < 0) - goto end; - if (sync_mode == CIP_SYNC_TO_DEVICE) { - master = &dice->tx_stream; - slave = &dice->rx_stream; - } else { - master = &dice->rx_stream; - slave = &dice->tx_stream; - } + master = &dice->rx_stream; + slave = &dice->tx_stream; /* Some packet queueing errors. */ if (amdtp_streaming_error(master) || amdtp_streaming_error(slave)) @@ -224,19 +216,19 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate) } if (rate == 0) rate = curr_rate; - if (rate != curr_rate) - stop_stream(dice, master); + if (rate != curr_rate) { + err = -EINVAL; + goto end; + } if (!amdtp_stream_running(master)) { stop_stream(dice, slave); snd_dice_transaction_clear_enable(dice); - amdtp_stream_set_sync(sync_mode, master, slave); - - err = snd_dice_transaction_set_rate(dice, rate); + err = ensure_phase_lock(dice); if (err < 0) { dev_err(&dice->unit->device, - "fail to set sampling rate\n"); + "fail to ensure phase lock\n"); goto end; } |