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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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