323 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * bebob_focusrite.c - a part of driver for BeBoB based devices4 *5 * Copyright (c) 2013-2014 Takashi Sakamoto6 */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 0x000100000000ULL17 18#define SAFFIRE_OFFSET_CLOCK_SOURCE 0x00f819#define SAFFIREPRO_OFFSET_CLOCK_SOURCE 0x017420 21/* whether sync to external device or not */22#define SAFFIRE_OFFSET_CLOCK_SYNC_EXT 0x013c23#define SAFFIRE_LE_OFFSET_CLOCK_SYNC_EXT 0x043224#define SAFFIREPRO_OFFSET_CLOCK_SYNC_EXT 0x016425 26#define SAFFIRE_CLOCK_SOURCE_INTERNAL 027#define SAFFIRE_CLOCK_SOURCE_SPDIF 128 29/* clock sources as returned from register of Saffire Pro 10 and 26 */30#define SAFFIREPRO_CLOCK_SOURCE_SELECT_MASK 0x000000ff31#define SAFFIREPRO_CLOCK_SOURCE_DETECT_MASK 0x0000ff0032#define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 033#define SAFFIREPRO_CLOCK_SOURCE_SKIP 1 /* never used on hardware */34#define SAFFIREPRO_CLOCK_SOURCE_SPDIF 235#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 538#define SAFFIREPRO_CLOCK_SOURCE_COUNT 639 40/* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */41#define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a442 43/* saffirepro has its own parameter for sampling frequency */44#define SAFFIREPRO_RATE_NOREBOOT 0x01cc45/* index is the value for this register */46static const unsigned int rates[] = {47 [0] = 0,48 [1] = 44100,49 [2] = 48000,50 [3] = 88200,51 [4] = 96000,52 [5] = 176400,53 [6] = 19200054};55 56/* saffire(no label)/saffire LE has metering */57#define SAFFIRE_OFFSET_METER 0x010058#define SAFFIRE_LE_OFFSET_METER 0x016859 60static inline int61saffire_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(bebob->unit, TCODE_READ_BLOCK_REQUEST,69 SAFFIRE_ADDRESS_BASE + offset,70 tmp, size, 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]);76end:77 return err;78}79 80static inline int81saffire_read_quad(struct snd_bebob *bebob, u64 offset, u32 *value)82{83 int err;84 __be32 tmp;85 86 err = snd_fw_transaction(bebob->unit, TCODE_READ_QUADLET_REQUEST,87 SAFFIRE_ADDRESS_BASE + offset,88 &tmp, sizeof(__be32), 0);89 if (err < 0)90 goto end;91 92 *value = be32_to_cpu(tmp);93end:94 return err;95}96 97static inline int98saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value)99{100 __be32 data = cpu_to_be32(value);101 102 return snd_fw_transaction(bebob->unit, TCODE_WRITE_QUADLET_REQUEST,103 SAFFIRE_ADDRESS_BASE + offset,104 &data, sizeof(__be32), 0);105}106 107static 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};112static 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. */120static 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 141static int142saffirepro_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, &id);148 if (err < 0)149 goto end;150 if (id >= ARRAY_SIZE(rates))151 err = -EIO;152 else153 *rate = rates[id];154end:155 return err;156}157static int158saffirepro_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, id);170}171 172/*173 * query hardware for current clock source, return our internally174 * used clock index in *id, depending on hardware.175 */176static int177saffirepro_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);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 else191 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];201end:202 return err;203}204 205const struct snd_bebob_spec saffire_le_spec;206static const enum snd_bebob_clock_type saffire_both_clk_src_types[] = {207 SND_BEBOB_CLOCK_TYPE_INTERNAL,208 SND_BEBOB_CLOCK_TYPE_EXTERNAL,209};210static int211saffire_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);217 if (err >= 0)218 *id = 0xff & value;219 220 return err;221};222static 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_IN226};227static const char *const saffire_meter_labels[] = {228 ANA_IN, ANA_IN,229 STM_IN, STM_IN, STM_IN, STM_IN, STM_IN,230};231static int232saffire_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 else242 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 265static 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 */270static 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};275const struct snd_bebob_spec saffirepro_26_spec = {276 .clock = &saffirepro_26_clk_spec,277 .rate = &saffirepro_both_rate_spec,278 .meter = NULL279};280/* Saffire Pro 10 I/O */281static 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};286const struct snd_bebob_spec saffirepro_10_spec = {287 .clock = &saffirepro_10_clk_spec,288 .rate = &saffirepro_both_rate_spec,289 .meter = NULL290};291 292static 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};296static 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 */302static 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};307const struct snd_bebob_spec saffire_le_spec = {308 .clock = &saffire_both_clk_spec,309 .rate = &saffire_both_rate_spec,310 .meter = &saffire_le_meter_spec311};312/* Saffire */313static 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};318const struct snd_bebob_spec saffire_spec = {319 .clock = &saffire_both_clk_spec,320 .rate = &saffire_both_rate_spec,321 .meter = &saffire_meter_spec322};323