1
2
3
4
5
6
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
28static 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, ®,
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
48static 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, ®,
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, ®,
78 sizeof(reg));
79}
80
81static 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, ®,
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
98 err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, ®,
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
129static 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 ®, 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 ®, sizeof(reg));
153 }
154
155 return err;
156}
157
158static 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
188
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
200
201
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
211static 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
219
220
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
230 formats->differed_part_pcm_chunks[0] = pcm_chunks[0];
231 formats->differed_part_pcm_chunks[1] = pcm_chunks[1];
232}
233
234static 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, ®,
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
262const 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