All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] ALSA: firewire-motu: add support for MOTU 828 and 896
@ 2021-06-16  8:28 Takashi Sakamoto
  2021-06-16  8:28 ` [PATCH 1/2] ALSA: firewire-motu: add support for MOTU 828 Takashi Sakamoto
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Takashi Sakamoto @ 2021-06-16  8:28 UTC (permalink / raw)
  To: tiwai; +Cc: alsa-devel, clemens

Hi,

This patchset is to add support for Mark of the unicorn (MOTU) 828 and
896, which were shipped two decades ago (2001) and already discontinued.
(yes, it's 2021).

It's reasonable to count them as first generation of MOTU FireWire
series since they are based on QuickLogic QuickRAM FPGA apart from
Altera or Xilinx FPGA in the latter generation. Unlike the latter
generation, they doesn't allow software to configure internal
multiplexer.

I note that the sequence replay for media clock recovery[1] allows to
support them. The device doesn't generate better sound with nominal (ideal)
sequence of packets, thus the patches should be applied to development
tree for v5.14 kernel.

[1] [PATCH 0/3] ALSA: firewire-motu: media clock recovery for sph-aware devices
https://lore.kernel.org/alsa-devel/20210602013406.26442-1-o-takashi@sakamocchi.jp/

Takashi Sakamoto (2):
  ALSA: firewire-motu: add support for MOTU 828
  ALSA: firewire-motu: add support for MOTU 896

 sound/firewire/Kconfig                 |   2 +
 sound/firewire/motu/Makefile           |   3 +-
 sound/firewire/motu/motu-protocol-v1.c | 440 +++++++++++++++++++++++++
 sound/firewire/motu/motu.c             |   2 +
 sound/firewire/motu/motu.h             |  24 ++
 5 files changed, 470 insertions(+), 1 deletion(-)
 create mode 100644 sound/firewire/motu/motu-protocol-v1.c

-- 
2.30.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] ALSA: firewire-motu: add support for MOTU 828
  2021-06-16  8:28 [PATCH 0/2] ALSA: firewire-motu: add support for MOTU 828 and 896 Takashi Sakamoto
@ 2021-06-16  8:28 ` Takashi Sakamoto
  2021-06-16  8:28 ` [PATCH 2/2] ALSA: firewire-motu: add support for MOTU 896 Takashi Sakamoto
  2021-06-17  9:37 ` [PATCH 0/2] ALSA: firewire-motu: add support for MOTU 828 and 896 Takashi Iwai
  2 siblings, 0 replies; 5+ messages in thread
From: Takashi Sakamoto @ 2021-06-16  8:28 UTC (permalink / raw)
  To: tiwai; +Cc: alsa-devel, clemens

MOTU 828 is a first model in MOTU FireWire series, produced in 2001. This
model consists of three chips:
 * Texas Instruments TSB41AB1 (Physical layer for IEEE 1394 bus)
 * Philips Semiconductors 1394L21BE (Link layer for IEEE 1394 bus and
   packet processing layer)
 * QuickLogic QuickRAM QL4016 (Data block processing layer and digital
   signal processing)

