diff mbox series

[3/9] ALSA: emu10k1: query rate of external clock sources on E-MU cards

Message ID 20230612191325.1315854-4-oswald.buddenhagen@gmx.de (mailing list archive)
State Accepted
Commit e73b597e63ebad26d9dee5feb5d47251ed53b8a4
Headers show
Series ALSA: emu10k1: improvements related to the switchable word clock of E-MU cards | expand

Commit Message

Oswald Buddenhagen June 12, 2023, 7:13 p.m. UTC
The value isn't used yet; the subsequent commits will do that.

This ignores the existence of rates above 48 kHz, which is fine, as the
hardware will just switch to the fallback clock source when fed with a
rate which is incompatible with the base clock multiplier, which
currently is always x1.

The sample rate display in /proc spdif-in is adjusted to reflect our
understanding of the input rates.

This is tested only with an 0404b card without sync card, so there is a
lot of room for improvement.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>

---

FIXME: needs a lot of testing to figure out things for real: 0404, 1010,
1010b, and 1616 hardware, with adat, s/pdif on 1010 and dock, and bnc
sync. what are the lock status and the displayed rates with no signal,
good signal async to internal clock, and synced signal? test s/pdif at
least with 48 & 96 khz (192 works on 1010b & 1616m cards on the RCA
port).
---
 include/sound/emu10k1.h     |  5 ++++
 sound/pci/emu10k1/emuproc.c | 43 ++++++++++++++++---------------
 sound/pci/emu10k1/io.c      | 51 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 78 insertions(+), 21 deletions(-)
diff mbox series

Patch

diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 703ef441bb2a..d64cf1697586 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1110,6 +1110,9 @@  SUB_REG_NC(A_EHC, A_I2S_CAPTURE_RATE, 0x00000e00)  /* This sets the capture PCM
 #define EMU_DOCK_BOARD_ID0		0x00	/* ID bit 0 */
 #define EMU_DOCK_BOARD_ID1		0x03	/* ID bit 1 */
 
+// The actual code disagrees about the bit width of the registers -
+// the formula used is freq = 0x1770000 / (((X_HI << 5) | X_LO) + 1)
+
 #define EMU_HANA_WC_SPDIF_HI	0x28	/* 0xxxxxx  6 bit  SPDIF IN Word clock, upper 6 bits */
 #define EMU_HANA_WC_SPDIF_LO	0x29	/* 0xxxxxx  6 bit  SPDIF IN Word clock, lower 6 bits */
 
@@ -1669,6 +1672,7 @@  struct snd_emu1010 {
 	unsigned int adc_pads; /* bit mask */
 	unsigned int dac_pads; /* bit mask */
 	unsigned int wclock;  /* Cached register value */
+	unsigned int word_clock;  /* Cached effective value */
 	unsigned int clock_source;
 	unsigned int clock_fallback;
 	unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
@@ -1825,6 +1829,7 @@  void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
 void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value);
 void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src);
 u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst);
+int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src);
 void snd_emu1010_update_clock(struct snd_emu10k1 *emu);
 unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index ca7b4dddbea8..993b35362499 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -168,29 +168,32 @@  static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry,
 	struct snd_emu10k1 *emu = entry->private_data;
 	u32 value;
 	u32 value2;
-	u32 rate;
 
 	if (emu->card_capabilities->emu_model) {
-		if (!emu->card_capabilities->no_adat) {
-			snd_emu1010_fpga_read(emu, 0x38, &value);
-			if ((value & 0x1) == 0) {
-				snd_emu1010_fpga_read(emu, 0x2a, &value);
-				snd_emu1010_fpga_read(emu, 0x2b, &value2);
-				rate = 0x1770000 / (((value << 5) | value2)+1);
-				snd_iprintf(buffer, "ADAT Locked : %u\n", rate);
-			} else {
-				snd_iprintf(buffer, "ADAT Unlocked\n");
-			}
-		}
-		snd_emu1010_fpga_read(emu, 0x20, &value);
-		if ((value & 0x4) == 0) {
-			snd_emu1010_fpga_read(emu, 0x28, &value);
-			snd_emu1010_fpga_read(emu, 0x29, &value2);
-			rate = 0x1770000 / (((value << 5) | value2)+1);	
-			snd_iprintf(buffer, "SPDIF Locked : %d\n", rate);
-		} else {
-			snd_iprintf(buffer, "SPDIF Unlocked\n");
+		// This represents the S/PDIF lock status on 0404b, which is
+		// kinda weird and unhelpful, because monitoring it via IRQ is
+		// impractical (one gets an IRQ flood as long as it is desynced).
+		snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &value);
+		snd_iprintf(buffer, "Lock status 1: %#x\n", value & 0x10);
+
+		// Bit 0x1 in LO being 0 is supposedly for ADAT lock.
+		// The registers are always all zero on 0404b.
+		snd_emu1010_fpga_read(emu, EMU_HANA_LOCK_STS_LO, &value);
+		snd_emu1010_fpga_read(emu, EMU_HANA_LOCK_STS_HI, &value2);
+		snd_iprintf(buffer, "Lock status 2: %#x %#x\n", value, value2);
+
+		snd_iprintf(buffer, "S/PDIF rate: %dHz\n",
+			    snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_HANA_SPDIF_IN));
+		if (emu->card_capabilities->emu_model != EMU_MODEL_EMU0404) {
+			snd_iprintf(buffer, "ADAT rate: %dHz\n",
+				    snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_HANA_ADAT_IN));
+			snd_iprintf(buffer, "Dock rate: %dHz\n",
+				    snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_2ND_HANA));
 		}
