GNU Linux-libre 5.13.14-gnu1
[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
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, &reg,
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, &reg,
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, &reg,
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, &reg, 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, &reg,
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, &reg,
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, &reg,
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, &reg,
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 };