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_FETCH_ENABLE                  0x02000000
  16#define  V2_CLOCK_MODEL_SPECIFIC                0x04000000
  17
  18#define V2_IN_OUT_CONF_OFFSET                   0x0c04
  19#define  V2_OPT_OUT_IFACE_MASK                  0x00000c00
  20#define  V2_OPT_OUT_IFACE_SHIFT                 10
  21#define  V2_OPT_IN_IFACE_MASK                   0x00000300
  22#define  V2_OPT_IN_IFACE_SHIFT                  8
  23#define  V2_OPT_IFACE_MODE_NONE                 0
  24#define  V2_OPT_IFACE_MODE_ADAT                 1
  25#define  V2_OPT_IFACE_MODE_SPDIF                2
  26
  27static int get_clock_rate(u32 data, unsigned int *rate)
  28{
  29        unsigned int index = (data & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT;
  30        if (index >= ARRAY_SIZE(snd_motu_clock_rates))
  31                return -EIO;
  32
  33        *rate = snd_motu_clock_rates[index];
  34
  35        return 0;
  36}
  37
  38int snd_motu_protocol_v2_get_clock_rate(struct snd_motu *motu,
  39                                        unsigned int *rate)
  40{
  41        __be32 reg;
  42        int err;
  43
  44        err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
  45                                        sizeof(reg));
  46        if (err < 0)
  47                return err;
  48
  49        return get_clock_rate(be32_to_cpu(reg), rate);
  50}
  51
  52int snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu,
  53                                        unsigned int rate)
  54{
  55        __be32 reg;
  56        u32 data;
  57        int i;
  58        int 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, V2_CLOCK_STATUS_OFFSET, &reg,
  68                                        sizeof(reg));
  69        if (err < 0)
  70                return err;
  71        data = be32_to_cpu(reg);
  72
  73        data &= ~V2_CLOCK_RATE_MASK;
  74        data |= i << V2_CLOCK_RATE_SHIFT;
  75
  76        reg = cpu_to_be32(data);
  77        return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, &reg,
  78                                          sizeof(reg));
  79}
  80
  81static int detect_clock_source_optical_model(struct snd_motu *motu, u32 data,
  82                                             enum snd_motu_clock_source *src)
  83{
  84        switch (data) {
  85        case 0:
  86                *src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
  87                break;
  88        case 1:
  89                *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
  90                break;
  91        case 2:
  92        {
  93                __be32 reg;
  94
  95                // To check the configuration of optical interface.
  96                int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg, sizeof(reg));
  97                if (err < 0)
  98                        return err;
  99
 100                if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == V2_OPT_IFACE_MODE_SPDIF)
 101                        *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
 102                else
 103                        *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
 104                break;
 105        }
 106        case 3:
 107                *src = SND_MOTU_CLOCK_SOURCE_SPH;
 108                break;
 109        case 4:
 110                *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
 111                break;
 112        case 5:
 113                *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
 114                break;
 115        default:
 116                *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
 117                break;
 118        }
 119
 120        return 0;
 121}
 122
 123static int v2_detect_clock_source(struct snd_motu *motu, u32 data,
 124                                  enum snd_motu_clock_source *src)
 125{
 126        switch (data) {
 127        case 0:
 128                *src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
 129                break;
 130        case 2:
 131                *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
 132                break;
 133        case 3:
 134                *src = SND_MOTU_CLOCK_SOURCE_SPH;
 135                break;
 136        case 4:
 137                *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
 138                break;
 139        default:
 140                *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
 141                break;
 142        }
 143
 144        return 0;
 145}
 146
 147static int get_clock_source(struct snd_motu *motu, u32 data,
 148                            enum snd_motu_clock_source *src)
 149{
 150        data &= V2_CLOCK_SRC_MASK;
 151        if (motu->spec == &snd_motu_spec_828mk2 ||
 152            motu->spec == &snd_motu_spec_traveler)
 153                return detect_clock_source_optical_model(motu, data, src);
 154        else
 155                return v2_detect_clock_source(motu, data, src);
 156}
 157
 158int snd_motu_protocol_v2_get_clock_source(struct snd_motu *motu,
 159                                          enum snd_motu_clock_source *src)
 160{
 161        __be32 reg;
 162        int err;
 163
 164        err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
 165                                        sizeof(reg));
 166        if (err < 0)
 167                return err;
 168
 169        return get_clock_source(motu, be32_to_cpu(reg), src);
 170}
 171
 172// Expected for Traveler and 896HD, which implements Altera Cyclone EP1C3.
 173static int switch_fetching_mode_cyclone(struct snd_motu *motu, u32 *data,
 174                                        bool enable)
 175{
 176        *data |= V2_CLOCK_MODEL_SPECIFIC;
 177
 178        return 0;
 179}
 180
 181// For UltraLite and 8pre, which implements Xilinx Spartan XC3S200.
 182static int switch_fetching_mode_spartan(struct snd_motu *motu, u32 *data,
 183                                        bool enable)
 184{
 185        unsigned int rate;
 186        enum snd_motu_clock_source src;
 187        int err;
 188
 189        err = get_clock_source(motu, *data, &src);
 190        if (err < 0)
 191                return err;
 192
 193        err = get_clock_rate(*data, &rate);
 194        if (err < 0)
 195                return err;
 196
 197        if (src == SND_MOTU_CLOCK_SOURCE_SPH && rate > 48000)
 198                *data |= V2_CLOCK_MODEL_SPECIFIC;
 199
 200        return 0;
 201}
 202
 203int snd_motu_protocol_v2_switch_fetching_mode(struct snd_motu *motu,
 204                                              bool enable)
 205{
 206        if (motu->spec == &snd_motu_spec_828mk2) {
 207                // 828mkII implements Altera ACEX 1K EP1K30. Nothing to do.
 208                return 0;
 209        } else {
 210                __be32 reg;
 211                u32 data;
 212                int err;
 213
 214                err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,
 215                                                &reg, sizeof(reg));
 216                if (err < 0)
 217                        return err;
 218                data = be32_to_cpu(reg);
 219
 220                data &= ~(V2_CLOCK_FETCH_ENABLE | V2_CLOCK_MODEL_SPECIFIC);
 221                if (enable)
 222                        data |= V2_CLOCK_FETCH_ENABLE;
 223
 224                if (motu->spec == &snd_motu_spec_traveler)
 225                        err = switch_fetching_mode_cyclone(motu, &data, enable);
 226                else
 227                        err = switch_fetching_mode_spartan(motu, &data, enable);
 228                if (err < 0)
 229                        return err;
 230
 231                reg = cpu_to_be32(data);
 232                return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,
 233                                                  &reg, sizeof(reg));
 234        }
 235}
 236
 237static int detect_packet_formats_828mk2(struct snd_motu *motu, u32 data)
 238{
 239        if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==
 240            V2_OPT_IFACE_MODE_ADAT) {
 241                motu->tx_packet_formats.pcm_chunks[0] += 8;
 242                motu->tx_packet_formats.pcm_chunks[1] += 4;
 243        }
 244
 245        if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) ==
 246            V2_OPT_IFACE_MODE_ADAT) {
 247                motu->rx_packet_formats.pcm_chunks[0] += 8;
 248                motu->rx_packet_formats.pcm_chunks[1] += 4;
 249        }
 250
 251        return 0;
 252}
 253
 254static int detect_packet_formats_traveler(struct snd_motu *motu, u32 data)
 255{
 256        if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==
 257            V2_OPT_IFACE_MODE_ADAT) {
 258                motu->tx_packet_formats.pcm_chunks[0] += 8;
 259                motu->tx_packet_formats.pcm_chunks[1] += 4;
 260        }
 261
 262        if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) ==
 263            V2_OPT_IFACE_MODE_ADAT) {
 264                motu->rx_packet_formats.pcm_chunks[0] += 8;
 265                motu->rx_packet_formats.pcm_chunks[1] += 4;
 266        }
 267
 268        return 0;
 269}
 270
 271static int detect_packet_formats_8pre(struct snd_motu *motu, u32 data)
 272{
 273        if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==
 274            V2_OPT_IFACE_MODE_ADAT) {
 275                motu->tx_packet_formats.pcm_chunks[0] += 8;
 276                motu->tx_packet_formats.pcm_chunks[1] += 8;
 277        }
 278
 279        if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) ==
 280            V2_OPT_IFACE_MODE_ADAT) {
 281                motu->rx_packet_formats.pcm_chunks[0] += 8;
 282                motu->rx_packet_formats.pcm_chunks[1] += 8;
 283        }
 284
 285        return 0;
 286}
 287
 288int snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu)
 289{
 290        __be32 reg;
 291        u32 data;
 292        int err;
 293
 294        motu->tx_packet_formats.pcm_byte_offset = 10;
 295        motu->rx_packet_formats.pcm_byte_offset = 10;
 296
 297        motu->tx_packet_formats.msg_chunks = 2;
 298        motu->rx_packet_formats.msg_chunks = 2;
 299
 300        err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
 301                                        sizeof(reg));
 302        if (err < 0)
 303                return err;
 304        data = be32_to_cpu(reg);
 305
 306        memcpy(motu->tx_packet_formats.pcm_chunks,
 307               motu->spec->tx_fixed_pcm_chunks,
 308               sizeof(motu->tx_packet_formats.pcm_chunks));
 309        memcpy(motu->rx_packet_formats.pcm_chunks,
 310               motu->spec->rx_fixed_pcm_chunks,
 311               sizeof(motu->rx_packet_formats.pcm_chunks));
 312
 313        if (motu->spec == &snd_motu_spec_828mk2)
 314                return detect_packet_formats_828mk2(motu, data);
 315        else if (motu->spec == &snd_motu_spec_traveler)
 316                return detect_packet_formats_traveler(motu, data);
 317        else if (motu->spec == &snd_motu_spec_8pre)
 318                return detect_packet_formats_8pre(motu, data);
 319        else
 320                return 0;
 321}
 322
 323const struct snd_motu_spec snd_motu_spec_828mk2 = {
 324        .name = "828mk2",
 325        .protocol_version = SND_MOTU_PROTOCOL_V2,
 326        .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
 327                 SND_MOTU_SPEC_TX_MIDI_2ND_Q,
 328        .tx_fixed_pcm_chunks = {14, 14, 0},
 329        .rx_fixed_pcm_chunks = {14, 14, 0},
 330};
 331
 332const struct snd_motu_spec snd_motu_spec_traveler = {
 333        .name = "Traveler",
 334        .protocol_version = SND_MOTU_PROTOCOL_V2,
 335        .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
 336                 SND_MOTU_SPEC_TX_MIDI_2ND_Q,
 337        .tx_fixed_pcm_chunks = {14, 14, 8},
 338        .rx_fixed_pcm_chunks = {14, 14, 8},
 339};
 340
 341const struct snd_motu_spec snd_motu_spec_ultralite = {
 342        .name = "UltraLite",
 343        .protocol_version = SND_MOTU_PROTOCOL_V2,
 344        .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
 345                 SND_MOTU_SPEC_TX_MIDI_2ND_Q,
 346        .tx_fixed_pcm_chunks = {14, 14, 0},
 347        .rx_fixed_pcm_chunks = {14, 14, 0},
 348};
 349
 350const struct snd_motu_spec snd_motu_spec_8pre = {
 351        .name = "8pre",
 352        .protocol_version = SND_MOTU_PROTOCOL_V2,
 353        .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
 354                 SND_MOTU_SPEC_TX_MIDI_2ND_Q,
 355        // Two dummy chunks always in the end of data block.
 356        .tx_fixed_pcm_chunks = {10, 10, 0},
 357        .rx_fixed_pcm_chunks = {6, 6, 0},
 358};
 359