1 /* 2 * motu-protocol-v3.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 <linux/delay.h> 10 #include "motu.h" 11 12 #define V3_CLOCK_STATUS_OFFSET 0x0b14 13 #define V3_FETCH_PCM_FRAMES 0x02000000 14 #define V3_CLOCK_RATE_MASK 0x0000ff00 15 #define V3_CLOCK_RATE_SHIFT 8 16 #define V3_CLOCK_SOURCE_MASK 0x000000ff 17 18 #define V3_OPT_IFACE_MODE_OFFSET 0x0c94 19 #define V3_ENABLE_OPT_IN_IFACE_A 0x00000001 20 #define V3_ENABLE_OPT_IN_IFACE_B 0x00000002 21 #define V3_ENABLE_OPT_OUT_IFACE_A 0x00000100 22 #define V3_ENABLE_OPT_OUT_IFACE_B 0x00000200 23 #define V3_NO_ADAT_OPT_IN_IFACE_A 0x00010000 24 #define V3_NO_ADAT_OPT_IN_IFACE_B 0x00100000 25 #define V3_NO_ADAT_OPT_OUT_IFACE_A 0x00040000 26 #define V3_NO_ADAT_OPT_OUT_IFACE_B 0x00400000 27 28 static int v3_get_clock_rate(struct snd_motu *motu, unsigned int *rate) 29 { 30 __be32 reg; 31 u32 data; 32 int err; 33 34 err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, 35 sizeof(reg)); 36 if (err < 0) 37 return err; 38 data = be32_to_cpu(reg); 39 40 data = (data & V3_CLOCK_RATE_MASK) >> V3_CLOCK_RATE_SHIFT; 41 if (data >= ARRAY_SIZE(snd_motu_clock_rates)) 42 return -EIO; 43 44 *rate = snd_motu_clock_rates[data]; 45 46 return 0; 47 } 48 49 static int v3_set_clock_rate(struct snd_motu *motu, unsigned int rate) 50 { 51 __be32 reg; 52 u32 data; 53 bool need_to_wait; 54 int i, 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, V3_CLOCK_STATUS_OFFSET, ®, 64 sizeof(reg)); 65 if (err < 0) 66 return err; 67 data = be32_to_cpu(reg); 68 69 data &= ~(V3_CLOCK_RATE_MASK | V3_FETCH_PCM_FRAMES); 70 data |= i << V3_CLOCK_RATE_SHIFT; 71 72 need_to_wait = data != be32_to_cpu(reg); 73 74 reg = cpu_to_be32(data); 75 err = snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, ®, 76 sizeof(reg)); 77 if (err < 0) 78 return err; 79 80 if (need_to_wait) { 81 /* Cost expensive. */ 82 if (msleep_interruptible(4000) > 0) 83 return -EINTR; 84 } 85 86 return 0; 87 } 88 89 static int v3_get_clock_source(struct snd_motu *motu, 90 enum snd_motu_clock_source *src) 91 { 92 __be32 reg; 93 u32 data; 94 unsigned int val; 95 int err; 96 97 err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, 98 sizeof(reg)); 99 if (err < 0) 100 return err; 101 data = be32_to_cpu(reg); 102 103 val = data & V3_CLOCK_SOURCE_MASK; 104 if (val == 0x00) { 105 *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; 106 } else if (val == 0x01) { 107 *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; 108 } else if (val == 0x10) { 109 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; 110 } else if (val == 0x18 || val == 0x19) { 111 err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, 112 ®, sizeof(reg)); 113 if (err < 0) 114 return err; 115 data = be32_to_cpu(reg); 116 117 if (val == 0x18) { 118 if (data & V3_NO_ADAT_OPT_IN_IFACE_A) 119 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A; 120 else 121 *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A; 122 } else { 123 if (data & V3_NO_ADAT_OPT_IN_IFACE_B) 124 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B; 125 else 126 *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B; 127 } 128 } else { 129 *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN; 130 } 131 132 return 0; 133 } 134 135 static int v3_switch_fetching_mode(struct snd_motu *motu, bool enable) 136 { 137 __be32 reg; 138 u32 data; 139 int err; 140 141 err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, 142 sizeof(reg)); 143 if (err < 0) 144 return 0; 145 data = be32_to_cpu(reg); 146 147 if (enable) 148 data |= V3_FETCH_PCM_FRAMES; 149 else 150 data &= ~V3_FETCH_PCM_FRAMES; 151 152 reg = cpu_to_be32(data); 153 return snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, ®, 154 sizeof(reg)); 155 } 156 157 static void calculate_fixed_part(struct snd_motu_packet_format *formats, 158 enum amdtp_stream_direction dir, 159 enum snd_motu_spec_flags flags, 160 unsigned char analog_ports) 161 { 162 unsigned char pcm_chunks[3] = {0, 0, 0}; 163 164 formats->msg_chunks = 2; 165 166 pcm_chunks[0] = analog_ports; 167 pcm_chunks[1] = analog_ports; 168 if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) 169 pcm_chunks[2] = analog_ports; 170 171 if (dir == AMDTP_IN_STREAM) { 172 if (flags & SND_MOTU_SPEC_TX_MICINST_CHUNK) { 173 pcm_chunks[0] += 2; 174 pcm_chunks[1] += 2; 175 if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) 176 pcm_chunks[2] += 2; 177 } 178 179 if (flags & SND_MOTU_SPEC_TX_RETURN_CHUNK) { 180 pcm_chunks[0] += 2; 181 pcm_chunks[1] += 2; 182 if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) 183 pcm_chunks[2] += 2; 184 } 185 186 if (flags & SND_MOTU_SPEC_TX_REVERB_CHUNK) { 187 pcm_chunks[0] += 2; 188 pcm_chunks[1] += 2; 189 } 190 } else { 191 if (flags & SND_MOTU_SPEC_RX_SEPARETED_MAIN) { 192 pcm_chunks[0] += 2; 193 pcm_chunks[1] += 2; 194 } 195 196 // Packets to v3 units include 2 chunks for phone 1/2, except 197 // for 176.4/192.0 kHz. 198 pcm_chunks[0] += 2; 199 pcm_chunks[1] += 2; 200 } 201 202 if (flags & SND_MOTU_SPEC_HAS_AESEBU_IFACE) { 203 pcm_chunks[0] += 2; 204 pcm_chunks[1] += 2; 205 } 206 207 /* 208 * At least, packets have two data chunks for S/PDIF on coaxial 209 * interface. 210 */ 211 pcm_chunks[0] += 2; 212 pcm_chunks[1] += 2; 213 214 /* 215 * Fixed part consists of PCM chunks multiple of 4, with msg chunks. As 216 * a result, this part can includes empty data chunks. 217 */ 218 formats->fixed_part_pcm_chunks[0] = round_up(2 + pcm_chunks[0], 4) - 2; 219 formats->fixed_part_pcm_chunks[1] = round_up(2 + pcm_chunks[1], 4) - 2; 220 if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) 221 formats->fixed_part_pcm_chunks[2] = 222 round_up(2 + pcm_chunks[2], 4) - 2; 223 } 224 225 static void calculate_differed_part(struct snd_motu_packet_format *formats, 226 enum snd_motu_spec_flags flags, u32 data, 227 u32 a_enable_mask, u32 a_no_adat_mask, 228 u32 b_enable_mask, u32 b_no_adat_mask) 229 { 230 unsigned char pcm_chunks[3] = {0, 0, 0}; 231 int i; 232 233 if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) && (data & a_enable_mask)) { 234 if (data & a_no_adat_mask) { 235 /* 236 * Additional two data chunks for S/PDIF on optical 237 * interface A. This includes empty data chunks. 238 */ 239 pcm_chunks[0] += 4; 240 pcm_chunks[1] += 4; 241 } else { 242 /* 243 * Additional data chunks for ADAT on optical interface 244 * A. 245 */ 246 pcm_chunks[0] += 8; 247 pcm_chunks[1] += 4; 248 } 249 } 250 251 if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_B) && (data & b_enable_mask)) { 252 if (data & b_no_adat_mask) { 253 /* 254 * Additional two data chunks for S/PDIF on optical 255 * interface B. This includes empty data chunks. 256 */ 257 pcm_chunks[0] += 4; 258 pcm_chunks[1] += 4; 259 } else { 260 /* 261 * Additional data chunks for ADAT on optical interface 262 * B. 263 */ 264 pcm_chunks[0] += 8; 265 pcm_chunks[1] += 4; 266 } 267 } 268 269 for (i = 0; i < 3; ++i) { 270 if (pcm_chunks[i] > 0) 271 pcm_chunks[i] = round_up(pcm_chunks[i], 4); 272 273 formats->differed_part_pcm_chunks[i] = pcm_chunks[i]; 274 } 275 } 276 277 static int v3_cache_packet_formats(struct snd_motu *motu) 278 { 279 __be32 reg; 280 u32 data; 281 int err; 282 283 err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, ®, 284 sizeof(reg)); 285 if (err < 0) 286 return err; 287 data = be32_to_cpu(reg); 288 289 calculate_fixed_part(&motu->tx_packet_formats, AMDTP_IN_STREAM, 290 motu->spec->flags, motu->spec->analog_in_ports); 291 calculate_differed_part(&motu->tx_packet_formats, 292 motu->spec->flags, data, 293 V3_ENABLE_OPT_IN_IFACE_A, V3_NO_ADAT_OPT_IN_IFACE_A, 294 V3_ENABLE_OPT_IN_IFACE_B, V3_NO_ADAT_OPT_IN_IFACE_B); 295 296 calculate_fixed_part(&motu->rx_packet_formats, AMDTP_OUT_STREAM, 297 motu->spec->flags, motu->spec->analog_out_ports); 298 calculate_differed_part(&motu->rx_packet_formats, 299 motu->spec->flags, data, 300 V3_ENABLE_OPT_OUT_IFACE_A, V3_NO_ADAT_OPT_OUT_IFACE_A, 301 V3_ENABLE_OPT_OUT_IFACE_B, V3_NO_ADAT_OPT_OUT_IFACE_B); 302 303 motu->tx_packet_formats.pcm_byte_offset = 10; 304 motu->rx_packet_formats.pcm_byte_offset = 10; 305 306 return 0; 307 } 308 309 const struct snd_motu_protocol snd_motu_protocol_v3 = { 310 .get_clock_rate = v3_get_clock_rate, 311 .set_clock_rate = v3_set_clock_rate, 312 .get_clock_source = v3_get_clock_source, 313 .switch_fetching_mode = v3_switch_fetching_mode, 314 .cache_packet_formats = v3_cache_packet_formats, 315 }; 316