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