// SPDX-License-Identifier: GPL-2.0 // ff-protocol-latter.c - a part of driver for RME Fireface series // // Copyright (c) 2019 Takashi Sakamoto #include <linux/delay.h> #include "ff.h" #define LATTER_STF … #define LATTER_ISOC_CHANNELS … #define LATTER_ISOC_START … #define LATTER_FETCH_MODE … #define LATTER_SYNC_STATUS … // The content of sync status register differs between models. // // Fireface UCX: // 0xf0000000: (unidentified) // 0x0f000000: effective rate of sampling clock // 0x00f00000: detected rate of word clock on BNC interface // 0x000f0000: detected rate of ADAT or S/PDIF on optical interface // 0x0000f000: detected rate of S/PDIF on coaxial interface // 0x00000e00: effective source of sampling clock // 0x00000e00: Internal // 0x00000800: (unidentified) // 0x00000600: Word clock on BNC interface // 0x00000400: ADAT on optical interface // 0x00000200: S/PDIF on coaxial or optical interface // 0x00000100: Optical interface is used for ADAT signal // 0x00000080: (unidentified) // 0x00000040: Synchronized to word clock on BNC interface // 0x00000020: Synchronized to ADAT or S/PDIF on optical interface // 0x00000010: Synchronized to S/PDIF on coaxial interface // 0x00000008: (unidentified) // 0x00000004: Lock word clock on BNC interface // 0x00000002: Lock ADAT or S/PDIF on optical interface // 0x00000001: Lock S/PDIF on coaxial interface // // Fireface 802 (and perhaps UFX): // 0xf0000000: effective rate of sampling clock // 0x0f000000: detected rate of ADAT-B on 2nd optical interface // 0x00f00000: detected rate of ADAT-A on 1st optical interface // 0x000f0000: detected rate of AES/EBU on XLR or coaxial interface // 0x0000f000: detected rate of word clock on BNC interface // 0x00000e00: effective source of sampling clock // 0x00000e00: internal // 0x00000800: ADAT-B // 0x00000600: ADAT-A // 0x00000400: AES/EBU // 0x00000200: Word clock // 0x00000080: Synchronized to ADAT-B on 2nd optical interface // 0x00000040: Synchronized to ADAT-A on 1st optical interface // 0x00000020: Synchronized to AES/EBU on XLR or 2nd optical interface // 0x00000010: Synchronized to word clock on BNC interface // 0x00000008: Lock ADAT-B on 2nd optical interface // 0x00000004: Lock ADAT-A on 1st optical interface // 0x00000002: Lock AES/EBU on XLR or 2nd optical interface // 0x00000001: Lock word clock on BNC interface // // The pattern for rate bits: // 0x00: 32.0 kHz // 0x01: 44.1 kHz // 0x02: 48.0 kHz // 0x04: 64.0 kHz // 0x05: 88.2 kHz // 0x06: 96.0 kHz // 0x08: 128.0 kHz // 0x09: 176.4 kHz // 0x0a: 192.0 kHz static int parse_clock_bits(u32 data, unsigned int *rate, enum snd_ff_clock_src *src, enum snd_ff_unit_version unit_version) { … } static int latter_get_clock(struct snd_ff *ff, unsigned int *rate, enum snd_ff_clock_src *src) { … } static int latter_switch_fetching_mode(struct snd_ff *ff, bool enable) { … } static int latter_allocate_resources(struct snd_ff *ff, unsigned int rate) { … } static int latter_begin_session(struct snd_ff *ff, unsigned int rate) { … } static void latter_finish_session(struct snd_ff *ff) { … } static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer) { … } // NOTE: transactions are transferred within 0x00-0x7f in allocated range of // address. This seems to be for check of discontinuity in receiver side. // // Like Fireface 400, drivers can select one of 4 options for lower 4 bytes of // destination address by bit flags in quadlet register (little endian) at // 0x'ffff'0000'0014: // // bit flags: offset of destination address // - 0x00002000: 0x'....'....'0000'0000 // - 0x00004000: 0x'....'....'0000'0080 // - 0x00008000: 0x'....'....'0000'0100 // - 0x00010000: 0x'....'....'0000'0180 // // Drivers can suppress the device to transfer asynchronous transactions by // clear these bit flags. // // Actually, the register is write-only and includes the other settings such as // input attenuation. This driver allocates for the first option // (0x'....'....'0000'0000) and expects userspace application to configure the // register for it. static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset, const __le32 *buf, size_t length, u32 tstamp) { … } /* * When return minus value, given argument is not MIDI status. * When return 0, given argument is a beginning of system exclusive. * When return the others, given argument is MIDI data. */ static inline int calculate_message_bytes(u8 status) { … } static int latter_fill_midi_msg(struct snd_ff *ff, struct snd_rawmidi_substream *substream, unsigned int port) { … } const struct snd_ff_protocol snd_ff_protocol_latter = …;