Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: emu10k1: query rate of external clock sources on E-MU cards

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>

Link: https://lore.kernel.org/r/20230612191325.1315854-4-oswald.buddenhagen@gmx.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Oswald Buddenhagen and committed by
Takashi Iwai
e73b597e 60985241

+78 -21
+5
include/sound/emu10k1.h
··· 1110 1110 #define EMU_DOCK_BOARD_ID0 0x00 /* ID bit 0 */ 1111 1111 #define EMU_DOCK_BOARD_ID1 0x03 /* ID bit 1 */ 1112 1112 1113 + // The actual code disagrees about the bit width of the registers - 1114 + // the formula used is freq = 0x1770000 / (((X_HI << 5) | X_LO) + 1) 1115 + 1113 1116 #define EMU_HANA_WC_SPDIF_HI 0x28 /* 0xxxxxx 6 bit SPDIF IN Word clock, upper 6 bits */ 1114 1117 #define EMU_HANA_WC_SPDIF_LO 0x29 /* 0xxxxxx 6 bit SPDIF IN Word clock, lower 6 bits */ 1115 1118 ··· 1672 1669 unsigned int adc_pads; /* bit mask */ 1673 1670 unsigned int dac_pads; /* bit mask */ 1674 1671 unsigned int wclock; /* Cached register value */ 1672 + unsigned int word_clock; /* Cached effective value */ 1675 1673 unsigned int clock_source; 1676 1674 unsigned int clock_fallback; 1677 1675 unsigned int optical_in; /* 0:SPDIF, 1:ADAT */ ··· 1829 1825 void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value); 1830 1826 void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src); 1831 1827 u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst); 1828 + int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src); 1832 1829 void snd_emu1010_update_clock(struct snd_emu10k1 *emu); 1833 1830 unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc); 1834 1831 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
+23 -20
sound/pci/emu10k1/emuproc.c
··· 168 168 struct snd_emu10k1 *emu = entry->private_data; 169 169 u32 value; 170 170 u32 value2; 171 - u32 rate; 172 171 173 172 if (emu->card_capabilities->emu_model) { 174 - if (!emu->card_capabilities->no_adat) { 175 - snd_emu1010_fpga_read(emu, 0x38, &value); 176 - if ((value & 0x1) == 0) { 177 - snd_emu1010_fpga_read(emu, 0x2a, &value); 178 - snd_emu1010_fpga_read(emu, 0x2b, &value2); 179 - rate = 0x1770000 / (((value << 5) | value2)+1); 180 - snd_iprintf(buffer, "ADAT Locked : %u\n", rate); 181 - } else { 182 - snd_iprintf(buffer, "ADAT Unlocked\n"); 183 - } 173 + // This represents the S/PDIF lock status on 0404b, which is 174 + // kinda weird and unhelpful, because monitoring it via IRQ is 175 + // impractical (one gets an IRQ flood as long as it is desynced). 176 + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &value); 177 + snd_iprintf(buffer, "Lock status 1: %#x\n", value & 0x10); 178 + 179 + // Bit 0x1 in LO being 0 is supposedly for ADAT lock. 180 + // The registers are always all zero on 0404b. 181 + snd_emu1010_fpga_read(emu, EMU_HANA_LOCK_STS_LO, &value); 182 + snd_emu1010_fpga_read(emu, EMU_HANA_LOCK_STS_HI, &value2); 183 + snd_iprintf(buffer, "Lock status 2: %#x %#x\n", value, value2); 184 + 185 + snd_iprintf(buffer, "S/PDIF rate: %dHz\n", 186 + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_HANA_SPDIF_IN)); 187 + if (emu->card_capabilities->emu_model != EMU_MODEL_EMU0404) { 188 + snd_iprintf(buffer, "ADAT rate: %dHz\n", 189 + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_HANA_ADAT_IN)); 190 + snd_iprintf(buffer, "Dock rate: %dHz\n", 191 + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_2ND_HANA)); 184 192 } 185 - snd_emu1010_fpga_read(emu, 0x20, &value); 186 - if ((value & 0x4) == 0) { 187 - snd_emu1010_fpga_read(emu, 0x28, &value); 188 - snd_emu1010_fpga_read(emu, 0x29, &value2); 189 - rate = 0x1770000 / (((value << 5) | value2)+1); 190 - snd_iprintf(buffer, "SPDIF Locked : %d\n", rate); 191 - } else { 192 - snd_iprintf(buffer, "SPDIF Unlocked\n"); 193 - } 193 + if (emu->card_capabilities->emu_model == EMU_MODEL_EMU0404 || 194 + emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) 195 + snd_iprintf(buffer, "BNC rate: %dHz\n", 196 + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_SYNC_BNC)); 194 197 } else { 195 198 snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); 196 199 snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS);
+50 -1
sound/pci/emu10k1/io.c
··· 357 357 return (hi << 8) | lo; 358 358 } 359 359 360 + int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src) 361 + { 362 + u32 reg_lo, reg_hi, value, value2; 363 + 364 + switch (src) { 365 + case EMU_HANA_WCLOCK_HANA_SPDIF_IN: 366 + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &value); 367 + if (value & EMU_HANA_SPDIF_MODE_RX_INVALID) 368 + return 0; 369 + reg_lo = EMU_HANA_WC_SPDIF_LO; 370 + reg_hi = EMU_HANA_WC_SPDIF_HI; 371 + break; 372 + case EMU_HANA_WCLOCK_HANA_ADAT_IN: 373 + reg_lo = EMU_HANA_WC_ADAT_LO; 374 + reg_hi = EMU_HANA_WC_ADAT_HI; 375 + break; 376 + case EMU_HANA_WCLOCK_SYNC_BNC: 377 + reg_lo = EMU_HANA_WC_BNC_LO; 378 + reg_hi = EMU_HANA_WC_BNC_HI; 379 + break; 380 + case EMU_HANA_WCLOCK_2ND_HANA: 381 + reg_lo = EMU_HANA2_WC_SPDIF_LO; 382 + reg_hi = EMU_HANA2_WC_SPDIF_HI; 383 + break; 384 + default: 385 + return 0; 386 + } 387 + snd_emu1010_fpga_read(emu, reg_hi, &value); 388 + snd_emu1010_fpga_read(emu, reg_lo, &value2); 389 + // FIXME: The /4 is valid for 0404b, but contradicts all other info. 390 + return 0x1770000 / 4 / (((value << 5) | value2) + 1); 391 + } 392 + 360 393 void snd_emu1010_update_clock(struct snd_emu10k1 *emu) 361 394 { 395 + int clock; 362 396 u32 leds; 363 397 364 398 switch (emu->emu1010.wclock) { 365 399 case EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X: 400 + clock = 44100; 366 401 leds = EMU_HANA_DOCK_LEDS_2_44K; 367 402 break; 368 403 case EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X: 404 + clock = 48000; 369 405 leds = EMU_HANA_DOCK_LEDS_2_48K; 370 406 break; 371 407 default: 372 - leds = EMU_HANA_DOCK_LEDS_2_EXT; 408 + clock = snd_emu1010_get_raw_rate( 409 + emu, emu->emu1010.wclock & EMU_HANA_WCLOCK_SRC_MASK); 410 + // The raw rate reading is rather coarse (it cannot accurately 411 + // represent 44.1 kHz) and fluctuates slightly. Luckily, the 412 + // clock comes from digital inputs, which use standardized rates. 413 + // So we round to the closest standard rate and ignore discrepancies. 414 + if (clock < 46000) { 415 + clock = 44100; 416 + leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_44K; 417 + } else { 418 + clock = 48000; 419 + leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_48K; 420 + } 373 421 break; 374 422 } 423 + emu->emu1010.word_clock = clock; 375 424 376 425 // FIXME: this should probably represent the AND of all currently 377 426 // used sources' lock status. But we don't know how to get that ...