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 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 (!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, ®, 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 142 int 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, ®, 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. 157 static 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. 166 static 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 187 int 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 ®, 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 ®, sizeof(reg)); 218 } 219 } 220 221 int 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, ®, 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 268 const 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 277 const 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 286 const 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 295 const 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