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 | ||
30 | /* '1' is absent, why... */ | |
31 | #define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0 | |
32 | #define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2 | |
33 | #define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 | |
34 | #define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 | |
35 | #define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5 | |
36 | ||
37 | /* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */ | |
9b5f0edf | 38 | #define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a4 |
25784ec2 TS |
39 | |
40 | /* saffirepro has its own parameter for sampling frequency */ | |
9b5f0edf | 41 | #define SAFFIREPRO_RATE_NOREBOOT 0x01cc |
25784ec2 TS |
42 | /* index is the value for this register */ |
43 | static const unsigned int rates[] = { | |
44 | [0] = 0, | |
45 | [1] = 44100, | |
46 | [2] = 48000, | |
47 | [3] = 88200, | |
48 | [4] = 96000, | |
49 | [5] = 176400, | |
50 | [6] = 192000 | |
51 | }; | |
52 | ||
53 | /* saffire(no label)/saffire LE has metering */ | |
9b5f0edf TS |
54 | #define SAFFIRE_OFFSET_METER 0x0100 |
55 | #define SAFFIRE_LE_OFFSET_METER 0x0168 | |
25784ec2 TS |
56 | |
57 | static inline int | |
58 | saffire_read_block(struct snd_bebob *bebob, u64 offset, | |
59 | u32 *buf, unsigned int size) | |
60 | { | |
61 | unsigned int i; | |
62 | int err; | |
63 | __be32 *tmp = (__be32 *)buf; | |
64 | ||
65 | err = snd_fw_transaction(bebob->unit, TCODE_READ_BLOCK_REQUEST, | |
66 | SAFFIRE_ADDRESS_BASE + offset, | |
67 | tmp, size, 0); | |
68 | if (err < 0) | |
69 | goto end; | |
70 | ||
71 | for (i = 0; i < size / sizeof(u32); i++) | |
72 | buf[i] = be32_to_cpu(tmp[i]); | |
73 | end: | |
74 | return err; | |
75 | } | |
76 | ||
77 | static inline int | |
78 | saffire_read_quad(struct snd_bebob *bebob, u64 offset, u32 *value) | |
79 | { | |
80 | int err; | |
81 | __be32 tmp; | |
82 | ||
83 | err = snd_fw_transaction(bebob->unit, TCODE_READ_QUADLET_REQUEST, | |
84 | SAFFIRE_ADDRESS_BASE + offset, | |
85 | &tmp, sizeof(__be32), 0); | |
86 | if (err < 0) | |
87 | goto end; | |
88 | ||
89 | *value = be32_to_cpu(tmp); | |
90 | end: | |
91 | return err; | |
92 | } | |
93 | ||
94 | static inline int | |
95 | saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value) | |
96 | { | |
97 | __be32 data = cpu_to_be32(value); | |
98 | ||
99 | return snd_fw_transaction(bebob->unit, TCODE_WRITE_QUADLET_REQUEST, | |
100 | SAFFIRE_ADDRESS_BASE + offset, | |
101 | &data, sizeof(__be32), 0); | |
102 | } | |
103 | ||
104 | static char *const saffirepro_26_clk_src_labels[] = { | |
105 | SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock" | |
106 | }; | |
107 | ||
108 | static char *const saffirepro_10_clk_src_labels[] = { | |
109 | SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock" | |
110 | }; | |
111 | static int | |
112 | saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate) | |
113 | { | |
114 | u32 id; | |
115 | int err; | |
116 | ||
117 | err = saffire_read_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, &id); | |
118 | if (err < 0) | |
119 | goto end; | |
120 | if (id >= ARRAY_SIZE(rates)) | |
121 | err = -EIO; | |
122 | else | |
123 | *rate = rates[id]; | |
124 | end: | |
125 | return err; | |
126 | } | |
127 | static int | |
128 | saffirepro_both_clk_freq_set(struct snd_bebob *bebob, unsigned int rate) | |
129 | { | |
130 | u32 id; | |
131 | ||
132 | for (id = 0; id < ARRAY_SIZE(rates); id++) { | |
133 | if (rates[id] == rate) | |
134 | break; | |
135 | } | |
136 | if (id == ARRAY_SIZE(rates)) | |
137 | return -EINVAL; | |
138 | ||
139 | return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id); | |
140 | } | |
141 | static int | |
142 | saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) | |
143 | { | |
144 | int err; | |
145 | u32 value; | |
146 | ||
147 | err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value); | |
148 | if (err < 0) | |
149 | goto end; | |
150 | ||
151 | if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels) { | |
152 | if (value == SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK) | |
153 | *id = 2; | |
154 | else if (value == SAFFIREPRO_CLOCK_SOURCE_SPDIF) | |
155 | *id = 1; | |
156 | } else if (value > 1) { | |
157 | *id = value - 1; | |
158 | } | |
159 | end: | |
160 | return err; | |
161 | } | |
162 | ||
163 | struct snd_bebob_spec saffire_le_spec; | |
164 | static char *const saffire_both_clk_src_labels[] = { | |
165 | SND_BEBOB_CLOCK_INTERNAL, "S/PDIF" | |
166 | }; | |
167 | static int | |
168 | saffire_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) | |
169 | { | |
170 | int err; | |
171 | u32 value; | |
172 | ||
173 | err = saffire_read_quad(bebob, SAFFIRE_OFFSET_CLOCK_SOURCE, &value); | |
174 | if (err >= 0) | |
175 | *id = 0xff & value; | |
176 | ||
177 | return err; | |
178 | }; | |
179 | static char *const saffire_le_meter_labels[] = { | |
180 | ANA_IN, ANA_IN, DIG_IN, | |
181 | ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, | |
182 | STM_IN, STM_IN | |
183 | }; | |
184 | static char *const saffire_meter_labels[] = { | |
185 | ANA_IN, ANA_IN, | |
186 | STM_IN, STM_IN, STM_IN, STM_IN, STM_IN, | |
187 | }; | |
188 | static int | |
189 | saffire_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size) | |
190 | { | |
191 | struct snd_bebob_meter_spec *spec = bebob->spec->meter; | |
192 | unsigned int channels; | |
193 | u64 offset; | |
194 | int err; | |
195 | ||
196 | if (spec->labels == saffire_le_meter_labels) | |
197 | offset = SAFFIRE_LE_OFFSET_METER; | |
198 | else | |
199 | offset = SAFFIRE_OFFSET_METER; | |
200 | ||
201 | channels = spec->num * 2; | |
202 | if (size < channels * sizeof(u32)) | |
203 | return -EIO; | |
204 | ||
205 | err = saffire_read_block(bebob, offset, buf, size); | |
206 | if (err >= 0 && spec->labels == saffire_le_meter_labels) { | |
207 | swap(buf[1], buf[3]); | |
208 | swap(buf[2], buf[3]); | |
209 | swap(buf[3], buf[4]); | |
210 | ||
211 | swap(buf[7], buf[10]); | |
212 | swap(buf[8], buf[10]); | |
213 | swap(buf[9], buf[11]); | |
214 | swap(buf[11], buf[12]); | |
215 | ||
216 | swap(buf[15], buf[16]); | |
217 | } | |
218 | ||
219 | return err; | |
220 | } | |
221 | ||
222 | static struct snd_bebob_rate_spec saffirepro_both_rate_spec = { | |
223 | .get = &saffirepro_both_clk_freq_get, | |
224 | .set = &saffirepro_both_clk_freq_set, | |
225 | }; | |
226 | /* Saffire Pro 26 I/O */ | |
227 | static struct snd_bebob_clock_spec saffirepro_26_clk_spec = { | |
228 | .num = ARRAY_SIZE(saffirepro_26_clk_src_labels), | |
229 | .labels = saffirepro_26_clk_src_labels, | |
230 | .get = &saffirepro_both_clk_src_get, | |
231 | }; | |
232 | struct snd_bebob_spec saffirepro_26_spec = { | |
233 | .clock = &saffirepro_26_clk_spec, | |
234 | .rate = &saffirepro_both_rate_spec, | |
235 | .meter = NULL | |
236 | }; | |
237 | /* Saffire Pro 10 I/O */ | |
238 | static struct snd_bebob_clock_spec saffirepro_10_clk_spec = { | |
239 | .num = ARRAY_SIZE(saffirepro_10_clk_src_labels), | |
240 | .labels = saffirepro_10_clk_src_labels, | |
241 | .get = &saffirepro_both_clk_src_get, | |
242 | }; | |
243 | struct snd_bebob_spec saffirepro_10_spec = { | |
244 | .clock = &saffirepro_10_clk_spec, | |
245 | .rate = &saffirepro_both_rate_spec, | |
246 | .meter = NULL | |
247 | }; | |
248 | ||
249 | static struct snd_bebob_rate_spec saffire_both_rate_spec = { | |
250 | .get = &snd_bebob_stream_get_rate, | |
251 | .set = &snd_bebob_stream_set_rate, | |
252 | }; | |
253 | static struct snd_bebob_clock_spec saffire_both_clk_spec = { | |
254 | .num = ARRAY_SIZE(saffire_both_clk_src_labels), | |
255 | .labels = saffire_both_clk_src_labels, | |
256 | .get = &saffire_both_clk_src_get, | |
257 | }; | |
258 | /* Saffire LE */ | |
9fb01cdb | 259 | static struct snd_bebob_meter_spec saffire_le_meter_spec = { |
25784ec2 TS |
260 | .num = ARRAY_SIZE(saffire_le_meter_labels), |
261 | .labels = saffire_le_meter_labels, | |
262 | .get = &saffire_meter_get, | |
263 | }; | |
264 | struct snd_bebob_spec saffire_le_spec = { | |
265 | .clock = &saffire_both_clk_spec, | |
266 | .rate = &saffire_both_rate_spec, | |
267 | .meter = &saffire_le_meter_spec | |
268 | }; | |
269 | /* Saffire */ | |
9fb01cdb | 270 | static struct snd_bebob_meter_spec saffire_meter_spec = { |
25784ec2 TS |
271 | .num = ARRAY_SIZE(saffire_meter_labels), |
272 | .labels = saffire_meter_labels, | |
273 | .get = &saffire_meter_get, | |
274 | }; | |
275 | struct snd_bebob_spec saffire_spec = { | |
276 | .clock = &saffire_both_clk_spec, | |
277 | .rate = &saffire_both_rate_spec, | |
278 | .meter = &saffire_meter_spec | |
279 | }; |