+		if (emu->card_capabilities->emu_model == EMU_MODEL_EMU0404 ||
+		    emu->card_capabilities->emu_model == EMU_MODEL_EMU1010)
+			snd_iprintf(buffer, "BNC rate: %dHz\n",
+				    snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_SYNC_BNC));
 	} else {
 		snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS);
 		snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS);
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index e7a44443023a..a0d66ce3ee83 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -357,21 +357,70 @@  u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst)
 	return (hi << 8) | lo;
 }
 
+int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src)
+{
+	u32 reg_lo, reg_hi, value, value2;
+
+	switch (src) {
+	case EMU_HANA_WCLOCK_HANA_SPDIF_IN:
+		snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &value);
+		if (value & EMU_HANA_SPDIF_MODE_RX_INVALID)
+			return 0;
+		reg_lo = EMU_HANA_WC_SPDIF_LO;
+		reg_hi = EMU_HANA_WC_SPDIF_HI;
+		break;
+	case EMU_HANA_WCLOCK_HANA_ADAT_IN:
+		reg_lo = EMU_HANA_WC_ADAT_LO;
+		reg_hi = EMU_HANA_WC_ADAT_HI;
+		break;
+	case EMU_HANA_WCLOCK_SYNC_BNC:
+		reg_lo = EMU_HANA_WC_BNC_LO;
+		reg_hi = EMU_HANA_WC_BNC_HI;
+		break;
+	case EMU_HANA_WCLOCK_2ND_HANA:
+		reg_lo = EMU_HANA2_WC_SPDIF_LO;
+		reg_hi = EMU_HANA2_WC_SPDIF_HI;
+		break;
+	default:
+		return 0;
+	}
+	snd_emu1010_fpga_read(emu, reg_hi, &value);
+	snd_emu1010_fpga_read(emu, reg_lo, &value2);
+	// FIXME: The /4 is valid for 0404b, but contradicts all other info.
+	return 0x1770000 / 4 / (((value << 5) | value2) + 1);
+}
+
 void snd_emu1010_update_clock(struct snd_emu10k1 *emu)
 {
+	int clock;
 	u32 leds;
 
 	switch (emu->emu1010.wclock) {
 	case EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X:
+		clock = 44100;
 		leds = EMU_HANA_DOCK_LEDS_2_44K;
 		break;
 	case EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X:
+		clock = 48000;
 		leds = EMU_HANA_DOCK_LEDS_2_48K;
 		break;
 	default:
-		leds = EMU_HANA_DOCK_LEDS_2_EXT;
+		clock = snd_emu1010_get_raw_rate(
+				emu, emu->emu1010.wclock & EMU_HANA_WCLOCK_SRC_MASK);
+		// The raw rate reading is rather coarse (it cannot accurately
+		// represent 44.1 kHz) and fluctuates slightly. Luckily, the
+		// clock comes from digital inputs, which use standardized rates.
+		// So we round to the closest standard rate and ignore discrepancies.
+		if (clock < 46000) {
+			clock = 44100;
+			leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_44K;
+		} else {
+			clock = 48000;
+			leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_48K;
+		}
 		break;
 	}
+	emu->emu1010.word_clock = clock;
 
 	// FIXME: this should probably represent the AND of all currently
 	// used sources' lock status. But we don't know how to get that ...