1 /*
2  * motu-protocol-v2.c - a part of driver for MOTU FireWire series
3  *
4  * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
5  *
6  * Licensed under the terms of the GNU General Public License, version 2.
7  */
8 
9 #include "motu.h"
10 
11 #define V2_CLOCK_STATUS_OFFSET			0x0b14
12 #define  V2_CLOCK_RATE_MASK			0x00000038
13 #define  V2_CLOCK_RATE_SHIFT			3
14 #define  V2_CLOCK_SRC_MASK			0x00000007
15 #define  V2_CLOCK_SRC_SHIFT			0
16 #define  V2_CLOCK_TRAVELER_FETCH_DISABLE	0x04000000
17 #define  V2_CLOCK_TRAVELER_FETCH_ENABLE		0x03000000
18 
19 #define V2_IN_OUT_CONF_OFFSET			0x0c04
20 #define  V2_OPT_OUT_IFACE_MASK			0x00000c00
21 #define  V2_OPT_OUT_IFACE_SHIFT			10
22 #define  V2_OPT_IN_IFACE_MASK			0x00000300
23 #define  V2_OPT_IN_IFACE_SHIFT			8
24 #define  V2_OPT_IFACE_MODE_NONE			0
25 #define  V2_OPT_IFACE_MODE_ADAT			1
26 #define  V2_OPT_IFACE_MODE_SPDIF		2
27 
28 static int v2_get_clock_rate(struct snd_motu *motu, unsigned int *rate)
29 {
30 	__be32 reg;
31 	unsigned int index;
32 	int err;
33 
34 	err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
35 					sizeof(reg));
36 	if (err < 0)
37 		return err;
38 
39 	index = (be32_to_cpu(reg) & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT;
40 	if (index >= ARRAY_SIZE(snd_motu_clock_rates))
41 		return -EIO;
42 
43 	*rate = snd_motu_clock_rates[index];
44 
45 	return 0;
46 }
47 
48 static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate)
49 {
50 	__be32 reg;
51 	u32 data;
52 	int i;
53 	int err;
54 
55 	for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
56 		if (snd_motu_clock_rates[i] == rate)
57 			break;
58 	}
59 	if (i == ARRAY_SIZE(snd_motu_clock_rates))
60 		return -EINVAL;
61 
62 	err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
63 					sizeof(reg));
64 	if (err < 0)
65 		return err;
66 	data = be32_to_cpu(reg);
67 
68 	data &= ~V2_CLOCK_RATE_MASK;
69 	data |= i << V2_CLOCK_RATE_SHIFT;
70 
71 	if (motu->spec == &snd_motu_spec_traveler) {
72 		data &= ~V2_CLOCK_TRAVELER_FETCH_ENABLE;
73 		data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
74 	}
75 
76 	reg = cpu_to_be32(data);
77 	return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, &reg,
78 					  sizeof(reg));
79 }
80 
81 static int v2_get_clock_source(struct snd_motu *motu,
82 			       enum snd_motu_clock_source *src)
83 {
84 	__be32 reg;
85 	unsigned int index;
86 	int err;
87 
88 	err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
89 					sizeof(reg));
90 	if (err < 0)
91 		return err;
92 
93 	index = be32_to_cpu(reg) & V2_CLOCK_SRC_MASK;
94 	if (index > 5)
95 		return -EIO;
96 
97 	/* To check the configuration of optical interface. */
98 	err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
99 					sizeof(reg));
100 	if (err < 0)
101 		return err;
102 
103 	switch (index) {
104 	case 0:
105 		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
106 		break;
107 	case 1:
108 		if (be32_to_cpu(reg) & 0x00000200)
109 			*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
110 		else
111 			*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
112 		break;
113 	case 2:
114 		*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
115 		break;
116 	case 4:
117 		*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
118 		break;
119 	case 5:
120 		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
121 		break;
122 	default:
123 		return -EIO;
124 	}
125 
126 	return 0;
127 }
128 
129 static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable)
130 {
131 	__be32 reg;
132 	u32 data;
133 	int err = 0;
134 
135 	if (motu->spec == &snd_motu_spec_traveler) {
136 		err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,
137 						&reg, sizeof(reg));
138 		if (err < 0)
139 			return err;
140 		data = be32_to_cpu(reg);
141 
142 		data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE |
143 			  V2_CLOCK_TRAVELER_FETCH_ENABLE);
144 
145 		if (enable)
146 			data |= V2_CLOCK_TRAVELER_FETCH_ENABLE;
147 		else
148 			data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
149 
150 		reg = cpu_to_be32(data);
151 		err = snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,
152 						 &reg, sizeof(reg));
153 	}
154 
155 	return err;
156 }
157 
158 static void calculate_fixed_part(struct snd_motu_packet_format *formats,
159 				 enum amdtp_stream_direction dir,
160 				 enum snd_motu_spec_flags flags,
161 				 unsigned char analog_ports)
162 {
163 	unsigned char pcm_chunks[3] = {0, 0, 0};
164 
165 	formats->msg_chunks = 2;
166 
167 	pcm_chunks[0] = analog_ports;
168 	pcm_chunks[1] = analog_ports;
169 	if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4)
170 		pcm_chunks[2] = analog_ports;
171 
172 	if (dir == AMDTP_IN_STREAM) {
173 		if (flags & SND_MOTU_SPEC_TX_MICINST_CHUNK) {
174 			pcm_chunks[0] += 2;
175 			pcm_chunks[1] += 2;
176 		}
177 		if (flags & SND_MOTU_SPEC_TX_RETURN_CHUNK) {
178 			pcm_chunks[0] += 2;
179 			pcm_chunks[1] += 2;
180 		}
181 	} else {
182 		if (flags & SND_MOTU_SPEC_RX_SEPARETED_MAIN) {
183 			pcm_chunks[0] += 2;
184 			pcm_chunks[1] += 2;
185 		}
186 
187 		// Packets to v2 units include 2 chunks for phone 1/2, except
188 		// for 176.4/192.0 kHz.
189 		pcm_chunks[0] += 2;
190 		pcm_chunks[1] += 2;
191 	}
192 
193 	if (flags & SND_MOTU_SPEC_HAS_AESEBU_IFACE) {
194 		pcm_chunks[0] += 2;
195 		pcm_chunks[1] += 2;
196 	}
197 
198 	/*
199 	 * All of v2 models have a pair of coaxial interfaces for digital in/out
200 	 * port. At 44.1/48.0/88.2/96.0 kHz, packets includes PCM from these
201 	 * ports.
202 	 */
203 	pcm_chunks[0] += 2;
204 	pcm_chunks[1] += 2;
205 
206 	formats->fixed_part_pcm_chunks[0] = pcm_chunks[0];
207 	formats->fixed_part_pcm_chunks[1] = pcm_chunks[1];
208 	formats->fixed_part_pcm_chunks[2] = pcm_chunks[2];
209 }
210 
211 static void calculate_differed_part(struct snd_motu_packet_format *formats,
212 				    enum snd_motu_spec_flags flags,
213 				    u32 data, u32 mask, u32 shift)
214 {
215 	unsigned char pcm_chunks[2] = {0, 0};
216 
217 	/*
218 	 * When optical interfaces are configured for S/PDIF (TOSLINK),
219 	 * the above PCM frames come from them, instead of coaxial
220 	 * interfaces.
221 	 */
222 	data = (data & mask) >> shift;
223 	if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) &&
224 	    data == V2_OPT_IFACE_MODE_ADAT) {
225 		pcm_chunks[0] += 8;
226 		pcm_chunks[1] += 4;
227 	}
228 
229 	/* At mode x4, no data chunks are supported in this part. */
230 	formats->differed_part_pcm_chunks[0] = pcm_chunks[0];
231 	formats->differed_part_pcm_chunks[1] = pcm_chunks[1];
232 }
233 
234 static int v2_cache_packet_formats(struct snd_motu *motu)
235 {
236 	__be32 reg;
237 	u32 data;
238 	int err;
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 	calculate_fixed_part(&motu->tx_packet_formats, AMDTP_IN_STREAM,
247 			     motu->spec->flags, motu->spec->analog_in_ports);
248 	calculate_differed_part(&motu->tx_packet_formats, motu->spec->flags,
249 			data, V2_OPT_IN_IFACE_MASK, V2_OPT_IN_IFACE_SHIFT);
250 
251 	calculate_fixed_part(&motu->rx_packet_formats, AMDTP_OUT_STREAM,
252 			     motu->spec->flags, motu->spec->analog_out_ports);
253 	calculate_differed_part(&motu->rx_packet_formats, motu->spec->flags,
254 			data, V2_OPT_OUT_IFACE_MASK, V2_OPT_OUT_IFACE_SHIFT);
255 
256 	motu->tx_packet_formats.pcm_byte_offset = 10;
257 	motu->rx_packet_formats.pcm_byte_offset = 10;
258 
259 	return 0;
260 }
261 
262 const struct snd_motu_protocol snd_motu_protocol_v2 = {
263 	.get_clock_rate		= v2_get_clock_rate,
264 	.set_clock_rate		= v2_set_clock_rate,
265 	.get_clock_source	= v2_get_clock_source,
266 	.switch_fetching_mode	= v2_switch_fetching_mode,
267 	.cache_packet_formats	= v2_cache_packet_formats,
268 };
269