1 // SPDX-License-Identifier: GPL-2.0-only
3 * motu-protocol-v3.c - a part of driver for MOTU FireWire series
5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
8 #include <linux/delay.h>
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
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
27 #define V3_MSG_FLAG_CLK_CHANGED 0x00000002
28 #define V3_CLK_WAIT_MSEC 4000
30 int snd_motu_protocol_v3_get_clock_rate(struct snd_motu
*motu
,
37 err
= snd_motu_transaction_read(motu
, V3_CLOCK_STATUS_OFFSET
, ®
,
41 data
= be32_to_cpu(reg
);
43 data
= (data
& V3_CLOCK_RATE_MASK
) >> V3_CLOCK_RATE_SHIFT
;
44 if (data
>= ARRAY_SIZE(snd_motu_clock_rates
))
47 *rate
= snd_motu_clock_rates
[data
];
52 int snd_motu_protocol_v3_set_clock_rate(struct snd_motu
*motu
,
60 for (i
= 0; i
< ARRAY_SIZE(snd_motu_clock_rates
); ++i
) {
61 if (snd_motu_clock_rates
[i
] == rate
)
64 if (i
== ARRAY_SIZE(snd_motu_clock_rates
))
67 err
= snd_motu_transaction_read(motu
, V3_CLOCK_STATUS_OFFSET
, ®
,
71 data
= be32_to_cpu(reg
);
73 data
&= ~(V3_CLOCK_RATE_MASK
| V3_FETCH_PCM_FRAMES
);
74 data
|= i
<< V3_CLOCK_RATE_SHIFT
;
76 need_to_wait
= data
!= be32_to_cpu(reg
);
78 reg
= cpu_to_be32(data
);
79 err
= snd_motu_transaction_write(motu
, V3_CLOCK_STATUS_OFFSET
, ®
,
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
));
100 static int detect_clock_source_828mk3(struct snd_motu
*motu
, u32 data
,
101 enum snd_motu_clock_source
*src
)
105 *src
= SND_MOTU_CLOCK_SOURCE_INTERNAL
;
108 *src
= SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC
;
111 *src
= SND_MOTU_CLOCK_SOURCE_SPH
;
114 *src
= SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX
;
123 err
= snd_motu_transaction_read(motu
,
124 V3_OPT_IFACE_MODE_OFFSET
, ®
, sizeof(reg
));
127 options
= be32_to_cpu(reg
);
130 if (options
& V3_NO_ADAT_OPT_IN_IFACE_A
)
131 *src
= SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A
;
133 *src
= SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A
;
135 if (options
& V3_NO_ADAT_OPT_IN_IFACE_B
)
136 *src
= SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B
;
138 *src
= SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B
;
144 *src
= SND_MOTU_CLOCK_SOURCE_UNKNOWN
;
151 static int v3_detect_clock_source(struct snd_motu
*motu
, u32 data
,
152 enum snd_motu_clock_source
*src
)
156 *src
= SND_MOTU_CLOCK_SOURCE_INTERNAL
;
159 *src
= SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC
;
162 *src
= SND_MOTU_CLOCK_SOURCE_SPH
;
165 *src
= SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX
;
168 *src
= SND_MOTU_CLOCK_SOURCE_UNKNOWN
;
175 int snd_motu_protocol_v3_get_clock_source(struct snd_motu
*motu
,
176 enum snd_motu_clock_source
*src
)
182 err
= snd_motu_transaction_read(motu
, V3_CLOCK_STATUS_OFFSET
, ®
,
186 data
= be32_to_cpu(reg
) & V3_CLOCK_SOURCE_MASK
;
188 if (motu
->spec
== &snd_motu_spec_828mk3
)
189 return detect_clock_source_828mk3(motu
, data
, src
);
191 return v3_detect_clock_source(motu
, data
, src
);
194 int snd_motu_protocol_v3_switch_fetching_mode(struct snd_motu
*motu
,
201 err
= snd_motu_transaction_read(motu
, V3_CLOCK_STATUS_OFFSET
, ®
,
205 data
= be32_to_cpu(reg
);
208 data
|= V3_FETCH_PCM_FRAMES
;
210 data
&= ~V3_FETCH_PCM_FRAMES
;
212 reg
= cpu_to_be32(data
);
213 return snd_motu_transaction_write(motu
, V3_CLOCK_STATUS_OFFSET
, ®
,
217 static int detect_packet_formats_828mk3(struct snd_motu
*motu
, u32 data
)
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;
224 motu
->tx_packet_formats
.pcm_chunks
[0] += 8;
225 motu
->tx_packet_formats
.pcm_chunks
[1] += 4;
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;
234 motu
->tx_packet_formats
.pcm_chunks
[0] += 8;
235 motu
->tx_packet_formats
.pcm_chunks
[1] += 4;
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;
244 motu
->rx_packet_formats
.pcm_chunks
[0] += 8;
245 motu
->rx_packet_formats
.pcm_chunks
[1] += 4;
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;
254 motu
->rx_packet_formats
.pcm_chunks
[0] += 8;
255 motu
->rx_packet_formats
.pcm_chunks
[1] += 4;
262 int snd_motu_protocol_v3_cache_packet_formats(struct snd_motu
*motu
)
268 motu
->tx_packet_formats
.pcm_byte_offset
= 10;
269 motu
->rx_packet_formats
.pcm_byte_offset
= 10;
271 motu
->tx_packet_formats
.msg_chunks
= 2;
272 motu
->rx_packet_formats
.msg_chunks
= 2;
274 err
= snd_motu_transaction_read(motu
, V3_OPT_IFACE_MODE_OFFSET
, ®
,
278 data
= be32_to_cpu(reg
);
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
));
287 if (motu
->spec
== &snd_motu_spec_828mk3
)
288 return detect_packet_formats_828mk3(motu
, data
);
294 const struct snd_motu_spec snd_motu_spec_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},
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},
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},
321 const struct snd_motu_spec snd_motu_spec_4pre
= {
323 .protocol_version
= SND_MOTU_PROTOCOL_V3
,
324 .tx_fixed_pcm_chunks
= {10, 10, 0},
325 .rx_fixed_pcm_chunks
= {10, 10, 0},