1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 // motu-protocol-v1.c - a part of driver for MOTU FireWire series
4 //
5 // Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6 //
7 // Licensed under the terms of the GNU General Public License, version 2.
8 
9 #include "motu.h"
10 
11 #include <linux/delay.h>
12 
13 // Status register for MOTU 828 (0x'ffff'f000'0b00).
14 //
15 // 0xffff0000: ISOC_COMM_CONTROL_MASK in motu-stream.c.
16 // 0x00008000: mode of optical input interface.
17 //   0x00008000: for S/PDIF signal.
18 //   0x00000000: disabled or for ADAT signal.
19 // 0x00004000: mode of optical output interface.
20 //   0x00004000: for S/PDIF signal.
21 //   0x00000000: disabled or for ADAT signal.
22 // 0x00003f40: monitor input mode.
23 //   0x00000800: analog-1/2
24 //   0x00001a00: analog-3/4
25 //   0x00002c00: analog-5/6
26 //   0x00003e00: analog-7/8
27 //   0x00000000: analog-1
28 //   0x00000900: analog-2
29 //   0x00001200: analog-3
30 //   0x00001b00: analog-4
31 //   0x00002400: analog-5
32 //   0x00002d00: analog-6
33 //   0x00003600: analog-7
34 //   0x00003f00: analog-8
35 //   0x00000040: disabled
36 // 0x00000004: rate of sampling clock.
37 //   0x00000004: 48.0 kHz
38 //   0x00000000: 44.1 kHz
39 // 0x00000023: source of sampling clock.
40 //   0x00000002: S/PDIF on optical/coaxial interface.
41 //   0x00000021: ADAT on optical interface
42 //   0x00000001: ADAT on Dsub 9pin
43 //   0x00000000: internal or SMPTE
44 
45 #define CLK_828_STATUS_OFFSET				0x0b00
46 #define  CLK_828_STATUS_MASK				0x0000ffff
47 #define  CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF	0x00008000
48 #define  CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF	0x00004000
49 #define  CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES		0x00000080
50 #define  CLK_828_STATUS_FLAG_SRC_IS_NOT_FROM_ADAT_DSUB	0x00000020
51 #define  CLK_828_STATUS_FLAG_OUTPUT_MUTE		0x00000008
52 #define  CLK_828_STATUS_FLAG_RATE_48000			0x00000004
53 #define  CLK_828_STATUS_FLAG_SRC_SPDIF_ON_OPT_OR_COAX	0x00000002
54 #define  CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT_OR_DSUB	0x00000001
55 
56 static void parse_clock_rate_828(u32 data, unsigned int *rate)
57 {
58 	if (data & CLK_828_STATUS_FLAG_RATE_48000)
59 		*rate = 48000;
60 	else
61 		*rate = 44100;
62 }
63 
64 static int get_clock_rate_828(struct snd_motu *motu, unsigned int *rate)
65 {
66 	__be32 reg;
67 	int err;
68 
69 	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
70 	if (err < 0)
71 		return err;
72 	parse_clock_rate_828(be32_to_cpu(reg), rate);
73 
74 	return 0;
75 }
76 
77 int snd_motu_protocol_v1_get_clock_rate(struct snd_motu *motu, unsigned int *rate)
78 {
79 	if (motu->spec == &snd_motu_spec_828)
80 		return get_clock_rate_828(motu, rate);
81 	else
82 		return -ENXIO;
83 }
84 
85 static int set_clock_rate_828(struct snd_motu *motu, unsigned int rate)
86 {
87 	__be32 reg;
88 	u32 data;
89 	int err;
90 
91 	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
92 	if (err < 0)
93 		return err;
94 	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
95 
96 	data &= ~CLK_828_STATUS_FLAG_RATE_48000;
97 	if (rate == 48000)
98 		data |= CLK_828_STATUS_FLAG_RATE_48000;
99 
100 	reg = cpu_to_be32(data);
101 	return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
102 }
103 
104 int snd_motu_protocol_v1_set_clock_rate(struct snd_motu *motu, unsigned int rate)
105 {
106 	if (motu->spec == &snd_motu_spec_828)
107 		return set_clock_rate_828(motu, rate);
108 	else
109 		return -ENXIO;
110 }
111 
112 static int get_clock_source_828(struct snd_motu *motu, enum snd_motu_clock_source *src)
113 {
114 	__be32 reg;
115 	u32 data;
116 	int err;
117 
118 	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
119 	if (err < 0)
120 		return err;
121 	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
122 
123 	if (data & CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT_OR_DSUB) {
124 		if (data & CLK_828_STATUS_FLAG_SRC_IS_NOT_FROM_ADAT_DSUB)
125 			*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
126 		else
127 			*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
128 	} else if (data & CLK_828_STATUS_FLAG_SRC_SPDIF_ON_OPT_OR_COAX) {
129 		if (data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF)
130 			*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
131 		else
132 			*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
133 	} else {
134 		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
135 	}
136 
137 	return 0;
138 }
139 
140 int snd_motu_protocol_v1_get_clock_source(struct snd_motu *motu, enum snd_motu_clock_source *src)
141 {
142 	if (motu->spec == &snd_motu_spec_828)
143 		return get_clock_source_828(motu, src);
144 	else
145 		return -ENXIO;
146 }
147 
148 static int switch_fetching_mode_828(struct snd_motu *motu, bool enable)
149 {
150 	__be32 reg;
151 	u32 data;
152 	int err;
153 
154 	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
155 	if (err < 0)
156 		return err;
157 	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
158 
159 	data &= ~(CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_OUTPUT_MUTE);
160 	if (enable) {
161 		// This transaction should be initiated after the device receives batch of packets
162 		// since the device voluntarily mutes outputs. As a workaround, yield processor over
163 		// 100 msec.
164 		msleep(100);
165 		data |= CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_OUTPUT_MUTE;
166 	}
167 
168 	reg = cpu_to_be32(data);
169 	return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
170 }
171 
172 int snd_motu_protocol_v1_switch_fetching_mode(struct snd_motu *motu, bool enable)
173 {
174 	if (motu->spec == &snd_motu_spec_828)
175 		return switch_fetching_mode_828(motu, enable);
176 	else
177 		return -ENXIO;
178 }
179 
180 static int detect_packet_formats_828(struct snd_motu *motu)
181 {
182 	__be32 reg;
183 	u32 data;
184 	int err;
185 
186 	motu->tx_packet_formats.pcm_byte_offset = 4;
187 	motu->tx_packet_formats.msg_chunks = 2;
188 
189 	motu->rx_packet_formats.pcm_byte_offset = 4;
190 	motu->rx_packet_formats.msg_chunks = 0;
191 
192 	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
193 	if (err < 0)
194 		return err;
195 	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
196 
197 	// The number of chunks is just reduced when SPDIF is activated.
198 	if (!(data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF))
199 		motu->tx_packet_formats.pcm_chunks[0] += 8;
200 
201 	if (!(data & CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF))
202 		motu->rx_packet_formats.pcm_chunks[0] += 8;
203 
204 	return 0;
205 }
206 
207 int snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu)
208 {
209 	memcpy(motu->tx_packet_formats.pcm_chunks, motu->spec->tx_fixed_pcm_chunks,
210 	       sizeof(motu->tx_packet_formats.pcm_chunks));
211 	memcpy(motu->rx_packet_formats.pcm_chunks, motu->spec->rx_fixed_pcm_chunks,
212 	       sizeof(motu->rx_packet_formats.pcm_chunks));
213 
214 	if (motu->spec == &snd_motu_spec_828)
215 		return detect_packet_formats_828(motu);
216 	else
217 		return 0;
218 }
219 
220 const struct snd_motu_spec snd_motu_spec_828 = {
221 	.name = "828",
222 	.protocol_version = SND_MOTU_PROTOCOL_V1,
223 	.tx_fixed_pcm_chunks = {10, 0, 0},
224 	.rx_fixed_pcm_chunks = {10, 0, 0},
225 };
226