Linux 6.7-rc7
[linux-modified.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_traveler_mk3 ||
265             motu->spec == &snd_motu_spec_track16)
266                 return detect_packet_formats_with_opt_ifaces(motu, data);
267         else
268                 return 0;
269 }
270
271 const struct snd_motu_spec snd_motu_spec_828mk3_fw = {
272         .name = "828mk3",
273         .protocol_version = SND_MOTU_PROTOCOL_V3,
274         .flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
275                  SND_MOTU_SPEC_TX_MIDI_3RD_Q |
276                  SND_MOTU_SPEC_COMMAND_DSP,
277         .tx_fixed_pcm_chunks = {18, 18, 14},
278         .rx_fixed_pcm_chunks = {14, 14, 10},
279 };
280
281 const struct snd_motu_spec snd_motu_spec_828mk3_hybrid = {
282         .name = "828mk3",
283         .protocol_version = SND_MOTU_PROTOCOL_V3,
284         .flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
285                  SND_MOTU_SPEC_TX_MIDI_3RD_Q |
286                  SND_MOTU_SPEC_COMMAND_DSP,
287         .tx_fixed_pcm_chunks = {18, 18, 14},
288         .rx_fixed_pcm_chunks = {14, 14, 14},    // Additional 4 dummy chunks at higher rate.
289 };
290
291 const struct snd_motu_spec snd_motu_spec_traveler_mk3 = {
292         .name = "TravelerMk3",
293         .protocol_version = SND_MOTU_PROTOCOL_V3,
294         .flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
295                  SND_MOTU_SPEC_TX_MIDI_3RD_Q |
296                  SND_MOTU_SPEC_COMMAND_DSP,
297         .tx_fixed_pcm_chunks = {18, 14, 10},
298         .rx_fixed_pcm_chunks = {14, 14, 10},
299 };
300
301 const struct snd_motu_spec snd_motu_spec_ultralite_mk3 = {
302         .name = "UltraLiteMk3",
303         .protocol_version = SND_MOTU_PROTOCOL_V3,
304         .flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
305                  SND_MOTU_SPEC_TX_MIDI_3RD_Q |
306                  SND_MOTU_SPEC_COMMAND_DSP,
307         .tx_fixed_pcm_chunks = {18, 14, 10},
308         .rx_fixed_pcm_chunks = {14, 14, 14},
309 };
310
311 const struct snd_motu_spec snd_motu_spec_audio_express = {
312         .name = "AudioExpress",
313         .protocol_version = SND_MOTU_PROTOCOL_V3,
314         .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
315                  SND_MOTU_SPEC_TX_MIDI_3RD_Q |
316                  SND_MOTU_SPEC_REGISTER_DSP,
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_track16 = {
322         .name = "Track16",
323         .protocol_version = SND_MOTU_PROTOCOL_V3,
324         .flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
325                  SND_MOTU_SPEC_TX_MIDI_3RD_Q |
326                  SND_MOTU_SPEC_COMMAND_DSP,
327         .tx_fixed_pcm_chunks = {14, 14, 14},
328         .rx_fixed_pcm_chunks = {6, 6, 6},
329 };
330
331 const struct snd_motu_spec snd_motu_spec_4pre = {
332         .name = "4pre",
333         .protocol_version = SND_MOTU_PROTOCOL_V3,
334         .flags = SND_MOTU_SPEC_REGISTER_DSP,
335         .tx_fixed_pcm_chunks = {10, 10, 0},
336         .rx_fixed_pcm_chunks = {10, 10, 0},
337 };