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