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 == 0x02) { 108 *src = SND_MOTU_CLOCK_SOURCE_SPH; 109 } else if (val == 0x10) { 110 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; 111 } else if (val == 0x18 || val == 0x19) { 112 err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, 113 ®, sizeof(reg)); 114 if (err < 0) 115 return err; 116 data = be32_to_cpu(reg); 117 118 if (val == 0x18) { 119 if (data & V3_NO_ADAT_OPT_IN_IFACE_A) 120 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A; 121 else 122 *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A; 123 } else { 124 if (data & V3_NO_ADAT_OPT_IN_IFACE_B) 125 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B; 126 else 127 *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B; 128 } 129 } else { 130 *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN; 131 } 132 133 return 0; 134 } 135 136 static int v3_switch_fetching_mode(struct snd_motu *motu, bool enable) 137 { 138 __be32 reg; 139 u32 data; 140 int err; 141 142 err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, 143 sizeof(reg)); 144 if (err < 0) 145 return 0; 146 data = be32_to_cpu(reg); 147 148 if (enable) 149 data |= V3_FETCH_PCM_FRAMES; 150 else 151 data &= ~V3_FETCH_PCM_FRAMES; 152 153 reg = cpu_to_be32(data); 154 return snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, ®, 155 sizeof(reg)); 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 if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) 177 pcm_chunks[2] += 2; 178 } 179 180 if (flags & SND_MOTU_SPEC_TX_RETURN_CHUNK) { 181 pcm_chunks[0] += 2; 182 pcm_chunks[1] += 2; 183 if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) 184 pcm_chunks[2] += 2; 185 } 186 187 if (flags & SND_MOTU_SPEC_TX_REVERB_CHUNK) { 188 pcm_chunks[0] += 2; 189 pcm_chunks[1] += 2; 190 } 191 } else { 192 if (flags & SND_MOTU_SPEC_RX_SEPARATED_MAIN) { 193 pcm_chunks[0] += 2; 194 pcm_chunks[1] += 2; 195 } 196 197 // Packets to v3 units include 2 chunks for phone 1/2, except 198 // for 176.4/192.0 kHz. 199 pcm_chunks[0] += 2; 200 pcm_chunks[1] += 2; 201 } 202 203 if (flags & SND_MOTU_SPEC_HAS_AESEBU_IFACE) { 204 pcm_chunks[0] += 2; 205 pcm_chunks[1] += 2; 206 } 207 208 /* 209 * At least, packets have two data chunks for S/PDIF on coaxial 210 * interface. 211 */ 212 pcm_chunks[0] += 2; 213 pcm_chunks[1] += 2; 214 215 /* 216 * Fixed part consists of PCM chunks multiple of 4, with msg chunks. As 217 * a result, this part can includes empty data chunks. 218 */ 219 formats->fixed_part_pcm_chunks[0] = round_up(2 + pcm_chunks[0], 4) - 2; 220 formats->fixed_part_pcm_chunks[1] = round_up(2 + pcm_chunks[1], 4) - 2; 221 if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) 222 formats->fixed_part_pcm_chunks[2] = 223 round_up(2 + pcm_chunks[2], 4) - 2; 224 } 225 226 static void calculate_differed_part(struct snd_motu_packet_format *formats, 227 enum snd_motu_spec_flags flags, u32 data, 228 u32 a_enable_mask, u32 a_no_adat_mask, 229 u32 b_enable_mask, u32 b_no_adat_mask) 230 { 231 unsigned char pcm_chunks[3] = {0, 0, 0}; 232 int i; 233 234 if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) && (data & a_enable_mask)) { 235 if (data & a_no_adat_mask) { 236 /* 237 * Additional two data chunks for S/PDIF on optical 238 * interface A. This includes empty data chunks. 239 */ 240 pcm_chunks[0] += 4; 241 pcm_chunks[1] += 4; 242 } else { 243 /* 244 * Additional data chunks for ADAT on optical interface 245 * A. 246 */ 247 pcm_chunks[0] += 8; 248 pcm_chunks[1] += 4; 249 } 250 } 251 252 if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_B) && (data & b_enable_mask)) { 253 if (data & b_no_adat_mask) { 254 /* 255 * Additional two data chunks for S/PDIF on optical 256 * interface B. This includes empty data chunks. 257 */ 258 pcm_chunks[0] += 4; 259 pcm_chunks[1] += 4; 260 } else { 261 /* 262 * Additional data chunks for ADAT on optical interface 263 * B. 264 */ 265 pcm_chunks[0] += 8; 266 pcm_chunks[1] += 4; 267 } 268 } 269 270 for (i = 0; i < 3; ++i) { 271 if (pcm_chunks[i] > 0) 272 pcm_chunks[i] = round_up(pcm_chunks[i], 4); 273 274 formats->differed_part_pcm_chunks[i] = pcm_chunks[i]; 275 } 276 } 277 278 static int v3_cache_packet_formats(struct snd_motu *motu) 279 { 280 __be32 reg; 281 u32 data; 282 int err; 283 284 err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, ®, 285 sizeof(reg)); 286 if (err < 0) 287 return err; 288 data = be32_to_cpu(reg); 289 290 calculate_fixed_part(&motu->tx_packet_formats, AMDTP_IN_STREAM, 291 motu->spec->flags, motu->spec->analog_in_ports); 292 calculate_differed_part(&motu->tx_packet_formats, 293 motu->spec->flags, data, 294 V3_ENABLE_OPT_IN_IFACE_A, V3_NO_ADAT_OPT_IN_IFACE_A, 295 V3_ENABLE_OPT_IN_IFACE_B, V3_NO_ADAT_OPT_IN_IFACE_B); 296 297 calculate_fixed_part(&motu->rx_packet_formats, AMDTP_OUT_STREAM, 298 motu->spec->flags, motu->spec->analog_out_ports); 299 calculate_differed_part(&motu->rx_packet_formats, 300 motu->spec->flags, data, 301 V3_ENABLE_OPT_OUT_IFACE_A, V3_NO_ADAT_OPT_OUT_IFACE_A, 302 V3_ENABLE_OPT_OUT_IFACE_B, V3_NO_ADAT_OPT_OUT_IFACE_B); 303 304 motu->tx_packet_formats.pcm_byte_offset = 10; 305 motu->rx_packet_formats.pcm_byte_offset = 10; 306 307 return 0; 308 } 309 310 const struct snd_motu_protocol snd_motu_protocol_v3 = { 311 .get_clock_rate = v3_get_clock_rate, 312 .set_clock_rate = v3_set_clock_rate, 313 .get_clock_source = v3_get_clock_source, 314 .switch_fetching_mode = v3_switch_fetching_mode, 315 .cache_packet_formats = v3_cache_packet_formats, 316 }; 317