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