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