linux/sound/firewire/motu/motu-protocol-v2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * motu-protocol-v2.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 "motu.h"
   9
  10#define V2_CLOCK_STATUS_OFFSET                  0x0b14
  11#define  V2_CLOCK_RATE_MASK                     0x00000038
  12#define  V2_CLOCK_RATE_SHIFT                    3
  13#define  V2_CLOCK_SRC_MASK                      0x00000007
  14#define  V2_CLOCK_SRC_SHIFT                     0
  15#define   V2_CLOCK_SRC_AESEBU_ON_XLR            0x07
  16#define   V2_CLOCK_SRC_ADAT_ON_DSUB             0x05
  17#define   V2_CLOCK_SRC_WORD_ON_BNC              0x04
  18#define   V2_CLOCK_SRC_SPH                      0x03
  19#define   V2_CLOCK_SRC_SPDIF                    0x02    // on either coaxial or optical
  20#define   V2_CLOCK_SRC_ADAT_ON_OPT              0x01
  21#define   V2_CLOCK_SRC_INTERNAL                 0x00
  22#define  V2_CLOCK_FETCH_ENABLE                  0x02000000
  23#define  V2_CLOCK_MODEL_SPECIFIC                0x04000000
  24
  25#define V2_IN_OUT_CONF_OFFSET                   0x0c04
  26#define  V2_OPT_OUT_IFACE_MASK                  0x00000c00
  27#define  V2_OPT_OUT_IFACE_SHIFT                 10
  28#define  V2_OPT_IN_IFACE_MASK                   0x00000300
  29#define  V2_OPT_IN_IFACE_SHIFT                  8
  30#define  V2_OPT_IFACE_MODE_NONE                 0
  31#define  V2_OPT_IFACE_MODE_ADAT                 1
  32#define  V2_OPT_IFACE_MODE_SPDIF                2
  33
  34static int get_clock_rate(u32 data, unsigned int *rate)
  35{
  36        unsigned int index = (data & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT;
  37        if (index >= ARRAY_SIZE(snd_motu_clock_rates))
  38                return -EIO;
  39
  40        *rate = snd_motu_clock_rates[index];
  41
  42        return 0;
  43}
  44
  45int snd_motu_protocol_v2_get_clock_rate(struct snd_motu *motu,
  46                                        unsigned int *rate)
  47{
  48        __be32 reg;
  49        int err;
  50
  51        err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
  52                                        sizeof(reg));
  53        if (err < 0)
  54                return err;
  55
  56        return get_clock_rate(be32_to_cpu(reg), rate);
  57}
  58
  59int snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu,
  60                                        unsigned int rate)
  61{
  62        __be32 reg;
  63        u32 data;
  64        int i;
  65        int err;
  66
  67        for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
  68                if (snd_motu_clock_rates[i] == rate)
  69                        break;
  70        }
  71        if (i == ARRAY_SIZE(snd_motu_clock_rates))
  72                return -EINVAL;
  73
  74        err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
  75                                        sizeof(reg));
  76        if (err < 0)
  77                return err;
  78        data = be32_to_cpu(reg);
  79
  80        data &= ~V2_CLOCK_RATE_MASK;
  81        data |= i << V2_CLOCK_RATE_SHIFT;
  82
  83        reg = cpu_to_be32(data);
  84        return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, &reg,
  85                                          sizeof(reg));
  86}
  87
  88static int get_clock_source(struct snd_motu *motu, u32 data,
  89                            enum snd_motu_clock_source *src)
  90{
  91        switch (data & V2_CLOCK_SRC_MASK) {
  92        case V2_CLOCK_SRC_INTERNAL:
  93                *src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
  94                break;
  95        case V2_CLOCK_SRC_ADAT_ON_OPT:
  96                *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
  97                break;
  98        case V2_CLOCK_SRC_SPDIF:
  99        {
 100                bool support_iec60958_on_opt = (motu->spec == &snd_motu_spec_828mk2 ||
 101                                                motu->spec == &snd_motu_spec_traveler);
 102
 103                if (!support_iec60958_on_opt) {
 104                        *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
 105                } else {
 106                        __be32 reg;
 107
 108                        // To check the configuration of optical interface.
 109                        int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
 110                                                            sizeof(reg));
 111                        if (err < 0)
 112                                return err;
 113
 114                        if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==
 115                            V2_OPT_IFACE_MODE_SPDIF)
 116                                *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
 117                        else
 118                                *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
 119                }
 120                break;
 121        }
 122        case V2_CLOCK_SRC_SPH:
 123                *src = SND_MOTU_CLOCK_SOURCE_SPH;
 124                break;
 125        case V2_CLOCK_SRC_WORD_ON_BNC:
 126                *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
 127                break;
 128        case V2_CLOCK_SRC_ADAT_ON_DSUB:
 129                *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
 130                break;
 131        case V2_CLOCK_SRC_AESEBU_ON_XLR:
 132                *src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;
 133                break;
 134        default:
 135                *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
 136                break;
 137        }
 138
 139        return 0;
 140}
 141
 142int snd_motu_protocol_v2_get_clock_source(struct snd_motu *motu,
 143                                          enum snd_motu_clock_source *src)
 144{
 145        __be32 reg;
 146        int err;
 147
 148        err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
 149                                        sizeof(reg));
 150        if (err < 0)
 151                return err;
 152
 153        return get_clock_source(motu, be32_to_cpu(reg), src);
 154}
 155
 156// Expected for Traveler and 896HD, which implements Altera Cyclone EP1C3.
 157static int switch_fetching_mode_cyclone(struct snd_motu *motu, u32 *data,
 158                                        bool enable)
 159{
 160        *data |= V2_CLOCK_MODEL_SPECIFIC;
 161
 162        return 0;
 163}
 164
 165// For UltraLite and 8pre, which implements Xilinx Spartan XC3S200.
 166static int switch_fetching_mode_spartan(struct snd_motu *motu, u32 *data,
 167                                        bool enable)
 168{
 169        unsigned int rate;
 170        enum snd_motu_clock_source src;
 171        int err;
 172
 173        err = get_clock_source(motu, *data, &src);
 174        if (err < 0)
 175                return err;
 176
 177        err = get_clock_rate(*data, &rate);
 178        if (err < 0)
 179                return err;
 180
 181        if (src == SND_MOTU_CLOCK_SOURCE_SPH && rate > 48000)
 182                *data |= V2_CLOCK_MODEL_SPECIFIC;
 183
 184        return 0;
 185}
 186
 187int snd_motu_protocol_v2_switch_fetching_mode(struct snd_motu *motu,
 188                                              bool enable)
 189{
 190        if (motu->spec == &snd_motu_spec_828mk2) {
 191                // 828mkII implements Altera ACEX 1K EP1K30. Nothing to do.
 192                return 0;
 193        } else {
 194                __be32 reg;
 195                u32 data;
 196                int err;
 197
 198                err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,
 199                                                &reg, sizeof(reg));
 200                if (err < 0)
 201                        return err;
 202                data = be32_to_cpu(reg);
 203
 204                data &= ~(V2_CLOCK_FETCH_ENABLE | V2_CLOCK_MODEL_SPECIFIC);
 205                if (enable)
 206                        data |= V2_CLOCK_FETCH_ENABLE;
 207
 208                if (motu->spec == &snd_motu_spec_traveler)
 209                        err = switch_fetching_mode_cyclone(motu, &data, enable);
 210                else
 211                        err = switch_fetching_mode_spartan(motu, &data, enable);
 212                if (err < 0)
 213                        return err;
 214
 215                reg = cpu_to_be32(data);
 216                return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,
 217                                                  &reg, sizeof(reg));
 218        }
 219}
 220
 221int snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu)
 222{
 223        bool has_two_opt_ifaces = (motu->spec == &snd_motu_spec_8pre);
 224        __be32 reg;
 225        u32 data;
 226        int err;
 227
 228        motu->tx_packet_formats.pcm_byte_offset = 10;
 229        motu->rx_packet_formats.pcm_byte_offset = 10;
 230
 231        motu->tx_packet_formats.msg_chunks = 2;
 232        motu->rx_packet_formats.msg_chunks = 2;
 233
 234        err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
 235                                        sizeof(reg));
 236        if (err < 0)
 237                return err;
 238        data = be32_to_cpu(reg);
 239
 240        memcpy(motu->tx_packet_formats.pcm_chunks,
 241               motu->spec->tx_fixed_pcm_chunks,
 242               sizeof(motu->tx_packet_formats.pcm_chunks));
 243        memcpy(motu->rx_packet_formats.pcm_chunks,
 244               motu->spec->rx_fixed_pcm_chunks,
 245               sizeof(motu->rx_packet_formats.pcm_chunks));
 246
 247        if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {
 248                motu->tx_packet_formats.pcm_chunks[0] += 8;
 249
 250                if (!has_two_opt_ifaces)
 251                        motu->tx_packet_formats.pcm_chunks[1] += 4;
 252                else
 253                        motu->tx_packet_formats.pcm_chunks[1] += 8;
 254        }
 255
 256        if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {
 257                motu->rx_packet_formats.pcm_chunks[0] += 8;
 258
 259                if (!has_two_opt_ifaces)
 260                        motu->rx_packet_formats.pcm_chunks[1] += 4;
 261                else
 262                        motu->rx_packet_formats.pcm_chunks[1] += 8;
 263        }
 264
 265        return 0;
 266}
 267
 268const struct snd_motu_spec snd_motu_spec_828mk2 = {
 269        .name = "828mk2",
 270        .protocol_version = SND_MOTU_PROTOCOL_V2,
 271        .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
 272                 SND_MOTU_SPEC_TX_MIDI_2ND_Q,
 273        .tx_fixed_pcm_chunks = {14, 14, 0},
 274        .rx_fixed_pcm_chunks = {14, 14, 0},
 275};
 276
 277const struct snd_motu_spec snd_motu_spec_traveler = {
 278        .name = "Traveler",
 279        .protocol_version = SND_MOTU_PROTOCOL_V2,
 280        .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
 281                 SND_MOTU_SPEC_TX_MIDI_2ND_Q,
 282        .tx_fixed_pcm_chunks = {14, 14, 8},
 283        .rx_fixed_pcm_chunks = {14, 14, 8},
 284};
 285
 286const struct snd_motu_spec snd_motu_spec_ultralite = {
 287        .name = "UltraLite",
 288        .protocol_version = SND_MOTU_PROTOCOL_V2,
 289        .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
 290                 SND_MOTU_SPEC_TX_MIDI_2ND_Q,
 291        .tx_fixed_pcm_chunks = {14, 14, 0},
 292        .rx_fixed_pcm_chunks = {14, 14, 0},
 293};
 294
 295const struct snd_motu_spec snd_motu_spec_8pre = {
 296        .name = "8pre",
 297        .protocol_version = SND_MOTU_PROTOCOL_V2,
 298        .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
 299                 SND_MOTU_SPEC_TX_MIDI_2ND_Q,
 300        // Two dummy chunks always in the end of data block.
 301        .tx_fixed_pcm_chunks = {10, 10, 0},
 302        .rx_fixed_pcm_chunks = {6, 6, 0},
 303};
 304