Path: blob/master/sound/firewire/bebob/bebob_focusrite.c
26442 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* bebob_focusrite.c - a part of driver for BeBoB based devices3*4* Copyright (c) 2013-2014 Takashi Sakamoto5*/67#include "./bebob.h"89#define ANA_IN "Analog In"10#define DIG_IN "Digital In"11#define ANA_OUT "Analog Out"12#define DIG_OUT "Digital Out"13#define STM_IN "Stream In"1415#define SAFFIRE_ADDRESS_BASE 0x000100000000ULL1617#define SAFFIRE_OFFSET_CLOCK_SOURCE 0x00f818#define SAFFIREPRO_OFFSET_CLOCK_SOURCE 0x01741920/* whether sync to external device or not */21#define SAFFIRE_OFFSET_CLOCK_SYNC_EXT 0x013c22#define SAFFIRE_LE_OFFSET_CLOCK_SYNC_EXT 0x043223#define SAFFIREPRO_OFFSET_CLOCK_SYNC_EXT 0x01642425#define SAFFIRE_CLOCK_SOURCE_INTERNAL 026#define SAFFIRE_CLOCK_SOURCE_SPDIF 12728/* clock sources as returned from register of Saffire Pro 10 and 26 */29#define SAFFIREPRO_CLOCK_SOURCE_SELECT_MASK 0x000000ff30#define SAFFIREPRO_CLOCK_SOURCE_DETECT_MASK 0x0000ff0031#define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 032#define SAFFIREPRO_CLOCK_SOURCE_SKIP 1 /* never used on hardware */33#define SAFFIREPRO_CLOCK_SOURCE_SPDIF 234#define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 /* not used on s.pro. 10 */35#define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 /* not used on s.pro. 10 */36#define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 537#define SAFFIREPRO_CLOCK_SOURCE_COUNT 63839/* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */40#define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a44142/* saffirepro has its own parameter for sampling frequency */43#define SAFFIREPRO_RATE_NOREBOOT 0x01cc44/* index is the value for this register */45static const unsigned int rates[] = {46[0] = 0,47[1] = 44100,48[2] = 48000,49[3] = 88200,50[4] = 96000,51[5] = 176400,52[6] = 19200053};5455/* saffire(no label)/saffire LE has metering */56#define SAFFIRE_OFFSET_METER 0x010057#define SAFFIRE_LE_OFFSET_METER 0x01685859static inline int60saffire_read_block(struct snd_bebob *bebob, u64 offset,61u32 *buf, unsigned int size)62{63unsigned int i;64int err;65__be32 *tmp = (__be32 *)buf;6667err = snd_fw_transaction(bebob->unit, TCODE_READ_BLOCK_REQUEST,68SAFFIRE_ADDRESS_BASE + offset,69tmp, size, 0);70if (err < 0)71goto end;7273for (i = 0; i < size / sizeof(u32); i++)74buf[i] = be32_to_cpu(tmp[i]);75end:76return err;77}7879static inline int80saffire_read_quad(struct snd_bebob *bebob, u64 offset, u32 *value)81{82int err;83__be32 tmp;8485err = snd_fw_transaction(bebob->unit, TCODE_READ_QUADLET_REQUEST,86SAFFIRE_ADDRESS_BASE + offset,87&tmp, sizeof(__be32), 0);88if (err < 0)89goto end;9091*value = be32_to_cpu(tmp);92end:93return err;94}9596static inline int97saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value)98{99__be32 data = cpu_to_be32(value);100101return snd_fw_transaction(bebob->unit, TCODE_WRITE_QUADLET_REQUEST,102SAFFIRE_ADDRESS_BASE + offset,103&data, sizeof(__be32), 0);104}105106static const enum snd_bebob_clock_type saffirepro_10_clk_src_types[] = {107SND_BEBOB_CLOCK_TYPE_INTERNAL,108SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* S/PDIF */109SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* Word Clock */110};111static const enum snd_bebob_clock_type saffirepro_26_clk_src_types[] = {112SND_BEBOB_CLOCK_TYPE_INTERNAL,113SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* S/PDIF */114SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* ADAT1 */115SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* ADAT2 */116SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* Word Clock */117};118/* Value maps between registers and labels for SaffirePro 10/26. */119static const signed char saffirepro_clk_maps[][SAFFIREPRO_CLOCK_SOURCE_COUNT] = {120/* SaffirePro 10 */121[0] = {122[SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0,123[SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */124[SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1,125[SAFFIREPRO_CLOCK_SOURCE_ADAT1] = -1, /* not supported */126[SAFFIREPRO_CLOCK_SOURCE_ADAT2] = -1, /* not supported */127[SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 2,128},129/* SaffirePro 26 */130[1] = {131[SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0,132[SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */133[SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1,134[SAFFIREPRO_CLOCK_SOURCE_ADAT1] = 2,135[SAFFIREPRO_CLOCK_SOURCE_ADAT2] = 3,136[SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 4,137}138};139140static int141saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate)142{143u32 id;144int err;145146err = saffire_read_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, &id);147if (err < 0)148goto end;149if (id >= ARRAY_SIZE(rates))150err = -EIO;151else152*rate = rates[id];153end:154return err;155}156static int157saffirepro_both_clk_freq_set(struct snd_bebob *bebob, unsigned int rate)158{159u32 id;160161for (id = 0; id < ARRAY_SIZE(rates); id++) {162if (rates[id] == rate)163break;164}165if (id == ARRAY_SIZE(rates))166return -EINVAL;167168return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id);169}170171/*172* query hardware for current clock source, return our internally173* used clock index in *id, depending on hardware.174*/175static int176saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id)177{178int err;179u32 value; /* clock source read from hw register */180const signed char *map;181182err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value);183if (err < 0)184goto end;185186/* depending on hardware, use a different mapping */187if (bebob->spec->clock->types == saffirepro_10_clk_src_types)188map = saffirepro_clk_maps[0];189else190map = saffirepro_clk_maps[1];191192/* In a case that this driver cannot handle the value of register. */193value &= SAFFIREPRO_CLOCK_SOURCE_SELECT_MASK;194if (value >= SAFFIREPRO_CLOCK_SOURCE_COUNT || map[value] < 0) {195err = -EIO;196goto end;197}198199*id = (unsigned int)map[value];200end:201return err;202}203204const struct snd_bebob_spec saffire_le_spec;205static const enum snd_bebob_clock_type saffire_both_clk_src_types[] = {206SND_BEBOB_CLOCK_TYPE_INTERNAL,207SND_BEBOB_CLOCK_TYPE_EXTERNAL,208};209static int210saffire_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id)211{212int err;213u32 value;214215err = saffire_read_quad(bebob, SAFFIRE_OFFSET_CLOCK_SOURCE, &value);216if (err >= 0)217*id = 0xff & value;218219return err;220};221static const char *const saffire_le_meter_labels[] = {222ANA_IN, ANA_IN, DIG_IN,223ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT,224STM_IN, STM_IN225};226static const char *const saffire_meter_labels[] = {227ANA_IN, ANA_IN,228STM_IN, STM_IN, STM_IN, STM_IN, STM_IN,229};230static int231saffire_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size)232{233const struct snd_bebob_meter_spec *spec = bebob->spec->meter;234unsigned int channels;235u64 offset;236int err;237238if (spec->labels == saffire_le_meter_labels)239offset = SAFFIRE_LE_OFFSET_METER;240else241offset = SAFFIRE_OFFSET_METER;242243channels = spec->num * 2;244if (size < channels * sizeof(u32))245return -EIO;246247err = saffire_read_block(bebob, offset, buf, size);248if (err >= 0 && spec->labels == saffire_le_meter_labels) {249swap(buf[1], buf[3]);250swap(buf[2], buf[3]);251swap(buf[3], buf[4]);252253swap(buf[7], buf[10]);254swap(buf[8], buf[10]);255swap(buf[9], buf[11]);256swap(buf[11], buf[12]);257258swap(buf[15], buf[16]);259}260261return err;262}263264static const struct snd_bebob_rate_spec saffirepro_both_rate_spec = {265.get = &saffirepro_both_clk_freq_get,266.set = &saffirepro_both_clk_freq_set,267};268/* Saffire Pro 26 I/O */269static const struct snd_bebob_clock_spec saffirepro_26_clk_spec = {270.num = ARRAY_SIZE(saffirepro_26_clk_src_types),271.types = saffirepro_26_clk_src_types,272.get = &saffirepro_both_clk_src_get,273};274const struct snd_bebob_spec saffirepro_26_spec = {275.clock = &saffirepro_26_clk_spec,276.rate = &saffirepro_both_rate_spec,277.meter = NULL278};279/* Saffire Pro 10 I/O */280static const struct snd_bebob_clock_spec saffirepro_10_clk_spec = {281.num = ARRAY_SIZE(saffirepro_10_clk_src_types),282.types = saffirepro_10_clk_src_types,283.get = &saffirepro_both_clk_src_get,284};285const struct snd_bebob_spec saffirepro_10_spec = {286.clock = &saffirepro_10_clk_spec,287.rate = &saffirepro_both_rate_spec,288.meter = NULL289};290291static const struct snd_bebob_rate_spec saffire_both_rate_spec = {292.get = &snd_bebob_stream_get_rate,293.set = &snd_bebob_stream_set_rate,294};295static const struct snd_bebob_clock_spec saffire_both_clk_spec = {296.num = ARRAY_SIZE(saffire_both_clk_src_types),297.types = saffire_both_clk_src_types,298.get = &saffire_both_clk_src_get,299};300/* Saffire LE */301static const struct snd_bebob_meter_spec saffire_le_meter_spec = {302.num = ARRAY_SIZE(saffire_le_meter_labels),303.labels = saffire_le_meter_labels,304.get = &saffire_meter_get,305};306const struct snd_bebob_spec saffire_le_spec = {307.clock = &saffire_both_clk_spec,308.rate = &saffire_both_rate_spec,309.meter = &saffire_le_meter_spec310};311/* Saffire */312static const struct snd_bebob_meter_spec saffire_meter_spec = {313.num = ARRAY_SIZE(saffire_meter_labels),314.labels = saffire_meter_labels,315.get = &saffire_meter_get,316};317const struct snd_bebob_spec saffire_spec = {318.clock = &saffire_both_clk_spec,319.rate = &saffire_both_rate_spec,320.meter = &saffire_meter_spec321};322323324