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