This commit adds a support for this model, with its unique protocol as
version 1. The features of this protocol are:

 * no MIDI support.
 * Rx packets have no data chunks for control and status messages.
 * Tx packets have 2 data chunks for control and status messages in the
   end of each data block. The chunks consist of data block counter
   (4 byte) and message (2 byte).
 * All of settings are represented in bit flag in one quadlet address
   (0x'ffff'f000'0b00).
 * When optical interface is configured as S/PDIF, signals of the interface
   is multiplexed for packets, instead of signals of coaxial interface.
 * The internal multiplexer is not configured by software.

I note that the device has a quirk to mute output voluntarily during
receiving batch of packets in the beginning of packet streaming. The
operation to unmute should be done by software enough after the device
shifts the state, however it's not deterministic. Furthermore, just
after switching rate of sampling clock, the device keeps the state longer.
This patch manages to sleep 100 msec before unmute operation, but it may
fail to release the mute in the case that the rate is changed. As a
workaround, users can restart packet streaming at the same rate, or write
to specific register from userspace.

$ python3 crpp < /sys/bus/firewire/devices/fw1/config_rom
               ROM header and bus information block
               -----------------------------------------------------------------
400  04105c54  bus_info_length 4, crc_length 16, crc 23636
404  31333934  bus_name "1394"
408  20001000  irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 0, max_rec 1 (4)
40c  0001f200  company_id 0001f2     |
410  00005015  device_id 0000005015  | EUI-64 0001f20000005015

               root directory
               -----------------------------------------------------------------
414  0004c65c  directory_length 4, crc 50780
418  030001f2  vendor
41c  0c0083c0  node capabilities per IEEE 1394
420  8d000006  --> eui-64 leaf at 438
424  d1000001  --> unit directory at 428

               unit directory at 428
               -----------------------------------------------------------------
428  00035052  directory_length 3, crc 20562
42c  120001f2  specifier id
430  13000001  version
434  17101800  model

               eui-64 leaf at 438
               -----------------------------------------------------------------
438  0002eeb6  leaf_length 2, crc 61110
43c  0001f200  company_id 0001f2     |
440  00005015  device_id 0000005015  | EUI-64 0001f20000005015

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/Kconfig                 |   1 +
 sound/firewire/motu/Makefile           |   3 +-
 sound/firewire/motu/motu-protocol-v1.c | 225 +++++++++++++++++++++++++
 sound/firewire/motu/motu.c             |   1 +
 sound/firewire/motu/motu.h             |  23 +++
 5 files changed, 252 insertions(+), 1 deletion(-)
 create mode 100644 sound/firewire/motu/motu-protocol-v1.c

diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index a08a0dbfc951..a70732bbddab 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -165,6 +165,7 @@ config SND_FIREWIRE_MOTU
 	select SND_HWDEP
 	help
 	 Say Y here to enable support for FireWire devices which MOTU produced:
+	  * 828
 	  * 828mk2
 	  * Traveler
 	  * Ultralite
diff --git a/sound/firewire/motu/Makefile b/sound/firewire/motu/Makefile
index 7c502d35103c..acdf66564fb0 100644
--- a/sound/firewire/motu/Makefile
+++ b/sound/firewire/motu/Makefile
@@ -3,5 +3,6 @@ CFLAGS_amdtp-motu.o	:= -I$(src)
 
 snd-firewire-motu-objs := motu.o amdtp-motu.o motu-transaction.o motu-stream.o \
 			  motu-proc.o motu-pcm.o motu-midi.o motu-hwdep.o \
-			  motu-protocol-v2.o motu-protocol-v3.o
+			  motu-protocol-v2.o motu-protocol-v3.o \
+			  motu-protocol-v1.o
 obj-$(CONFIG_SND_FIREWIRE_MOTU) += snd-firewire-motu.o
diff --git a/sound/firewire/motu/motu-protocol-v1.c b/sound/firewire/motu/motu-protocol-v1.c
new file mode 100644
index 000000000000..fab6aef392af
--- /dev/null
+++ b/sound/firewire/motu/motu-protocol-v1.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+// motu-protocol-v1.c - a part of driver for MOTU FireWire series
+//
+// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+//
+// Licensed under the terms of the GNU General Public License, version 2.
+
+#include "motu.h"
+
+#include <linux/delay.h>
+
+// Status register for MOTU 828 (0x'ffff'f000'0b00).
+//
+// 0xffff0000: ISOC_COMM_CONTROL_MASK in motu-stream.c.
+// 0x00008000: mode of optical input interface.
+//   0x00008000: for S/PDIF signal.
+//   0x00000000: disabled or for ADAT signal.
+// 0x00004000: mode of optical output interface.
+//   0x00004000: for S/PDIF signal.
+//   0x00000000: disabled or for ADAT signal.
+// 0x00003f40: monitor input mode.
+//   0x00000800: analog-1/2
+//   0x00001a00: analog-3/4
+//   0x00002c00: analog-5/6
+//   0x00003e00: analog-7/8
+//   0x00000000: analog-1
+//   0x00000900: analog-2
+//   0x00001200: analog-3
+//   0x00001b00: analog-4
+//   0x00002400: analog-5
+//   0x00002d00: analog-6
+//   0x00003600: analog-7
+//   0x00003f00: analog-8
+//   0x00000040: disabled
+// 0x00000004: rate of sampling clock.
+//   0x00000004: 48.0 kHz
+//   0x00000000: 44.1 kHz
+// 0x00000023: source of sampling clock.
+//   0x00000002: S/PDIF on optical/coaxial interface.
+//   0x00000021: ADAT on optical interface
+//   0x00000001: ADAT on Dsub 9pin
+//   0x00000000: internal or SMPTE
+
+#define CLK_828_STATUS_OFFSET				0x0b00
+#define  CLK_828_STATUS_MASK				0x0000ffff
+#define  CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF	0x00008000
+#define  CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF	0x00004000
+#define  CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES		0x00000080
+#define  CLK_828_STATUS_FLAG_SRC_IS_NOT_FROM_ADAT_DSUB	0x00000020
+#define  CLK_828_STATUS_FLAG_OUTPUT_MUTE		0x00000008
+#define  CLK_828_STATUS_FLAG_RATE_48000			0x00000004
+#define  CLK_828_STATUS_FLAG_SRC_SPDIF_ON_OPT_OR_COAX	0x00000002
+#define  CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT_OR_DSUB	0x00000001
+
+static void parse_clock_rate_828(u32 data, unsigned int *rate)
+{
+	if (data & CLK_828_STATUS_FLAG_RATE_48000)
+		*rate = 48000;
+	else
+		*rate = 44100;
+}
+
+static int get_clock_rate_828(struct snd_motu *motu, unsigned int *rate)
+{
+	__be32 reg;
+	int err;
+
+	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
+	if (err < 0)
+		return err;
+	parse_clock_rate_828(be32_to_cpu(reg), rate);
+
+	return 0;
+}
+
+int snd_motu_protocol_v1_get_clock_rate(struct snd_motu *motu, unsigned int *rate)
+{
+	if (motu->spec == &snd_motu_spec_828)
+		return get_clock_rate_828(motu, rate);
+	else
+		return -ENXIO;
+}
+
+static int set_clock_rate_828(struct snd_motu *motu, unsigned int rate)
+{
+	__be32 reg;
+	u32 data;
+	int err;
+
+	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
+	if (err < 0)
+		return err;
+	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
+
+	data &= ~CLK_828_STATUS_FLAG_RATE_48000;
+	if (rate == 48000)
+		data |= CLK_828_STATUS_FLAG_RATE_48000;
+
+	reg = cpu_to_be32(data);
+	return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
+}
+
+int snd_motu_protocol_v1_set_clock_rate(struct snd_motu *motu, unsigned int rate)
+{
+	if (motu->spec == &snd_motu_spec_828)
+		return set_clock_rate_828(motu, rate);
+	else
+		return -ENXIO;
+}
+
+static int get_clock_source_828(struct snd_motu *motu, enum snd_motu_clock_source *src)
+{
+	__be32 reg;
+	u32 data;
+	int err;
+
+	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
+	if (err < 0)
+		return err;
+	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
+
+	if (data & CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT_OR_DSUB) {
+		if (data & CLK_828_STATUS_FLAG_SRC_IS_NOT_FROM_ADAT_DSUB)
+			*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
+		else
+			*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
+	} else if (data & CLK_828_STATUS_FLAG_SRC_SPDIF_ON_OPT_OR_COAX) {
+		if (data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF)
+			*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
+		else
+			*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
+	} else {
+		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
+	}
+
+	return 0;
+}
+
+int snd_motu_protocol_v1_get_clock_source(struct snd_motu *motu, enum snd_motu_clock_source *src)
+{
+	if (motu->spec == &snd_motu_spec_828)
+		return get_clock_source_828(motu, src);
+	else
+		return -ENXIO;
+}
+
+static int switch_fetching_mode_828(struct snd_motu *motu, bool enable)
+{
+	__be32 reg;
+	u32 data;
+	int err;
+
+	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
+	if (err < 0)
+		return err;
+	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
+
+	data &= ~(CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_OUTPUT_MUTE);
+	if (enable) {
+		// This transaction should be initiated after the device receives batch of packets
+		// since the device voluntarily mutes outputs. As a workaround, yield processor over
+		// 100 msec.
+		msleep(100);
+		data |= CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_OUTPUT_MUTE;
+	}
+
+	reg = cpu_to_be32(data);
+	return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
+}
+
+int snd_motu_protocol_v1_switch_fetching_mode(struct snd_motu *motu, bool enable)
+{
+	if (motu->spec == &snd_motu_spec_828)
+		return switch_fetching_mode_828(motu, enable);
+	else
+		return -ENXIO;
+}
+
+static int detect_packet_formats_828(struct snd_motu *motu)
+{
+	__be32 reg;
+	u32 data;
+	int err;
+
+	motu->tx_packet_formats.pcm_byte_offset = 4;
+	motu->tx_packet_formats.msg_chunks = 2;
+
+	motu->rx_packet_formats.pcm_byte_offset = 4;
+	motu->rx_packet_formats.msg_chunks = 0;
+
+	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
+	if (err < 0)
+		return err;
+	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
+
+	// The number of chunks is just reduced when SPDIF is activated.
+	if (!(data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF))
+		motu->tx_packet_formats.pcm_chunks[0] += 8;
+
+	if (!(data & CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF))
+		motu->rx_packet_formats.pcm_chunks[0] += 8;
+
+	return 0;
+}
+
+int snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu)
+{
+	memcpy(motu->tx_packet_formats.pcm_chunks, motu->spec->tx_fixed_pcm_chunks,
+	       sizeof(motu->tx_packet_formats.pcm_chunks));
+	memcpy(motu->rx_packet_formats.pcm_chunks, motu->spec->rx_fixed_pcm_chunks,
+	       sizeof(motu->rx_packet_formats.pcm_chunks));
+
+	if (motu->spec == &snd_motu_spec_828)
+		return detect_packet_formats_828(motu);
+	else
+		return 0;
+}
+
+const struct snd_motu_spec snd_motu_spec_828 = {
+	.name = "828",
+	.protocol_version = SND_MOTU_PROTOCOL_V1,
+	.tx_fixed_pcm_chunks = {10, 0, 0},
+	.rx_fixed_pcm_chunks = {10, 0, 0},
+};
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c
index 531eeb36eb87..add5f183dc1d 100644
--- a/sound/firewire/motu/motu.c
+++ b/sound/firewire/motu/motu.c
@@ -150,6 +150,7 @@ static void motu_bus_update(struct fw_unit *unit)
 }
 
 static const struct ieee1394_device_id motu_id_table[] = {
+	SND_MOTU_DEV_ENTRY(0x000001, &snd_motu_spec_828),
 	SND_MOTU_DEV_ENTRY(0x000003, &snd_motu_spec_828mk2),
 	SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler),
 	SND_MOTU_DEV_ENTRY(0x00000d, &snd_motu_spec_ultralite),
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h
index c5c0e446deb2..13e2637a0330 100644
--- a/sound/firewire/motu/motu.h
+++ b/sound/firewire/motu/motu.h
@@ -107,6 +107,7 @@ enum snd_motu_clock_source {
 };
 
 enum snd_motu_protocol_version {
+	SND_MOTU_PROTOCOL_V1,
 	SND_MOTU_PROTOCOL_V2,
 	SND_MOTU_PROTOCOL_V3,
 };
