brintos

brintos / linux-shallow public Read only

0
0
Text · 8.3 KiB · a5f70ef Raw
322 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * motu-protocol-v2.c - a part of driver for MOTU FireWire series4 *5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>6 */7 8#include "motu.h"9 10#define V2_CLOCK_STATUS_OFFSET			0x0b1411#define  V2_CLOCK_RATE_MASK			0x0000003812#define  V2_CLOCK_RATE_SHIFT			313#define  V2_CLOCK_SRC_MASK			0x0000000714#define  V2_CLOCK_SRC_SHIFT			015#define   V2_CLOCK_SRC_AESEBU_ON_XLR		0x07	// In Traveler.16#define   V2_CLOCK_SRC_ADAT_ON_DSUB		0x0517#define   V2_CLOCK_SRC_WORD_ON_BNC		0x0418#define   V2_CLOCK_SRC_SPH			0x0319#define   V2_CLOCK_SRC_SPDIF			0x02	// on either coaxial or optical. AES/EBU in 896HD.20#define   V2_CLOCK_SRC_ADAT_ON_OPT		0x0121#define   V2_CLOCK_SRC_INTERNAL			0x0022#define  V2_CLOCK_FETCH_ENABLE			0x0200000023#define  V2_CLOCK_MODEL_SPECIFIC		0x0400000024 25#define V2_IN_OUT_CONF_OFFSET			0x0c0426#define  V2_OPT_OUT_IFACE_MASK			0x00000c0027#define  V2_OPT_OUT_IFACE_SHIFT			1028#define  V2_OPT_IN_IFACE_MASK			0x0000030029#define  V2_OPT_IN_IFACE_SHIFT			830#define  V2_OPT_IFACE_MODE_NONE			031#define  V2_OPT_IFACE_MODE_ADAT			132#define  V2_OPT_IFACE_MODE_SPDIF		233 34static int get_clock_rate(u32 data, unsigned int *rate)35{36	unsigned int index = (data & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT;37	if (index >= ARRAY_SIZE(snd_motu_clock_rates))38		return -EIO;39 40	*rate = snd_motu_clock_rates[index];41 42	return 0;43}44 45int snd_motu_protocol_v2_get_clock_rate(struct snd_motu *motu,46					unsigned int *rate)47{48	__be32 reg;49	int err;50 51	err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,52					sizeof(reg));53	if (err < 0)54		return err;55 56	return get_clock_rate(be32_to_cpu(reg), rate);57}58 59int snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu,60					unsigned int rate)61{62	__be32 reg;63	u32 data;64	int i;65	int err;66 67	for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {68		if (snd_motu_clock_rates[i] == rate)69			break;70	}71	if (i == ARRAY_SIZE(snd_motu_clock_rates))72		return -EINVAL;73 74	err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,75					sizeof(reg));76	if (err < 0)77		return err;78	data = be32_to_cpu(reg);79 80	data &= ~V2_CLOCK_RATE_MASK;81	data |= i << V2_CLOCK_RATE_SHIFT;82 83	reg = cpu_to_be32(data);84	return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, &reg,85					  sizeof(reg));86}87 88static int get_clock_source(struct snd_motu *motu, u32 data,89			    enum snd_motu_clock_source *src)90{91	switch (data & V2_CLOCK_SRC_MASK) {92	case V2_CLOCK_SRC_INTERNAL:93		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;94		break;95	case V2_CLOCK_SRC_ADAT_ON_OPT:96		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;97		break;98	case V2_CLOCK_SRC_SPDIF:99	{100		bool support_iec60958_on_opt = (motu->spec == &snd_motu_spec_828mk2 ||101						motu->spec == &snd_motu_spec_traveler);102 103		if (motu->spec == &snd_motu_spec_896hd) {104			*src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;105		} else if (!support_iec60958_on_opt) {106			*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;107		} else {108			__be32 reg;109 110			// To check the configuration of optical interface.111			int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,112							    sizeof(reg));113			if (err < 0)114				return err;115 116			if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==117			    V2_OPT_IFACE_MODE_SPDIF)118				*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;119			else120				*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;121		}122		break;123	}124	case V2_CLOCK_SRC_SPH:125		*src = SND_MOTU_CLOCK_SOURCE_SPH;126		break;127	case V2_CLOCK_SRC_WORD_ON_BNC:128		*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;129		break;130	case V2_CLOCK_SRC_ADAT_ON_DSUB:131		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;132		break;133	case V2_CLOCK_SRC_AESEBU_ON_XLR:134		// For Traveler.135		*src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;136		break;137	default:138		*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;139		break;140	}141 142	return 0;143}144 145int snd_motu_protocol_v2_get_clock_source(struct snd_motu *motu,146					  enum snd_motu_clock_source *src)147{148	__be32 reg;149	int err;150 151	err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,152					sizeof(reg));153	if (err < 0)154		return err;155 156	return get_clock_source(motu, be32_to_cpu(reg), src);157}158 159// Expected for Traveler, which implements Altera Cyclone EP1C3.160static int switch_fetching_mode_cyclone(struct snd_motu *motu, u32 *data,161					bool enable)162{163	*data |= V2_CLOCK_MODEL_SPECIFIC;164 165	return 0;166}167 168// For UltraLite and 8pre, which implements Xilinx Spartan XC3S200.169static int switch_fetching_mode_spartan(struct snd_motu *motu, u32 *data,170					bool enable)171{172	unsigned int rate;173	enum snd_motu_clock_source src;174	int err;175 176	err = get_clock_source(motu, *data, &src);177	if (err < 0)178		return err;179 180	err = get_clock_rate(*data, &rate);181	if (err < 0)182		return err;183 184	if (src == SND_MOTU_CLOCK_SOURCE_SPH && rate > 48000)185		*data |= V2_CLOCK_MODEL_SPECIFIC;186 187	return 0;188}189 190int snd_motu_protocol_v2_switch_fetching_mode(struct snd_motu *motu,191					      bool enable)192{193	if (motu->spec == &snd_motu_spec_828mk2) {194		// 828mkII implements Altera ACEX 1K EP1K30. Nothing to do.195		return 0;196	} else if (motu->spec == &snd_motu_spec_896hd) {197		// 896HD implements Altera Cyclone EP1C3 but nothing to do.198		return 0;199	} else {200		__be32 reg;201		u32 data;202		int err;203 204		err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,205						&reg, sizeof(reg));206		if (err < 0)207			return err;208		data = be32_to_cpu(reg);209 210		data &= ~(V2_CLOCK_FETCH_ENABLE | V2_CLOCK_MODEL_SPECIFIC);211		if (enable)212			data |= V2_CLOCK_FETCH_ENABLE;213 214		if (motu->spec == &snd_motu_spec_traveler)215			err = switch_fetching_mode_cyclone(motu, &data, enable);216		else217			err = switch_fetching_mode_spartan(motu, &data, enable);218		if (err < 0)219			return err;220 221		reg = cpu_to_be32(data);222		return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,223						  &reg, sizeof(reg));224	}225}226 227int snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu)228{229	bool has_two_opt_ifaces = (motu->spec == &snd_motu_spec_8pre);230	__be32 reg;231	u32 data;232	int err;233 234	motu->tx_packet_formats.pcm_byte_offset = 10;235	motu->rx_packet_formats.pcm_byte_offset = 10;236 237	motu->tx_packet_formats.msg_chunks = 2;238	motu->rx_packet_formats.msg_chunks = 2;239 240	err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,241					sizeof(reg));242	if (err < 0)243		return err;244	data = be32_to_cpu(reg);245 246	memcpy(motu->tx_packet_formats.pcm_chunks,247	       motu->spec->tx_fixed_pcm_chunks,248	       sizeof(motu->tx_packet_formats.pcm_chunks));249	memcpy(motu->rx_packet_formats.pcm_chunks,250	       motu->spec->rx_fixed_pcm_chunks,251	       sizeof(motu->rx_packet_formats.pcm_chunks));252 253	if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {254		motu->tx_packet_formats.pcm_chunks[0] += 8;255 256		if (!has_two_opt_ifaces)257			motu->tx_packet_formats.pcm_chunks[1] += 4;258		else259			motu->tx_packet_formats.pcm_chunks[1] += 8;260	}261 262	if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {263		motu->rx_packet_formats.pcm_chunks[0] += 8;264 265		if (!has_two_opt_ifaces)266			motu->rx_packet_formats.pcm_chunks[1] += 4;267		else268			motu->rx_packet_formats.pcm_chunks[1] += 8;269	}270 271	return 0;272}273 274const struct snd_motu_spec snd_motu_spec_828mk2 = {275	.name = "828mk2",276	.protocol_version = SND_MOTU_PROTOCOL_V2,277	.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |278		 SND_MOTU_SPEC_TX_MIDI_2ND_Q |279		 SND_MOTU_SPEC_REGISTER_DSP,280	.tx_fixed_pcm_chunks = {14, 14, 0},281	.rx_fixed_pcm_chunks = {14, 14, 0},282};283 284const struct snd_motu_spec snd_motu_spec_896hd = {285	.name = "896HD",286	.protocol_version = SND_MOTU_PROTOCOL_V2,287	.flags = SND_MOTU_SPEC_REGISTER_DSP,288	.tx_fixed_pcm_chunks = {14, 14, 8},289	.rx_fixed_pcm_chunks = {14, 14, 8},290};291 292const struct snd_motu_spec snd_motu_spec_traveler = {293	.name = "Traveler",294	.protocol_version = SND_MOTU_PROTOCOL_V2,295	.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |296		 SND_MOTU_SPEC_TX_MIDI_2ND_Q |297		 SND_MOTU_SPEC_REGISTER_DSP,298	.tx_fixed_pcm_chunks = {14, 14, 8},299	.rx_fixed_pcm_chunks = {14, 14, 8},300};301 302const struct snd_motu_spec snd_motu_spec_ultralite = {303	.name = "UltraLite",304	.protocol_version = SND_MOTU_PROTOCOL_V2,305	.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |306		 SND_MOTU_SPEC_TX_MIDI_2ND_Q |307		 SND_MOTU_SPEC_REGISTER_DSP,308	.tx_fixed_pcm_chunks = {14, 14, 0},309	.rx_fixed_pcm_chunks = {14, 14, 0},310};311 312const struct snd_motu_spec snd_motu_spec_8pre = {313	.name = "8pre",314	.protocol_version = SND_MOTU_PROTOCOL_V2,315	.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |316		 SND_MOTU_SPEC_TX_MIDI_2ND_Q |317		 SND_MOTU_SPEC_REGISTER_DSP,318	// Two dummy chunks always in the end of data block.319	.tx_fixed_pcm_chunks = {10, 10, 0},320	.rx_fixed_pcm_chunks = {6, 6, 0},321};322