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
34static 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
45int 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
59int 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
88static 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
145int 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.
160static 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.
169static 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
190int 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
227int 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
274const 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
284const 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
292const 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
302const 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
312const 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};
322