@@ -121,6 +122,8 @@ struct snd_motu_spec {
 	unsigned char rx_fixed_pcm_chunks[3];
 };
 
+extern const struct snd_motu_spec snd_motu_spec_828;
+
 extern const struct snd_motu_spec snd_motu_spec_828mk2;
 extern const struct snd_motu_spec snd_motu_spec_traveler;
 extern const struct snd_motu_spec snd_motu_spec_ultralite;
@@ -170,6 +173,16 @@ int snd_motu_create_midi_devices(struct snd_motu *motu);
 
 int snd_motu_create_hwdep_device(struct snd_motu *motu);
 
+int snd_motu_protocol_v1_get_clock_rate(struct snd_motu *motu,
+					unsigned int *rate);
+int snd_motu_protocol_v1_set_clock_rate(struct snd_motu *motu,
+					unsigned int rate);
+int snd_motu_protocol_v1_get_clock_source(struct snd_motu *motu,
+					  enum snd_motu_clock_source *src);
+int snd_motu_protocol_v1_switch_fetching_mode(struct snd_motu *motu,
+					      bool enable);
+int snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu);
+
 int snd_motu_protocol_v2_get_clock_rate(struct snd_motu *motu,
 					unsigned int *rate);
 int snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu,
@@ -197,6 +210,8 @@ static inline int snd_motu_protocol_get_clock_rate(struct snd_motu *motu,
 		return snd_motu_protocol_v2_get_clock_rate(motu, rate);
 	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
 		return snd_motu_protocol_v3_get_clock_rate(motu, rate);
+	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
+		return snd_motu_protocol_v1_get_clock_rate(motu, rate);
 	else
 		return -ENXIO;
 }
