18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * motu-protocol-v3.c - a part of driver for MOTU FireWire series
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/delay.h>
98c2ecf20Sopenharmony_ci#include "motu.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#define V3_CLOCK_STATUS_OFFSET		0x0b14
128c2ecf20Sopenharmony_ci#define  V3_FETCH_PCM_FRAMES		0x02000000
138c2ecf20Sopenharmony_ci#define  V3_CLOCK_RATE_MASK		0x0000ff00
148c2ecf20Sopenharmony_ci#define  V3_CLOCK_RATE_SHIFT		8
158c2ecf20Sopenharmony_ci#define  V3_CLOCK_SOURCE_MASK		0x000000ff
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define V3_OPT_IFACE_MODE_OFFSET	0x0c94
188c2ecf20Sopenharmony_ci#define  V3_ENABLE_OPT_IN_IFACE_A	0x00000001
198c2ecf20Sopenharmony_ci#define  V3_ENABLE_OPT_IN_IFACE_B	0x00000002
208c2ecf20Sopenharmony_ci#define  V3_ENABLE_OPT_OUT_IFACE_A	0x00000100
218c2ecf20Sopenharmony_ci#define  V3_ENABLE_OPT_OUT_IFACE_B	0x00000200
228c2ecf20Sopenharmony_ci#define  V3_NO_ADAT_OPT_IN_IFACE_A	0x00010000
238c2ecf20Sopenharmony_ci#define  V3_NO_ADAT_OPT_IN_IFACE_B	0x00100000
248c2ecf20Sopenharmony_ci#define  V3_NO_ADAT_OPT_OUT_IFACE_A	0x00040000
258c2ecf20Sopenharmony_ci#define  V3_NO_ADAT_OPT_OUT_IFACE_B	0x00400000
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define V3_MSG_FLAG_CLK_CHANGED		0x00000002
288c2ecf20Sopenharmony_ci#define V3_CLK_WAIT_MSEC		4000
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ciint snd_motu_protocol_v3_get_clock_rate(struct snd_motu *motu,
318c2ecf20Sopenharmony_ci					unsigned int *rate)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	__be32 reg;
348c2ecf20Sopenharmony_ci	u32 data;
358c2ecf20Sopenharmony_ci	int err;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
388c2ecf20Sopenharmony_ci					sizeof(reg));
398c2ecf20Sopenharmony_ci	if (err < 0)
408c2ecf20Sopenharmony_ci		return err;
418c2ecf20Sopenharmony_ci	data = be32_to_cpu(reg);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	data = (data & V3_CLOCK_RATE_MASK) >> V3_CLOCK_RATE_SHIFT;
448c2ecf20Sopenharmony_ci	if (data >= ARRAY_SIZE(snd_motu_clock_rates))
458c2ecf20Sopenharmony_ci		return -EIO;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	*rate = snd_motu_clock_rates[data];
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	return 0;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciint snd_motu_protocol_v3_set_clock_rate(struct snd_motu *motu,
538c2ecf20Sopenharmony_ci					unsigned int rate)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	__be32 reg;
568c2ecf20Sopenharmony_ci	u32 data;
578c2ecf20Sopenharmony_ci	bool need_to_wait;
588c2ecf20Sopenharmony_ci	int i, err;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
618c2ecf20Sopenharmony_ci		if (snd_motu_clock_rates[i] == rate)
628c2ecf20Sopenharmony_ci			break;
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci	if (i == ARRAY_SIZE(snd_motu_clock_rates))
658c2ecf20Sopenharmony_ci		return -EINVAL;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
688c2ecf20Sopenharmony_ci					sizeof(reg));
698c2ecf20Sopenharmony_ci	if (err < 0)
708c2ecf20Sopenharmony_ci		return err;
718c2ecf20Sopenharmony_ci	data = be32_to_cpu(reg);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	data &= ~(V3_CLOCK_RATE_MASK | V3_FETCH_PCM_FRAMES);
748c2ecf20Sopenharmony_ci	data |= i << V3_CLOCK_RATE_SHIFT;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	need_to_wait = data != be32_to_cpu(reg);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	reg = cpu_to_be32(data);
798c2ecf20Sopenharmony_ci	err = snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, &reg,
808c2ecf20Sopenharmony_ci					 sizeof(reg));
818c2ecf20Sopenharmony_ci	if (err < 0)
828c2ecf20Sopenharmony_ci		return err;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (need_to_wait) {
858c2ecf20Sopenharmony_ci		int result;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci		motu->msg = 0;
888c2ecf20Sopenharmony_ci		result = wait_event_interruptible_timeout(motu->hwdep_wait,
898c2ecf20Sopenharmony_ci					motu->msg & V3_MSG_FLAG_CLK_CHANGED,
908c2ecf20Sopenharmony_ci					msecs_to_jiffies(V3_CLK_WAIT_MSEC));
918c2ecf20Sopenharmony_ci		if (result < 0)
928c2ecf20Sopenharmony_ci			return result;
938c2ecf20Sopenharmony_ci		if (result == 0)
948c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return 0;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic int detect_clock_source_828mk3(struct snd_motu *motu, u32 data,
1018c2ecf20Sopenharmony_ci				      enum snd_motu_clock_source *src)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	switch (data) {
1048c2ecf20Sopenharmony_ci	case 0x00:
1058c2ecf20Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
1068c2ecf20Sopenharmony_ci		break;
1078c2ecf20Sopenharmony_ci	case 0x01:
1088c2ecf20Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
1098c2ecf20Sopenharmony_ci		break;
1108c2ecf20Sopenharmony_ci	case 0x02:
1118c2ecf20Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_SPH;
1128c2ecf20Sopenharmony_ci		break;
1138c2ecf20Sopenharmony_ci	case 0x10:
1148c2ecf20Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
1158c2ecf20Sopenharmony_ci		break;
1168c2ecf20Sopenharmony_ci	case 0x18:
1178c2ecf20Sopenharmony_ci	case 0x19:
1188c2ecf20Sopenharmony_ci	{
1198c2ecf20Sopenharmony_ci		__be32 reg;
1208c2ecf20Sopenharmony_ci		u32 options;
1218c2ecf20Sopenharmony_ci		int err;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci		err = snd_motu_transaction_read(motu,
1248c2ecf20Sopenharmony_ci				V3_OPT_IFACE_MODE_OFFSET, &reg, sizeof(reg));
1258c2ecf20Sopenharmony_ci		if (err < 0)
1268c2ecf20Sopenharmony_ci			return err;
1278c2ecf20Sopenharmony_ci		options = be32_to_cpu(reg);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci		if (data == 0x18) {
1308c2ecf20Sopenharmony_ci			if (options & V3_NO_ADAT_OPT_IN_IFACE_A)
1318c2ecf20Sopenharmony_ci				*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A;
1328c2ecf20Sopenharmony_ci			else
1338c2ecf20Sopenharmony_ci				*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A;
1348c2ecf20Sopenharmony_ci		} else {
1358c2ecf20Sopenharmony_ci			if (options & V3_NO_ADAT_OPT_IN_IFACE_B)
1368c2ecf20Sopenharmony_ci				*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B;
1378c2ecf20Sopenharmony_ci			else
1388c2ecf20Sopenharmony_ci				*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B;
1398c2ecf20Sopenharmony_ci		}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci		break;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci	default:
1448c2ecf20Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
1458c2ecf20Sopenharmony_ci		break;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return 0;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic int v3_detect_clock_source(struct snd_motu *motu, u32 data,
1528c2ecf20Sopenharmony_ci				  enum snd_motu_clock_source *src)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	switch (data) {
1558c2ecf20Sopenharmony_ci	case 0x00:
1568c2ecf20Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
1578c2ecf20Sopenharmony_ci		break;
1588c2ecf20Sopenharmony_ci	case 0x01:
1598c2ecf20Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
1608c2ecf20Sopenharmony_ci		break;
1618c2ecf20Sopenharmony_ci	case 0x02:
1628c2ecf20Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_SPH;
1638c2ecf20Sopenharmony_ci		break;
1648c2ecf20Sopenharmony_ci	case 0x10:
1658c2ecf20Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
1668c2ecf20Sopenharmony_ci		break;
1678c2ecf20Sopenharmony_ci	default:
1688c2ecf20Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
1698c2ecf20Sopenharmony_ci		break;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return 0;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ciint snd_motu_protocol_v3_get_clock_source(struct snd_motu *motu,
1768c2ecf20Sopenharmony_ci					  enum snd_motu_clock_source *src)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	__be32 reg;
1798c2ecf20Sopenharmony_ci	u32 data;
1808c2ecf20Sopenharmony_ci	int err;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
1838c2ecf20Sopenharmony_ci					sizeof(reg));
1848c2ecf20Sopenharmony_ci	if (err < 0)
1858c2ecf20Sopenharmony_ci		return err;
1868c2ecf20Sopenharmony_ci	data = be32_to_cpu(reg) & V3_CLOCK_SOURCE_MASK;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (motu->spec == &snd_motu_spec_828mk3)
1898c2ecf20Sopenharmony_ci		return detect_clock_source_828mk3(motu, data, src);
1908c2ecf20Sopenharmony_ci	else
1918c2ecf20Sopenharmony_ci		return v3_detect_clock_source(motu, data, src);
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ciint snd_motu_protocol_v3_switch_fetching_mode(struct snd_motu *motu,
1958c2ecf20Sopenharmony_ci					      bool enable)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	__be32 reg;
1988c2ecf20Sopenharmony_ci	u32 data;
1998c2ecf20Sopenharmony_ci	int err;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
2028c2ecf20Sopenharmony_ci					sizeof(reg));
2038c2ecf20Sopenharmony_ci	if (err < 0)
2048c2ecf20Sopenharmony_ci		return 0;
2058c2ecf20Sopenharmony_ci	data = be32_to_cpu(reg);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (enable)
2088c2ecf20Sopenharmony_ci		data |= V3_FETCH_PCM_FRAMES;
2098c2ecf20Sopenharmony_ci	else
2108c2ecf20Sopenharmony_ci		data &= ~V3_FETCH_PCM_FRAMES;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	reg = cpu_to_be32(data);
2138c2ecf20Sopenharmony_ci	return snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, &reg,
2148c2ecf20Sopenharmony_ci					  sizeof(reg));
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic int detect_packet_formats_828mk3(struct snd_motu *motu, u32 data)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	if (data & V3_ENABLE_OPT_IN_IFACE_A) {
2208c2ecf20Sopenharmony_ci		if (data & V3_NO_ADAT_OPT_IN_IFACE_A) {
2218c2ecf20Sopenharmony_ci			motu->tx_packet_formats.pcm_chunks[0] += 4;
2228c2ecf20Sopenharmony_ci			motu->tx_packet_formats.pcm_chunks[1] += 4;
2238c2ecf20Sopenharmony_ci		} else {
2248c2ecf20Sopenharmony_ci			motu->tx_packet_formats.pcm_chunks[0] += 8;
2258c2ecf20Sopenharmony_ci			motu->tx_packet_formats.pcm_chunks[1] += 4;
2268c2ecf20Sopenharmony_ci		}
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	if (data & V3_ENABLE_OPT_IN_IFACE_B) {
2308c2ecf20Sopenharmony_ci		if (data & V3_NO_ADAT_OPT_IN_IFACE_B) {
2318c2ecf20Sopenharmony_ci			motu->tx_packet_formats.pcm_chunks[0] += 4;
2328c2ecf20Sopenharmony_ci			motu->tx_packet_formats.pcm_chunks[1] += 4;
2338c2ecf20Sopenharmony_ci		} else {
2348c2ecf20Sopenharmony_ci			motu->tx_packet_formats.pcm_chunks[0] += 8;
2358c2ecf20Sopenharmony_ci			motu->tx_packet_formats.pcm_chunks[1] += 4;
2368c2ecf20Sopenharmony_ci		}
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (data & V3_ENABLE_OPT_OUT_IFACE_A) {
2408c2ecf20Sopenharmony_ci		if (data & V3_NO_ADAT_OPT_OUT_IFACE_A) {
2418c2ecf20Sopenharmony_ci			motu->rx_packet_formats.pcm_chunks[0] += 4;
2428c2ecf20Sopenharmony_ci			motu->rx_packet_formats.pcm_chunks[1] += 4;
2438c2ecf20Sopenharmony_ci		} else {
2448c2ecf20Sopenharmony_ci			motu->rx_packet_formats.pcm_chunks[0] += 8;
2458c2ecf20Sopenharmony_ci			motu->rx_packet_formats.pcm_chunks[1] += 4;
2468c2ecf20Sopenharmony_ci		}
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (data & V3_ENABLE_OPT_OUT_IFACE_B) {
2508c2ecf20Sopenharmony_ci		if (data & V3_NO_ADAT_OPT_OUT_IFACE_B) {
2518c2ecf20Sopenharmony_ci			motu->rx_packet_formats.pcm_chunks[0] += 4;
2528c2ecf20Sopenharmony_ci			motu->rx_packet_formats.pcm_chunks[1] += 4;
2538c2ecf20Sopenharmony_ci		} else {
2548c2ecf20Sopenharmony_ci			motu->rx_packet_formats.pcm_chunks[0] += 8;
2558c2ecf20Sopenharmony_ci			motu->rx_packet_formats.pcm_chunks[1] += 4;
2568c2ecf20Sopenharmony_ci		}
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return 0;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ciint snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	__be32 reg;
2658c2ecf20Sopenharmony_ci	u32 data;
2668c2ecf20Sopenharmony_ci	int err;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	motu->tx_packet_formats.pcm_byte_offset = 10;
2698c2ecf20Sopenharmony_ci	motu->rx_packet_formats.pcm_byte_offset = 10;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	motu->tx_packet_formats.msg_chunks = 2;
2728c2ecf20Sopenharmony_ci	motu->rx_packet_formats.msg_chunks = 2;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, &reg,
2758c2ecf20Sopenharmony_ci					sizeof(reg));
2768c2ecf20Sopenharmony_ci	if (err < 0)
2778c2ecf20Sopenharmony_ci		return err;
2788c2ecf20Sopenharmony_ci	data = be32_to_cpu(reg);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	memcpy(motu->tx_packet_formats.pcm_chunks,
2818c2ecf20Sopenharmony_ci	       motu->spec->tx_fixed_pcm_chunks,
2828c2ecf20Sopenharmony_ci	       sizeof(motu->tx_packet_formats.pcm_chunks));
2838c2ecf20Sopenharmony_ci	memcpy(motu->rx_packet_formats.pcm_chunks,
2848c2ecf20Sopenharmony_ci	       motu->spec->rx_fixed_pcm_chunks,
2858c2ecf20Sopenharmony_ci	       sizeof(motu->rx_packet_formats.pcm_chunks));
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (motu->spec == &snd_motu_spec_828mk3)
2888c2ecf20Sopenharmony_ci		return detect_packet_formats_828mk3(motu, data);
2898c2ecf20Sopenharmony_ci	else
2908c2ecf20Sopenharmony_ci		return 0;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ciconst struct snd_motu_spec snd_motu_spec_828mk3 = {
2958c2ecf20Sopenharmony_ci	.name = "828mk3",
2968c2ecf20Sopenharmony_ci	.protocol_version = SND_MOTU_PROTOCOL_V3,
2978c2ecf20Sopenharmony_ci	.flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
2988c2ecf20Sopenharmony_ci		 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
2998c2ecf20Sopenharmony_ci	.tx_fixed_pcm_chunks = {18, 18, 14},
3008c2ecf20Sopenharmony_ci	.rx_fixed_pcm_chunks = {14, 14, 10},
3018c2ecf20Sopenharmony_ci};
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ciconst struct snd_motu_spec snd_motu_spec_ultralite_mk3 = {
3048c2ecf20Sopenharmony_ci	.name = "UltraLiteMk3",
3058c2ecf20Sopenharmony_ci	.protocol_version = SND_MOTU_PROTOCOL_V3,
3068c2ecf20Sopenharmony_ci	.flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
3078c2ecf20Sopenharmony_ci		 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
3088c2ecf20Sopenharmony_ci	.tx_fixed_pcm_chunks = {18, 14, 10},
3098c2ecf20Sopenharmony_ci	.rx_fixed_pcm_chunks = {14, 14, 14},
3108c2ecf20Sopenharmony_ci};
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ciconst struct snd_motu_spec snd_motu_spec_audio_express = {
3138c2ecf20Sopenharmony_ci	.name = "AudioExpress",
3148c2ecf20Sopenharmony_ci	.protocol_version = SND_MOTU_PROTOCOL_V3,
3158c2ecf20Sopenharmony_ci	.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
3168c2ecf20Sopenharmony_ci		 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
3178c2ecf20Sopenharmony_ci	.tx_fixed_pcm_chunks = {10, 10, 0},
3188c2ecf20Sopenharmony_ci	.rx_fixed_pcm_chunks = {10, 10, 0},
3198c2ecf20Sopenharmony_ci};
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ciconst struct snd_motu_spec snd_motu_spec_4pre = {
3228c2ecf20Sopenharmony_ci	.name = "4pre",
3238c2ecf20Sopenharmony_ci	.protocol_version = SND_MOTU_PROTOCOL_V3,
3248c2ecf20Sopenharmony_ci	.tx_fixed_pcm_chunks = {10, 10, 0},
3258c2ecf20Sopenharmony_ci	.rx_fixed_pcm_chunks = {10, 10, 0},
3268c2ecf20Sopenharmony_ci};
327