162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci// motu-protocol-v1.c - a part of driver for MOTU FireWire series
362306a36Sopenharmony_ci//
462306a36Sopenharmony_ci// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "motu.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci// Status register for MOTU 828 (0x'ffff'f000'0b00).
1162306a36Sopenharmony_ci//
1262306a36Sopenharmony_ci// 0xffff0000: ISOC_COMM_CONTROL_MASK in motu-stream.c.
1362306a36Sopenharmony_ci// 0x00008000: mode of optical input interface.
1462306a36Sopenharmony_ci//   0x00008000: for S/PDIF signal.
1562306a36Sopenharmony_ci//   0x00000000: disabled or for ADAT signal.
1662306a36Sopenharmony_ci// 0x00004000: mode of optical output interface.
1762306a36Sopenharmony_ci//   0x00004000: for S/PDIF signal.
1862306a36Sopenharmony_ci//   0x00000000: disabled or for ADAT signal.
1962306a36Sopenharmony_ci// 0x00003f00: monitor input mode.
2062306a36Sopenharmony_ci//   0x00000800: analog-1/2
2162306a36Sopenharmony_ci//   0x00001a00: analog-3/4
2262306a36Sopenharmony_ci//   0x00002c00: analog-5/6
2362306a36Sopenharmony_ci//   0x00003e00: analog-7/8
2462306a36Sopenharmony_ci//   0x00000000: analog-1
2562306a36Sopenharmony_ci//   0x00000900: analog-2
2662306a36Sopenharmony_ci//   0x00001200: analog-3
2762306a36Sopenharmony_ci//   0x00001b00: analog-4
2862306a36Sopenharmony_ci//   0x00002400: analog-5
2962306a36Sopenharmony_ci//   0x00002d00: analog-6
3062306a36Sopenharmony_ci//   0x00003600: analog-7
3162306a36Sopenharmony_ci//   0x00003f00: analog-8
3262306a36Sopenharmony_ci// 0x00000080: enable stream input.
3362306a36Sopenharmony_ci// 0x00000040: disable monitor input.
3462306a36Sopenharmony_ci// 0x00000008: enable main out.
3562306a36Sopenharmony_ci// 0x00000004: rate of sampling clock.
3662306a36Sopenharmony_ci//   0x00000004: 48.0 kHz
3762306a36Sopenharmony_ci//   0x00000000: 44.1 kHz
3862306a36Sopenharmony_ci// 0x00000023: source of sampling clock.
3962306a36Sopenharmony_ci//   0x00000003: source packet header (SPH)
4062306a36Sopenharmony_ci//   0x00000002: S/PDIF on optical/coaxial interface.
4162306a36Sopenharmony_ci//   0x00000021: ADAT on optical interface
4262306a36Sopenharmony_ci//   0x00000001: ADAT on Dsub 9pin
4362306a36Sopenharmony_ci//   0x00000000: internal
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define CLK_828_STATUS_OFFSET				0x0b00
4662306a36Sopenharmony_ci#define  CLK_828_STATUS_MASK				0x0000ffff
4762306a36Sopenharmony_ci#define  CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF	0x00008000
4862306a36Sopenharmony_ci#define  CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF	0x00004000
4962306a36Sopenharmony_ci#define  CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES		0x00000080
5062306a36Sopenharmony_ci#define  CLK_828_STATUS_FLAG_ENABLE_OUTPUT		0x00000008
5162306a36Sopenharmony_ci#define  CLK_828_STATUS_FLAG_RATE_48000			0x00000004
5262306a36Sopenharmony_ci#define  CLK_828_STATUS_MASK_SRC			0x00000023
5362306a36Sopenharmony_ci#define   CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT		0x00000021
5462306a36Sopenharmony_ci#define   CLK_828_STATUS_FLAG_SRC_SPH			0x00000003
5562306a36Sopenharmony_ci#define   CLK_828_STATUS_FLAG_SRC_SPDIF			0x00000002
5662306a36Sopenharmony_ci#define   CLK_828_STATUS_FLAG_SRC_ADAT_ON_DSUB		0x00000001
5762306a36Sopenharmony_ci#define   CLK_828_STATUS_FLAG_SRC_INTERNAL		0x00000000
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci// Status register for MOTU 896 (0x'ffff'f000'0b14).
6062306a36Sopenharmony_ci//
6162306a36Sopenharmony_ci// 0xf0000000: enable physical and stream input to DAC.
6262306a36Sopenharmony_ci//   0x80000000: disable
6362306a36Sopenharmony_ci//   0x40000000: disable
6462306a36Sopenharmony_ci//   0x20000000: enable (prior to the other bits)
6562306a36Sopenharmony_ci//   0x10000000: disable
6662306a36Sopenharmony_ci//   0x00000000: disable
6762306a36Sopenharmony_ci// 0x08000000: speed of word clock signal output on BNC interface.
6862306a36Sopenharmony_ci//   0x00000000: force to low rate (44.1/48.0 kHz).
6962306a36Sopenharmony_ci//   0x08000000: follow to system clock.
7062306a36Sopenharmony_ci// 0x04000000: something relevant to clock.
7162306a36Sopenharmony_ci// 0x03000000: enable output.
7262306a36Sopenharmony_ci//  0x02000000: enabled irreversibly once standing unless the device voluntarily disables it.
7362306a36Sopenharmony_ci//  0x01000000: enabled irreversibly once standing unless the device voluntarily disables it.
7462306a36Sopenharmony_ci// 0x00ffff00: monitor input mode.
7562306a36Sopenharmony_ci//   0x00000000: disabled
7662306a36Sopenharmony_ci//   0x00004800: analog-1/2
7762306a36Sopenharmony_ci//   0x00005a00: analog-3/4
7862306a36Sopenharmony_ci//   0x00006c00: analog-5/6
7962306a36Sopenharmony_ci//   0x00007e00: analog-7/8
8062306a36Sopenharmony_ci//   0x00104800: AES/EBU-1/2
8162306a36Sopenharmony_ci//   0x00004000: analog-1
8262306a36Sopenharmony_ci//   0x00004900: analog-2
8362306a36Sopenharmony_ci//   0x00005200: analog-3
8462306a36Sopenharmony_ci//   0x00005b00: analog-4
8562306a36Sopenharmony_ci//   0x00006400: analog-5
8662306a36Sopenharmony_ci//   0x00006d00: analog-6
8762306a36Sopenharmony_ci//   0x00007600: analog-7
8862306a36Sopenharmony_ci//   0x00007f00: analog-8
8962306a36Sopenharmony_ci//   0x00104000: AES/EBU-1
9062306a36Sopenharmony_ci//   0x00104900: AES/EBU-2
9162306a36Sopenharmony_ci// 0x00000060: sample rate conversion for AES/EBU input/output.
9262306a36Sopenharmony_ci//   0x00000000: None
9362306a36Sopenharmony_ci//   0x00000020: input signal is converted to system rate
9462306a36Sopenharmony_ci//   0x00000040: output is slave to input, ignoring system rate
9562306a36Sopenharmony_ci//   0x00000060: output is double rate than system rate
9662306a36Sopenharmony_ci// 0x00000018: nominal rate of sampling clock.
9762306a36Sopenharmony_ci//   0x00000000: 44.1 kHz
9862306a36Sopenharmony_ci//   0x00000008: 48.0 kHz
9962306a36Sopenharmony_ci//   0x00000010: 88.2 kHz
10062306a36Sopenharmony_ci//   0x00000018: 96.0 kHz
10162306a36Sopenharmony_ci// 0x00000007: source of sampling clock.
10262306a36Sopenharmony_ci//   0x00000000: internal
10362306a36Sopenharmony_ci//   0x00000001: ADAT on optical interface
10462306a36Sopenharmony_ci//   0x00000002: AES/EBU on XLR
10562306a36Sopenharmony_ci//   0x00000003: source packet header (SPH)
10662306a36Sopenharmony_ci//   0x00000004: word clock on BNC
10762306a36Sopenharmony_ci//   0x00000005: ADAT on Dsub 9pin
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define CLK_896_STATUS_OFFSET			0x0b14
11062306a36Sopenharmony_ci#define  CLK_896_STATUS_FLAG_FETCH_ENABLE	0x20000000
11162306a36Sopenharmony_ci#define  CLK_896_STATUS_FLAG_OUTPUT_ON		0x03000000
11262306a36Sopenharmony_ci#define  CLK_896_STATUS_MASK_SRC		0x00000007
11362306a36Sopenharmony_ci#define   CLK_896_STATUS_FLAG_SRC_INTERNAL	0x00000000
11462306a36Sopenharmony_ci#define   CLK_896_STATUS_FLAG_SRC_ADAT_ON_OPT	0x00000001
11562306a36Sopenharmony_ci#define   CLK_896_STATUS_FLAG_SRC_AESEBU	0x00000002
11662306a36Sopenharmony_ci#define   CLK_896_STATUS_FLAG_SRC_SPH		0x00000003
11762306a36Sopenharmony_ci#define   CLK_896_STATUS_FLAG_SRC_WORD		0x00000004
11862306a36Sopenharmony_ci#define   CLK_896_STATUS_FLAG_SRC_ADAT_ON_DSUB	0x00000005
11962306a36Sopenharmony_ci#define  CLK_896_STATUS_MASK_RATE		0x00000018
12062306a36Sopenharmony_ci#define   CLK_896_STATUS_FLAG_RATE_44100	0x00000000
12162306a36Sopenharmony_ci#define   CLK_896_STATUS_FLAG_RATE_48000	0x00000008
12262306a36Sopenharmony_ci#define   CLK_896_STATUS_FLAG_RATE_88200	0x00000010
12362306a36Sopenharmony_ci#define   CLK_896_STATUS_FLAG_RATE_96000	0x00000018
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic void parse_clock_rate_828(u32 data, unsigned int *rate)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	if (data & CLK_828_STATUS_FLAG_RATE_48000)
12862306a36Sopenharmony_ci		*rate = 48000;
12962306a36Sopenharmony_ci	else
13062306a36Sopenharmony_ci		*rate = 44100;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int get_clock_rate_828(struct snd_motu *motu, unsigned int *rate)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	__be32 reg;
13662306a36Sopenharmony_ci	int err;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
13962306a36Sopenharmony_ci	if (err < 0)
14062306a36Sopenharmony_ci		return err;
14162306a36Sopenharmony_ci	parse_clock_rate_828(be32_to_cpu(reg), rate);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return 0;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int parse_clock_rate_896(u32 data, unsigned int *rate)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	switch (data & CLK_896_STATUS_MASK_RATE) {
14962306a36Sopenharmony_ci	case CLK_896_STATUS_FLAG_RATE_44100:
15062306a36Sopenharmony_ci		*rate = 44100;
15162306a36Sopenharmony_ci		break;
15262306a36Sopenharmony_ci	case CLK_896_STATUS_FLAG_RATE_48000:
15362306a36Sopenharmony_ci		*rate = 48000;
15462306a36Sopenharmony_ci		break;
15562306a36Sopenharmony_ci	case CLK_896_STATUS_FLAG_RATE_88200:
15662306a36Sopenharmony_ci		*rate = 88200;
15762306a36Sopenharmony_ci		break;
15862306a36Sopenharmony_ci	case CLK_896_STATUS_FLAG_RATE_96000:
15962306a36Sopenharmony_ci		*rate = 96000;
16062306a36Sopenharmony_ci		break;
16162306a36Sopenharmony_ci	default:
16262306a36Sopenharmony_ci		return -ENXIO;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return 0;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int get_clock_rate_896(struct snd_motu *motu, unsigned int *rate)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	__be32 reg;
17162306a36Sopenharmony_ci	int err;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
17462306a36Sopenharmony_ci	if (err < 0)
17562306a36Sopenharmony_ci		return err;
17662306a36Sopenharmony_ci	return parse_clock_rate_896(be32_to_cpu(reg), rate);
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ciint snd_motu_protocol_v1_get_clock_rate(struct snd_motu *motu, unsigned int *rate)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	if (motu->spec == &snd_motu_spec_828)
18262306a36Sopenharmony_ci		return get_clock_rate_828(motu, rate);
18362306a36Sopenharmony_ci	else if (motu->spec == &snd_motu_spec_896)
18462306a36Sopenharmony_ci		return get_clock_rate_896(motu, rate);
18562306a36Sopenharmony_ci	else
18662306a36Sopenharmony_ci		return -ENXIO;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int set_clock_rate_828(struct snd_motu *motu, unsigned int rate)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	__be32 reg;
19262306a36Sopenharmony_ci	u32 data;
19362306a36Sopenharmony_ci	int err;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
19662306a36Sopenharmony_ci	if (err < 0)
19762306a36Sopenharmony_ci		return err;
19862306a36Sopenharmony_ci	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	data &= ~CLK_828_STATUS_FLAG_RATE_48000;
20162306a36Sopenharmony_ci	if (rate == 48000)
20262306a36Sopenharmony_ci		data |= CLK_828_STATUS_FLAG_RATE_48000;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	reg = cpu_to_be32(data);
20562306a36Sopenharmony_ci	return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic int set_clock_rate_896(struct snd_motu *motu, unsigned int rate)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	unsigned int flag;
21162306a36Sopenharmony_ci	__be32 reg;
21262306a36Sopenharmony_ci	u32 data;
21362306a36Sopenharmony_ci	int err;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
21662306a36Sopenharmony_ci	if (err < 0)
21762306a36Sopenharmony_ci		return err;
21862306a36Sopenharmony_ci	data = be32_to_cpu(reg);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	switch (rate) {
22162306a36Sopenharmony_ci	case 44100:
22262306a36Sopenharmony_ci		flag = CLK_896_STATUS_FLAG_RATE_44100;
22362306a36Sopenharmony_ci		break;
22462306a36Sopenharmony_ci	case 48000:
22562306a36Sopenharmony_ci		flag = CLK_896_STATUS_FLAG_RATE_48000;
22662306a36Sopenharmony_ci		break;
22762306a36Sopenharmony_ci	case 88200:
22862306a36Sopenharmony_ci		flag = CLK_896_STATUS_FLAG_RATE_88200;
22962306a36Sopenharmony_ci		break;
23062306a36Sopenharmony_ci	case 96000:
23162306a36Sopenharmony_ci		flag = CLK_896_STATUS_FLAG_RATE_96000;
23262306a36Sopenharmony_ci		break;
23362306a36Sopenharmony_ci	default:
23462306a36Sopenharmony_ci		return -EINVAL;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	data &= ~CLK_896_STATUS_MASK_RATE;
23862306a36Sopenharmony_ci	data |= flag;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	reg = cpu_to_be32(data);
24162306a36Sopenharmony_ci	return snd_motu_transaction_write(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ciint snd_motu_protocol_v1_set_clock_rate(struct snd_motu *motu, unsigned int rate)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	if (motu->spec == &snd_motu_spec_828)
24762306a36Sopenharmony_ci		return set_clock_rate_828(motu, rate);
24862306a36Sopenharmony_ci	else if (motu->spec == &snd_motu_spec_896)
24962306a36Sopenharmony_ci		return set_clock_rate_896(motu, rate);
25062306a36Sopenharmony_ci	else
25162306a36Sopenharmony_ci		return -ENXIO;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int get_clock_source_828(struct snd_motu *motu, enum snd_motu_clock_source *src)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	__be32 reg;
25762306a36Sopenharmony_ci	u32 data;
25862306a36Sopenharmony_ci	int err;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
26162306a36Sopenharmony_ci	if (err < 0)
26262306a36Sopenharmony_ci		return err;
26362306a36Sopenharmony_ci	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	switch (data & CLK_828_STATUS_MASK_SRC) {
26662306a36Sopenharmony_ci	case CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT:
26762306a36Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
26862306a36Sopenharmony_ci		break;
26962306a36Sopenharmony_ci	case CLK_828_STATUS_FLAG_SRC_SPH:
27062306a36Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_SPH;
27162306a36Sopenharmony_ci		break;
27262306a36Sopenharmony_ci	case CLK_828_STATUS_FLAG_SRC_SPDIF:
27362306a36Sopenharmony_ci	{
27462306a36Sopenharmony_ci		if (data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF)
27562306a36Sopenharmony_ci			*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
27662306a36Sopenharmony_ci		else
27762306a36Sopenharmony_ci			*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
27862306a36Sopenharmony_ci		break;
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci	case CLK_828_STATUS_FLAG_SRC_ADAT_ON_DSUB:
28162306a36Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
28262306a36Sopenharmony_ci		break;
28362306a36Sopenharmony_ci	case CLK_828_STATUS_FLAG_SRC_INTERNAL:
28462306a36Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
28562306a36Sopenharmony_ci		break;
28662306a36Sopenharmony_ci	default:
28762306a36Sopenharmony_ci		return -ENXIO;
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	return 0;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic int get_clock_source_896(struct snd_motu *motu, enum snd_motu_clock_source *src)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	__be32 reg;
29662306a36Sopenharmony_ci	u32 data;
29762306a36Sopenharmony_ci	int err;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
30062306a36Sopenharmony_ci	if (err < 0)
30162306a36Sopenharmony_ci		return err;
30262306a36Sopenharmony_ci	data = be32_to_cpu(reg);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	switch (data & CLK_896_STATUS_MASK_SRC) {
30562306a36Sopenharmony_ci	case CLK_896_STATUS_FLAG_SRC_INTERNAL:
30662306a36Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci	case CLK_896_STATUS_FLAG_SRC_ADAT_ON_OPT:
30962306a36Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
31062306a36Sopenharmony_ci		break;
31162306a36Sopenharmony_ci	case CLK_896_STATUS_FLAG_SRC_AESEBU:
31262306a36Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;
31362306a36Sopenharmony_ci		break;
31462306a36Sopenharmony_ci	case CLK_896_STATUS_FLAG_SRC_SPH:
31562306a36Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_SPH;
31662306a36Sopenharmony_ci		break;
31762306a36Sopenharmony_ci	case CLK_896_STATUS_FLAG_SRC_WORD:
31862306a36Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
31962306a36Sopenharmony_ci		break;
32062306a36Sopenharmony_ci	case CLK_896_STATUS_FLAG_SRC_ADAT_ON_DSUB:
32162306a36Sopenharmony_ci		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
32262306a36Sopenharmony_ci		break;
32362306a36Sopenharmony_ci	default:
32462306a36Sopenharmony_ci		return -ENXIO;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return 0;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ciint snd_motu_protocol_v1_get_clock_source(struct snd_motu *motu, enum snd_motu_clock_source *src)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	if (motu->spec == &snd_motu_spec_828)
33362306a36Sopenharmony_ci		return get_clock_source_828(motu, src);
33462306a36Sopenharmony_ci	else if (motu->spec == &snd_motu_spec_896)
33562306a36Sopenharmony_ci		return get_clock_source_896(motu, src);
33662306a36Sopenharmony_ci	else
33762306a36Sopenharmony_ci		return -ENXIO;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic int switch_fetching_mode_828(struct snd_motu *motu, bool enable)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	__be32 reg;
34362306a36Sopenharmony_ci	u32 data;
34462306a36Sopenharmony_ci	int err;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
34762306a36Sopenharmony_ci	if (err < 0)
34862306a36Sopenharmony_ci		return err;
34962306a36Sopenharmony_ci	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	data &= ~(CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_ENABLE_OUTPUT);
35262306a36Sopenharmony_ci	if (enable) {
35362306a36Sopenharmony_ci		// This transaction should be initiated after the device receives batch of packets
35462306a36Sopenharmony_ci		// since the device voluntarily mutes outputs. As a workaround, yield processor over
35562306a36Sopenharmony_ci		// 100 msec.
35662306a36Sopenharmony_ci		msleep(100);
35762306a36Sopenharmony_ci		data |= CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_ENABLE_OUTPUT;
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	reg = cpu_to_be32(data);
36162306a36Sopenharmony_ci	return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic int switch_fetching_mode_896(struct snd_motu *motu, bool enable)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	__be32 reg;
36762306a36Sopenharmony_ci	u32 data;
36862306a36Sopenharmony_ci	int err;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
37162306a36Sopenharmony_ci	if (err < 0)
37262306a36Sopenharmony_ci		return err;
37362306a36Sopenharmony_ci	data = be32_to_cpu(reg);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	data &= ~CLK_896_STATUS_FLAG_FETCH_ENABLE;
37662306a36Sopenharmony_ci	if (enable)
37762306a36Sopenharmony_ci		data |= CLK_896_STATUS_FLAG_FETCH_ENABLE | CLK_896_STATUS_FLAG_OUTPUT_ON;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	reg = cpu_to_be32(data);
38062306a36Sopenharmony_ci	return snd_motu_transaction_write(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ciint snd_motu_protocol_v1_switch_fetching_mode(struct snd_motu *motu, bool enable)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	if (motu->spec == &snd_motu_spec_828)
38662306a36Sopenharmony_ci		return switch_fetching_mode_828(motu, enable);
38762306a36Sopenharmony_ci	else if (motu->spec == &snd_motu_spec_896)
38862306a36Sopenharmony_ci		return switch_fetching_mode_896(motu, enable);
38962306a36Sopenharmony_ci	else
39062306a36Sopenharmony_ci		return -ENXIO;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic int detect_packet_formats_828(struct snd_motu *motu)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	__be32 reg;
39662306a36Sopenharmony_ci	u32 data;
39762306a36Sopenharmony_ci	int err;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	motu->tx_packet_formats.pcm_byte_offset = 4;
40062306a36Sopenharmony_ci	motu->tx_packet_formats.msg_chunks = 2;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	motu->rx_packet_formats.pcm_byte_offset = 4;
40362306a36Sopenharmony_ci	motu->rx_packet_formats.msg_chunks = 0;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
40662306a36Sopenharmony_ci	if (err < 0)
40762306a36Sopenharmony_ci		return err;
40862306a36Sopenharmony_ci	data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	// The number of chunks is just reduced when SPDIF is activated.
41162306a36Sopenharmony_ci	if (!(data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF))
41262306a36Sopenharmony_ci		motu->tx_packet_formats.pcm_chunks[0] += 8;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (!(data & CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF))
41562306a36Sopenharmony_ci		motu->rx_packet_formats.pcm_chunks[0] += 8;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	return 0;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic int detect_packet_formats_896(struct snd_motu *motu)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	// 24bit PCM frames follow to source packet header without message chunk.
42362306a36Sopenharmony_ci	motu->tx_packet_formats.pcm_byte_offset = 4;
42462306a36Sopenharmony_ci	motu->rx_packet_formats.pcm_byte_offset = 4;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	// No message chunk in data block.
42762306a36Sopenharmony_ci	motu->tx_packet_formats.msg_chunks = 0;
42862306a36Sopenharmony_ci	motu->rx_packet_formats.msg_chunks = 0;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	// Always enable optical interface for ADAT signal since the device have no registers
43162306a36Sopenharmony_ci	// to refer to current configuration.
43262306a36Sopenharmony_ci	motu->tx_packet_formats.pcm_chunks[0] += 8;
43362306a36Sopenharmony_ci	motu->tx_packet_formats.pcm_chunks[1] += 8;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	motu->rx_packet_formats.pcm_chunks[0] += 8;
43662306a36Sopenharmony_ci	motu->rx_packet_formats.pcm_chunks[1] += 8;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return 0;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ciint snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	memcpy(motu->tx_packet_formats.pcm_chunks, motu->spec->tx_fixed_pcm_chunks,
44462306a36Sopenharmony_ci	       sizeof(motu->tx_packet_formats.pcm_chunks));
44562306a36Sopenharmony_ci	memcpy(motu->rx_packet_formats.pcm_chunks, motu->spec->rx_fixed_pcm_chunks,
44662306a36Sopenharmony_ci	       sizeof(motu->rx_packet_formats.pcm_chunks));
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (motu->spec == &snd_motu_spec_828)
44962306a36Sopenharmony_ci		return detect_packet_formats_828(motu);
45062306a36Sopenharmony_ci	else if (motu->spec == &snd_motu_spec_896)
45162306a36Sopenharmony_ci		return detect_packet_formats_896(motu);
45262306a36Sopenharmony_ci	else
45362306a36Sopenharmony_ci		return 0;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ciconst struct snd_motu_spec snd_motu_spec_828 = {
45762306a36Sopenharmony_ci	.name = "828",
45862306a36Sopenharmony_ci	.protocol_version = SND_MOTU_PROTOCOL_V1,
45962306a36Sopenharmony_ci	.tx_fixed_pcm_chunks = {10, 0, 0},
46062306a36Sopenharmony_ci	.rx_fixed_pcm_chunks = {10, 0, 0},
46162306a36Sopenharmony_ci};
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ciconst struct snd_motu_spec snd_motu_spec_896 = {
46462306a36Sopenharmony_ci	.name = "896",
46562306a36Sopenharmony_ci	.tx_fixed_pcm_chunks = {10, 10, 0},
46662306a36Sopenharmony_ci	.rx_fixed_pcm_chunks = {10, 10, 0},
46762306a36Sopenharmony_ci};
468