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