xref: /OK3568_Linux_fs/kernel/sound/firewire/motu/motu-protocol-v3.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * motu-protocol-v3.c - a part of driver for MOTU FireWire series
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/delay.h>
9*4882a593Smuzhiyun #include "motu.h"
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #define V3_CLOCK_STATUS_OFFSET		0x0b14
12*4882a593Smuzhiyun #define  V3_FETCH_PCM_FRAMES		0x02000000
13*4882a593Smuzhiyun #define  V3_CLOCK_RATE_MASK		0x0000ff00
14*4882a593Smuzhiyun #define  V3_CLOCK_RATE_SHIFT		8
15*4882a593Smuzhiyun #define  V3_CLOCK_SOURCE_MASK		0x000000ff
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define V3_OPT_IFACE_MODE_OFFSET	0x0c94
18*4882a593Smuzhiyun #define  V3_ENABLE_OPT_IN_IFACE_A	0x00000001
19*4882a593Smuzhiyun #define  V3_ENABLE_OPT_IN_IFACE_B	0x00000002
20*4882a593Smuzhiyun #define  V3_ENABLE_OPT_OUT_IFACE_A	0x00000100
21*4882a593Smuzhiyun #define  V3_ENABLE_OPT_OUT_IFACE_B	0x00000200
22*4882a593Smuzhiyun #define  V3_NO_ADAT_OPT_IN_IFACE_A	0x00010000
23*4882a593Smuzhiyun #define  V3_NO_ADAT_OPT_IN_IFACE_B	0x00100000
24*4882a593Smuzhiyun #define  V3_NO_ADAT_OPT_OUT_IFACE_A	0x00040000
25*4882a593Smuzhiyun #define  V3_NO_ADAT_OPT_OUT_IFACE_B	0x00400000
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #define V3_MSG_FLAG_CLK_CHANGED		0x00000002
28*4882a593Smuzhiyun #define V3_CLK_WAIT_MSEC		4000
29*4882a593Smuzhiyun 
snd_motu_protocol_v3_get_clock_rate(struct snd_motu * motu,unsigned int * rate)30*4882a593Smuzhiyun int snd_motu_protocol_v3_get_clock_rate(struct snd_motu *motu,
31*4882a593Smuzhiyun 					unsigned int *rate)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	__be32 reg;
34*4882a593Smuzhiyun 	u32 data;
35*4882a593Smuzhiyun 	int err;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
38*4882a593Smuzhiyun 					sizeof(reg));
39*4882a593Smuzhiyun 	if (err < 0)
40*4882a593Smuzhiyun 		return err;
41*4882a593Smuzhiyun 	data = be32_to_cpu(reg);
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	data = (data & V3_CLOCK_RATE_MASK) >> V3_CLOCK_RATE_SHIFT;
44*4882a593Smuzhiyun 	if (data >= ARRAY_SIZE(snd_motu_clock_rates))
45*4882a593Smuzhiyun 		return -EIO;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	*rate = snd_motu_clock_rates[data];
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	return 0;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun 
snd_motu_protocol_v3_set_clock_rate(struct snd_motu * motu,unsigned int rate)52*4882a593Smuzhiyun int snd_motu_protocol_v3_set_clock_rate(struct snd_motu *motu,
53*4882a593Smuzhiyun 					unsigned int rate)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	__be32 reg;
56*4882a593Smuzhiyun 	u32 data;
57*4882a593Smuzhiyun 	bool need_to_wait;
58*4882a593Smuzhiyun 	int i, err;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
61*4882a593Smuzhiyun 		if (snd_motu_clock_rates[i] == rate)
62*4882a593Smuzhiyun 			break;
63*4882a593Smuzhiyun 	}
64*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(snd_motu_clock_rates))
65*4882a593Smuzhiyun 		return -EINVAL;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
68*4882a593Smuzhiyun 					sizeof(reg));
69*4882a593Smuzhiyun 	if (err < 0)
70*4882a593Smuzhiyun 		return err;
71*4882a593Smuzhiyun 	data = be32_to_cpu(reg);
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	data &= ~(V3_CLOCK_RATE_MASK | V3_FETCH_PCM_FRAMES);
74*4882a593Smuzhiyun 	data |= i << V3_CLOCK_RATE_SHIFT;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	need_to_wait = data != be32_to_cpu(reg);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	reg = cpu_to_be32(data);
79*4882a593Smuzhiyun 	err = snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, &reg,
80*4882a593Smuzhiyun 					 sizeof(reg));
81*4882a593Smuzhiyun 	if (err < 0)
82*4882a593Smuzhiyun 		return err;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	if (need_to_wait) {
85*4882a593Smuzhiyun 		int result;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 		motu->msg = 0;
88*4882a593Smuzhiyun 		result = wait_event_interruptible_timeout(motu->hwdep_wait,
89*4882a593Smuzhiyun 					motu->msg & V3_MSG_FLAG_CLK_CHANGED,
90*4882a593Smuzhiyun 					msecs_to_jiffies(V3_CLK_WAIT_MSEC));
91*4882a593Smuzhiyun 		if (result < 0)
92*4882a593Smuzhiyun 			return result;
93*4882a593Smuzhiyun 		if (result == 0)
94*4882a593Smuzhiyun 			return -ETIMEDOUT;
95*4882a593Smuzhiyun 	}
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	return 0;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
detect_clock_source_828mk3(struct snd_motu * motu,u32 data,enum snd_motu_clock_source * src)100*4882a593Smuzhiyun static int detect_clock_source_828mk3(struct snd_motu *motu, u32 data,
101*4882a593Smuzhiyun 				      enum snd_motu_clock_source *src)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	switch (data) {
104*4882a593Smuzhiyun 	case 0x00:
105*4882a593Smuzhiyun 		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
106*4882a593Smuzhiyun 		break;
107*4882a593Smuzhiyun 	case 0x01:
108*4882a593Smuzhiyun 		*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
109*4882a593Smuzhiyun 		break;
110*4882a593Smuzhiyun 	case 0x02:
111*4882a593Smuzhiyun 		*src = SND_MOTU_CLOCK_SOURCE_SPH;
112*4882a593Smuzhiyun 		break;
113*4882a593Smuzhiyun 	case 0x10:
114*4882a593Smuzhiyun 		*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
115*4882a593Smuzhiyun 		break;
116*4882a593Smuzhiyun 	case 0x18:
117*4882a593Smuzhiyun 	case 0x19:
118*4882a593Smuzhiyun 	{
119*4882a593Smuzhiyun 		__be32 reg;
120*4882a593Smuzhiyun 		u32 options;
121*4882a593Smuzhiyun 		int err;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 		err = snd_motu_transaction_read(motu,
124*4882a593Smuzhiyun 				V3_OPT_IFACE_MODE_OFFSET, &reg, sizeof(reg));
125*4882a593Smuzhiyun 		if (err < 0)
126*4882a593Smuzhiyun 			return err;
127*4882a593Smuzhiyun 		options = be32_to_cpu(reg);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 		if (data == 0x18) {
130*4882a593Smuzhiyun 			if (options & V3_NO_ADAT_OPT_IN_IFACE_A)
131*4882a593Smuzhiyun 				*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A;
132*4882a593Smuzhiyun 			else
133*4882a593Smuzhiyun 				*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A;
134*4882a593Smuzhiyun 		} else {
135*4882a593Smuzhiyun 			if (options & V3_NO_ADAT_OPT_IN_IFACE_B)
136*4882a593Smuzhiyun 				*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B;
137*4882a593Smuzhiyun 			else
138*4882a593Smuzhiyun 				*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B;
139*4882a593Smuzhiyun 		}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 		break;
142*4882a593Smuzhiyun 	}
143*4882a593Smuzhiyun 	default:
144*4882a593Smuzhiyun 		*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
145*4882a593Smuzhiyun 		break;
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
v3_detect_clock_source(struct snd_motu * motu,u32 data,enum snd_motu_clock_source * src)151*4882a593Smuzhiyun static int v3_detect_clock_source(struct snd_motu *motu, u32 data,
152*4882a593Smuzhiyun 				  enum snd_motu_clock_source *src)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	switch (data) {
155*4882a593Smuzhiyun 	case 0x00:
156*4882a593Smuzhiyun 		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
157*4882a593Smuzhiyun 		break;
158*4882a593Smuzhiyun 	case 0x01:
159*4882a593Smuzhiyun 		*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
160*4882a593Smuzhiyun 		break;
161*4882a593Smuzhiyun 	case 0x02:
162*4882a593Smuzhiyun 		*src = SND_MOTU_CLOCK_SOURCE_SPH;
163*4882a593Smuzhiyun 		break;
164*4882a593Smuzhiyun 	case 0x10:
165*4882a593Smuzhiyun 		*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
166*4882a593Smuzhiyun 		break;
167*4882a593Smuzhiyun 	default:
168*4882a593Smuzhiyun 		*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
169*4882a593Smuzhiyun 		break;
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	return 0;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
snd_motu_protocol_v3_get_clock_source(struct snd_motu * motu,enum snd_motu_clock_source * src)175*4882a593Smuzhiyun int snd_motu_protocol_v3_get_clock_source(struct snd_motu *motu,
176*4882a593Smuzhiyun 					  enum snd_motu_clock_source *src)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	__be32 reg;
179*4882a593Smuzhiyun 	u32 data;
180*4882a593Smuzhiyun 	int err;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
183*4882a593Smuzhiyun 					sizeof(reg));
184*4882a593Smuzhiyun 	if (err < 0)
185*4882a593Smuzhiyun 		return err;
186*4882a593Smuzhiyun 	data = be32_to_cpu(reg) & V3_CLOCK_SOURCE_MASK;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (motu->spec == &snd_motu_spec_828mk3)
189*4882a593Smuzhiyun 		return detect_clock_source_828mk3(motu, data, src);
190*4882a593Smuzhiyun 	else
191*4882a593Smuzhiyun 		return v3_detect_clock_source(motu, data, src);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
snd_motu_protocol_v3_switch_fetching_mode(struct snd_motu * motu,bool enable)194*4882a593Smuzhiyun int snd_motu_protocol_v3_switch_fetching_mode(struct snd_motu *motu,
195*4882a593Smuzhiyun 					      bool enable)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	__be32 reg;
198*4882a593Smuzhiyun 	u32 data;
199*4882a593Smuzhiyun 	int err;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
202*4882a593Smuzhiyun 					sizeof(reg));
203*4882a593Smuzhiyun 	if (err < 0)
204*4882a593Smuzhiyun 		return 0;
205*4882a593Smuzhiyun 	data = be32_to_cpu(reg);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	if (enable)
208*4882a593Smuzhiyun 		data |= V3_FETCH_PCM_FRAMES;
209*4882a593Smuzhiyun 	else
210*4882a593Smuzhiyun 		data &= ~V3_FETCH_PCM_FRAMES;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	reg = cpu_to_be32(data);
213*4882a593Smuzhiyun 	return snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, &reg,
214*4882a593Smuzhiyun 					  sizeof(reg));
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
detect_packet_formats_828mk3(struct snd_motu * motu,u32 data)217*4882a593Smuzhiyun static int detect_packet_formats_828mk3(struct snd_motu *motu, u32 data)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	if (data & V3_ENABLE_OPT_IN_IFACE_A) {
220*4882a593Smuzhiyun 		if (data & V3_NO_ADAT_OPT_IN_IFACE_A) {
221*4882a593Smuzhiyun 			motu->tx_packet_formats.pcm_chunks[0] += 4;
222*4882a593Smuzhiyun 			motu->tx_packet_formats.pcm_chunks[1] += 4;
223*4882a593Smuzhiyun 		} else {
224*4882a593Smuzhiyun 			motu->tx_packet_formats.pcm_chunks[0] += 8;
225*4882a593Smuzhiyun 			motu->tx_packet_formats.pcm_chunks[1] += 4;
226*4882a593Smuzhiyun 		}
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	if (data & V3_ENABLE_OPT_IN_IFACE_B) {
230*4882a593Smuzhiyun 		if (data & V3_NO_ADAT_OPT_IN_IFACE_B) {
231*4882a593Smuzhiyun 			motu->tx_packet_formats.pcm_chunks[0] += 4;
232*4882a593Smuzhiyun 			motu->tx_packet_formats.pcm_chunks[1] += 4;
233*4882a593Smuzhiyun 		} else {
234*4882a593Smuzhiyun 			motu->tx_packet_formats.pcm_chunks[0] += 8;
235*4882a593Smuzhiyun 			motu->tx_packet_formats.pcm_chunks[1] += 4;
236*4882a593Smuzhiyun 		}
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	if (data & V3_ENABLE_OPT_OUT_IFACE_A) {
240*4882a593Smuzhiyun 		if (data & V3_NO_ADAT_OPT_OUT_IFACE_A) {
241*4882a593Smuzhiyun 			motu->rx_packet_formats.pcm_chunks[0] += 4;
242*4882a593Smuzhiyun 			motu->rx_packet_formats.pcm_chunks[1] += 4;
243*4882a593Smuzhiyun 		} else {
244*4882a593Smuzhiyun 			motu->rx_packet_formats.pcm_chunks[0] += 8;
245*4882a593Smuzhiyun 			motu->rx_packet_formats.pcm_chunks[1] += 4;
246*4882a593Smuzhiyun 		}
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	if (data & V3_ENABLE_OPT_OUT_IFACE_B) {
250*4882a593Smuzhiyun 		if (data & V3_NO_ADAT_OPT_OUT_IFACE_B) {
251*4882a593Smuzhiyun 			motu->rx_packet_formats.pcm_chunks[0] += 4;
252*4882a593Smuzhiyun 			motu->rx_packet_formats.pcm_chunks[1] += 4;
253*4882a593Smuzhiyun 		} else {
254*4882a593Smuzhiyun 			motu->rx_packet_formats.pcm_chunks[0] += 8;
255*4882a593Smuzhiyun 			motu->rx_packet_formats.pcm_chunks[1] += 4;
256*4882a593Smuzhiyun 		}
257*4882a593Smuzhiyun 	}
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	return 0;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
snd_motu_protocol_v3_cache_packet_formats(struct snd_motu * motu)262*4882a593Smuzhiyun int snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	__be32 reg;
265*4882a593Smuzhiyun 	u32 data;
266*4882a593Smuzhiyun 	int err;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	motu->tx_packet_formats.pcm_byte_offset = 10;
269*4882a593Smuzhiyun 	motu->rx_packet_formats.pcm_byte_offset = 10;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	motu->tx_packet_formats.msg_chunks = 2;
272*4882a593Smuzhiyun 	motu->rx_packet_formats.msg_chunks = 2;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, &reg,
275*4882a593Smuzhiyun 					sizeof(reg));
276*4882a593Smuzhiyun 	if (err < 0)
277*4882a593Smuzhiyun 		return err;
278*4882a593Smuzhiyun 	data = be32_to_cpu(reg);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	memcpy(motu->tx_packet_formats.pcm_chunks,
281*4882a593Smuzhiyun 	       motu->spec->tx_fixed_pcm_chunks,
282*4882a593Smuzhiyun 	       sizeof(motu->tx_packet_formats.pcm_chunks));
283*4882a593Smuzhiyun 	memcpy(motu->rx_packet_formats.pcm_chunks,
284*4882a593Smuzhiyun 	       motu->spec->rx_fixed_pcm_chunks,
285*4882a593Smuzhiyun 	       sizeof(motu->rx_packet_formats.pcm_chunks));
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	if (motu->spec == &snd_motu_spec_828mk3)
288*4882a593Smuzhiyun 		return detect_packet_formats_828mk3(motu, data);
289*4882a593Smuzhiyun 	else
290*4882a593Smuzhiyun 		return 0;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun const struct snd_motu_spec snd_motu_spec_828mk3 = {
295*4882a593Smuzhiyun 	.name = "828mk3",
296*4882a593Smuzhiyun 	.protocol_version = SND_MOTU_PROTOCOL_V3,
297*4882a593Smuzhiyun 	.flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
298*4882a593Smuzhiyun 		 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
299*4882a593Smuzhiyun 	.tx_fixed_pcm_chunks = {18, 18, 14},
300*4882a593Smuzhiyun 	.rx_fixed_pcm_chunks = {14, 14, 10},
301*4882a593Smuzhiyun };
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun const struct snd_motu_spec snd_motu_spec_ultralite_mk3 = {
304*4882a593Smuzhiyun 	.name = "UltraLiteMk3",
305*4882a593Smuzhiyun 	.protocol_version = SND_MOTU_PROTOCOL_V3,
306*4882a593Smuzhiyun 	.flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
307*4882a593Smuzhiyun 		 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
308*4882a593Smuzhiyun 	.tx_fixed_pcm_chunks = {18, 14, 10},
309*4882a593Smuzhiyun 	.rx_fixed_pcm_chunks = {14, 14, 14},
310*4882a593Smuzhiyun };
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun const struct snd_motu_spec snd_motu_spec_audio_express = {
313*4882a593Smuzhiyun 	.name = "AudioExpress",
314*4882a593Smuzhiyun 	.protocol_version = SND_MOTU_PROTOCOL_V3,
315*4882a593Smuzhiyun 	.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
316*4882a593Smuzhiyun 		 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
317*4882a593Smuzhiyun 	.tx_fixed_pcm_chunks = {10, 10, 0},
318*4882a593Smuzhiyun 	.rx_fixed_pcm_chunks = {10, 10, 0},
319*4882a593Smuzhiyun };
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun const struct snd_motu_spec snd_motu_spec_4pre = {
322*4882a593Smuzhiyun 	.name = "4pre",
323*4882a593Smuzhiyun 	.protocol_version = SND_MOTU_PROTOCOL_V3,
324*4882a593Smuzhiyun 	.tx_fixed_pcm_chunks = {10, 10, 0},
325*4882a593Smuzhiyun 	.rx_fixed_pcm_chunks = {10, 10, 0},
326*4882a593Smuzhiyun };
327