@@ -208,6 +223,8 @@ static inline int snd_motu_protocol_set_clock_rate(struct snd_motu *motu,
 		return snd_motu_protocol_v2_set_clock_rate(motu, rate);
 	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
 		return snd_motu_protocol_v3_set_clock_rate(motu, rate);
+	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
+		return snd_motu_protocol_v1_set_clock_rate(motu, rate);
 	else
 		return -ENXIO;
 }
@@ -219,6 +236,8 @@ static inline int snd_motu_protocol_get_clock_source(struct snd_motu *motu,
 		return snd_motu_protocol_v2_get_clock_source(motu, source);
 	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
 		return snd_motu_protocol_v3_get_clock_source(motu, source);
+	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
+		return snd_motu_protocol_v1_get_clock_source(motu, source);
 	else
 		return -ENXIO;
 }
@@ -230,6 +249,8 @@ static inline int snd_motu_protocol_switch_fetching_mode(struct snd_motu *motu,
 		return snd_motu_protocol_v2_switch_fetching_mode(motu, enable);
 	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
 		return snd_motu_protocol_v3_switch_fetching_mode(motu, enable);
+	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
+		return snd_motu_protocol_v1_switch_fetching_mode(motu, enable);
 	else
 		return -ENXIO;
 }
@@ -240,6 +261,8 @@ static inline int snd_motu_protocol_cache_packet_formats(struct snd_motu *motu)
 		return snd_motu_protocol_v2_cache_packet_formats(motu);
 	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
 		return snd_motu_protocol_v3_cache_packet_formats(motu);
