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