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 
snd_motu_protocol_v3_get_clock_rate(struct snd_motu * motu,unsigned int * rate)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 
snd_motu_protocol_v3_set_clock_rate(struct snd_motu * motu,unsigned int rate)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 
snd_motu_protocol_v3_get_clock_source(struct snd_motu * motu,enum snd_motu_clock_source * src)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 
snd_motu_protocol_v3_switch_fetching_mode(struct snd_motu * motu,bool enable)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 
detect_packet_formats_with_opt_ifaces(struct snd_motu * motu,u32 data)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 
snd_motu_protocol_v3_cache_packet_formats(struct snd_motu * motu)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 };
338