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 const struct snd_motu_spec snd_motu_spec_828mk3_fw = {
265 	.name = "828mk3",
266 	.protocol_version = SND_MOTU_PROTOCOL_V3,
267 	.flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
268 		 SND_MOTU_SPEC_TX_MIDI_3RD_Q |
269 		 SND_MOTU_SPEC_COMMAND_DSP,
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 		 SND_MOTU_SPEC_COMMAND_DSP,
280 	.tx_fixed_pcm_chunks = {18, 18, 14},
281 	.rx_fixed_pcm_chunks = {14, 14, 14},	// Additional 4 dummy chunks at higher rate.
282 };
283 
284 const struct snd_motu_spec snd_motu_spec_ultralite_mk3 = {
285 	.name = "UltraLiteMk3",
286 	.protocol_version = SND_MOTU_PROTOCOL_V3,
287 	.flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
288 		 SND_MOTU_SPEC_TX_MIDI_3RD_Q |
289 		 SND_MOTU_SPEC_COMMAND_DSP,
290 	.tx_fixed_pcm_chunks = {18, 14, 10},
291 	.rx_fixed_pcm_chunks = {14, 14, 14},
292 };
293 
294 const struct snd_motu_spec snd_motu_spec_audio_express = {
295 	.name = "AudioExpress",
296 	.protocol_version = SND_MOTU_PROTOCOL_V3,
297 	.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
298 		 SND_MOTU_SPEC_TX_MIDI_3RD_Q |
299 		 SND_MOTU_SPEC_REGISTER_DSP,
300 	.tx_fixed_pcm_chunks = {10, 10, 0},
301 	.rx_fixed_pcm_chunks = {10, 10, 0},
302 };
303 
304 const struct snd_motu_spec snd_motu_spec_4pre = {
305 	.name = "4pre",
306 	.protocol_version = SND_MOTU_PROTOCOL_V3,
307 	.flags = SND_MOTU_SPEC_REGISTER_DSP,
308 	.tx_fixed_pcm_chunks = {10, 10, 0},
309 	.rx_fixed_pcm_chunks = {10, 10, 0},
310 };
311