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 // In Traveler. 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. AES/EBU in 896HD. 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 34 static 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 45 int 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 59 int 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 88 static 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 else 120 *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 145 int 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. 160 static 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. 169 static 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 190 int 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 else 217 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 227 int 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 else 259 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 else 268 motu->rx_packet_formats.pcm_chunks[1] += 8; 269 } 270 271 return 0; 272 } 273 274 const 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 284 const 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 292 const 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 302 const 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 312 const 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.