brintos

brintos / linux-shallow public Read only

0
0
Text · 13.2 KiB · e811629 Raw
468 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// motu-protocol-v1.c - a part of driver for MOTU FireWire series3//4// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>5 6#include "motu.h"7 8#include <linux/delay.h>9 10// Status register for MOTU 828 (0x'ffff'f000'0b00).11//12// 0xffff0000: ISOC_COMM_CONTROL_MASK in motu-stream.c.13// 0x00008000: mode of optical input interface.14//   0x00008000: for S/PDIF signal.15//   0x00000000: disabled or for ADAT signal.16// 0x00004000: mode of optical output interface.17//   0x00004000: for S/PDIF signal.18//   0x00000000: disabled or for ADAT signal.19// 0x00003f00: monitor input mode.20//   0x00000800: analog-1/221//   0x00001a00: analog-3/422//   0x00002c00: analog-5/623//   0x00003e00: analog-7/824//   0x00000000: analog-125//   0x00000900: analog-226//   0x00001200: analog-327//   0x00001b00: analog-428//   0x00002400: analog-529//   0x00002d00: analog-630//   0x00003600: analog-731//   0x00003f00: analog-832// 0x00000080: enable stream input.33// 0x00000040: disable monitor input.34// 0x00000008: enable main out.35// 0x00000004: rate of sampling clock.36//   0x00000004: 48.0 kHz37//   0x00000000: 44.1 kHz38// 0x00000023: source of sampling clock.39//   0x00000003: source packet header (SPH)40//   0x00000002: S/PDIF on optical/coaxial interface.41//   0x00000021: ADAT on optical interface42//   0x00000001: ADAT on Dsub 9pin43//   0x00000000: internal44 45#define CLK_828_STATUS_OFFSET				0x0b0046#define  CLK_828_STATUS_MASK				0x0000ffff47#define  CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF	0x0000800048#define  CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF	0x0000400049#define  CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES		0x0000008050#define  CLK_828_STATUS_FLAG_ENABLE_OUTPUT		0x0000000851#define  CLK_828_STATUS_FLAG_RATE_48000			0x0000000452#define  CLK_828_STATUS_MASK_SRC			0x0000002353#define   CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT		0x0000002154#define   CLK_828_STATUS_FLAG_SRC_SPH			0x0000000355#define   CLK_828_STATUS_FLAG_SRC_SPDIF			0x0000000256#define   CLK_828_STATUS_FLAG_SRC_ADAT_ON_DSUB		0x0000000157#define   CLK_828_STATUS_FLAG_SRC_INTERNAL		0x0000000058 59// Status register for MOTU 896 (0x'ffff'f000'0b14).60//61// 0xf0000000: enable physical and stream input to DAC.62//   0x80000000: disable63//   0x40000000: disable64//   0x20000000: enable (prior to the other bits)65//   0x10000000: disable66//   0x00000000: disable67// 0x08000000: speed of word clock signal output on BNC interface.68//   0x00000000: force to low rate (44.1/48.0 kHz).69//   0x08000000: follow to system clock.70// 0x04000000: something relevant to clock.71// 0x03000000: enable output.72//  0x02000000: enabled irreversibly once standing unless the device voluntarily disables it.73//  0x01000000: enabled irreversibly once standing unless the device voluntarily disables it.74// 0x00ffff00: monitor input mode.75//   0x00000000: disabled76//   0x00004800: analog-1/277//   0x00005a00: analog-3/478//   0x00006c00: analog-5/679//   0x00007e00: analog-7/880//   0x00104800: AES/EBU-1/281//   0x00004000: analog-182//   0x00004900: analog-283//   0x00005200: analog-384//   0x00005b00: analog-485//   0x00006400: analog-586//   0x00006d00: analog-687//   0x00007600: analog-788//   0x00007f00: analog-889//   0x00104000: AES/EBU-190//   0x00104900: AES/EBU-291// 0x00000060: sample rate conversion for AES/EBU input/output.92//   0x00000000: None93//   0x00000020: input signal is converted to system rate94//   0x00000040: output is slave to input, ignoring system rate95//   0x00000060: output is double rate than system rate96// 0x00000018: nominal rate of sampling clock.97//   0x00000000: 44.1 kHz98//   0x00000008: 48.0 kHz99//   0x00000010: 88.2 kHz100//   0x00000018: 96.0 kHz101// 0x00000007: source of sampling clock.102//   0x00000000: internal103//   0x00000001: ADAT on optical interface104//   0x00000002: AES/EBU on XLR105//   0x00000003: source packet header (SPH)106//   0x00000004: word clock on BNC107//   0x00000005: ADAT on Dsub 9pin108 109#define CLK_896_STATUS_OFFSET			0x0b14110#define  CLK_896_STATUS_FLAG_FETCH_ENABLE	0x20000000111#define  CLK_896_STATUS_FLAG_OUTPUT_ON		0x03000000112#define  CLK_896_STATUS_MASK_SRC		0x00000007113#define   CLK_896_STATUS_FLAG_SRC_INTERNAL	0x00000000114#define   CLK_896_STATUS_FLAG_SRC_ADAT_ON_OPT	0x00000001115#define   CLK_896_STATUS_FLAG_SRC_AESEBU	0x00000002116#define   CLK_896_STATUS_FLAG_SRC_SPH		0x00000003117#define   CLK_896_STATUS_FLAG_SRC_WORD		0x00000004118#define   CLK_896_STATUS_FLAG_SRC_ADAT_ON_DSUB	0x00000005119#define  CLK_896_STATUS_MASK_RATE		0x00000018120#define   CLK_896_STATUS_FLAG_RATE_44100	0x00000000121#define   CLK_896_STATUS_FLAG_RATE_48000	0x00000008122#define   CLK_896_STATUS_FLAG_RATE_88200	0x00000010123#define   CLK_896_STATUS_FLAG_RATE_96000	0x00000018124 125static void parse_clock_rate_828(u32 data, unsigned int *rate)126{127	if (data & CLK_828_STATUS_FLAG_RATE_48000)128		*rate = 48000;129	else130		*rate = 44100;131}132 133static int get_clock_rate_828(struct snd_motu *motu, unsigned int *rate)134{135	__be32 reg;136	int err;137 138	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));139	if (err < 0)140		return err;141	parse_clock_rate_828(be32_to_cpu(reg), rate);142 143	return 0;144}145 146static int parse_clock_rate_896(u32 data, unsigned int *rate)147{148	switch (data & CLK_896_STATUS_MASK_RATE) {149	case CLK_896_STATUS_FLAG_RATE_44100:150		*rate = 44100;151		break;152	case CLK_896_STATUS_FLAG_RATE_48000:153		*rate = 48000;154		break;155	case CLK_896_STATUS_FLAG_RATE_88200:156		*rate = 88200;157		break;158	case CLK_896_STATUS_FLAG_RATE_96000:159		*rate = 96000;160		break;161	default:162		return -ENXIO;163	}164 165	return 0;166}167 168static int get_clock_rate_896(struct snd_motu *motu, unsigned int *rate)169{170	__be32 reg;171	int err;172 173	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));174	if (err < 0)175		return err;176	return parse_clock_rate_896(be32_to_cpu(reg), rate);177}178 179int snd_motu_protocol_v1_get_clock_rate(struct snd_motu *motu, unsigned int *rate)180{181	if (motu->spec == &snd_motu_spec_828)182		return get_clock_rate_828(motu, rate);183	else if (motu->spec == &snd_motu_spec_896)184		return get_clock_rate_896(motu, rate);185	else186		return -ENXIO;187}188 189static int set_clock_rate_828(struct snd_motu *motu, unsigned int rate)190{191	__be32 reg;192	u32 data;193	int err;194 195	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));196	if (err < 0)197		return err;198	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;199 200	data &= ~CLK_828_STATUS_FLAG_RATE_48000;201	if (rate == 48000)202		data |= CLK_828_STATUS_FLAG_RATE_48000;203 204	reg = cpu_to_be32(data);205	return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));206}207 208static int set_clock_rate_896(struct snd_motu *motu, unsigned int rate)209{210	unsigned int flag;211	__be32 reg;212	u32 data;213	int err;214 215	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));216	if (err < 0)217		return err;218	data = be32_to_cpu(reg);219 220	switch (rate) {221	case 44100:222		flag = CLK_896_STATUS_FLAG_RATE_44100;223		break;224	case 48000:225		flag = CLK_896_STATUS_FLAG_RATE_48000;226		break;227	case 88200:228		flag = CLK_896_STATUS_FLAG_RATE_88200;229		break;230	case 96000:231		flag = CLK_896_STATUS_FLAG_RATE_96000;232		break;233	default:234		return -EINVAL;235	}236 237	data &= ~CLK_896_STATUS_MASK_RATE;238	data |= flag;239 240	reg = cpu_to_be32(data);241	return snd_motu_transaction_write(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));242}243 244int snd_motu_protocol_v1_set_clock_rate(struct snd_motu *motu, unsigned int rate)245{246	if (motu->spec == &snd_motu_spec_828)247		return set_clock_rate_828(motu, rate);248	else if (motu->spec == &snd_motu_spec_896)249		return set_clock_rate_896(motu, rate);250	else251		return -ENXIO;252}253 254static int get_clock_source_828(struct snd_motu *motu, enum snd_motu_clock_source *src)255{256	__be32 reg;257	u32 data;258	int err;259 260	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));261	if (err < 0)262		return err;263	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;264 265	switch (data & CLK_828_STATUS_MASK_SRC) {266	case CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT:267		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;268		break;269	case CLK_828_STATUS_FLAG_SRC_SPH:270		*src = SND_MOTU_CLOCK_SOURCE_SPH;271		break;272	case CLK_828_STATUS_FLAG_SRC_SPDIF:273	{274		if (data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF)275			*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;276		else277			*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;278		break;279	}280	case CLK_828_STATUS_FLAG_SRC_ADAT_ON_DSUB:281		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;282		break;283	case CLK_828_STATUS_FLAG_SRC_INTERNAL:284		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;285		break;286	default:287		return -ENXIO;288	}289 290	return 0;291}292 293static int get_clock_source_896(struct snd_motu *motu, enum snd_motu_clock_source *src)294{295	__be32 reg;296	u32 data;297	int err;298 299	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));300	if (err < 0)301		return err;302	data = be32_to_cpu(reg);303 304	switch (data & CLK_896_STATUS_MASK_SRC) {305	case CLK_896_STATUS_FLAG_SRC_INTERNAL:306		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;307		break;308	case CLK_896_STATUS_FLAG_SRC_ADAT_ON_OPT:309		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;310		break;311	case CLK_896_STATUS_FLAG_SRC_AESEBU:312		*src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;313		break;314	case CLK_896_STATUS_FLAG_SRC_SPH:315		*src = SND_MOTU_CLOCK_SOURCE_SPH;316		break;317	case CLK_896_STATUS_FLAG_SRC_WORD:318		*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;319		break;320	case CLK_896_STATUS_FLAG_SRC_ADAT_ON_DSUB:321		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;322		break;323	default:324		return -ENXIO;325	}326 327	return 0;328}329 330int snd_motu_protocol_v1_get_clock_source(struct snd_motu *motu, enum snd_motu_clock_source *src)331{332	if (motu->spec == &snd_motu_spec_828)333		return get_clock_source_828(motu, src);334	else if (motu->spec == &snd_motu_spec_896)335		return get_clock_source_896(motu, src);336	else337		return -ENXIO;338}339 340static int switch_fetching_mode_828(struct snd_motu *motu, bool enable)341{342	__be32 reg;343	u32 data;344	int err;345 346	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));347	if (err < 0)348		return err;349	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;350 351	data &= ~(CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_ENABLE_OUTPUT);352	if (enable) {353		// This transaction should be initiated after the device receives batch of packets354		// since the device voluntarily mutes outputs. As a workaround, yield processor over355		// 100 msec.356		msleep(100);357		data |= CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_ENABLE_OUTPUT;358	}359 360	reg = cpu_to_be32(data);361	return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));362}363 364static int switch_fetching_mode_896(struct snd_motu *motu, bool enable)365{366	__be32 reg;367	u32 data;368	int err;369 370	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));371	if (err < 0)372		return err;373	data = be32_to_cpu(reg);374 375	data &= ~CLK_896_STATUS_FLAG_FETCH_ENABLE;376	if (enable)377		data |= CLK_896_STATUS_FLAG_FETCH_ENABLE | CLK_896_STATUS_FLAG_OUTPUT_ON;378 379	reg = cpu_to_be32(data);380	return snd_motu_transaction_write(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));381}382 383int snd_motu_protocol_v1_switch_fetching_mode(struct snd_motu *motu, bool enable)384{385	if (motu->spec == &snd_motu_spec_828)386		return switch_fetching_mode_828(motu, enable);387	else if (motu->spec == &snd_motu_spec_896)388		return switch_fetching_mode_896(motu, enable);389	else390		return -ENXIO;391}392 393static int detect_packet_formats_828(struct snd_motu *motu)394{395	__be32 reg;396	u32 data;397	int err;398 399	motu->tx_packet_formats.pcm_byte_offset = 4;400	motu->tx_packet_formats.msg_chunks = 2;401 402	motu->rx_packet_formats.pcm_byte_offset = 4;403	motu->rx_packet_formats.msg_chunks = 0;404 405	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));406	if (err < 0)407		return err;408	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;409 410	// The number of chunks is just reduced when SPDIF is activated.411	if (!(data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF))412		motu->tx_packet_formats.pcm_chunks[0] += 8;413 414	if (!(data & CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF))415		motu->rx_packet_formats.pcm_chunks[0] += 8;416 417	return 0;418}419 420static int detect_packet_formats_896(struct snd_motu *motu)421{422	// 24bit PCM frames follow to source packet header without message chunk.423	motu->tx_packet_formats.pcm_byte_offset = 4;424	motu->rx_packet_formats.pcm_byte_offset = 4;425 426	// No message chunk in data block.427	motu->tx_packet_formats.msg_chunks = 0;428	motu->rx_packet_formats.msg_chunks = 0;429 430	// Always enable optical interface for ADAT signal since the device have no registers431	// to refer to current configuration.432	motu->tx_packet_formats.pcm_chunks[0] += 8;433	motu->tx_packet_formats.pcm_chunks[1] += 8;434 435	motu->rx_packet_formats.pcm_chunks[0] += 8;436	motu->rx_packet_formats.pcm_chunks[1] += 8;437 438	return 0;439}440 441int snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu)442{443	memcpy(motu->tx_packet_formats.pcm_chunks, motu->spec->tx_fixed_pcm_chunks,444	       sizeof(motu->tx_packet_formats.pcm_chunks));445	memcpy(motu->rx_packet_formats.pcm_chunks, motu->spec->rx_fixed_pcm_chunks,446	       sizeof(motu->rx_packet_formats.pcm_chunks));447 448	if (motu->spec == &snd_motu_spec_828)449		return detect_packet_formats_828(motu);450	else if (motu->spec == &snd_motu_spec_896)451		return detect_packet_formats_896(motu);452	else453		return 0;454}455 456const struct snd_motu_spec snd_motu_spec_828 = {457	.name = "828",458	.protocol_version = SND_MOTU_PROTOCOL_V1,459	.tx_fixed_pcm_chunks = {10, 0, 0},460	.rx_fixed_pcm_chunks = {10, 0, 0},461};462 463const struct snd_motu_spec snd_motu_spec_896 = {464	.name = "896",465	.tx_fixed_pcm_chunks = {10, 10, 0},466	.rx_fixed_pcm_chunks = {10, 10, 0},467};468