brintos

brintos / linux-shallow public Read only

0
0
Text · 8.6 KiB · 06d6a37 Raw
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