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 27 static 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 38 static int v2_get_clock_rate(struct snd_motu *motu, unsigned int *rate) 39 { 40 __be32 reg; 41 int err; 42 43 err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®, 44 sizeof(reg)); 45 if (err < 0) 46 return err; 47 48 return get_clock_rate(be32_to_cpu(reg), rate); 49 } 50 51 static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate) 52 { 53 __be32 reg; 54 u32 data; 55 int i; 56 int err; 57 58 for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) { 59 if (snd_motu_clock_rates[i] == rate) 60 break; 61 } 62 if (i == ARRAY_SIZE(snd_motu_clock_rates)) 63 return -EINVAL; 64 65 err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®, 66 sizeof(reg)); 67 if (err < 0) 68 return err; 69 data = be32_to_cpu(reg); 70 71 data &= ~V2_CLOCK_RATE_MASK; 72 data |= i << V2_CLOCK_RATE_SHIFT; 73 74 reg = cpu_to_be32(data); 75 return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, ®, 76 sizeof(reg)); 77 } 78 79 static int get_clock_source(struct snd_motu *motu, u32 data, 80 enum snd_motu_clock_source *src) 81 { 82 unsigned int index = data & V2_CLOCK_SRC_MASK; 83 if (index > 5) 84 return -EIO; 85 86 switch (index) { 87 case 0: 88 *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; 89 break; 90 case 1: 91 { 92 __be32 reg; 93 94 // To check the configuration of optical interface. 95 int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, 96 ®, sizeof(reg)); 97 if (err < 0) 98 return err; 99 100 if (be32_to_cpu(reg) & 0x00000200) 101 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT; 102 else 103 *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT; 104 break; 105 } 106 case 2: 107 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; 108 break; 109 case 3: 110 *src = SND_MOTU_CLOCK_SOURCE_SPH; 111 break; 112 case 4: 113 *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; 114 break; 115 case 5: 116 *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB; 117 break; 118 default: 119 return -EIO; 120 } 121 122 return 0; 123 } 124 125 static int v2_get_clock_source(struct snd_motu *motu, 126 enum snd_motu_clock_source *src) 127 { 128 __be32 reg; 129 int err; 130 131 err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®, 132 sizeof(reg)); 133 if (err < 0) 134 return err; 135 136 return get_clock_source(motu, be32_to_cpu(reg), src); 137 } 138 139 static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable) 140 { 141 enum snd_motu_clock_source src; 142 __be32 reg; 143 u32 data; 144 int err = 0; 145 146 // 828mkII implements Altera ACEX 1K EP1K30. Nothing to do. 147 if (motu->spec == &snd_motu_spec_828mk2) 148 return 0; 149 150 err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®, 151 sizeof(reg)); 152 if (err < 0) 153 return err; 154 data = be32_to_cpu(reg); 155 156 err = get_clock_source(motu, data, &src); 157 if (err < 0) 158 return err; 159 160 data &= ~(V2_CLOCK_FETCH_ENABLE | V2_CLOCK_MODEL_SPECIFIC); 161 if (enable) 162 data |= V2_CLOCK_FETCH_ENABLE; 163 164 if (motu->spec->flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) { 165 // Expected for Traveler and 896HD, which implements Altera 166 // Cyclone EP1C3. 167 data |= V2_CLOCK_MODEL_SPECIFIC; 168 } else { 169 // For UltraLite and 8pre, which implements Xilinx Spartan 170 // XC3S200. 171 unsigned int rate; 172 173 err = get_clock_rate(data, &rate); 174 if (err < 0) 175 return err; 176 177 if (src == SND_MOTU_CLOCK_SOURCE_SPH && rate > 48000) 178 data |= V2_CLOCK_MODEL_SPECIFIC; 179 } 180 181 reg = cpu_to_be32(data); 182 return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, ®, 183 sizeof(reg)); 184 } 185 186 static void calculate_fixed_part(struct snd_motu_packet_format *formats, 187 enum amdtp_stream_direction dir, 188 enum snd_motu_spec_flags flags, 189 unsigned char analog_ports) 190 { 191 unsigned char pcm_chunks[3] = {0, 0, 0}; 192 193 formats->msg_chunks = 2; 194 195 pcm_chunks[0] = analog_ports; 196 pcm_chunks[1] = analog_ports; 197 if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) 198 pcm_chunks[2] = analog_ports; 199 200 if (dir == AMDTP_IN_STREAM) { 201 if (flags & SND_MOTU_SPEC_TX_MICINST_CHUNK) { 202 pcm_chunks[0] += 2; 203 pcm_chunks[1] += 2; 204 } 205 if (flags & SND_MOTU_SPEC_TX_RETURN_CHUNK) { 206 pcm_chunks[0] += 2; 207 pcm_chunks[1] += 2; 208 } 209 } else { 210 if (flags & SND_MOTU_SPEC_RX_SEPARATED_MAIN) { 211 pcm_chunks[0] += 2; 212 pcm_chunks[1] += 2; 213 } 214 215 // Packets to v2 units include 2 chunks for phone 1/2, except 216 // for 176.4/192.0 kHz. 217 pcm_chunks[0] += 2; 218 pcm_chunks[1] += 2; 219 } 220 221 if (flags & SND_MOTU_SPEC_HAS_AESEBU_IFACE) { 222 pcm_chunks[0] += 2; 223 pcm_chunks[1] += 2; 224 } 225 226 /* 227 * All of v2 models have a pair of coaxial interfaces for digital in/out 228 * port. At 44.1/48.0/88.2/96.0 kHz, packets includes PCM from these 229 * ports. 230 */ 231 pcm_chunks[0] += 2; 232 pcm_chunks[1] += 2; 233 234 formats->fixed_part_pcm_chunks[0] = pcm_chunks[0]; 235 formats->fixed_part_pcm_chunks[1] = pcm_chunks[1]; 236 formats->fixed_part_pcm_chunks[2] = pcm_chunks[2]; 237 } 238 239 static void calculate_differed_part(struct snd_motu_packet_format *formats, 240 enum snd_motu_spec_flags flags, 241 u32 data, u32 mask, u32 shift) 242 { 243 unsigned char pcm_chunks[2] = {0, 0}; 244 245 /* 246 * When optical interfaces are configured for S/PDIF (TOSLINK), 247 * the above PCM frames come from them, instead of coaxial 248 * interfaces. 249 */ 250 data = (data & mask) >> shift; 251 if (data == V2_OPT_IFACE_MODE_ADAT) { 252 if (flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) { 253 pcm_chunks[0] += 8; 254 pcm_chunks[1] += 4; 255 } 256 // 8pre has two sets of optical interface and doesn't reduce 257 // chunks for ADAT signals. 258 if (flags & SND_MOTU_SPEC_HAS_OPT_IFACE_B) { 259 pcm_chunks[1] += 4; 260 } 261 } 262 263 /* At mode x4, no data chunks are supported in this part. */ 264 formats->differed_part_pcm_chunks[0] = pcm_chunks[0]; 265 formats->differed_part_pcm_chunks[1] = pcm_chunks[1]; 266 } 267 268 static int v2_cache_packet_formats(struct snd_motu *motu) 269 { 270 __be32 reg; 271 u32 data; 272 int err; 273 274 err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, ®, 275 sizeof(reg)); 276 if (err < 0) 277 return err; 278 data = be32_to_cpu(reg); 279 280 calculate_fixed_part(&motu->tx_packet_formats, AMDTP_IN_STREAM, 281 motu->spec->flags, motu->spec->analog_in_ports); 282 calculate_differed_part(&motu->tx_packet_formats, motu->spec->flags, 283 data, V2_OPT_IN_IFACE_MASK, V2_OPT_IN_IFACE_SHIFT); 284 285 calculate_fixed_part(&motu->rx_packet_formats, AMDTP_OUT_STREAM, 286 motu->spec->flags, motu->spec->analog_out_ports); 287 calculate_differed_part(&motu->rx_packet_formats, motu->spec->flags, 288 data, V2_OPT_OUT_IFACE_MASK, V2_OPT_OUT_IFACE_SHIFT); 289 290 motu->tx_packet_formats.pcm_byte_offset = 10; 291 motu->rx_packet_formats.pcm_byte_offset = 10; 292 293 return 0; 294 } 295 296 const struct snd_motu_protocol snd_motu_protocol_v2 = { 297 .get_clock_rate = v2_get_clock_rate, 298 .set_clock_rate = v2_set_clock_rate, 299 .get_clock_source = v2_get_clock_source, 300 .switch_fetching_mode = v2_switch_fetching_mode, 301 .cache_packet_formats = v2_cache_packet_formats, 302 }; 303