linux/sound/firewire/motu/motu-protocol-v3.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * motu-protocol-v3.c - a part of driver for MOTU FireWire series
   4 *
   5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
   6 */
   7
   8#include <linux/delay.h>
   9#include "motu.h"
  10
  11#define V3_CLOCK_STATUS_OFFSET          0x0b14
  12#define  V3_FETCH_PCM_FRAMES            0x02000000
  13#define  V3_CLOCK_RATE_MASK             0x0000ff00
  14#define  V3_CLOCK_RATE_SHIFT            8
  15#define  V3_CLOCK_SOURCE_MASK           0x000000ff
  16
  17#define V3_OPT_IFACE_MODE_OFFSET        0x0c94
  18#define  V3_ENABLE_OPT_IN_IFACE_A       0x00000001
  19#define  V3_ENABLE_OPT_IN_IFACE_B       0x00000002
  20#define  V3_ENABLE_OPT_OUT_IFACE_A      0x00000100
  21#define  V3_ENABLE_OPT_OUT_IFACE_B      0x00000200
  22#define  V3_NO_ADAT_OPT_IN_IFACE_A      0x00010000
  23#define  V3_NO_ADAT_OPT_IN_IFACE_B      0x00100000
  24#define  V3_NO_ADAT_OPT_OUT_IFACE_A     0x00040000
  25#define  V3_NO_ADAT_OPT_OUT_IFACE_B     0x00400000
  26
  27#define V3_MSG_FLAG_CLK_CHANGED         0x00000002
  28#define V3_CLK_WAIT_MSEC                4000
  29
  30int snd_motu_protocol_v3_get_clock_rate(struct snd_motu *motu,
  31                                        unsigned int *rate)
  32{
  33        __be32 reg;
  34        u32 data;
  35        int err;
  36
  37        err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
  38                                        sizeof(reg));
  39        if (err < 0)
  40                return err;
  41        data = be32_to_cpu(reg);
  42
  43        data = (data & V3_CLOCK_RATE_MASK) >> V3_CLOCK_RATE_SHIFT;
  44        if (data >= ARRAY_SIZE(snd_motu_clock_rates))
  45                return -EIO;
  46
  47        *rate = snd_motu_clock_rates[data];
  48
  49        return 0;
  50}
  51
  52int snd_motu_protocol_v3_set_clock_rate(struct snd_motu *motu,
  53                                        unsigned int rate)
  54{
  55        __be32 reg;
  56        u32 data;
  57        bool need_to_wait;
  58        int i, err;
  59
  60        for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
  61                if (snd_motu_clock_rates[i] == rate)
  62                        break;
  63        }
  64        if (i == ARRAY_SIZE(snd_motu_clock_rates))
  65                return -EINVAL;
  66
  67        err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
  68                                        sizeof(reg));
  69        if (err < 0)
  70                return err;
  71        data = be32_to_cpu(reg);
  72
  73        data &= ~(V3_CLOCK_RATE_MASK | V3_FETCH_PCM_FRAMES);
  74        data |= i << V3_CLOCK_RATE_SHIFT;
  75
  76        need_to_wait = data != be32_to_cpu(reg);
  77
  78        reg = cpu_to_be32(data);
  79        err = snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, &reg,
  80                                         sizeof(reg));
  81        if (err < 0)
  82                return err;
  83
  84        if (need_to_wait) {
  85                int result;
  86
  87                motu->msg = 0;
  88                result = wait_event_interruptible_timeout(motu->hwdep_wait,
  89                                        motu->msg & V3_MSG_FLAG_CLK_CHANGED,
  90                                        msecs_to_jiffies(V3_CLK_WAIT_MSEC));
  91                if (result < 0)
  92                        return result;
  93                if (result == 0)
  94                        return -ETIMEDOUT;
  95        }
  96
  97        return 0;
  98}
  99
 100static int detect_clock_source_828mk3(struct snd_motu *motu, u32 data,
 101                                      enum snd_motu_clock_source *src)
 102{
 103        switch (data) {
 104        case 0x00:
 105                *src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
 106                break;
 107        case 0x01:
 108                *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
 109                break;
 110        case 0x02:
 111                *src = SND_MOTU_CLOCK_SOURCE_SPH;
 112                break;
 113        case 0x10:
 114                *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
 115                break;
 116        case 0x18:
 117        case 0x19:
 118        {
 119                __be32 reg;
 120                u32 options;
 121                int err;
 122
 123                err = snd_motu_transaction_read(motu,
 124                                V3_OPT_IFACE_MODE_OFFSET, &reg, sizeof(reg));
 125                if (err < 0)
 126                        return err;
 127                options = be32_to_cpu(reg);
 128
 129                if (data == 0x18) {
 130                        if (options & V3_NO_ADAT_OPT_IN_IFACE_A)
 131                                *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A;
 132                        else
 133                                *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A;
 134                } else {
 135                        if (options & V3_NO_ADAT_OPT_IN_IFACE_B)
 136                                *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B;
 137                        else
 138                                *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B;
 139                }
 140
 141                break;
 142        }
 143        default:
 144                *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
 145                break;
 146        }
 147
 148        return 0;
 149}
 150
 151static int v3_detect_clock_source(struct snd_motu *motu, u32 data,
 152                                  enum snd_motu_clock_source *src)
 153{
 154        switch (data) {
 155        case 0x00:
 156                *src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
 157                break;
 158        case 0x01:
 159                *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
 160                break;
 161        case 0x02:
 162                *src = SND_MOTU_CLOCK_SOURCE_SPH;
 163                break;
 164        case 0x10:
 165                *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
 166                break;
 167        default:
 168                *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
 169                break;
 170        }
 171
 172        return 0;
 173}
 174
 175int snd_motu_protocol_v3_get_clock_source(struct snd_motu *motu,
 176                                          enum snd_motu_clock_source *src)
 177{
 178        __be32 reg;
 179        u32 data;
 180        int err;
 181
 182        err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
 183                                        sizeof(reg));
 184        if (err < 0)
 185                return err;
 186        data = be32_to_cpu(reg) & V3_CLOCK_SOURCE_MASK;
 187
 188        if (motu->spec == &snd_motu_spec_828mk3)
 189                return detect_clock_source_828mk3(motu, data, src);
 190        else
 191                return v3_detect_clock_source(motu, data, src);
 192}
 193
 194int snd_motu_protocol_v3_switch_fetching_mode(struct snd_motu *motu,
 195                                              bool enable)
 196{
 197        __be32 reg;
 198        u32 data;
 199        int err;
 200
 201        err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
 202                                        sizeof(reg));
 203        if (err < 0)
 204                return 0;
 205        data = be32_to_cpu(reg);
 206
 207        if (enable)
 208                data |= V3_FETCH_PCM_FRAMES;
 209        else
 210                data &= ~V3_FETCH_PCM_FRAMES;
 211
 212        reg = cpu_to_be32(data);
 213        return snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, &reg,
 214                                          sizeof(reg));
 215}
 216
 217static int detect_packet_formats_828mk3(struct snd_motu *motu, u32 data)
 218{
 219        if (data & V3_ENABLE_OPT_IN_IFACE_A) {
 220                if (data & V3_NO_ADAT_OPT_IN_IFACE_A) {
 221                        motu->tx_packet_formats.pcm_chunks[0] += 4;
 222                        motu->tx_packet_formats.pcm_chunks[1] += 4;
 223                } else {
 224                        motu->tx_packet_formats.pcm_chunks[0] += 8;
 225                        motu->tx_packet_formats.pcm_chunks[1] += 4;
 226                }
 227        }
 228
 229        if (data & V3_ENABLE_OPT_IN_IFACE_B) {
 230                if (data & V3_NO_ADAT_OPT_IN_IFACE_B) {
 231                        motu->tx_packet_formats.pcm_chunks[0] += 4;
 232                        motu->tx_packet_formats.pcm_chunks[1] += 4;
 233                } else {
 234                        motu->tx_packet_formats.pcm_chunks[0] += 8;
 235                        motu->tx_packet_formats.pcm_chunks[1] += 4;
 236                }
 237        }
 238
 239        if (data & V3_ENABLE_OPT_OUT_IFACE_A) {
 240                if (data & V3_NO_ADAT_OPT_OUT_IFACE_A) {
 241                        motu->rx_packet_formats.pcm_chunks[0] += 4;
 242                        motu->rx_packet_formats.pcm_chunks[1] += 4;
 243                } else {
 244                        motu->rx_packet_formats.pcm_chunks[0] += 8;
 245                        motu->rx_packet_formats.pcm_chunks[1] += 4;
 246                }
 247        }
 248
 249        if (data & V3_ENABLE_OPT_OUT_IFACE_B) {
 250                if (data & V3_NO_ADAT_OPT_OUT_IFACE_B) {
 251                        motu->rx_packet_formats.pcm_chunks[0] += 4;
 252                        motu->rx_packet_formats.pcm_chunks[1] += 4;
 253                } else {
 254                        motu->rx_packet_formats.pcm_chunks[0] += 8;
 255                        motu->rx_packet_formats.pcm_chunks[1] += 4;
 256                }
 257        }
 258
 259        return 0;
 260}
 261
 262int snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu)
 263{
 264        __be32 reg;
 265        u32 data;
 266        int err;
 267
 268        motu->tx_packet_formats.pcm_byte_offset = 10;
 269        motu->rx_packet_formats.pcm_byte_offset = 10;
 270
 271        motu->tx_packet_formats.msg_chunks = 2;
 272        motu->rx_packet_formats.msg_chunks = 2;
 273
 274        err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, &reg,
 275                                        sizeof(reg));
 276        if (err < 0)
 277                return err;
 278        data = be32_to_cpu(reg);
 279
 280        memcpy(motu->tx_packet_formats.pcm_chunks,
 281               motu->spec->tx_fixed_pcm_chunks,
 282               sizeof(motu->tx_packet_formats.pcm_chunks));
 283        memcpy(motu->rx_packet_formats.pcm_chunks,
 284               motu->spec->rx_fixed_pcm_chunks,
 285               sizeof(motu->rx_packet_formats.pcm_chunks));
 286
 287        if (motu->spec == &snd_motu_spec_828mk3)
 288                return detect_packet_formats_828mk3(motu, data);
 289        else
 290                return 0;
 291}
 292
 293
 294const struct snd_motu_spec snd_motu_spec_828mk3 = {
 295        .name = "828mk3",
 296        .protocol_version = SND_MOTU_PROTOCOL_V3,
 297        .flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
 298                 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
 299        .tx_fixed_pcm_chunks = {18, 18, 14},
 300        .rx_fixed_pcm_chunks = {14, 14, 10},
 301};
 302
 303const struct snd_motu_spec snd_motu_spec_ultralite_mk3 = {
 304        .name = "UltraLiteMk3",
 305        .protocol_version = SND_MOTU_PROTOCOL_V3,
 306        .flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
 307                 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
 308        .tx_fixed_pcm_chunks = {18, 14, 10},
 309        .rx_fixed_pcm_chunks = {14, 14, 14},
 310};
 311
 312const struct snd_motu_spec snd_motu_spec_audio_express = {
 313        .name = "AudioExpress",
 314        .protocol_version = SND_MOTU_PROTOCOL_V3,
 315        .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
 316                 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
 317        .tx_fixed_pcm_chunks = {10, 10, 0},
 318        .rx_fixed_pcm_chunks = {10, 10, 0},
 319};
 320
 321const struct snd_motu_spec snd_motu_spec_4pre = {
 322        .name = "4pre",
 323        .protocol_version = SND_MOTU_PROTOCOL_V3,
 324        .tx_fixed_pcm_chunks = {10, 10, 0},
 325        .rx_fixed_pcm_chunks = {10, 10, 0},
 326};
 327