Linux 6.7-rc7
[linux-modified.git] / sound / firewire / motu / motu-protocol-v2.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * motu-protocol-v2.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 "motu.h"
9
10 #define V2_CLOCK_STATUS_OFFSET                  0x0b14
11 #define  V2_CLOCK_RATE_MASK                     0x00000038
12 #define  V2_CLOCK_RATE_SHIFT                    3
13 #define  V2_CLOCK_SRC_MASK                      0x00000007
14 #define  V2_CLOCK_SRC_SHIFT                     0
15 #define   V2_CLOCK_SRC_AESEBU_ON_XLR            0x07    // In Traveler.
16 #define   V2_CLOCK_SRC_ADAT_ON_DSUB             0x05
17 #define   V2_CLOCK_SRC_WORD_ON_BNC              0x04
18 #define   V2_CLOCK_SRC_SPH                      0x03
19 #define   V2_CLOCK_SRC_SPDIF                    0x02    // on either coaxial or optical. AES/EBU in 896HD.
20 #define   V2_CLOCK_SRC_ADAT_ON_OPT              0x01
21 #define   V2_CLOCK_SRC_INTERNAL                 0x00
22 #define  V2_CLOCK_FETCH_ENABLE                  0x02000000
23 #define  V2_CLOCK_MODEL_SPECIFIC                0x04000000
24
25 #define V2_IN_OUT_CONF_OFFSET                   0x0c04
26 #define  V2_OPT_OUT_IFACE_MASK                  0x00000c00
27 #define  V2_OPT_OUT_IFACE_SHIFT                 10
28 #define  V2_OPT_IN_IFACE_MASK                   0x00000300
29 #define  V2_OPT_IN_IFACE_SHIFT                  8
30 #define  V2_OPT_IFACE_MODE_NONE                 0
31 #define  V2_OPT_IFACE_MODE_ADAT                 1
32 #define  V2_OPT_IFACE_MODE_SPDIF                2
33
34 static int get_clock_rate(u32 data, unsigned int *rate)
35 {
36         unsigned int index = (data & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT;
37         if (index >= ARRAY_SIZE(snd_motu_clock_rates))
38                 return -EIO;
39
40         *rate = snd_motu_clock_rates[index];
41
42         return 0;
43 }
44
45 int snd_motu_protocol_v2_get_clock_rate(struct snd_motu *motu,
46                                         unsigned int *rate)
47 {
48         __be32 reg;
49         int err;
50
51         err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
52                                         sizeof(reg));
53         if (err < 0)
54                 return err;
55
56         return get_clock_rate(be32_to_cpu(reg), rate);
57 }
58
59 int snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu,
60                                         unsigned int rate)
61 {
62         __be32 reg;
63         u32 data;
64         int i;
65         int 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, V2_CLOCK_STATUS_OFFSET, &reg,
75                                         sizeof(reg));
76         if (err < 0)
77                 return err;
78         data = be32_to_cpu(reg);
79
80         data &= ~V2_CLOCK_RATE_MASK;
81         data |= i << V2_CLOCK_RATE_SHIFT;
82
83         reg = cpu_to_be32(data);
84         return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, &reg,
85                                           sizeof(reg));
86 }
87
88 static int get_clock_source(struct snd_motu *motu, u32 data,
89                             enum snd_motu_clock_source *src)
90 {
91         switch (data & V2_CLOCK_SRC_MASK) {
92         case V2_CLOCK_SRC_INTERNAL:
93                 *src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
94                 break;
95         case V2_CLOCK_SRC_ADAT_ON_OPT:
96                 *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
97                 break;
98         case V2_CLOCK_SRC_SPDIF:
99         {
100                 bool support_iec60958_on_opt = (motu->spec == &snd_motu_spec_828mk2 ||
101                                                 motu->spec == &snd_motu_spec_traveler);
102
103                 if (motu->spec == &snd_motu_spec_896hd) {
104                         *src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;
105                 } else if (!support_iec60958_on_opt) {
106                         *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
107                 } else {
108                         __be32 reg;
109
110                         // To check the configuration of optical interface.
111                         int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
112                                                             sizeof(reg));
113                         if (err < 0)
114                                 return err;
115
116                         if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==
117                             V2_OPT_IFACE_MODE_SPDIF)
118                                 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
119                         else
120                                 *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
121                 }
122                 break;
123         }
124         case V2_CLOCK_SRC_SPH:
125                 *src = SND_MOTU_CLOCK_SOURCE_SPH;
126                 break;
127         case V2_CLOCK_SRC_WORD_ON_BNC:
128                 *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
129                 break;
130         case V2_CLOCK_SRC_ADAT_ON_DSUB:
131                 *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
132                 break;
133         case V2_CLOCK_SRC_AESEBU_ON_XLR:
134                 // For Traveler.
135                 *src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;
136                 break;
137         default:
138                 *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
139                 break;
140         }
141
142         return 0;
143 }
144
145 int snd_motu_protocol_v2_get_clock_source(struct snd_motu *motu,
146                                           enum snd_motu_clock_source *src)
147 {
148         __be32 reg;
149         int err;
150
151         err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
152                                         sizeof(reg));
153         if (err < 0)
154                 return err;
155
156         return get_clock_source(motu, be32_to_cpu(reg), src);
157 }
158
159 // Expected for Traveler, which implements Altera Cyclone EP1C3.
160 static int switch_fetching_mode_cyclone(struct snd_motu *motu, u32 *data,
161                                         bool enable)
162 {
163         *data |= V2_CLOCK_MODEL_SPECIFIC;
164
165         return 0;
166 }
167
168 // For UltraLite and 8pre, which implements Xilinx Spartan XC3S200.
169 static int switch_fetching_mode_spartan(struct snd_motu *motu, u32 *data,
170                                         bool enable)
171 {
172         unsigned int rate;
173         enum snd_motu_clock_source src;
174         int err;
175
176         err = get_clock_source(motu, *data, &src);
177         if (err < 0)
178                 return err;
179
180         err = get_clock_rate(*data, &rate);
181         if (err < 0)
182                 return err;
183
184         if (src == SND_MOTU_CLOCK_SOURCE_SPH && rate > 48000)
185                 *data |= V2_CLOCK_MODEL_SPECIFIC;
186
187         return 0;
188 }
189
190 int snd_motu_protocol_v2_switch_fetching_mode(struct snd_motu *motu,
191                                               bool enable)
192 {
193         if (motu->spec == &snd_motu_spec_828mk2) {
194                 // 828mkII implements Altera ACEX 1K EP1K30. Nothing to do.
195                 return 0;
196         } else if (motu->spec == &snd_motu_spec_896hd) {
197                 // 896HD implements Altera Cyclone EP1C3 but nothing to do.
198                 return 0;
199         } else {
200                 __be32 reg;
201                 u32 data;
202                 int err;
203
204                 err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,
205                                                 &reg, sizeof(reg));
206                 if (err < 0)
207                         return err;
208                 data = be32_to_cpu(reg);
209
210                 data &= ~(V2_CLOCK_FETCH_ENABLE | V2_CLOCK_MODEL_SPECIFIC);
211                 if (enable)
212                         data |= V2_CLOCK_FETCH_ENABLE;
213
214                 if (motu->spec == &snd_motu_spec_traveler)
215                         err = switch_fetching_mode_cyclone(motu, &data, enable);
216                 else
217                         err = switch_fetching_mode_spartan(motu, &data, enable);
218                 if (err < 0)
219                         return err;
220
221                 reg = cpu_to_be32(data);
222                 return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,
223                                                   &reg, sizeof(reg));
224         }
225 }
226
227 int snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu)
228 {
229         bool has_two_opt_ifaces = (motu->spec == &snd_motu_spec_8pre);
230         __be32 reg;
231         u32 data;
232         int err;
233
234         motu->tx_packet_formats.pcm_byte_offset = 10;
235         motu->rx_packet_formats.pcm_byte_offset = 10;
236
237         motu->tx_packet_formats.msg_chunks = 2;
238         motu->rx_packet_formats.msg_chunks = 2;
239
240         err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
241                                         sizeof(reg));
242         if (err < 0)
243                 return err;
244         data = be32_to_cpu(reg);
245
246         memcpy(motu->tx_packet_formats.pcm_chunks,
247                motu->spec->tx_fixed_pcm_chunks,
248                sizeof(motu->tx_packet_formats.pcm_chunks));
249         memcpy(motu->rx_packet_formats.pcm_chunks,
250                motu->spec->rx_fixed_pcm_chunks,
251                sizeof(motu->rx_packet_formats.pcm_chunks));
252
253         if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {
254                 motu->tx_packet_formats.pcm_chunks[0] += 8;
255
256                 if (!has_two_opt_ifaces)
257                         motu->tx_packet_formats.pcm_chunks[1] += 4;
258                 else
259                         motu->tx_packet_formats.pcm_chunks[1] += 8;
260         }
261
262         if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {
263                 motu->rx_packet_formats.pcm_chunks[0] += 8;
264
265                 if (!has_two_opt_ifaces)
266                         motu->rx_packet_formats.pcm_chunks[1] += 4;
267                 else
268                         motu->rx_packet_formats.pcm_chunks[1] += 8;
269         }
270
271         return 0;
272 }
273
274 const struct snd_motu_spec snd_motu_spec_828mk2 = {
275         .name = "828mk2",
276         .protocol_version = SND_MOTU_PROTOCOL_V2,
277         .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
278                  SND_MOTU_SPEC_TX_MIDI_2ND_Q |
279                  SND_MOTU_SPEC_REGISTER_DSP,
280         .tx_fixed_pcm_chunks = {14, 14, 0},
281         .rx_fixed_pcm_chunks = {14, 14, 0},
282 };
283
284 const struct snd_motu_spec snd_motu_spec_896hd = {
285         .name = "896HD",
286         .protocol_version = SND_MOTU_PROTOCOL_V2,
287         .flags = SND_MOTU_SPEC_REGISTER_DSP,
288         .tx_fixed_pcm_chunks = {14, 14, 8},
289         .rx_fixed_pcm_chunks = {14, 14, 8},
290 };
291
292 const struct snd_motu_spec snd_motu_spec_traveler = {
293         .name = "Traveler",
294         .protocol_version = SND_MOTU_PROTOCOL_V2,
295         .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
296                  SND_MOTU_SPEC_TX_MIDI_2ND_Q |
297                  SND_MOTU_SPEC_REGISTER_DSP,
298         .tx_fixed_pcm_chunks = {14, 14, 8},
299         .rx_fixed_pcm_chunks = {14, 14, 8},
300 };
301
302 const struct snd_motu_spec snd_motu_spec_ultralite = {
303         .name = "UltraLite",
304         .protocol_version = SND_MOTU_PROTOCOL_V2,
305         .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
306                  SND_MOTU_SPEC_TX_MIDI_2ND_Q |
307                  SND_MOTU_SPEC_REGISTER_DSP,
308         .tx_fixed_pcm_chunks = {14, 14, 0},
309         .rx_fixed_pcm_chunks = {14, 14, 0},
310 };
311
312 const struct snd_motu_spec snd_motu_spec_8pre = {
313         .name = "8pre",
314         .protocol_version = SND_MOTU_PROTOCOL_V2,
315         .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
316                  SND_MOTU_SPEC_TX_MIDI_2ND_Q |
317                  SND_MOTU_SPEC_REGISTER_DSP,
318         // Two dummy chunks always in the end of data block.
319         .tx_fixed_pcm_chunks = {10, 10, 0},
320         .rx_fixed_pcm_chunks = {6, 6, 0},
321 };