162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * bebob_focusrite.c - a part of driver for BeBoB based devices 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2013-2014 Takashi Sakamoto 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "./bebob.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define ANA_IN "Analog In" 1162306a36Sopenharmony_ci#define DIG_IN "Digital In" 1262306a36Sopenharmony_ci#define ANA_OUT "Analog Out" 1362306a36Sopenharmony_ci#define DIG_OUT "Digital Out" 1462306a36Sopenharmony_ci#define STM_IN "Stream In" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define SAFFIRE_ADDRESS_BASE 0x000100000000ULL 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define SAFFIRE_OFFSET_CLOCK_SOURCE 0x00f8 1962306a36Sopenharmony_ci#define SAFFIREPRO_OFFSET_CLOCK_SOURCE 0x0174 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* whether sync to external device or not */ 2262306a36Sopenharmony_ci#define SAFFIRE_OFFSET_CLOCK_SYNC_EXT 0x013c 2362306a36Sopenharmony_ci#define SAFFIRE_LE_OFFSET_CLOCK_SYNC_EXT 0x0432 2462306a36Sopenharmony_ci#define SAFFIREPRO_OFFSET_CLOCK_SYNC_EXT 0x0164 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define SAFFIRE_CLOCK_SOURCE_INTERNAL 0 2762306a36Sopenharmony_ci#define SAFFIRE_CLOCK_SOURCE_SPDIF 1 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* clock sources as returned from register of Saffire Pro 10 and 26 */ 3062306a36Sopenharmony_ci#define SAFFIREPRO_CLOCK_SOURCE_SELECT_MASK 0x000000ff 3162306a36Sopenharmony_ci#define SAFFIREPRO_CLOCK_SOURCE_DETECT_MASK 0x0000ff00 3262306a36Sopenharmony_ci#define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0 3362306a36Sopenharmony_ci#define SAFFIREPRO_CLOCK_SOURCE_SKIP 1 /* never used on hardware */ 3462306a36Sopenharmony_ci#define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2 3562306a36Sopenharmony_ci#define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 /* not used on s.pro. 10 */ 3662306a36Sopenharmony_ci#define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 /* not used on s.pro. 10 */ 3762306a36Sopenharmony_ci#define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5 3862306a36Sopenharmony_ci#define SAFFIREPRO_CLOCK_SOURCE_COUNT 6 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */ 4162306a36Sopenharmony_ci#define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a4 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* saffirepro has its own parameter for sampling frequency */ 4462306a36Sopenharmony_ci#define SAFFIREPRO_RATE_NOREBOOT 0x01cc 4562306a36Sopenharmony_ci/* index is the value for this register */ 4662306a36Sopenharmony_cistatic const unsigned int rates[] = { 4762306a36Sopenharmony_ci [0] = 0, 4862306a36Sopenharmony_ci [1] = 44100, 4962306a36Sopenharmony_ci [2] = 48000, 5062306a36Sopenharmony_ci [3] = 88200, 5162306a36Sopenharmony_ci [4] = 96000, 5262306a36Sopenharmony_ci [5] = 176400, 5362306a36Sopenharmony_ci [6] = 192000 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* saffire(no label)/saffire LE has metering */ 5762306a36Sopenharmony_ci#define SAFFIRE_OFFSET_METER 0x0100 5862306a36Sopenharmony_ci#define SAFFIRE_LE_OFFSET_METER 0x0168 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic inline int 6162306a36Sopenharmony_cisaffire_read_block(struct snd_bebob *bebob, u64 offset, 6262306a36Sopenharmony_ci u32 *buf, unsigned int size) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci unsigned int i; 6562306a36Sopenharmony_ci int err; 6662306a36Sopenharmony_ci __be32 *tmp = (__be32 *)buf; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci err = snd_fw_transaction(bebob->unit, TCODE_READ_BLOCK_REQUEST, 6962306a36Sopenharmony_ci SAFFIRE_ADDRESS_BASE + offset, 7062306a36Sopenharmony_ci tmp, size, 0); 7162306a36Sopenharmony_ci if (err < 0) 7262306a36Sopenharmony_ci goto end; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci for (i = 0; i < size / sizeof(u32); i++) 7562306a36Sopenharmony_ci buf[i] = be32_to_cpu(tmp[i]); 7662306a36Sopenharmony_ciend: 7762306a36Sopenharmony_ci return err; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic inline int 8162306a36Sopenharmony_cisaffire_read_quad(struct snd_bebob *bebob, u64 offset, u32 *value) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci int err; 8462306a36Sopenharmony_ci __be32 tmp; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci err = snd_fw_transaction(bebob->unit, TCODE_READ_QUADLET_REQUEST, 8762306a36Sopenharmony_ci SAFFIRE_ADDRESS_BASE + offset, 8862306a36Sopenharmony_ci &tmp, sizeof(__be32), 0); 8962306a36Sopenharmony_ci if (err < 0) 9062306a36Sopenharmony_ci goto end; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci *value = be32_to_cpu(tmp); 9362306a36Sopenharmony_ciend: 9462306a36Sopenharmony_ci return err; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic inline int 9862306a36Sopenharmony_cisaffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci __be32 data = cpu_to_be32(value); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return snd_fw_transaction(bebob->unit, TCODE_WRITE_QUADLET_REQUEST, 10362306a36Sopenharmony_ci SAFFIRE_ADDRESS_BASE + offset, 10462306a36Sopenharmony_ci &data, sizeof(__be32), 0); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic const enum snd_bebob_clock_type saffirepro_10_clk_src_types[] = { 10862306a36Sopenharmony_ci SND_BEBOB_CLOCK_TYPE_INTERNAL, 10962306a36Sopenharmony_ci SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* S/PDIF */ 11062306a36Sopenharmony_ci SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* Word Clock */ 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_cistatic const enum snd_bebob_clock_type saffirepro_26_clk_src_types[] = { 11362306a36Sopenharmony_ci SND_BEBOB_CLOCK_TYPE_INTERNAL, 11462306a36Sopenharmony_ci SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* S/PDIF */ 11562306a36Sopenharmony_ci SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* ADAT1 */ 11662306a36Sopenharmony_ci SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* ADAT2 */ 11762306a36Sopenharmony_ci SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* Word Clock */ 11862306a36Sopenharmony_ci}; 11962306a36Sopenharmony_ci/* Value maps between registers and labels for SaffirePro 10/26. */ 12062306a36Sopenharmony_cistatic const signed char saffirepro_clk_maps[][SAFFIREPRO_CLOCK_SOURCE_COUNT] = { 12162306a36Sopenharmony_ci /* SaffirePro 10 */ 12262306a36Sopenharmony_ci [0] = { 12362306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0, 12462306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */ 12562306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1, 12662306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = -1, /* not supported */ 12762306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = -1, /* not supported */ 12862306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 2, 12962306a36Sopenharmony_ci }, 13062306a36Sopenharmony_ci /* SaffirePro 26 */ 13162306a36Sopenharmony_ci [1] = { 13262306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0, 13362306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */ 13462306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1, 13562306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = 2, 13662306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = 3, 13762306a36Sopenharmony_ci [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 4, 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci}; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int 14262306a36Sopenharmony_cisaffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci u32 id; 14562306a36Sopenharmony_ci int err; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci err = saffire_read_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, &id); 14862306a36Sopenharmony_ci if (err < 0) 14962306a36Sopenharmony_ci goto end; 15062306a36Sopenharmony_ci if (id >= ARRAY_SIZE(rates)) 15162306a36Sopenharmony_ci err = -EIO; 15262306a36Sopenharmony_ci else 15362306a36Sopenharmony_ci *rate = rates[id]; 15462306a36Sopenharmony_ciend: 15562306a36Sopenharmony_ci return err; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_cistatic int 15862306a36Sopenharmony_cisaffirepro_both_clk_freq_set(struct snd_bebob *bebob, unsigned int rate) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci u32 id; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci for (id = 0; id < ARRAY_SIZE(rates); id++) { 16362306a36Sopenharmony_ci if (rates[id] == rate) 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci if (id == ARRAY_SIZE(rates)) 16762306a36Sopenharmony_ci return -EINVAL; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* 17362306a36Sopenharmony_ci * query hardware for current clock source, return our internally 17462306a36Sopenharmony_ci * used clock index in *id, depending on hardware. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_cistatic int 17762306a36Sopenharmony_cisaffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci int err; 18062306a36Sopenharmony_ci u32 value; /* clock source read from hw register */ 18162306a36Sopenharmony_ci const signed char *map; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value); 18462306a36Sopenharmony_ci if (err < 0) 18562306a36Sopenharmony_ci goto end; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* depending on hardware, use a different mapping */ 18862306a36Sopenharmony_ci if (bebob->spec->clock->types == saffirepro_10_clk_src_types) 18962306a36Sopenharmony_ci map = saffirepro_clk_maps[0]; 19062306a36Sopenharmony_ci else 19162306a36Sopenharmony_ci map = saffirepro_clk_maps[1]; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* In a case that this driver cannot handle the value of register. */ 19462306a36Sopenharmony_ci value &= SAFFIREPRO_CLOCK_SOURCE_SELECT_MASK; 19562306a36Sopenharmony_ci if (value >= SAFFIREPRO_CLOCK_SOURCE_COUNT || map[value] < 0) { 19662306a36Sopenharmony_ci err = -EIO; 19762306a36Sopenharmony_ci goto end; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci *id = (unsigned int)map[value]; 20162306a36Sopenharmony_ciend: 20262306a36Sopenharmony_ci return err; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ciconst struct snd_bebob_spec saffire_le_spec; 20662306a36Sopenharmony_cistatic const enum snd_bebob_clock_type saffire_both_clk_src_types[] = { 20762306a36Sopenharmony_ci SND_BEBOB_CLOCK_TYPE_INTERNAL, 20862306a36Sopenharmony_ci SND_BEBOB_CLOCK_TYPE_EXTERNAL, 20962306a36Sopenharmony_ci}; 21062306a36Sopenharmony_cistatic int 21162306a36Sopenharmony_cisaffire_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci int err; 21462306a36Sopenharmony_ci u32 value; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci err = saffire_read_quad(bebob, SAFFIRE_OFFSET_CLOCK_SOURCE, &value); 21762306a36Sopenharmony_ci if (err >= 0) 21862306a36Sopenharmony_ci *id = 0xff & value; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return err; 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_cistatic const char *const saffire_le_meter_labels[] = { 22362306a36Sopenharmony_ci ANA_IN, ANA_IN, DIG_IN, 22462306a36Sopenharmony_ci ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, 22562306a36Sopenharmony_ci STM_IN, STM_IN 22662306a36Sopenharmony_ci}; 22762306a36Sopenharmony_cistatic const char *const saffire_meter_labels[] = { 22862306a36Sopenharmony_ci ANA_IN, ANA_IN, 22962306a36Sopenharmony_ci STM_IN, STM_IN, STM_IN, STM_IN, STM_IN, 23062306a36Sopenharmony_ci}; 23162306a36Sopenharmony_cistatic int 23262306a36Sopenharmony_cisaffire_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci const struct snd_bebob_meter_spec *spec = bebob->spec->meter; 23562306a36Sopenharmony_ci unsigned int channels; 23662306a36Sopenharmony_ci u64 offset; 23762306a36Sopenharmony_ci int err; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (spec->labels == saffire_le_meter_labels) 24062306a36Sopenharmony_ci offset = SAFFIRE_LE_OFFSET_METER; 24162306a36Sopenharmony_ci else 24262306a36Sopenharmony_ci offset = SAFFIRE_OFFSET_METER; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci channels = spec->num * 2; 24562306a36Sopenharmony_ci if (size < channels * sizeof(u32)) 24662306a36Sopenharmony_ci return -EIO; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci err = saffire_read_block(bebob, offset, buf, size); 24962306a36Sopenharmony_ci if (err >= 0 && spec->labels == saffire_le_meter_labels) { 25062306a36Sopenharmony_ci swap(buf[1], buf[3]); 25162306a36Sopenharmony_ci swap(buf[2], buf[3]); 25262306a36Sopenharmony_ci swap(buf[3], buf[4]); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci swap(buf[7], buf[10]); 25562306a36Sopenharmony_ci swap(buf[8], buf[10]); 25662306a36Sopenharmony_ci swap(buf[9], buf[11]); 25762306a36Sopenharmony_ci swap(buf[11], buf[12]); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci swap(buf[15], buf[16]); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return err; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic const struct snd_bebob_rate_spec saffirepro_both_rate_spec = { 26662306a36Sopenharmony_ci .get = &saffirepro_both_clk_freq_get, 26762306a36Sopenharmony_ci .set = &saffirepro_both_clk_freq_set, 26862306a36Sopenharmony_ci}; 26962306a36Sopenharmony_ci/* Saffire Pro 26 I/O */ 27062306a36Sopenharmony_cistatic const struct snd_bebob_clock_spec saffirepro_26_clk_spec = { 27162306a36Sopenharmony_ci .num = ARRAY_SIZE(saffirepro_26_clk_src_types), 27262306a36Sopenharmony_ci .types = saffirepro_26_clk_src_types, 27362306a36Sopenharmony_ci .get = &saffirepro_both_clk_src_get, 27462306a36Sopenharmony_ci}; 27562306a36Sopenharmony_ciconst struct snd_bebob_spec saffirepro_26_spec = { 27662306a36Sopenharmony_ci .clock = &saffirepro_26_clk_spec, 27762306a36Sopenharmony_ci .rate = &saffirepro_both_rate_spec, 27862306a36Sopenharmony_ci .meter = NULL 27962306a36Sopenharmony_ci}; 28062306a36Sopenharmony_ci/* Saffire Pro 10 I/O */ 28162306a36Sopenharmony_cistatic const struct snd_bebob_clock_spec saffirepro_10_clk_spec = { 28262306a36Sopenharmony_ci .num = ARRAY_SIZE(saffirepro_10_clk_src_types), 28362306a36Sopenharmony_ci .types = saffirepro_10_clk_src_types, 28462306a36Sopenharmony_ci .get = &saffirepro_both_clk_src_get, 28562306a36Sopenharmony_ci}; 28662306a36Sopenharmony_ciconst struct snd_bebob_spec saffirepro_10_spec = { 28762306a36Sopenharmony_ci .clock = &saffirepro_10_clk_spec, 28862306a36Sopenharmony_ci .rate = &saffirepro_both_rate_spec, 28962306a36Sopenharmony_ci .meter = NULL 29062306a36Sopenharmony_ci}; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic const struct snd_bebob_rate_spec saffire_both_rate_spec = { 29362306a36Sopenharmony_ci .get = &snd_bebob_stream_get_rate, 29462306a36Sopenharmony_ci .set = &snd_bebob_stream_set_rate, 29562306a36Sopenharmony_ci}; 29662306a36Sopenharmony_cistatic const struct snd_bebob_clock_spec saffire_both_clk_spec = { 29762306a36Sopenharmony_ci .num = ARRAY_SIZE(saffire_both_clk_src_types), 29862306a36Sopenharmony_ci .types = saffire_both_clk_src_types, 29962306a36Sopenharmony_ci .get = &saffire_both_clk_src_get, 30062306a36Sopenharmony_ci}; 30162306a36Sopenharmony_ci/* Saffire LE */ 30262306a36Sopenharmony_cistatic const struct snd_bebob_meter_spec saffire_le_meter_spec = { 30362306a36Sopenharmony_ci .num = ARRAY_SIZE(saffire_le_meter_labels), 30462306a36Sopenharmony_ci .labels = saffire_le_meter_labels, 30562306a36Sopenharmony_ci .get = &saffire_meter_get, 30662306a36Sopenharmony_ci}; 30762306a36Sopenharmony_ciconst struct snd_bebob_spec saffire_le_spec = { 30862306a36Sopenharmony_ci .clock = &saffire_both_clk_spec, 30962306a36Sopenharmony_ci .rate = &saffire_both_rate_spec, 31062306a36Sopenharmony_ci .meter = &saffire_le_meter_spec 31162306a36Sopenharmony_ci}; 31262306a36Sopenharmony_ci/* Saffire */ 31362306a36Sopenharmony_cistatic const struct snd_bebob_meter_spec saffire_meter_spec = { 31462306a36Sopenharmony_ci .num = ARRAY_SIZE(saffire_meter_labels), 31562306a36Sopenharmony_ci .labels = saffire_meter_labels, 31662306a36Sopenharmony_ci .get = &saffire_meter_get, 31762306a36Sopenharmony_ci}; 31862306a36Sopenharmony_ciconst struct snd_bebob_spec saffire_spec = { 31962306a36Sopenharmony_ci .clock = &saffire_both_clk_spec, 32062306a36Sopenharmony_ci .rate = &saffire_both_rate_spec, 32162306a36Sopenharmony_ci .meter = &saffire_meter_spec 32262306a36Sopenharmony_ci}; 323