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