]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - sound/firewire/dice/dice-stream.c
Merge remote-tracking branch 'device-mapper/for-next'
[karo-tx-linux.git] / sound / firewire / dice / dice-stream.c
index a6a39f7ef58d8e32cf6e6ff60d45bcbbb23b1e04..e4938b0cddbea818d436906a5fd5615516e74ce5 100644 (file)
@@ -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,33 @@ 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;
+       int 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;
+       err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
+                                              &reg, sizeof(reg));
+       if (err < 0)
+               return err;
 
-               *mode = (i - 1) / 2;
-               return 0;
-       }
-       return -EINVAL;
+       if (completion_done(&dice->clock_accepted))
+               reinit_completion(&dice->clock_accepted);
+
+       err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
+                                               &reg, sizeof(reg));
+       if (err < 0)
+               return err;
+
+       if (wait_for_completion_timeout(&dice->clock_accepted,
+                       msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0)
+               return -ETIMEDOUT;
+
+       return 0;
 }
 
 static void release_resources(struct snd_dice *dice,
@@ -99,23 +112,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 +143,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;
@@ -224,8 +241,10 @@ 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);
@@ -233,10 +252,10 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
 
                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;
                }