1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * bebob_focusrite.c - a part of driver for BeBoB based devices |
4 | * |
5 | * Copyright (c) 2013-2014 Takashi Sakamoto |
6 | */ |
7 | |
8 | #include "./bebob.h" |
9 | |
10 | #define ANA_IN "Analog In" |
11 | #define DIG_IN "Digital In" |
12 | #define ANA_OUT "Analog Out" |
13 | #define DIG_OUT "Digital Out" |
14 | #define STM_IN "Stream In" |
15 | |
16 | #define SAFFIRE_ADDRESS_BASE 0x000100000000ULL |
17 | |
18 | #define SAFFIRE_OFFSET_CLOCK_SOURCE 0x00f8 |
19 | #define SAFFIREPRO_OFFSET_CLOCK_SOURCE 0x0174 |
20 | |
21 | /* whether sync to external device or not */ |
22 | #define SAFFIRE_OFFSET_CLOCK_SYNC_EXT 0x013c |
23 | #define SAFFIRE_LE_OFFSET_CLOCK_SYNC_EXT 0x0432 |
24 | #define SAFFIREPRO_OFFSET_CLOCK_SYNC_EXT 0x0164 |
25 | |
26 | #define SAFFIRE_CLOCK_SOURCE_INTERNAL 0 |
27 | #define SAFFIRE_CLOCK_SOURCE_SPDIF 1 |
28 | |
29 | /* clock sources as returned from register of Saffire Pro 10 and 26 */ |
30 | #define SAFFIREPRO_CLOCK_SOURCE_SELECT_MASK 0x000000ff |
31 | #define SAFFIREPRO_CLOCK_SOURCE_DETECT_MASK 0x0000ff00 |
32 | #define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0 |
33 | #define SAFFIREPRO_CLOCK_SOURCE_SKIP 1 /* never used on hardware */ |
34 | #define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2 |
35 | #define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 /* not used on s.pro. 10 */ |
36 | #define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 /* not used on s.pro. 10 */ |
37 | #define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5 |
38 | #define SAFFIREPRO_CLOCK_SOURCE_COUNT 6 |
39 | |
40 | /* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */ |
41 | #define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a4 |
42 | |
43 | /* saffirepro has its own parameter for sampling frequency */ |
44 | #define SAFFIREPRO_RATE_NOREBOOT 0x01cc |
45 | /* index is the value for this register */ |
46 | static const unsigned int rates[] = { |
47 | [0] = 0, |
48 | [1] = 44100, |
49 | [2] = 48000, |
50 | [3] = 88200, |
51 | [4] = 96000, |
52 | [5] = 176400, |
53 | [6] = 192000 |
54 | }; |
55 | |
56 | /* saffire(no label)/saffire LE has metering */ |
57 | #define SAFFIRE_OFFSET_METER 0x0100 |
58 | #define SAFFIRE_LE_OFFSET_METER 0x0168 |
59 | |
60 | static inline int |
61 | saffire_read_block(struct snd_bebob *bebob, u64 offset, |
62 | u32 *buf, unsigned int size) |
63 | { |
64 | unsigned int i; |
65 | int err; |
66 | __be32 *tmp = (__be32 *)buf; |
67 | |
68 | err = snd_fw_transaction(unit: bebob->unit, TCODE_READ_BLOCK_REQUEST, |
69 | SAFFIRE_ADDRESS_BASE + offset, |
70 | buffer: tmp, length: size, flags: 0); |
71 | if (err < 0) |
72 | goto end; |
73 | |
74 | for (i = 0; i < size / sizeof(u32); i++) |
75 | buf[i] = be32_to_cpu(tmp[i]); |
76 | end: |
77 | return err; |
78 | } |
79 | |
80 | static inline int |
81 | saffire_read_quad(struct snd_bebob *bebob, u64 offset, u32 *value) |
82 | { |
83 | int err; |
84 | __be32 tmp; |
85 | |
86 | err = snd_fw_transaction(unit: bebob->unit, TCODE_READ_QUADLET_REQUEST, |
87 | SAFFIRE_ADDRESS_BASE + offset, |
88 | buffer: &tmp, length: sizeof(__be32), flags: 0); |
89 | if (err < 0) |
90 | goto end; |
91 | |
92 | *value = be32_to_cpu(tmp); |
93 | end: |
94 | return err; |
95 | } |
96 | |
97 | static inline int |
98 | saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value) |
99 | { |
100 | __be32 data = cpu_to_be32(value); |
101 | |
102 | return snd_fw_transaction(unit: bebob->unit, TCODE_WRITE_QUADLET_REQUEST, |
103 | SAFFIRE_ADDRESS_BASE + offset, |
104 | buffer: &data, length: sizeof(__be32), flags: 0); |
105 | } |
106 | |
107 | static const enum snd_bebob_clock_type saffirepro_10_clk_src_types[] = { |
108 | SND_BEBOB_CLOCK_TYPE_INTERNAL, |
109 | SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* S/PDIF */ |
110 | SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* Word Clock */ |
111 | }; |
112 | static const enum snd_bebob_clock_type saffirepro_26_clk_src_types[] = { |
113 | SND_BEBOB_CLOCK_TYPE_INTERNAL, |
114 | SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* S/PDIF */ |
115 | SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* ADAT1 */ |
116 | SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* ADAT2 */ |
117 | SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* Word Clock */ |
118 | }; |
119 | /* Value maps between registers and labels for SaffirePro 10/26. */ |
120 | static const signed char saffirepro_clk_maps[][SAFFIREPRO_CLOCK_SOURCE_COUNT] = { |
121 | /* SaffirePro 10 */ |
122 | [0] = { |
123 | [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0, |
124 | [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */ |
125 | [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1, |
126 | [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = -1, /* not supported */ |
127 | [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = -1, /* not supported */ |
128 | [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 2, |
129 | }, |
130 | /* SaffirePro 26 */ |
131 | [1] = { |
132 | [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0, |
133 | [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */ |
134 | [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1, |
135 | [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = 2, |
136 | [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = 3, |
137 | [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 4, |
138 | } |
139 | }; |
140 | |
141 | static int |
142 | saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate) |
143 | { |
144 | u32 id; |
145 | int err; |
146 | |
147 | err = saffire_read_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, value: &id); |
148 | if (err < 0) |
149 | goto end; |
150 | if (id >= ARRAY_SIZE(rates)) |
151 | err = -EIO; |
152 | else |
153 | *rate = rates[id]; |
154 | end: |
155 | return err; |
156 | } |
157 | static int |
158 | saffirepro_both_clk_freq_set(struct snd_bebob *bebob, unsigned int rate) |
159 | { |
160 | u32 id; |
161 | |
162 | for (id = 0; id < ARRAY_SIZE(rates); id++) { |
163 | if (rates[id] == rate) |
164 | break; |
165 | } |
166 | if (id == ARRAY_SIZE(rates)) |
167 | return -EINVAL; |
168 | |
169 | return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, value: id); |
170 | } |
171 | |
172 | /* |
173 | * query hardware for current clock source, return our internally |
174 | * used clock index in *id, depending on hardware. |
175 | */ |
176 | static int |
177 | saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) |
178 | { |
179 | int err; |
180 | u32 value; /* clock source read from hw register */ |
181 | const signed char *map; |
182 | |
183 | err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, value: &value); |
184 | if (err < 0) |
185 | goto end; |
186 | |
187 | /* depending on hardware, use a different mapping */ |
188 | if (bebob->spec->clock->types == saffirepro_10_clk_src_types) |
189 | map = saffirepro_clk_maps[0]; |
190 | else |
191 | map = saffirepro_clk_maps[1]; |
192 | |
193 | /* In a case that this driver cannot handle the value of register. */ |
194 | value &= SAFFIREPRO_CLOCK_SOURCE_SELECT_MASK; |
195 | if (value >= SAFFIREPRO_CLOCK_SOURCE_COUNT || map[value] < 0) { |
196 | err = -EIO; |
197 | goto end; |
198 | } |
199 | |
200 | *id = (unsigned int)map[value]; |
201 | end: |
202 | return err; |
203 | } |
204 | |
205 | const struct snd_bebob_spec saffire_le_spec; |
206 | static const enum snd_bebob_clock_type saffire_both_clk_src_types[] = { |
207 | SND_BEBOB_CLOCK_TYPE_INTERNAL, |
208 | SND_BEBOB_CLOCK_TYPE_EXTERNAL, |
209 | }; |
210 | static int |
211 | saffire_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) |
212 | { |
213 | int err; |
214 | u32 value; |
215 | |
216 | err = saffire_read_quad(bebob, SAFFIRE_OFFSET_CLOCK_SOURCE, value: &value); |
217 | if (err >= 0) |
218 | *id = 0xff & value; |
219 | |
220 | return err; |
221 | }; |
222 | static const char *const saffire_le_meter_labels[] = { |
223 | ANA_IN, ANA_IN, DIG_IN, |
224 | ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, |
225 | STM_IN, STM_IN |
226 | }; |
227 | static const char *const saffire_meter_labels[] = { |
228 | ANA_IN, ANA_IN, |
229 | STM_IN, STM_IN, STM_IN, STM_IN, STM_IN, |
230 | }; |
231 | static int |
232 | saffire_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size) |
233 | { |
234 | const struct snd_bebob_meter_spec *spec = bebob->spec->meter; |
235 | unsigned int channels; |
236 | u64 offset; |
237 | int err; |
238 | |
239 | if (spec->labels == saffire_le_meter_labels) |
240 | offset = SAFFIRE_LE_OFFSET_METER; |
241 | else |
242 | offset = SAFFIRE_OFFSET_METER; |
243 | |
244 | channels = spec->num * 2; |
245 | if (size < channels * sizeof(u32)) |
246 | return -EIO; |
247 | |
248 | err = saffire_read_block(bebob, offset, buf, size); |
249 | if (err >= 0 && spec->labels == saffire_le_meter_labels) { |
250 | swap(buf[1], buf[3]); |
251 | swap(buf[2], buf[3]); |
252 | swap(buf[3], buf[4]); |
253 | |
254 | swap(buf[7], buf[10]); |
255 | swap(buf[8], buf[10]); |
256 | swap(buf[9], buf[11]); |
257 | swap(buf[11], buf[12]); |
258 | |
259 | swap(buf[15], buf[16]); |
260 | } |
261 | |
262 | return err; |
263 | } |
264 | |
265 | static const struct snd_bebob_rate_spec saffirepro_both_rate_spec = { |
266 | .get = &saffirepro_both_clk_freq_get, |
267 | .set = &saffirepro_both_clk_freq_set, |
268 | }; |
269 | /* Saffire Pro 26 I/O */ |
270 | static const struct snd_bebob_clock_spec saffirepro_26_clk_spec = { |
271 | .num = ARRAY_SIZE(saffirepro_26_clk_src_types), |
272 | .types = saffirepro_26_clk_src_types, |
273 | .get = &saffirepro_both_clk_src_get, |
274 | }; |
275 | const struct snd_bebob_spec saffirepro_26_spec = { |
276 | .clock = &saffirepro_26_clk_spec, |
277 | .rate = &saffirepro_both_rate_spec, |
278 | .meter = NULL |
279 | }; |
280 | /* Saffire Pro 10 I/O */ |
281 | static const struct snd_bebob_clock_spec saffirepro_10_clk_spec = { |
282 | .num = ARRAY_SIZE(saffirepro_10_clk_src_types), |
283 | .types = saffirepro_10_clk_src_types, |
284 | .get = &saffirepro_both_clk_src_get, |
285 | }; |
286 | const struct snd_bebob_spec saffirepro_10_spec = { |
287 | .clock = &saffirepro_10_clk_spec, |
288 | .rate = &saffirepro_both_rate_spec, |
289 | .meter = NULL |
290 | }; |
291 | |
292 | static const struct snd_bebob_rate_spec saffire_both_rate_spec = { |
293 | .get = &snd_bebob_stream_get_rate, |
294 | .set = &snd_bebob_stream_set_rate, |
295 | }; |
296 | static const struct snd_bebob_clock_spec saffire_both_clk_spec = { |
297 | .num = ARRAY_SIZE(saffire_both_clk_src_types), |
298 | .types = saffire_both_clk_src_types, |
299 | .get = &saffire_both_clk_src_get, |
300 | }; |
301 | /* Saffire LE */ |
302 | static const struct snd_bebob_meter_spec saffire_le_meter_spec = { |
303 | .num = ARRAY_SIZE(saffire_le_meter_labels), |
304 | .labels = saffire_le_meter_labels, |
305 | .get = &saffire_meter_get, |
306 | }; |
307 | const struct snd_bebob_spec saffire_le_spec = { |
308 | .clock = &saffire_both_clk_spec, |
309 | .rate = &saffire_both_rate_spec, |
310 | .meter = &saffire_le_meter_spec |
311 | }; |
312 | /* Saffire */ |
313 | static const struct snd_bebob_meter_spec saffire_meter_spec = { |
314 | .num = ARRAY_SIZE(saffire_meter_labels), |
315 | .labels = saffire_meter_labels, |
316 | .get = &saffire_meter_get, |
317 | }; |
318 | const struct snd_bebob_spec saffire_spec = { |
319 | .clock = &saffire_both_clk_spec, |
320 | .rate = &saffire_both_rate_spec, |
321 | .meter = &saffire_meter_spec |
322 | }; |
323 | |