+	else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
+		return snd_motu_protocol_v1_cache_packet_formats(motu);
 	else
 		return -ENXIO;
 }
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] ALSA: firewire-motu: add support for MOTU 896
  2021-06-16  8:28 [PATCH 0/2] ALSA: firewire-motu: add support for MOTU 828 and 896 Takashi Sakamoto
  2021-06-16  8:28 ` [PATCH 1/2] ALSA: firewire-motu: add support for MOTU 828 Takashi Sakamoto
@ 2021-06-16  8:28 ` Takashi Sakamoto
  2021-06-17  9:37 ` [PATCH 0/2] ALSA: firewire-motu: add support for MOTU 828 and 896 Takashi Iwai
  2 siblings, 0 replies; 5+ messages in thread
From: Takashi Sakamoto @ 2021-06-16  8:28 UTC (permalink / raw)
  To: tiwai; +Cc: alsa-devel, clemens

MOTU 896 is a second model in MOTU FireWire series, produced in 2001. This
model consists of three chips:

 * Texas Instruments TSB41AB2 (Physical layer for IEEE 1394 bus)
 * Philips Semiconductors PDI 1394L21BE (Link layer for IEEE 1394 bus and
   packet processing layer)
 * QuickLogic QuickRAM QL4016 (Data block processing layer and digital
   signal processing)

This commit adds a support for the model, with its unique protocol as
version 1. The features of this protocol are:

 * no MIDI support.
 * Rx packets have no data chunks for control and status messages.
 * Tx packets have 2 bytes for control and status messages in the end of
   each data block.
 * The most of settings are represented in bit flag in one quadlet address
   (0x'ffff'f000'0b14).
 * It's selectable to use signal on optical interface, however the device
   has no register specific to it. The state has effect just to whether
   to exclude differed data chunks.
 * The internal multiplexer is not configured by software.

Just after powering on, the device has a quirk to fail handling
transaction. I recommend users to connect the device enough after powering
on.

$ python3 crpp < /sys/bus/firewire/devices/fw1/config_rom
               ROM header and bus information block
               -----------------------------------------------------------------
400  04102814  bus_info_length 4, crc_length 16, crc 10260
404  31333934  bus_name "1394"
408  20001000  irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 0, max_rec 1 (4)
40c  0001f200  company_id 0001f2     |
410  0000d645  device_id 000000d645  | EUI-64 0001f2000000d645

               root directory
               -----------------------------------------------------------------
414  0004c65c  directory_length 4, crc 50780
418  030001f2  vendor
41c  0c0083c0  node capabilities per IEEE 1394
420  8d000006  --> eui-64 leaf at 438
424  d1000001  --> unit directory at 428

               unit directory at 428
               -----------------------------------------------------------------
428  0003ab34  directory_length 3, crc 43828
42c  120001f2  specifier id
430  13000002  version
434  17102801  model

               eui-64 leaf at 438
               -----------------------------------------------------------------
438  0002057d  leaf_length 2, crc 1405
43c  0001f200  company_id 0001f2     |
440  0000d645  device_id 000000d645  | EUI-64 0001f2000000d645

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/Kconfig                 |   1 +
 sound/firewire/motu/motu-protocol-v1.c | 215 +++++++++++++++++++++++++
 sound/firewire/motu/motu.c             |   1 +
 sound/firewire/motu/motu.h             |   1 +
 4 files changed, 218 insertions(+)

diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index a70732bbddab..62658e2b111a 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -166,6 +166,7 @@ config SND_FIREWIRE_MOTU
 	help
 	 Say Y here to enable support for FireWire devices which MOTU produced:
 	  * 828
+	  * 896
 	  * 828mk2
 	  * Traveler
 	  * Ultralite
diff --git a/sound/firewire/motu/motu-protocol-v1.c b/sound/firewire/motu/motu-protocol-v1.c
index fab6aef392af..d3eb9f377b71 100644
--- a/sound/firewire/motu/motu-protocol-v1.c
+++ b/sound/firewire/motu/motu-protocol-v1.c
@@ -53,6 +53,62 @@
 #define  CLK_828_STATUS_FLAG_SRC_SPDIF_ON_OPT_OR_COAX	0x00000002
 #define  CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT_OR_DSUB	0x00000001
 
+// Status register for MOTU 896 (0x'ffff'f000'0b14).
+//
+// 0x20000000: fetch PCM frames from communication IC to DAC.
+// 0x08000000: speed of word clock signal output on BNC interface.
+//   0x00000000: follow to system clock.
+//   0x08000000: half of system clock.
+// 0x01000000: Route main output to headphone output.
+// 0x00ffff00: input to monitor.
+//   0x00000000: none
+//   0x00004800: analog-1/2
+//   0x00005a00: analog-3/4
+//   0x00006c00: analog-5/6
+//   0x00007e00: analog-7/8
+//   0x00104800: AES/EBU-1/2
+//   0x00004000: analog-1
+//   0x00004900: analog-2
+//   0x00005200: analog-3
+//   0x00005b00: analog-4
+//   0x00006400: analog-5
+//   0x00006d00: analog-6
+//   0x00007600: analog-7
+//   0x00007f00: analog-8
+//   0x00104000: AES/EBU-1
+//   0x00104900: AES/EBU-2
+// 0x00000060: sample rate conversin for AES/EBU input/output.
+//   0x00000000: None
+//   0x00000020: input signal is converted to system rate
+//   0x00000040: output is slave to input, ignoring system rate
+//   0x00000060: output is double rate than system rate
+// 0x00000018: nominal rate of sampling clock.
+//   0x00000000: 44.1 kHz
+//   0x00000008: 48.0 kHz
+//   0x00000010: 88.2 kHz
+//   0x00000018: 96.0 kHz
+// 0x00000007: source of sampling clock.
+//   0x00000000: internal
+//   0x00000001: ADAT on optical interface
+//   0x00000002: AES/EBU on XLR
+//   0x00000004: word clock on BNC
+//   0x00000005: ADAT on Dsub 9pin
+
+#define CLK_896_STATUS_OFFSET			0x0b14
+#define  CLK_896_STATUS_FLAG_FETCH_ENABLE	0x20000000
+#define  CLK_896_STATUS_FLAG_MAIN_TO_HP		0x01000000
+#define  CLK_896_STATUS_MASK_SRC		0x00000007
+#define   CLK_896_STATUS_FLAG_SRC_INTERNAL	0x00000000
+#define   CLK_896_STATUS_FLAG_SRC_ADAT_ON_OPT	0x00000001
+#define   CLK_896_STATUS_FLAG_SRC_AESEBU	0x00000002
+#define   CLK_896_STATUS_FLAG_SRC_WORD		0x00000004
+#define   CLK_896_STATUS_FLAG_SRC_ADAT_ON_DSUB	0x00000005
+#define  CLK_896_STATUS_MASK_RATE		0x00000018
+#define   CLK_896_STATUS_FLAG_RATE_44100	0x00000000
+#define   CLK_896_STATUS_FLAG_RATE_48000	0x00000008
+#define   CLK_896_STATUS_FLAG_RATE_88200	0x00000010
+#define   CLK_896_STATUS_FLAG_RATE_96000	0x00000018
+
 static void parse_clock_rate_828(u32 data, unsigned int *rate)
 {
 	if (data & CLK_828_STATUS_FLAG_RATE_48000)
@@ -74,10 +130,45 @@ static int get_clock_rate_828(struct snd_motu *motu, unsigned int *rate)
 	return 0;
 }
 
+static int parse_clock_rate_896(u32 data, unsigned int *rate)
+{
+	switch (data & CLK_896_STATUS_MASK_RATE) {
+	case CLK_896_STATUS_FLAG_RATE_44100:
+		*rate = 44100;
+		break;
+	case CLK_896_STATUS_FLAG_RATE_48000:
+		*rate = 48000;
+		break;
+	case CLK_896_STATUS_FLAG_RATE_88200:
+		*rate = 88200;
+		break;
+	case CLK_896_STATUS_FLAG_RATE_96000:
+		*rate = 96000;
+		break;
+	default:
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int get_clock_rate_896(struct snd_motu *motu, unsigned int *rate)
+{
+	__be32 reg;
+	int err;
+
+	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
+	if (err < 0)
+		return err;
+	return parse_clock_rate_896(be32_to_cpu(reg), rate);
+}
+
 int snd_motu_protocol_v1_get_clock_rate(struct snd_motu *motu, unsigned int *rate)
 {
 	if (motu->spec == &snd_motu_spec_828)
 		return get_clock_rate_828(motu, rate);
+	else if (motu->spec == &snd_motu_spec_896)
+		return get_clock_rate_896(motu, rate);
 	else
 		return -ENXIO;
 }
@@ -101,10 +192,48 @@ static int set_clock_rate_828(struct snd_motu *motu, unsigned int rate)
 	return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
 }
 
+static int set_clock_rate_896(struct snd_motu *motu, unsigned int rate)
+{
+	unsigned int flag;
+	__be32 reg;
+	u32 data;
+	int err;
+
+	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
+	if (err < 0)
+		return err;
+	data = be32_to_cpu(reg);
+
+	switch (rate) {
+	case 44100:
+		flag = CLK_896_STATUS_FLAG_RATE_44100;
+		break;
+	case 48000:
+		flag = CLK_896_STATUS_FLAG_RATE_48000;
+		break;
+	case 88200:
+		flag = CLK_896_STATUS_FLAG_RATE_88200;
+		break;
+	case 96000:
+		flag = CLK_896_STATUS_FLAG_RATE_96000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	data &= ~CLK_896_STATUS_MASK_RATE;
+	data |= flag;
+
+	reg = cpu_to_be32(data);
+	return snd_motu_transaction_write(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
+}
+
 int snd_motu_protocol_v1_set_clock_rate(struct snd_motu *motu, unsigned int rate)
 {
 	if (motu->spec == &snd_motu_spec_828)
 		return set_clock_rate_828(motu, rate);
+	else if (motu->spec == &snd_motu_spec_896)
+		return set_clock_rate_896(motu, rate);
 	else
 		return -ENXIO;
 }
@@ -137,10 +266,46 @@ static int get_clock_source_828(struct snd_motu *motu, enum snd_motu_clock_sourc
 	return 0;
 }
 
+static int get_clock_source_896(struct snd_motu *motu, enum snd_motu_clock_source *src)
+{
+	__be32 reg;
+	u32 data;
+	int err;
+
+	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
+	if (err < 0)
+		return err;
+	data = be32_to_cpu(reg);
+
+	switch (data & CLK_896_STATUS_MASK_SRC) {
+	case CLK_896_STATUS_FLAG_SRC_INTERNAL:
+		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
+		break;
+	case CLK_896_STATUS_FLAG_SRC_ADAT_ON_OPT:
+		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
+		break;
+	case CLK_896_STATUS_FLAG_SRC_AESEBU:
+		*src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;
+		break;
+	case CLK_896_STATUS_FLAG_SRC_WORD:
+		*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
+		break;
+	case CLK_896_STATUS_FLAG_SRC_ADAT_ON_DSUB:
+		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
+		break;
+	default:
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
 int snd_motu_protocol_v1_get_clock_source(struct snd_motu *motu, enum snd_motu_clock_source *src)
 {
 	if (motu->spec == &snd_motu_spec_828)
 		return get_clock_source_828(motu, src);
+	else if (motu->spec == &snd_motu_spec_896)
+		return get_clock_source_896(motu, src);
 	else
 		return -ENXIO;
 }
@@ -169,10 +334,31 @@ static int switch_fetching_mode_828(struct snd_motu *motu, bool enable)
 	return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
 }
 
+static int switch_fetching_mode_896(struct snd_motu *motu, bool enable)
+{
+	__be32 reg;
+	u32 data;
+	int err;
+
+	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
+	if (err < 0)
+		return err;
+	data = be32_to_cpu(reg);
+
+	data &= ~(CLK_896_STATUS_FLAG_FETCH_ENABLE | CLK_896_STATUS_FLAG_MAIN_TO_HP);
+	if (enable)
+		data |= (CLK_896_STATUS_FLAG_FETCH_ENABLE | CLK_896_STATUS_FLAG_MAIN_TO_HP);
+
+	reg = cpu_to_be32(data);
+	return snd_motu_transaction_write(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
+}
+
 int snd_motu_protocol_v1_switch_fetching_mode(struct snd_motu *motu, bool enable)
 {
 	if (motu->spec == &snd_motu_spec_828)
 		return switch_fetching_mode_828(motu, enable);
+	else if (motu->spec == &snd_motu_spec_896)
+		return switch_fetching_mode_896(motu, enable);
 	else
 		return -ENXIO;
 }
@@ -204,6 +390,27 @@ static int detect_packet_formats_828(struct snd_motu *motu)
 	return 0;
 }
 
+static int detect_packet_formats_896(struct snd_motu *motu)
+{
+	// 24bit PCM frames follow to source packet header without message chunk.
+	motu->tx_packet_formats.pcm_byte_offset = 4;
+	motu->rx_packet_formats.pcm_byte_offset = 4;
+
+	// No message chunk in data block.
+	motu->tx_packet_formats.msg_chunks = 0;
+	motu->rx_packet_formats.msg_chunks = 0;
+
+	// Always enable optical interface for ADAT signal since the device have no registers
+	// to refer to current configuration.
+	motu->tx_packet_formats.pcm_chunks[0] += 8;
+	motu->tx_packet_formats.pcm_chunks[1] += 8;
+
+	motu->rx_packet_formats.pcm_chunks[0] += 8;
+	motu->rx_packet_formats.pcm_chunks[1] += 8;
+
+	return 0;
+}
+
 int snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu)
 {
 	memcpy(motu->tx_packet_formats.pcm_chunks, motu->spec->tx_fixed_pcm_chunks,
@@ -213,6 +420,8 @@ int snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu)
 
 	if (motu->spec == &snd_motu_spec_828)
 		return detect_packet_formats_828(motu);
+	else if (motu->spec == &snd_motu_spec_896)
+		return detect_packet_formats_896(motu);
 	else
 		return 0;
 }
@@ -223,3 +432,9 @@ const struct snd_motu_spec snd_motu_spec_828 = {
 	.tx_fixed_pcm_chunks = {10, 0, 0},
 	.rx_fixed_pcm_chunks = {10, 0, 0},
 };
+
+const struct snd_motu_spec snd_motu_spec_896 = {
+	.name = "896",
+	.tx_fixed_pcm_chunks = {10, 10, 0},
+	.rx_fixed_pcm_chunks = {10, 10, 0},
+};
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c
index add5f183dc1d..0cae670d711c 100644
--- a/sound/firewire/motu/motu.c
+++ b/sound/firewire/motu/motu.c
@@ -151,6 +151,7 @@ static void motu_bus_update(struct fw_unit *unit)
 
 static const struct ieee1394_device_id motu_id_table[] = {
 	SND_MOTU_DEV_ENTRY(0x000001, &snd_motu_spec_828),
+	SND_MOTU_DEV_ENTRY(0x000002, &snd_motu_spec_896),
 	SND_MOTU_DEV_ENTRY(0x000003, &snd_motu_spec_828mk2),
 	SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler),
 	SND_MOTU_DEV_ENTRY(0x00000d, &snd_motu_spec_ultralite),
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h
index 13e2637a0330..a3deabdf9e34 100644
--- a/sound/firewire/motu/motu.h
+++ b/sound/firewire/motu/motu.h
@@ -123,6 +123,7 @@ struct snd_motu_spec {
 };
 
 extern const struct snd_motu_spec snd_motu_spec_828;
+extern const struct snd_motu_spec snd_motu_spec_896;
 
 extern const struct snd_motu_spec snd_motu_spec_828mk2;
 extern const struct snd_motu_spec snd_motu_spec_traveler;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] ALSA: firewire-motu: add support for MOTU 828 and 896
  2021-06-16  8:28 [PATCH 0/2] ALSA: firewire-motu: add support for MOTU 828 and 896 Takashi Sakamoto
  2021-06-16  8:28 ` [PATCH 1/2] ALSA: firewire-motu: add support for MOTU 828 Takashi Sakamoto
  2021-06-16  8:28 ` [PATCH 2/2] ALSA: firewire-motu: add support for MOTU 896 Takashi Sakamoto
@ 2021-06-17  9:37 ` Takashi Iwai
  2021-06-17 10:03   ` Takashi Sakamoto
  2 siblings, 1 reply; 5+ messages in thread
From: Takashi Iwai @ 2021-06-17  9:37 UTC (permalink / raw)
  To: Takashi Sakamoto; +Cc: alsa-devel, clemens

On Wed, 16 Jun 2021 10:28:45 +0200,
Takashi Sakamoto wrote:
> 
> Hi,
> 
> This patchset is to add support for Mark of the unicorn (MOTU) 828 and
> 896, which were shipped two decades ago (2001) and already discontinued.
> (yes, it's 2021).
> 
> It's reasonable to count them as first generation of MOTU FireWire
> series since they are based on QuickLogic QuickRAM FPGA apart from
> Altera or Xilinx FPGA in the latter generation. Unlike the latter
> generation, they doesn't allow software to configure internal
> multiplexer.
> 
> I note that the sequence replay for media clock recovery[1] allows to
> support them. The device doesn't generate better sound with nominal (ideal)
> sequence of packets, thus the patches should be applied to development
> tree for v5.14 kernel.
> 
> [1] [PATCH 0/3] ALSA: firewire-motu: media clock recovery for sph-aware devices
> https://lore.kernel.org/alsa-devel/20210602013406.26442-1-o-takashi@sakamocchi.jp/
> 
> Takashi Sakamoto (2):
>   ALSA: firewire-motu: add support for MOTU 828
>   ALSA: firewire-motu: add support for MOTU 896

Applied both patches now.  Thanks.


Takashi

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] ALSA: firewire-motu: add support for MOTU 828 and 896
  2021-06-17  9:37 ` [PATCH 0/2] ALSA: firewire-motu: add support for MOTU 828 and 896 Takashi Iwai
