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