322 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * motu-protocol-v2.c - a part of driver for MOTU FireWire series4 *5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>6 */7 8#include "motu.h"9 10#define V2_CLOCK_STATUS_OFFSET 0x0b1411#define V2_CLOCK_RATE_MASK 0x0000003812#define V2_CLOCK_RATE_SHIFT 313#define V2_CLOCK_SRC_MASK 0x0000000714#define V2_CLOCK_SRC_SHIFT 015#define V2_CLOCK_SRC_AESEBU_ON_XLR 0x07 // In Traveler.16#define V2_CLOCK_SRC_ADAT_ON_DSUB 0x0517#define V2_CLOCK_SRC_WORD_ON_BNC 0x0418#define V2_CLOCK_SRC_SPH 0x0319#define V2_CLOCK_SRC_SPDIF 0x02 // on either coaxial or optical. AES/EBU in 896HD.20#define V2_CLOCK_SRC_ADAT_ON_OPT 0x0121#define V2_CLOCK_SRC_INTERNAL 0x0022#define V2_CLOCK_FETCH_ENABLE 0x0200000023#define V2_CLOCK_MODEL_SPECIFIC 0x0400000024 25#define V2_IN_OUT_CONF_OFFSET 0x0c0426#define V2_OPT_OUT_IFACE_MASK 0x00000c0027#define V2_OPT_OUT_IFACE_SHIFT 1028#define V2_OPT_IN_IFACE_MASK 0x0000030029#define V2_OPT_IN_IFACE_SHIFT 830#define V2_OPT_IFACE_MODE_NONE 031#define V2_OPT_IFACE_MODE_ADAT 132#define V2_OPT_IFACE_MODE_SPDIF 233 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, ®,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, ®,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, ®,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 (motu->spec == &snd_motu_spec_896hd) {104 *src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;105 } else if (!support_iec60958_on_opt) {106 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;107 } else {108 __be32 reg;109 110 // To check the configuration of optical interface.111 int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, ®,112 sizeof(reg));113 if (err < 0)114 return err;115 116 if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==117 V2_OPT_IFACE_MODE_SPDIF)118 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;119 else120 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;121 }122 break;123 }124 case V2_CLOCK_SRC_SPH:125 *src = SND_MOTU_CLOCK_SOURCE_SPH;126 break;127 case V2_CLOCK_SRC_WORD_ON_BNC:128 *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;129 break;130 case V2_CLOCK_SRC_ADAT_ON_DSUB:131 *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;132 break;133 case V2_CLOCK_SRC_AESEBU_ON_XLR:134 // For Traveler.135 *src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;136 break;137 default:138 *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;139 break;140 }141 142 return 0;143}144 145int snd_motu_protocol_v2_get_clock_source(struct snd_motu *motu,146 enum snd_motu_clock_source *src)147{148 __be32 reg;149 int err;150 151 err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®,152 sizeof(reg));153 if (err < 0)154 return err;155 156 return get_clock_source(motu, be32_to_cpu(reg), src);157}158 159// Expected for Traveler, which implements Altera Cyclone EP1C3.160static int switch_fetching_mode_cyclone(struct snd_motu *motu, u32 *data,161 bool enable)162{163 *data |= V2_CLOCK_MODEL_SPECIFIC;164 165 return 0;166}167 168// For UltraLite and 8pre, which implements Xilinx Spartan XC3S200.169static int switch_fetching_mode_spartan(struct snd_motu *motu, u32 *data,170 bool enable)171{172 unsigned int rate;173 enum snd_motu_clock_source src;174 int err;175 176 err = get_clock_source(motu, *data, &src);177 if (err < 0)178 return err;179 180 err = get_clock_rate(*data, &rate);181 if (err < 0)182 return err;183 184 if (src == SND_MOTU_CLOCK_SOURCE_SPH && rate > 48000)185 *data |= V2_CLOCK_MODEL_SPECIFIC;186 187 return 0;188}189 190int snd_motu_protocol_v2_switch_fetching_mode(struct snd_motu *motu,191 bool enable)192{193 if (motu->spec == &snd_motu_spec_828mk2) {194 // 828mkII implements Altera ACEX 1K EP1K30. Nothing to do.195 return 0;196 } else if (motu->spec == &snd_motu_spec_896hd) {197 // 896HD implements Altera Cyclone EP1C3 but nothing to do.198 return 0;199 } else {200 __be32 reg;201 u32 data;202 int err;203 204 err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,205 ®, sizeof(reg));206 if (err < 0)207 return err;208 data = be32_to_cpu(reg);209 210 data &= ~(V2_CLOCK_FETCH_ENABLE | V2_CLOCK_MODEL_SPECIFIC);211 if (enable)212 data |= V2_CLOCK_FETCH_ENABLE;213 214 if (motu->spec == &snd_motu_spec_traveler)215 err = switch_fetching_mode_cyclone(motu, &data, enable);216 else217 err = switch_fetching_mode_spartan(motu, &data, enable);218 if (err < 0)219 return err;220 221 reg = cpu_to_be32(data);222 return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,223 ®, sizeof(reg));224 }225}226 227int snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu)228{229 bool has_two_opt_ifaces = (motu->spec == &snd_motu_spec_8pre);230 __be32 reg;231 u32 data;232 int err;233 234 motu->tx_packet_formats.pcm_byte_offset = 10;235 motu->rx_packet_formats.pcm_byte_offset = 10;236 237 motu->tx_packet_formats.msg_chunks = 2;238 motu->rx_packet_formats.msg_chunks = 2;239 240 err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, ®,241 sizeof(reg));242 if (err < 0)243 return err;244 data = be32_to_cpu(reg);245 246 memcpy(motu->tx_packet_formats.pcm_chunks,247 motu->spec->tx_fixed_pcm_chunks,248 sizeof(motu->tx_packet_formats.pcm_chunks));249 memcpy(motu->rx_packet_formats.pcm_chunks,250 motu->spec->rx_fixed_pcm_chunks,251 sizeof(motu->rx_packet_formats.pcm_chunks));252 253 if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {254 motu->tx_packet_formats.pcm_chunks[0] += 8;255 256 if (!has_two_opt_ifaces)257 motu->tx_packet_formats.pcm_chunks[1] += 4;258 else259 motu->tx_packet_formats.pcm_chunks[1] += 8;260 }261 262 if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {263 motu->rx_packet_formats.pcm_chunks[0] += 8;264 265 if (!has_two_opt_ifaces)266 motu->rx_packet_formats.pcm_chunks[1] += 4;267 else268 motu->rx_packet_formats.pcm_chunks[1] += 8;269 }270 271 return 0;272}273 274const struct snd_motu_spec snd_motu_spec_828mk2 = {275 .name = "828mk2",276 .protocol_version = SND_MOTU_PROTOCOL_V2,277 .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |278 SND_MOTU_SPEC_TX_MIDI_2ND_Q |279 SND_MOTU_SPEC_REGISTER_DSP,280 .tx_fixed_pcm_chunks = {14, 14, 0},281 .rx_fixed_pcm_chunks = {14, 14, 0},282};283 284const struct snd_motu_spec snd_motu_spec_896hd = {285 .name = "896HD",286 .protocol_version = SND_MOTU_PROTOCOL_V2,287 .flags = SND_MOTU_SPEC_REGISTER_DSP,288 .tx_fixed_pcm_chunks = {14, 14, 8},289 .rx_fixed_pcm_chunks = {14, 14, 8},290};291 292const struct snd_motu_spec snd_motu_spec_traveler = {293 .name = "Traveler",294 .protocol_version = SND_MOTU_PROTOCOL_V2,295 .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |296 SND_MOTU_SPEC_TX_MIDI_2ND_Q |297 SND_MOTU_SPEC_REGISTER_DSP,298 .tx_fixed_pcm_chunks = {14, 14, 8},299 .rx_fixed_pcm_chunks = {14, 14, 8},300};301 302const struct snd_motu_spec snd_motu_spec_ultralite = {303 .name = "UltraLite",304 .protocol_version = SND_MOTU_PROTOCOL_V2,305 .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |306 SND_MOTU_SPEC_TX_MIDI_2ND_Q |307 SND_MOTU_SPEC_REGISTER_DSP,308 .tx_fixed_pcm_chunks = {14, 14, 0},309 .rx_fixed_pcm_chunks = {14, 14, 0},310};311 312const struct snd_motu_spec snd_motu_spec_8pre = {313 .name = "8pre",314 .protocol_version = SND_MOTU_PROTOCOL_V2,315 .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |316 SND_MOTU_SPEC_TX_MIDI_2ND_Q |317 SND_MOTU_SPEC_REGISTER_DSP,318 // Two dummy chunks always in the end of data block.319 .tx_fixed_pcm_chunks = {10, 10, 0},320 .rx_fixed_pcm_chunks = {6, 6, 0},321};322