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 #define V3_MSG_FLAG_CLK_CHANGED 0x00000002 28 #define V3_CLK_WAIT_MSEC 4000 29 30 int snd_motu_protocol_v3_get_clock_rate(struct snd_motu *motu, 31 unsigned int *rate) 32 { 33 __be32 reg; 34 u32 data; 35 int err; 36 37 err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, 38 sizeof(reg)); 39 if (err < 0) 40 return err; 41 data = be32_to_cpu(reg); 42 43 data = (data & V3_CLOCK_RATE_MASK) >> V3_CLOCK_RATE_SHIFT; 44 if (data >= ARRAY_SIZE(snd_motu_clock_rates)) 45 return -EIO; 46 47 *rate = snd_motu_clock_rates[data]; 48 49 return 0; 50 } 51 52 int snd_motu_protocol_v3_set_clock_rate(struct snd_motu *motu, 53 unsigned int rate) 54 { 55 __be32 reg; 56 u32 data; 57 bool need_to_wait; 58 int i, err; 59 60 for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) { 61 if (snd_motu_clock_rates[i] == rate) 62 break; 63 } 64 if (i == ARRAY_SIZE(snd_motu_clock_rates)) 65 return -EINVAL; 66 67 err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, 68 sizeof(reg)); 69 if (err < 0) 70 return err; 71 data = be32_to_cpu(reg); 72 73 data &= ~(V3_CLOCK_RATE_MASK | V3_FETCH_PCM_FRAMES); 74 data |= i << V3_CLOCK_RATE_SHIFT; 75 76 need_to_wait = data != be32_to_cpu(reg); 77 78 reg = cpu_to_be32(data); 79 err = snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, ®, 80 sizeof(reg)); 81 if (err < 0) 82 return err; 83 84 if (need_to_wait) { 85 int result; 86 87 motu->msg = 0; 88 result = wait_event_interruptible_timeout(motu->hwdep_wait, 89 motu->msg & V3_MSG_FLAG_CLK_CHANGED, 90 msecs_to_jiffies(V3_CLK_WAIT_MSEC)); 91 if (result < 0) 92 return result; 93 if (result == 0) 94 return -ETIMEDOUT; 95 } 96 97 return 0; 98 } 99 100 static int detect_clock_source_828mk3(struct snd_motu *motu, u32 data, 101 enum snd_motu_clock_source *src) 102 { 103 switch (data) { 104 case 0x00: 105 *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; 106 break; 107 case 0x01: 108 *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; 109 break; 110 case 0x02: 111 *src = SND_MOTU_CLOCK_SOURCE_SPH; 112 break; 113 case 0x10: 114 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; 115 break; 116 case 0x18: 117 case 0x19: 118 { 119 __be32 reg; 120 u32 options; 121 int err; 122 123 err = snd_motu_transaction_read(motu, 124 V3_OPT_IFACE_MODE_OFFSET, ®, sizeof(reg)); 125 if (err < 0) 126 return err; 127 options = be32_to_cpu(reg); 128 129 if (data == 0x18) { 130 if (options & V3_NO_ADAT_OPT_IN_IFACE_A) 131 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A; 132 else 133 *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A; 134 } else { 135 if (options & V3_NO_ADAT_OPT_IN_IFACE_B) 136 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B; 137 else 138 *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B; 139 } 140 141 break; 142 } 143 default: 144 *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN; 145 break; 146 } 147 148 return 0; 149 } 150 151 static int v3_detect_clock_source(struct snd_motu *motu, u32 data, 152 enum snd_motu_clock_source *src) 153 { 154 switch (data) { 155 case 0x00: 156 *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; 157 break; 158 case 0x01: 159 *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; 160 break; 161 case 0x02: 162 *src = SND_MOTU_CLOCK_SOURCE_SPH; 163 break; 164 case 0x10: 165 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; 166 break; 167 default: 168 *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN; 169 break; 170 } 171 172 return 0; 173 } 174 175 int snd_motu_protocol_v3_get_clock_source(struct snd_motu *motu, 176 enum snd_motu_clock_source *src) 177 { 178 __be32 reg; 179 u32 data; 180 int err; 181 182 err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, 183 sizeof(reg)); 184 if (err < 0) 185 return err; 186 data = be32_to_cpu(reg) & V3_CLOCK_SOURCE_MASK; 187 188 if (motu->spec == &snd_motu_spec_828mk3) 189 return detect_clock_source_828mk3(motu, data, src); 190 else 191 return v3_detect_clock_source(motu, data, src); 192 } 193 194 int snd_motu_protocol_v3_switch_fetching_mode(struct snd_motu *motu, 195 bool enable) 196 { 197 __be32 reg; 198 u32 data; 199 int err; 200 201 err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, 202 sizeof(reg)); 203 if (err < 0) 204 return 0; 205 data = be32_to_cpu(reg); 206 207 if (enable) 208 data |= V3_FETCH_PCM_FRAMES; 209 else 210 data &= ~V3_FETCH_PCM_FRAMES; 211 212 reg = cpu_to_be32(data); 213 return snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, ®, 214 sizeof(reg)); 215 } 216 217 static int detect_packet_formats_828mk3(struct snd_motu *motu, u32 data) 218 { 219 if (data & V3_ENABLE_OPT_IN_IFACE_A) { 220 if (data & V3_NO_ADAT_OPT_IN_IFACE_A) { 221 motu->tx_packet_formats.pcm_chunks[0] += 4; 222 motu->tx_packet_formats.pcm_chunks[1] += 4; 223 } else { 224 motu->tx_packet_formats.pcm_chunks[0] += 8; 225 motu->tx_packet_formats.pcm_chunks[1] += 4; 226 } 227 } 228 229 if (data & V3_ENABLE_OPT_IN_IFACE_B) { 230 if (data & V3_NO_ADAT_OPT_IN_IFACE_B) { 231 motu->tx_packet_formats.pcm_chunks[0] += 4; 232 motu->tx_packet_formats.pcm_chunks[1] += 4; 233 } else { 234 motu->tx_packet_formats.pcm_chunks[0] += 8; 235 motu->tx_packet_formats.pcm_chunks[1] += 4; 236 } 237 } 238 239 if (data & V3_ENABLE_OPT_OUT_IFACE_A) { 240 if (data & V3_NO_ADAT_OPT_OUT_IFACE_A) { 241 motu->rx_packet_formats.pcm_chunks[0] += 4; 242 motu->rx_packet_formats.pcm_chunks[1] += 4; 243 } else { 244 motu->rx_packet_formats.pcm_chunks[0] += 8; 245 motu->rx_packet_formats.pcm_chunks[1] += 4; 246 } 247 } 248 249 if (data & V3_ENABLE_OPT_OUT_IFACE_B) { 250 if (data & V3_NO_ADAT_OPT_OUT_IFACE_B) { 251 motu->rx_packet_formats.pcm_chunks[0] += 4; 252 motu->rx_packet_formats.pcm_chunks[1] += 4; 253 } else { 254 motu->rx_packet_formats.pcm_chunks[0] += 8; 255 motu->rx_packet_formats.pcm_chunks[1] += 4; 256 } 257 } 258 259 return 0; 260 } 261 262 int snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu) 263 { 264 __be32 reg; 265 u32 data; 266 int err; 267 268 motu->tx_packet_formats.pcm_byte_offset = 10; 269 motu->rx_packet_formats.pcm_byte_offset = 10; 270 271 motu->tx_packet_formats.msg_chunks = 2; 272 motu->rx_packet_formats.msg_chunks = 2; 273 274 err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, ®, 275 sizeof(reg)); 276 if (err < 0) 277 return err; 278 data = be32_to_cpu(reg); 279 280 memcpy(motu->tx_packet_formats.pcm_chunks, 281 motu->spec->tx_fixed_pcm_chunks, 282 sizeof(motu->tx_packet_formats.pcm_chunks)); 283 memcpy(motu->rx_packet_formats.pcm_chunks, 284 motu->spec->rx_fixed_pcm_chunks, 285 sizeof(motu->rx_packet_formats.pcm_chunks)); 286 287 if (motu->spec == &snd_motu_spec_828mk3) 288 return detect_packet_formats_828mk3(motu, data); 289 else 290 return 0; 291 } 292 293 294 const struct snd_motu_spec snd_motu_spec_828mk3 = { 295 .name = "828mk3", 296 .protocol_version = SND_MOTU_PROTOCOL_V3, 297 .flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q | 298 SND_MOTU_SPEC_TX_MIDI_3RD_Q, 299 .tx_fixed_pcm_chunks = {18, 18, 14}, 300 .rx_fixed_pcm_chunks = {14, 14, 10}, 301 }; 302 303 const struct snd_motu_spec snd_motu_spec_ultralite_mk3 = { 304 .name = "UltraLiteMk3", 305 .protocol_version = SND_MOTU_PROTOCOL_V3, 306 .flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q | 307 SND_MOTU_SPEC_TX_MIDI_3RD_Q, 308 .tx_fixed_pcm_chunks = {18, 14, 10}, 309 .rx_fixed_pcm_chunks = {14, 14, 14}, 310 }; 311 312 const struct snd_motu_spec snd_motu_spec_audio_express = { 313 .name = "AudioExpress", 314 .protocol_version = SND_MOTU_PROTOCOL_V3, 315 .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q | 316 SND_MOTU_SPEC_TX_MIDI_3RD_Q, 317 .tx_fixed_pcm_chunks = {10, 10, 0}, 318 .rx_fixed_pcm_chunks = {10, 10, 0}, 319 }; 320 321 const struct snd_motu_spec snd_motu_spec_4pre = { 322 .name = "4pre", 323 .protocol_version = SND_MOTU_PROTOCOL_V3, 324 .tx_fixed_pcm_chunks = {10, 10, 0}, 325 .rx_fixed_pcm_chunks = {10, 10, 0}, 326 }; 327