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