@ 2021-06-17 10:03   ` Takashi Sakamoto
  0 siblings, 0 replies; 5+ messages in thread
From: Takashi Sakamoto @ 2021-06-17 10:03 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

On Thu, Jun 17, 2021 at 11:37:57AM +0200, Takashi Iwai wrote:
> On Wed, 16 Jun 2021 10:28:45 +0200,
> Takashi Sakamoto wrote:
> > 
> > Hi,
> > 
> > This patchset is to add support for Mark of the unicorn (MOTU) 828 and
> > 896, which were shipped two decades ago (2001) and already discontinued.
> > (yes, it's 2021).
> > 
> > It's reasonable to count them as first generation of MOTU FireWire
> > series since they are based on QuickLogic QuickRAM FPGA apart from
> > Altera or Xilinx FPGA in the latter generation. Unlike the latter
> > generation, they doesn't allow software to configure internal
> > multiplexer.
> > 
> > I note that the sequence replay for media clock recovery[1] allows to
> > support them. The device doesn't generate better sound with nominal (ideal)
> > sequence of packets, thus the patches should be applied to development
> > tree for v5.14 kernel.
> > 
> > [1] [PATCH 0/3] ALSA: firewire-motu: media clock recovery for sph-aware devices
> > https://lore.kernel.org/alsa-devel/20210602013406.26442-1-o-takashi@sakamocchi.jp/
> > 
> > Takashi Sakamoto (2):
> >   ALSA: firewire-motu: add support for MOTU 828
> >   ALSA: firewire-motu: add support for MOTU 896
> 
> Applied both patches now.  Thanks.

Thanks for applying them.

I'm glad if getting your care of below fix:

[PATCH] ALSA: firewire-motu: fix stream format for MOTU 8pre FireWire
 * https://lore.kernel.org/alsa-devel/20210614083133.39753-1-o-takashi@sakamocchi.jp/


Thanks

Takashi Sakamoto

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-06-17 10:06 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-16  8:28 [PATCH 0/2] ALSA: firewire-motu: add support for MOTU 828 and 896 Takashi Sakamoto
2021-06-16  8:28 ` [PATCH 1/2] ALSA: firewire-motu: add support for MOTU 828 Takashi Sakamoto
2021-06-16  8:28 ` [PATCH 2/2] ALSA: firewire-motu: add support for MOTU 896 Takashi Sakamoto
2021-06-17  9:37 ` [PATCH 0/2] ALSA: firewire-motu: add support for MOTU 828 and 896 Takashi Iwai
2021-06-17 10:03   ` Takashi Sakamoto

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.