18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ALSA driver for RME Hammerfall DSP MADI audio interface(s) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2003 Winfried Ritsch (IEM) 68c2ecf20Sopenharmony_ci * code based on hdsp.c Paul Davis 78c2ecf20Sopenharmony_ci * Marcus Andersson 88c2ecf20Sopenharmony_ci * Thomas Charbonnel 98c2ecf20Sopenharmony_ci * Modified 2006-06-01 for AES32 support by Remy Bruno 108c2ecf20Sopenharmony_ci * <remy.bruno@trinnov.com> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Modified 2009-04-13 for proper metering by Florian Faber 138c2ecf20Sopenharmony_ci * <faber@faberman.de> 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Modified 2009-04-14 for native float support by Florian Faber 168c2ecf20Sopenharmony_ci * <faber@faberman.de> 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Modified 2009-04-26 fixed bug in rms metering by Florian Faber 198c2ecf20Sopenharmony_ci * <faber@faberman.de> 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Modified 2009-04-30 added hw serial number support by Florian Faber 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Modified 2011-01-14 added S/PDIF input on RayDATs by Adrian Knoth 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Modified 2011-01-25 variable period sizes on RayDAT/AIO by Adrian Knoth 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * Modified 2019-05-23 fix AIO single speed ADAT capture and playback 288c2ecf20Sopenharmony_ci * by Philippe.Bekaert@uhasselt.be 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* ************* Register Documentation ******************************************************* 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Work in progress! Documentation is based on the code in this file. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * --------- HDSPM_controlRegister --------- 368c2ecf20Sopenharmony_ci * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte 378c2ecf20Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 388c2ecf20Sopenharmony_ci * :3322.2222:2222.1111:1111.1100:0000.0000: bit number 398c2ecf20Sopenharmony_ci * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 408c2ecf20Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 418c2ecf20Sopenharmony_ci * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit 428c2ecf20Sopenharmony_ci * : . : . : . : x . : HDSPM_AudioInterruptEnable \_ setting both bits 438c2ecf20Sopenharmony_ci * : . : . : . : . x: HDSPM_Start / enables audio IO 448c2ecf20Sopenharmony_ci * : . : . : . : x. : HDSPM_ClockModeMaster - 1: Master, 0: Slave 458c2ecf20Sopenharmony_ci * : . : . : . : .210 : HDSPM_LatencyMask - 3 Bit value for latency 468c2ecf20Sopenharmony_ci * : . : . : . : . : 0:64, 1:128, 2:256, 3:512, 478c2ecf20Sopenharmony_ci * : . : . : . : . : 4:1024, 5:2048, 6:4096, 7:8192 488c2ecf20Sopenharmony_ci * :x . : . : . x:xx . : HDSPM_FrequencyMask 498c2ecf20Sopenharmony_ci * : . : . : . :10 . : HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=?? 508c2ecf20Sopenharmony_ci * : . : . : . x: . : <MADI> HDSPM_DoubleSpeed 518c2ecf20Sopenharmony_ci * :x . : . : . : . : <MADI> HDSPM_QuadSpeed 528c2ecf20Sopenharmony_ci * : . 3 : . 10: 2 . : . : HDSPM_SyncRefMask : 538c2ecf20Sopenharmony_ci * : . : . x: . : . : HDSPM_SyncRef0 548c2ecf20Sopenharmony_ci * : . : . x : . : . : HDSPM_SyncRef1 558c2ecf20Sopenharmony_ci * : . : . : x . : . : <AES32> HDSPM_SyncRef2 568c2ecf20Sopenharmony_ci * : . x : . : . : . : <AES32> HDSPM_SyncRef3 578c2ecf20Sopenharmony_ci * : . : . 10: . : . : <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn 588c2ecf20Sopenharmony_ci * : . 3 : . 10: 2 . : . : <AES32> 0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn? 598c2ecf20Sopenharmony_ci * : . x : . : . : . : <MADIe> HDSPe_FLOAT_FORMAT 608c2ecf20Sopenharmony_ci * : . : . : x . : . : <MADI> HDSPM_InputSelect0 : 0=optical,1=coax 618c2ecf20Sopenharmony_ci * : . : . :x . : . : <MADI> HDSPM_InputSelect1 628c2ecf20Sopenharmony_ci * : . : .x : . : . : <MADI> HDSPM_clr_tms 638c2ecf20Sopenharmony_ci * : . : . : . x : . : <MADI> HDSPM_TX_64ch 648c2ecf20Sopenharmony_ci * : . : . : . x : . : <AES32> HDSPM_Emphasis 658c2ecf20Sopenharmony_ci * : . : . : .x : . : <MADI> HDSPM_AutoInp 668c2ecf20Sopenharmony_ci * : . : . x : . : . : <MADI> HDSPM_SMUX 678c2ecf20Sopenharmony_ci * : . : .x : . : . : <MADI> HDSPM_clr_tms 688c2ecf20Sopenharmony_ci * : . : x. : . : . : <MADI> HDSPM_taxi_reset 698c2ecf20Sopenharmony_ci * : . x: . : . : . : <MADI> HDSPM_LineOut 708c2ecf20Sopenharmony_ci * : . x: . : . : . : <AES32> ?????????????????? 718c2ecf20Sopenharmony_ci * : . : x. : . : . : <AES32> HDSPM_WCK48 728c2ecf20Sopenharmony_ci * : . : . : .x : . : <AES32> HDSPM_Dolby 738c2ecf20Sopenharmony_ci * : . : x . : . : . : HDSPM_Midi0InterruptEnable 748c2ecf20Sopenharmony_ci * : . :x . : . : . : HDSPM_Midi1InterruptEnable 758c2ecf20Sopenharmony_ci * : . : x . : . : . : HDSPM_Midi2InterruptEnable 768c2ecf20Sopenharmony_ci * : . x : . : . : . : <MADI> HDSPM_Midi3InterruptEnable 778c2ecf20Sopenharmony_ci * : . x : . : . : . : <AES32> HDSPM_DS_DoubleWire 788c2ecf20Sopenharmony_ci * : .x : . : . : . : <AES32> HDSPM_QS_DoubleWire 798c2ecf20Sopenharmony_ci * : x. : . : . : . : <AES32> HDSPM_QS_QuadWire 808c2ecf20Sopenharmony_ci * : . : . : . x : . : <AES32> HDSPM_Professional 818c2ecf20Sopenharmony_ci * : x . : . : . : . : HDSPM_wclk_sel 828c2ecf20Sopenharmony_ci * : . : . : . : . : 838c2ecf20Sopenharmony_ci * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte 848c2ecf20Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 858c2ecf20Sopenharmony_ci * :3322.2222:2222.1111:1111.1100:0000.0000: bit number 868c2ecf20Sopenharmony_ci * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 878c2ecf20Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 888c2ecf20Sopenharmony_ci * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * AIO / RayDAT only 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * ------------ HDSPM_WR_SETTINGS ---------- 958c2ecf20Sopenharmony_ci * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte 968c2ecf20Sopenharmony_ci * :1098.7654:3210.9876:5432.1098:7654.3210: 978c2ecf20Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: bit number 988c2ecf20Sopenharmony_ci * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 998c2ecf20Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 1008c2ecf20Sopenharmony_ci * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit 1018c2ecf20Sopenharmony_ci * : . : . : . : . x: HDSPM_c0Master 1: Master, 0: Slave 1028c2ecf20Sopenharmony_ci * : . : . : . : . x : HDSPM_c0_SyncRef0 1038c2ecf20Sopenharmony_ci * : . : . : . : . x : HDSPM_c0_SyncRef1 1048c2ecf20Sopenharmony_ci * : . : . : . : .x : HDSPM_c0_SyncRef2 1058c2ecf20Sopenharmony_ci * : . : . : . : x. : HDSPM_c0_SyncRef3 1068c2ecf20Sopenharmony_ci * : . : . : . : 3.210 : HDSPM_c0_SyncRefMask: 1078c2ecf20Sopenharmony_ci * : . : . : . : . : RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4, 1088c2ecf20Sopenharmony_ci * : . : . : . : . : 9:TCO, 10:SyncIn 1098c2ecf20Sopenharmony_ci * : . : . : . : . : AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT, 1108c2ecf20Sopenharmony_ci * : . : . : . : . : 9:TCO, 10:SyncIn 1118c2ecf20Sopenharmony_ci * : . : . : . : . : 1128c2ecf20Sopenharmony_ci * : . : . : . : . : 1138c2ecf20Sopenharmony_ci * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte 1148c2ecf20Sopenharmony_ci * :1098.7654:3210.9876:5432.1098:7654.3210: 1158c2ecf20Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: bit number 1168c2ecf20Sopenharmony_ci * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 1178c2ecf20Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 1188c2ecf20Sopenharmony_ci * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit 1198c2ecf20Sopenharmony_ci * 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci#include <linux/init.h> 1228c2ecf20Sopenharmony_ci#include <linux/delay.h> 1238c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 1248c2ecf20Sopenharmony_ci#include <linux/module.h> 1258c2ecf20Sopenharmony_ci#include <linux/slab.h> 1268c2ecf20Sopenharmony_ci#include <linux/pci.h> 1278c2ecf20Sopenharmony_ci#include <linux/math64.h> 1288c2ecf20Sopenharmony_ci#include <linux/io.h> 1298c2ecf20Sopenharmony_ci#include <linux/nospec.h> 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#include <sound/core.h> 1328c2ecf20Sopenharmony_ci#include <sound/control.h> 1338c2ecf20Sopenharmony_ci#include <sound/pcm.h> 1348c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 1358c2ecf20Sopenharmony_ci#include <sound/info.h> 1368c2ecf20Sopenharmony_ci#include <sound/asoundef.h> 1378c2ecf20Sopenharmony_ci#include <sound/rawmidi.h> 1388c2ecf20Sopenharmony_ci#include <sound/hwdep.h> 1398c2ecf20Sopenharmony_ci#include <sound/initval.h> 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci#include <sound/hdspm.h> 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 1448c2ecf20Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 1458c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 1488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for RME HDSPM interface."); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 1518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for RME HDSPM interface."); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 1548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards."); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ciMODULE_AUTHOR 1588c2ecf20Sopenharmony_ci( 1598c2ecf20Sopenharmony_ci "Winfried Ritsch <ritsch_AT_iem.at>, " 1608c2ecf20Sopenharmony_ci "Paul Davis <paul@linuxaudiosystems.com>, " 1618c2ecf20Sopenharmony_ci "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, " 1628c2ecf20Sopenharmony_ci "Remy Bruno <remy.bruno@trinnov.com>, " 1638c2ecf20Sopenharmony_ci "Florian Faber <faberman@linuxproaudio.org>, " 1648c2ecf20Sopenharmony_ci "Adrian Knoth <adi@drcomp.erfurt.thur.de>" 1658c2ecf20Sopenharmony_ci); 1668c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RME HDSPM"); 1678c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1688c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* --- Write registers. --- 1718c2ecf20Sopenharmony_ci These are defined as byte-offsets from the iobase value. */ 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci#define HDSPM_WR_SETTINGS 0 1748c2ecf20Sopenharmony_ci#define HDSPM_outputBufferAddress 32 1758c2ecf20Sopenharmony_ci#define HDSPM_inputBufferAddress 36 1768c2ecf20Sopenharmony_ci#define HDSPM_controlRegister 64 1778c2ecf20Sopenharmony_ci#define HDSPM_interruptConfirmation 96 1788c2ecf20Sopenharmony_ci#define HDSPM_control2Reg 256 /* not in specs ???????? */ 1798c2ecf20Sopenharmony_ci#define HDSPM_freqReg 256 /* for setting arbitrary clock values (DDS feature) */ 1808c2ecf20Sopenharmony_ci#define HDSPM_midiDataOut0 352 /* just believe in old code */ 1818c2ecf20Sopenharmony_ci#define HDSPM_midiDataOut1 356 1828c2ecf20Sopenharmony_ci#define HDSPM_eeprom_wr 384 /* for AES32 */ 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* DMA enable for 64 channels, only Bit 0 is relevant */ 1858c2ecf20Sopenharmony_ci#define HDSPM_outputEnableBase 512 /* 512-767 input DMA */ 1868c2ecf20Sopenharmony_ci#define HDSPM_inputEnableBase 768 /* 768-1023 output DMA */ 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/* 16 page addresses for each of the 64 channels DMA buffer in and out 1898c2ecf20Sopenharmony_ci (each 64k=16*4k) Buffer must be 4k aligned (which is default i386 ????) */ 1908c2ecf20Sopenharmony_ci#define HDSPM_pageAddressBufferOut 8192 1918c2ecf20Sopenharmony_ci#define HDSPM_pageAddressBufferIn (HDSPM_pageAddressBufferOut+64*16*4) 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci#define HDSPM_MADI_mixerBase 32768 /* 32768-65535 for 2x64x64 Fader */ 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#define HDSPM_MATRIX_MIXER_SIZE 8192 /* = 2*64*64 * 4 Byte => 32kB */ 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* --- Read registers. --- 1988c2ecf20Sopenharmony_ci These are defined as byte-offsets from the iobase value */ 1998c2ecf20Sopenharmony_ci#define HDSPM_statusRegister 0 2008c2ecf20Sopenharmony_ci/*#define HDSPM_statusRegister2 96 */ 2018c2ecf20Sopenharmony_ci/* after RME Windows driver sources, status2 is 4-byte word # 48 = word at 2028c2ecf20Sopenharmony_ci * offset 192, for AES32 *and* MADI 2038c2ecf20Sopenharmony_ci * => need to check that offset 192 is working on MADI */ 2048c2ecf20Sopenharmony_ci#define HDSPM_statusRegister2 192 2058c2ecf20Sopenharmony_ci#define HDSPM_timecodeRegister 128 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* AIO, RayDAT */ 2088c2ecf20Sopenharmony_ci#define HDSPM_RD_STATUS_0 0 2098c2ecf20Sopenharmony_ci#define HDSPM_RD_STATUS_1 64 2108c2ecf20Sopenharmony_ci#define HDSPM_RD_STATUS_2 128 2118c2ecf20Sopenharmony_ci#define HDSPM_RD_STATUS_3 192 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci#define HDSPM_RD_TCO 256 2148c2ecf20Sopenharmony_ci#define HDSPM_RD_PLL_FREQ 512 2158c2ecf20Sopenharmony_ci#define HDSPM_WR_TCO 128 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci#define HDSPM_TCO1_TCO_lock 0x00000001 2188c2ecf20Sopenharmony_ci#define HDSPM_TCO1_WCK_Input_Range_LSB 0x00000002 2198c2ecf20Sopenharmony_ci#define HDSPM_TCO1_WCK_Input_Range_MSB 0x00000004 2208c2ecf20Sopenharmony_ci#define HDSPM_TCO1_LTC_Input_valid 0x00000008 2218c2ecf20Sopenharmony_ci#define HDSPM_TCO1_WCK_Input_valid 0x00000010 2228c2ecf20Sopenharmony_ci#define HDSPM_TCO1_Video_Input_Format_NTSC 0x00000020 2238c2ecf20Sopenharmony_ci#define HDSPM_TCO1_Video_Input_Format_PAL 0x00000040 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci#define HDSPM_TCO1_set_TC 0x00000100 2268c2ecf20Sopenharmony_ci#define HDSPM_TCO1_set_drop_frame_flag 0x00000200 2278c2ecf20Sopenharmony_ci#define HDSPM_TCO1_LTC_Format_LSB 0x00000400 2288c2ecf20Sopenharmony_ci#define HDSPM_TCO1_LTC_Format_MSB 0x00000800 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci#define HDSPM_TCO2_TC_run 0x00010000 2318c2ecf20Sopenharmony_ci#define HDSPM_TCO2_WCK_IO_ratio_LSB 0x00020000 2328c2ecf20Sopenharmony_ci#define HDSPM_TCO2_WCK_IO_ratio_MSB 0x00040000 2338c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_num_drop_frames_LSB 0x00080000 2348c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_num_drop_frames_MSB 0x00100000 2358c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_jam_sync 0x00200000 2368c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_flywheel 0x00400000 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_01_4 0x01000000 2398c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_pull_down 0x02000000 2408c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_pull_up 0x04000000 2418c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_freq 0x08000000 2428c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_term_75R 0x10000000 2438c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_input_LSB 0x20000000 2448c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_input_MSB 0x40000000 2458c2ecf20Sopenharmony_ci#define HDSPM_TCO2_set_freq_from_app 0x80000000 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci#define HDSPM_midiDataOut0 352 2498c2ecf20Sopenharmony_ci#define HDSPM_midiDataOut1 356 2508c2ecf20Sopenharmony_ci#define HDSPM_midiDataOut2 368 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci#define HDSPM_midiDataIn0 360 2538c2ecf20Sopenharmony_ci#define HDSPM_midiDataIn1 364 2548c2ecf20Sopenharmony_ci#define HDSPM_midiDataIn2 372 2558c2ecf20Sopenharmony_ci#define HDSPM_midiDataIn3 376 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* status is data bytes in MIDI-FIFO (0-128) */ 2588c2ecf20Sopenharmony_ci#define HDSPM_midiStatusOut0 384 2598c2ecf20Sopenharmony_ci#define HDSPM_midiStatusOut1 388 2608c2ecf20Sopenharmony_ci#define HDSPM_midiStatusOut2 400 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci#define HDSPM_midiStatusIn0 392 2638c2ecf20Sopenharmony_ci#define HDSPM_midiStatusIn1 396 2648c2ecf20Sopenharmony_ci#define HDSPM_midiStatusIn2 404 2658c2ecf20Sopenharmony_ci#define HDSPM_midiStatusIn3 408 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* the meters are regular i/o-mapped registers, but offset 2698c2ecf20Sopenharmony_ci considerably from the rest. the peak registers are reset 2708c2ecf20Sopenharmony_ci when read; the least-significant 4 bits are full-scale counters; 2718c2ecf20Sopenharmony_ci the actual peak value is in the most-significant 24 bits. 2728c2ecf20Sopenharmony_ci*/ 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci#define HDSPM_MADI_INPUT_PEAK 4096 2758c2ecf20Sopenharmony_ci#define HDSPM_MADI_PLAYBACK_PEAK 4352 2768c2ecf20Sopenharmony_ci#define HDSPM_MADI_OUTPUT_PEAK 4608 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci#define HDSPM_MADI_INPUT_RMS_L 6144 2798c2ecf20Sopenharmony_ci#define HDSPM_MADI_PLAYBACK_RMS_L 6400 2808c2ecf20Sopenharmony_ci#define HDSPM_MADI_OUTPUT_RMS_L 6656 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci#define HDSPM_MADI_INPUT_RMS_H 7168 2838c2ecf20Sopenharmony_ci#define HDSPM_MADI_PLAYBACK_RMS_H 7424 2848c2ecf20Sopenharmony_ci#define HDSPM_MADI_OUTPUT_RMS_H 7680 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* --- Control Register bits --------- */ 2878c2ecf20Sopenharmony_ci#define HDSPM_Start (1<<0) /* start engine */ 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci#define HDSPM_Latency0 (1<<1) /* buffer size = 2^n */ 2908c2ecf20Sopenharmony_ci#define HDSPM_Latency1 (1<<2) /* where n is defined */ 2918c2ecf20Sopenharmony_ci#define HDSPM_Latency2 (1<<3) /* by Latency{2,1,0} */ 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci#define HDSPM_ClockModeMaster (1<<4) /* 1=Master, 0=Autosync */ 2948c2ecf20Sopenharmony_ci#define HDSPM_c0Master 0x1 /* Master clock bit in settings 2958c2ecf20Sopenharmony_ci register [RayDAT, AIO] */ 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci#define HDSPM_AudioInterruptEnable (1<<5) /* what do you think ? */ 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci#define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ 3008c2ecf20Sopenharmony_ci#define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */ 3018c2ecf20Sopenharmony_ci#define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ 3028c2ecf20Sopenharmony_ci#define HDSPM_QuadSpeed (1<<31) /* quad speed bit */ 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci#define HDSPM_Professional (1<<9) /* Professional */ /* AES32 ONLY */ 3058c2ecf20Sopenharmony_ci#define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1, 3068c2ecf20Sopenharmony_ci 56channelMODE=0 */ /* MADI ONLY*/ 3078c2ecf20Sopenharmony_ci#define HDSPM_Emphasis (1<<10) /* Emphasis */ /* AES32 ONLY */ 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci#define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode, 3108c2ecf20Sopenharmony_ci 0=off, 1=on */ /* MADI ONLY */ 3118c2ecf20Sopenharmony_ci#define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */ 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax 3148c2ecf20Sopenharmony_ci * -- MADI ONLY 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci#define HDSPM_InputSelect1 (1<<15) /* should be 0 */ 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci#define HDSPM_SyncRef2 (1<<13) 3198c2ecf20Sopenharmony_ci#define HDSPM_SyncRef3 (1<<25) 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci#define HDSPM_SMUX (1<<18) /* Frame ??? */ /* MADI ONY */ 3228c2ecf20Sopenharmony_ci#define HDSPM_clr_tms (1<<19) /* clear track marker, do not use 3238c2ecf20Sopenharmony_ci AES additional bits in 3248c2ecf20Sopenharmony_ci lower 5 Audiodatabits ??? */ 3258c2ecf20Sopenharmony_ci#define HDSPM_taxi_reset (1<<20) /* ??? */ /* MADI ONLY ? */ 3268c2ecf20Sopenharmony_ci#define HDSPM_WCK48 (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */ 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci#define HDSPM_Midi0InterruptEnable 0x0400000 3298c2ecf20Sopenharmony_ci#define HDSPM_Midi1InterruptEnable 0x0800000 3308c2ecf20Sopenharmony_ci#define HDSPM_Midi2InterruptEnable 0x0200000 3318c2ecf20Sopenharmony_ci#define HDSPM_Midi3InterruptEnable 0x4000000 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci#define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */ 3348c2ecf20Sopenharmony_ci#define HDSPe_FLOAT_FORMAT 0x2000000 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci#define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */ 3378c2ecf20Sopenharmony_ci#define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */ 3388c2ecf20Sopenharmony_ci#define HDSPM_QS_QuadWire (1<<28) /* AES32 ONLY */ 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci#define HDSPM_wclk_sel (1<<30) 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci/* additional control register bits for AIO*/ 3438c2ecf20Sopenharmony_ci#define HDSPM_c0_Wck48 0x20 /* also RayDAT */ 3448c2ecf20Sopenharmony_ci#define HDSPM_c0_Input0 0x1000 3458c2ecf20Sopenharmony_ci#define HDSPM_c0_Input1 0x2000 3468c2ecf20Sopenharmony_ci#define HDSPM_c0_Spdif_Opt 0x4000 3478c2ecf20Sopenharmony_ci#define HDSPM_c0_Pro 0x8000 3488c2ecf20Sopenharmony_ci#define HDSPM_c0_clr_tms 0x10000 3498c2ecf20Sopenharmony_ci#define HDSPM_c0_AEB1 0x20000 3508c2ecf20Sopenharmony_ci#define HDSPM_c0_AEB2 0x40000 3518c2ecf20Sopenharmony_ci#define HDSPM_c0_LineOut 0x80000 3528c2ecf20Sopenharmony_ci#define HDSPM_c0_AD_GAIN0 0x100000 3538c2ecf20Sopenharmony_ci#define HDSPM_c0_AD_GAIN1 0x200000 3548c2ecf20Sopenharmony_ci#define HDSPM_c0_DA_GAIN0 0x400000 3558c2ecf20Sopenharmony_ci#define HDSPM_c0_DA_GAIN1 0x800000 3568c2ecf20Sopenharmony_ci#define HDSPM_c0_PH_GAIN0 0x1000000 3578c2ecf20Sopenharmony_ci#define HDSPM_c0_PH_GAIN1 0x2000000 3588c2ecf20Sopenharmony_ci#define HDSPM_c0_Sym6db 0x4000000 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci/* --- bit helper defines */ 3628c2ecf20Sopenharmony_ci#define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) 3638c2ecf20Sopenharmony_ci#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ 3648c2ecf20Sopenharmony_ci HDSPM_DoubleSpeed|HDSPM_QuadSpeed) 3658c2ecf20Sopenharmony_ci#define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) 3668c2ecf20Sopenharmony_ci#define HDSPM_InputOptical 0 3678c2ecf20Sopenharmony_ci#define HDSPM_InputCoaxial (HDSPM_InputSelect0) 3688c2ecf20Sopenharmony_ci#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|\ 3698c2ecf20Sopenharmony_ci HDSPM_SyncRef2|HDSPM_SyncRef3) 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci#define HDSPM_c0_SyncRef0 0x2 3728c2ecf20Sopenharmony_ci#define HDSPM_c0_SyncRef1 0x4 3738c2ecf20Sopenharmony_ci#define HDSPM_c0_SyncRef2 0x8 3748c2ecf20Sopenharmony_ci#define HDSPM_c0_SyncRef3 0x10 3758c2ecf20Sopenharmony_ci#define HDSPM_c0_SyncRefMask (HDSPM_c0_SyncRef0 | HDSPM_c0_SyncRef1 |\ 3768c2ecf20Sopenharmony_ci HDSPM_c0_SyncRef2 | HDSPM_c0_SyncRef3) 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci#define HDSPM_SYNC_FROM_WORD 0 /* Preferred sync reference */ 3798c2ecf20Sopenharmony_ci#define HDSPM_SYNC_FROM_MADI 1 /* choices - used by "pref_sync_ref" */ 3808c2ecf20Sopenharmony_ci#define HDSPM_SYNC_FROM_TCO 2 3818c2ecf20Sopenharmony_ci#define HDSPM_SYNC_FROM_SYNC_IN 3 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci#define HDSPM_Frequency32KHz HDSPM_Frequency0 3848c2ecf20Sopenharmony_ci#define HDSPM_Frequency44_1KHz HDSPM_Frequency1 3858c2ecf20Sopenharmony_ci#define HDSPM_Frequency48KHz (HDSPM_Frequency1|HDSPM_Frequency0) 3868c2ecf20Sopenharmony_ci#define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) 3878c2ecf20Sopenharmony_ci#define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) 3888c2ecf20Sopenharmony_ci#define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|\ 3898c2ecf20Sopenharmony_ci HDSPM_Frequency0) 3908c2ecf20Sopenharmony_ci#define HDSPM_Frequency128KHz (HDSPM_QuadSpeed|HDSPM_Frequency0) 3918c2ecf20Sopenharmony_ci#define HDSPM_Frequency176_4KHz (HDSPM_QuadSpeed|HDSPM_Frequency1) 3928c2ecf20Sopenharmony_ci#define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|\ 3938c2ecf20Sopenharmony_ci HDSPM_Frequency0) 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci/* Synccheck Status */ 3978c2ecf20Sopenharmony_ci#define HDSPM_SYNC_CHECK_NO_LOCK 0 3988c2ecf20Sopenharmony_ci#define HDSPM_SYNC_CHECK_LOCK 1 3998c2ecf20Sopenharmony_ci#define HDSPM_SYNC_CHECK_SYNC 2 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci/* AutoSync References - used by "autosync_ref" control switch */ 4028c2ecf20Sopenharmony_ci#define HDSPM_AUTOSYNC_FROM_WORD 0 4038c2ecf20Sopenharmony_ci#define HDSPM_AUTOSYNC_FROM_MADI 1 4048c2ecf20Sopenharmony_ci#define HDSPM_AUTOSYNC_FROM_TCO 2 4058c2ecf20Sopenharmony_ci#define HDSPM_AUTOSYNC_FROM_SYNC_IN 3 4068c2ecf20Sopenharmony_ci#define HDSPM_AUTOSYNC_FROM_NONE 4 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci/* Possible sources of MADI input */ 4098c2ecf20Sopenharmony_ci#define HDSPM_OPTICAL 0 /* optical */ 4108c2ecf20Sopenharmony_ci#define HDSPM_COAXIAL 1 /* BNC */ 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci#define hdspm_encode_latency(x) (((x)<<1) & HDSPM_LatencyMask) 4138c2ecf20Sopenharmony_ci#define hdspm_decode_latency(x) ((((x) & HDSPM_LatencyMask)>>1)) 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci#define hdspm_encode_in(x) (((x)&0x3)<<14) 4168c2ecf20Sopenharmony_ci#define hdspm_decode_in(x) (((x)>>14)&0x3) 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci/* --- control2 register bits --- */ 4198c2ecf20Sopenharmony_ci#define HDSPM_TMS (1<<0) 4208c2ecf20Sopenharmony_ci#define HDSPM_TCK (1<<1) 4218c2ecf20Sopenharmony_ci#define HDSPM_TDI (1<<2) 4228c2ecf20Sopenharmony_ci#define HDSPM_JTAG (1<<3) 4238c2ecf20Sopenharmony_ci#define HDSPM_PWDN (1<<4) 4248c2ecf20Sopenharmony_ci#define HDSPM_PROGRAM (1<<5) 4258c2ecf20Sopenharmony_ci#define HDSPM_CONFIG_MODE_0 (1<<6) 4268c2ecf20Sopenharmony_ci#define HDSPM_CONFIG_MODE_1 (1<<7) 4278c2ecf20Sopenharmony_ci/*#define HDSPM_VERSION_BIT (1<<8) not defined any more*/ 4288c2ecf20Sopenharmony_ci#define HDSPM_BIGENDIAN_MODE (1<<9) 4298c2ecf20Sopenharmony_ci#define HDSPM_RD_MULTIPLE (1<<10) 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci/* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and 4328c2ecf20Sopenharmony_ci that do not conflict with specific bits for AES32 seem to be valid also 4338c2ecf20Sopenharmony_ci for the AES32 4348c2ecf20Sopenharmony_ci */ 4358c2ecf20Sopenharmony_ci#define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ 4368c2ecf20Sopenharmony_ci#define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn MODE=0 */ 4378c2ecf20Sopenharmony_ci#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 4388c2ecf20Sopenharmony_ci * (like inp0) 4398c2ecf20Sopenharmony_ci */ 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci#define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ 4428c2ecf20Sopenharmony_ci#define HDSPM_madiSync (1<<18) /* MADI is in sync */ 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci#define HDSPM_tcoLockMadi 0x00000020 /* Optional TCO locked status for HDSPe MADI*/ 4458c2ecf20Sopenharmony_ci#define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/ 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci#define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */ 4488c2ecf20Sopenharmony_ci#define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */ 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci#define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ 4518c2ecf20Sopenharmony_ci /* since 64byte accurate, last 6 bits are not used */ 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci#define HDSPM_DoubleSpeedStatus (1<<19) /* (input) card in double speed */ 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci#define HDSPM_madiFreq0 (1<<22) /* system freq 0=error */ 4588c2ecf20Sopenharmony_ci#define HDSPM_madiFreq1 (1<<23) /* 1=32, 2=44.1 3=48 */ 4598c2ecf20Sopenharmony_ci#define HDSPM_madiFreq2 (1<<24) /* 4=64, 5=88.2 6=96 */ 4608c2ecf20Sopenharmony_ci#define HDSPM_madiFreq3 (1<<25) /* 7=128, 8=176.4 9=192 */ 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci#define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with 4638c2ecf20Sopenharmony_ci * Interrupt 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci#define HDSPM_tco_detect 0x08000000 4668c2ecf20Sopenharmony_ci#define HDSPM_tcoLockAes 0x20000000 /* Optional TCO locked status for HDSPe AES */ 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci#define HDSPM_s2_tco_detect 0x00000040 4698c2ecf20Sopenharmony_ci#define HDSPM_s2_AEBO_D 0x00000080 4708c2ecf20Sopenharmony_ci#define HDSPM_s2_AEBI_D 0x00000100 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci#define HDSPM_midi0IRQPending 0x40000000 4748c2ecf20Sopenharmony_ci#define HDSPM_midi1IRQPending 0x80000000 4758c2ecf20Sopenharmony_ci#define HDSPM_midi2IRQPending 0x20000000 4768c2ecf20Sopenharmony_ci#define HDSPM_midi2IRQPendingAES 0x00000020 4778c2ecf20Sopenharmony_ci#define HDSPM_midi3IRQPending 0x00200000 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci/* --- status bit helpers */ 4808c2ecf20Sopenharmony_ci#define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|\ 4818c2ecf20Sopenharmony_ci HDSPM_madiFreq2|HDSPM_madiFreq3) 4828c2ecf20Sopenharmony_ci#define HDSPM_madiFreq32 (HDSPM_madiFreq0) 4838c2ecf20Sopenharmony_ci#define HDSPM_madiFreq44_1 (HDSPM_madiFreq1) 4848c2ecf20Sopenharmony_ci#define HDSPM_madiFreq48 (HDSPM_madiFreq0|HDSPM_madiFreq1) 4858c2ecf20Sopenharmony_ci#define HDSPM_madiFreq64 (HDSPM_madiFreq2) 4868c2ecf20Sopenharmony_ci#define HDSPM_madiFreq88_2 (HDSPM_madiFreq0|HDSPM_madiFreq2) 4878c2ecf20Sopenharmony_ci#define HDSPM_madiFreq96 (HDSPM_madiFreq1|HDSPM_madiFreq2) 4888c2ecf20Sopenharmony_ci#define HDSPM_madiFreq128 (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2) 4898c2ecf20Sopenharmony_ci#define HDSPM_madiFreq176_4 (HDSPM_madiFreq3) 4908c2ecf20Sopenharmony_ci#define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0) 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci/* Status2 Register bits */ /* MADI ONLY */ 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci#define HDSPM_version0 (1<<0) /* not really defined but I guess */ 4958c2ecf20Sopenharmony_ci#define HDSPM_version1 (1<<1) /* in former cards it was ??? */ 4968c2ecf20Sopenharmony_ci#define HDSPM_version2 (1<<2) 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci#define HDSPM_wcLock (1<<3) /* Wordclock is detected and locked */ 4998c2ecf20Sopenharmony_ci#define HDSPM_wcSync (1<<4) /* Wordclock is in sync with systemclock */ 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci#define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */ 5028c2ecf20Sopenharmony_ci#define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */ 5038c2ecf20Sopenharmony_ci#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, 111=128 */ 5048c2ecf20Sopenharmony_ci#define HDSPM_wc_freq3 0x800 /* 1000=176.4, 1001=192 */ 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci#define HDSPM_SyncRef0 0x10000 /* Sync Reference */ 5078c2ecf20Sopenharmony_ci#define HDSPM_SyncRef1 0x20000 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci#define HDSPM_SelSyncRef0 (1<<8) /* AutoSync Source */ 5108c2ecf20Sopenharmony_ci#define HDSPM_SelSyncRef1 (1<<9) /* 000=word, 001=MADI, */ 5118c2ecf20Sopenharmony_ci#define HDSPM_SelSyncRef2 (1<<10) /* 111=no valid signal */ 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci#define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync) 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2|\ 5168c2ecf20Sopenharmony_ci HDSPM_wc_freq3) 5178c2ecf20Sopenharmony_ci#define HDSPM_wcFreq32 (HDSPM_wc_freq0) 5188c2ecf20Sopenharmony_ci#define HDSPM_wcFreq44_1 (HDSPM_wc_freq1) 5198c2ecf20Sopenharmony_ci#define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1) 5208c2ecf20Sopenharmony_ci#define HDSPM_wcFreq64 (HDSPM_wc_freq2) 5218c2ecf20Sopenharmony_ci#define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2) 5228c2ecf20Sopenharmony_ci#define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) 5238c2ecf20Sopenharmony_ci#define HDSPM_wcFreq128 (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) 5248c2ecf20Sopenharmony_ci#define HDSPM_wcFreq176_4 (HDSPM_wc_freq3) 5258c2ecf20Sopenharmony_ci#define HDSPM_wcFreq192 (HDSPM_wc_freq0|HDSPM_wc_freq3) 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci#define HDSPM_status1_F_0 0x0400000 5288c2ecf20Sopenharmony_ci#define HDSPM_status1_F_1 0x0800000 5298c2ecf20Sopenharmony_ci#define HDSPM_status1_F_2 0x1000000 5308c2ecf20Sopenharmony_ci#define HDSPM_status1_F_3 0x2000000 5318c2ecf20Sopenharmony_ci#define HDSPM_status1_freqMask (HDSPM_status1_F_0|HDSPM_status1_F_1|HDSPM_status1_F_2|HDSPM_status1_F_3) 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci#define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ 5358c2ecf20Sopenharmony_ci HDSPM_SelSyncRef2) 5368c2ecf20Sopenharmony_ci#define HDSPM_SelSyncRef_WORD 0 5378c2ecf20Sopenharmony_ci#define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) 5388c2ecf20Sopenharmony_ci#define HDSPM_SelSyncRef_TCO (HDSPM_SelSyncRef1) 5398c2ecf20Sopenharmony_ci#define HDSPM_SelSyncRef_SyncIn (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1) 5408c2ecf20Sopenharmony_ci#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ 5418c2ecf20Sopenharmony_ci HDSPM_SelSyncRef2) 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci/* 5448c2ecf20Sopenharmony_ci For AES32, bits for status, status2 and timecode are different 5458c2ecf20Sopenharmony_ci*/ 5468c2ecf20Sopenharmony_ci/* status */ 5478c2ecf20Sopenharmony_ci#define HDSPM_AES32_wcLock 0x0200000 5488c2ecf20Sopenharmony_ci#define HDSPM_AES32_wcSync 0x0100000 5498c2ecf20Sopenharmony_ci#define HDSPM_AES32_wcFreq_bit 22 5508c2ecf20Sopenharmony_ci/* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function 5518c2ecf20Sopenharmony_ci HDSPM_bit2freq */ 5528c2ecf20Sopenharmony_ci#define HDSPM_AES32_syncref_bit 16 5538c2ecf20Sopenharmony_ci/* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */ 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_WORD 0 5568c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES1 1 5578c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES2 2 5588c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES3 3 5598c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES4 4 5608c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES5 5 5618c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 5628c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 5638c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 5648c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_TCO 9 5658c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10 5668c2ecf20Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_NONE 11 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci/* status2 */ 5698c2ecf20Sopenharmony_ci/* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ 5708c2ecf20Sopenharmony_ci#define HDSPM_LockAES 0x80 5718c2ecf20Sopenharmony_ci#define HDSPM_LockAES1 0x80 5728c2ecf20Sopenharmony_ci#define HDSPM_LockAES2 0x40 5738c2ecf20Sopenharmony_ci#define HDSPM_LockAES3 0x20 5748c2ecf20Sopenharmony_ci#define HDSPM_LockAES4 0x10 5758c2ecf20Sopenharmony_ci#define HDSPM_LockAES5 0x8 5768c2ecf20Sopenharmony_ci#define HDSPM_LockAES6 0x4 5778c2ecf20Sopenharmony_ci#define HDSPM_LockAES7 0x2 5788c2ecf20Sopenharmony_ci#define HDSPM_LockAES8 0x1 5798c2ecf20Sopenharmony_ci/* 5808c2ecf20Sopenharmony_ci Timecode 5818c2ecf20Sopenharmony_ci After windows driver sources, bits 4*i to 4*i+3 give the input frequency on 5828c2ecf20Sopenharmony_ci AES i+1 5838c2ecf20Sopenharmony_ci bits 3210 5848c2ecf20Sopenharmony_ci 0001 32kHz 5858c2ecf20Sopenharmony_ci 0010 44.1kHz 5868c2ecf20Sopenharmony_ci 0011 48kHz 5878c2ecf20Sopenharmony_ci 0100 64kHz 5888c2ecf20Sopenharmony_ci 0101 88.2kHz 5898c2ecf20Sopenharmony_ci 0110 96kHz 5908c2ecf20Sopenharmony_ci 0111 128kHz 5918c2ecf20Sopenharmony_ci 1000 176.4kHz 5928c2ecf20Sopenharmony_ci 1001 192kHz 5938c2ecf20Sopenharmony_ci NB: Timecode register doesn't seem to work on AES32 card revision 230 5948c2ecf20Sopenharmony_ci*/ 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci/* Mixer Values */ 5978c2ecf20Sopenharmony_ci#define UNITY_GAIN 32768 /* = 65536/2 */ 5988c2ecf20Sopenharmony_ci#define MINUS_INFINITY_GAIN 0 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci/* Number of channels for different Speed Modes */ 6018c2ecf20Sopenharmony_ci#define MADI_SS_CHANNELS 64 6028c2ecf20Sopenharmony_ci#define MADI_DS_CHANNELS 32 6038c2ecf20Sopenharmony_ci#define MADI_QS_CHANNELS 16 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci#define RAYDAT_SS_CHANNELS 36 6068c2ecf20Sopenharmony_ci#define RAYDAT_DS_CHANNELS 20 6078c2ecf20Sopenharmony_ci#define RAYDAT_QS_CHANNELS 12 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci#define AIO_IN_SS_CHANNELS 14 6108c2ecf20Sopenharmony_ci#define AIO_IN_DS_CHANNELS 10 6118c2ecf20Sopenharmony_ci#define AIO_IN_QS_CHANNELS 8 6128c2ecf20Sopenharmony_ci#define AIO_OUT_SS_CHANNELS 16 6138c2ecf20Sopenharmony_ci#define AIO_OUT_DS_CHANNELS 12 6148c2ecf20Sopenharmony_ci#define AIO_OUT_QS_CHANNELS 10 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci#define AES32_CHANNELS 16 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* the size of a substream (1 mono data stream) */ 6198c2ecf20Sopenharmony_ci#define HDSPM_CHANNEL_BUFFER_SAMPLES (16*1024) 6208c2ecf20Sopenharmony_ci#define HDSPM_CHANNEL_BUFFER_BYTES (4*HDSPM_CHANNEL_BUFFER_SAMPLES) 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci/* the size of the area we need to allocate for DMA transfers. the 6238c2ecf20Sopenharmony_ci size is the same regardless of the number of channels, and 6248c2ecf20Sopenharmony_ci also the latency to use. 6258c2ecf20Sopenharmony_ci for one direction !!! 6268c2ecf20Sopenharmony_ci*/ 6278c2ecf20Sopenharmony_ci#define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) 6288c2ecf20Sopenharmony_ci#define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci#define HDSPM_RAYDAT_REV 211 6318c2ecf20Sopenharmony_ci#define HDSPM_AIO_REV 212 6328c2ecf20Sopenharmony_ci#define HDSPM_MADIFACE_REV 213 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci/* speed factor modes */ 6358c2ecf20Sopenharmony_ci#define HDSPM_SPEED_SINGLE 0 6368c2ecf20Sopenharmony_ci#define HDSPM_SPEED_DOUBLE 1 6378c2ecf20Sopenharmony_ci#define HDSPM_SPEED_QUAD 2 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci/* names for speed modes */ 6408c2ecf20Sopenharmony_cistatic const char * const hdspm_speed_names[] = { "single", "double", "quad" }; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic const char *const texts_autosync_aes_tco[] = { "Word Clock", 6438c2ecf20Sopenharmony_ci "AES1", "AES2", "AES3", "AES4", 6448c2ecf20Sopenharmony_ci "AES5", "AES6", "AES7", "AES8", 6458c2ecf20Sopenharmony_ci "TCO", "Sync In" 6468c2ecf20Sopenharmony_ci}; 6478c2ecf20Sopenharmony_cistatic const char *const texts_autosync_aes[] = { "Word Clock", 6488c2ecf20Sopenharmony_ci "AES1", "AES2", "AES3", "AES4", 6498c2ecf20Sopenharmony_ci "AES5", "AES6", "AES7", "AES8", 6508c2ecf20Sopenharmony_ci "Sync In" 6518c2ecf20Sopenharmony_ci}; 6528c2ecf20Sopenharmony_cistatic const char *const texts_autosync_madi_tco[] = { "Word Clock", 6538c2ecf20Sopenharmony_ci "MADI", "TCO", "Sync In" }; 6548c2ecf20Sopenharmony_cistatic const char *const texts_autosync_madi[] = { "Word Clock", 6558c2ecf20Sopenharmony_ci "MADI", "Sync In" }; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic const char *const texts_autosync_raydat_tco[] = { 6588c2ecf20Sopenharmony_ci "Word Clock", 6598c2ecf20Sopenharmony_ci "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", 6608c2ecf20Sopenharmony_ci "AES", "SPDIF", "TCO", "Sync In" 6618c2ecf20Sopenharmony_ci}; 6628c2ecf20Sopenharmony_cistatic const char *const texts_autosync_raydat[] = { 6638c2ecf20Sopenharmony_ci "Word Clock", 6648c2ecf20Sopenharmony_ci "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", 6658c2ecf20Sopenharmony_ci "AES", "SPDIF", "Sync In" 6668c2ecf20Sopenharmony_ci}; 6678c2ecf20Sopenharmony_cistatic const char *const texts_autosync_aio_tco[] = { 6688c2ecf20Sopenharmony_ci "Word Clock", 6698c2ecf20Sopenharmony_ci "ADAT", "AES", "SPDIF", "TCO", "Sync In" 6708c2ecf20Sopenharmony_ci}; 6718c2ecf20Sopenharmony_cistatic const char *const texts_autosync_aio[] = { "Word Clock", 6728c2ecf20Sopenharmony_ci "ADAT", "AES", "SPDIF", "Sync In" }; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic const char *const texts_freq[] = { 6758c2ecf20Sopenharmony_ci "No Lock", 6768c2ecf20Sopenharmony_ci "32 kHz", 6778c2ecf20Sopenharmony_ci "44.1 kHz", 6788c2ecf20Sopenharmony_ci "48 kHz", 6798c2ecf20Sopenharmony_ci "64 kHz", 6808c2ecf20Sopenharmony_ci "88.2 kHz", 6818c2ecf20Sopenharmony_ci "96 kHz", 6828c2ecf20Sopenharmony_ci "128 kHz", 6838c2ecf20Sopenharmony_ci "176.4 kHz", 6848c2ecf20Sopenharmony_ci "192 kHz" 6858c2ecf20Sopenharmony_ci}; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic const char * const texts_ports_madi[] = { 6888c2ecf20Sopenharmony_ci "MADI.1", "MADI.2", "MADI.3", "MADI.4", "MADI.5", "MADI.6", 6898c2ecf20Sopenharmony_ci "MADI.7", "MADI.8", "MADI.9", "MADI.10", "MADI.11", "MADI.12", 6908c2ecf20Sopenharmony_ci "MADI.13", "MADI.14", "MADI.15", "MADI.16", "MADI.17", "MADI.18", 6918c2ecf20Sopenharmony_ci "MADI.19", "MADI.20", "MADI.21", "MADI.22", "MADI.23", "MADI.24", 6928c2ecf20Sopenharmony_ci "MADI.25", "MADI.26", "MADI.27", "MADI.28", "MADI.29", "MADI.30", 6938c2ecf20Sopenharmony_ci "MADI.31", "MADI.32", "MADI.33", "MADI.34", "MADI.35", "MADI.36", 6948c2ecf20Sopenharmony_ci "MADI.37", "MADI.38", "MADI.39", "MADI.40", "MADI.41", "MADI.42", 6958c2ecf20Sopenharmony_ci "MADI.43", "MADI.44", "MADI.45", "MADI.46", "MADI.47", "MADI.48", 6968c2ecf20Sopenharmony_ci "MADI.49", "MADI.50", "MADI.51", "MADI.52", "MADI.53", "MADI.54", 6978c2ecf20Sopenharmony_ci "MADI.55", "MADI.56", "MADI.57", "MADI.58", "MADI.59", "MADI.60", 6988c2ecf20Sopenharmony_ci "MADI.61", "MADI.62", "MADI.63", "MADI.64", 6998c2ecf20Sopenharmony_ci}; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic const char * const texts_ports_raydat_ss[] = { 7038c2ecf20Sopenharmony_ci "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4", "ADAT1.5", "ADAT1.6", 7048c2ecf20Sopenharmony_ci "ADAT1.7", "ADAT1.8", "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4", 7058c2ecf20Sopenharmony_ci "ADAT2.5", "ADAT2.6", "ADAT2.7", "ADAT2.8", "ADAT3.1", "ADAT3.2", 7068c2ecf20Sopenharmony_ci "ADAT3.3", "ADAT3.4", "ADAT3.5", "ADAT3.6", "ADAT3.7", "ADAT3.8", 7078c2ecf20Sopenharmony_ci "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4", "ADAT4.5", "ADAT4.6", 7088c2ecf20Sopenharmony_ci "ADAT4.7", "ADAT4.8", 7098c2ecf20Sopenharmony_ci "AES.L", "AES.R", 7108c2ecf20Sopenharmony_ci "SPDIF.L", "SPDIF.R" 7118c2ecf20Sopenharmony_ci}; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic const char * const texts_ports_raydat_ds[] = { 7148c2ecf20Sopenharmony_ci "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4", 7158c2ecf20Sopenharmony_ci "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4", 7168c2ecf20Sopenharmony_ci "ADAT3.1", "ADAT3.2", "ADAT3.3", "ADAT3.4", 7178c2ecf20Sopenharmony_ci "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4", 7188c2ecf20Sopenharmony_ci "AES.L", "AES.R", 7198c2ecf20Sopenharmony_ci "SPDIF.L", "SPDIF.R" 7208c2ecf20Sopenharmony_ci}; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic const char * const texts_ports_raydat_qs[] = { 7238c2ecf20Sopenharmony_ci "ADAT1.1", "ADAT1.2", 7248c2ecf20Sopenharmony_ci "ADAT2.1", "ADAT2.2", 7258c2ecf20Sopenharmony_ci "ADAT3.1", "ADAT3.2", 7268c2ecf20Sopenharmony_ci "ADAT4.1", "ADAT4.2", 7278c2ecf20Sopenharmony_ci "AES.L", "AES.R", 7288c2ecf20Sopenharmony_ci "SPDIF.L", "SPDIF.R" 7298c2ecf20Sopenharmony_ci}; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic const char * const texts_ports_aio_in_ss[] = { 7338c2ecf20Sopenharmony_ci "Analogue.L", "Analogue.R", 7348c2ecf20Sopenharmony_ci "AES.L", "AES.R", 7358c2ecf20Sopenharmony_ci "SPDIF.L", "SPDIF.R", 7368c2ecf20Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", 7378c2ecf20Sopenharmony_ci "ADAT.7", "ADAT.8", 7388c2ecf20Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7398c2ecf20Sopenharmony_ci}; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic const char * const texts_ports_aio_out_ss[] = { 7428c2ecf20Sopenharmony_ci "Analogue.L", "Analogue.R", 7438c2ecf20Sopenharmony_ci "AES.L", "AES.R", 7448c2ecf20Sopenharmony_ci "SPDIF.L", "SPDIF.R", 7458c2ecf20Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", 7468c2ecf20Sopenharmony_ci "ADAT.7", "ADAT.8", 7478c2ecf20Sopenharmony_ci "Phone.L", "Phone.R", 7488c2ecf20Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7498c2ecf20Sopenharmony_ci}; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic const char * const texts_ports_aio_in_ds[] = { 7528c2ecf20Sopenharmony_ci "Analogue.L", "Analogue.R", 7538c2ecf20Sopenharmony_ci "AES.L", "AES.R", 7548c2ecf20Sopenharmony_ci "SPDIF.L", "SPDIF.R", 7558c2ecf20Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 7568c2ecf20Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7578c2ecf20Sopenharmony_ci}; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_cistatic const char * const texts_ports_aio_out_ds[] = { 7608c2ecf20Sopenharmony_ci "Analogue.L", "Analogue.R", 7618c2ecf20Sopenharmony_ci "AES.L", "AES.R", 7628c2ecf20Sopenharmony_ci "SPDIF.L", "SPDIF.R", 7638c2ecf20Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 7648c2ecf20Sopenharmony_ci "Phone.L", "Phone.R", 7658c2ecf20Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7668c2ecf20Sopenharmony_ci}; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic const char * const texts_ports_aio_in_qs[] = { 7698c2ecf20Sopenharmony_ci "Analogue.L", "Analogue.R", 7708c2ecf20Sopenharmony_ci "AES.L", "AES.R", 7718c2ecf20Sopenharmony_ci "SPDIF.L", "SPDIF.R", 7728c2ecf20Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 7738c2ecf20Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7748c2ecf20Sopenharmony_ci}; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic const char * const texts_ports_aio_out_qs[] = { 7778c2ecf20Sopenharmony_ci "Analogue.L", "Analogue.R", 7788c2ecf20Sopenharmony_ci "AES.L", "AES.R", 7798c2ecf20Sopenharmony_ci "SPDIF.L", "SPDIF.R", 7808c2ecf20Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 7818c2ecf20Sopenharmony_ci "Phone.L", "Phone.R", 7828c2ecf20Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7838c2ecf20Sopenharmony_ci}; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic const char * const texts_ports_aes32[] = { 7868c2ecf20Sopenharmony_ci "AES.1", "AES.2", "AES.3", "AES.4", "AES.5", "AES.6", "AES.7", 7878c2ecf20Sopenharmony_ci "AES.8", "AES.9.", "AES.10", "AES.11", "AES.12", "AES.13", "AES.14", 7888c2ecf20Sopenharmony_ci "AES.15", "AES.16" 7898c2ecf20Sopenharmony_ci}; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci/* These tables map the ALSA channels 1..N to the channels that we 7928c2ecf20Sopenharmony_ci need to use in order to find the relevant channel buffer. RME 7938c2ecf20Sopenharmony_ci refers to this kind of mapping as between "the ADAT channel and 7948c2ecf20Sopenharmony_ci the DMA channel." We index it using the logical audio channel, 7958c2ecf20Sopenharmony_ci and the value is the DMA channel (i.e. channel buffer number) 7968c2ecf20Sopenharmony_ci where the data for that channel can be read/written from/to. 7978c2ecf20Sopenharmony_ci*/ 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic const char channel_map_unity_ss[HDSPM_MAX_CHANNELS] = { 8008c2ecf20Sopenharmony_ci 0, 1, 2, 3, 4, 5, 6, 7, 8018c2ecf20Sopenharmony_ci 8, 9, 10, 11, 12, 13, 14, 15, 8028c2ecf20Sopenharmony_ci 16, 17, 18, 19, 20, 21, 22, 23, 8038c2ecf20Sopenharmony_ci 24, 25, 26, 27, 28, 29, 30, 31, 8048c2ecf20Sopenharmony_ci 32, 33, 34, 35, 36, 37, 38, 39, 8058c2ecf20Sopenharmony_ci 40, 41, 42, 43, 44, 45, 46, 47, 8068c2ecf20Sopenharmony_ci 48, 49, 50, 51, 52, 53, 54, 55, 8078c2ecf20Sopenharmony_ci 56, 57, 58, 59, 60, 61, 62, 63 8088c2ecf20Sopenharmony_ci}; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic const char channel_map_raydat_ss[HDSPM_MAX_CHANNELS] = { 8118c2ecf20Sopenharmony_ci 4, 5, 6, 7, 8, 9, 10, 11, /* ADAT 1 */ 8128c2ecf20Sopenharmony_ci 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT 2 */ 8138c2ecf20Sopenharmony_ci 20, 21, 22, 23, 24, 25, 26, 27, /* ADAT 3 */ 8148c2ecf20Sopenharmony_ci 28, 29, 30, 31, 32, 33, 34, 35, /* ADAT 4 */ 8158c2ecf20Sopenharmony_ci 0, 1, /* AES */ 8168c2ecf20Sopenharmony_ci 2, 3, /* SPDIF */ 8178c2ecf20Sopenharmony_ci -1, -1, -1, -1, 8188c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8198c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8208c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8218c2ecf20Sopenharmony_ci}; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_cistatic const char channel_map_raydat_ds[HDSPM_MAX_CHANNELS] = { 8248c2ecf20Sopenharmony_ci 4, 5, 6, 7, /* ADAT 1 */ 8258c2ecf20Sopenharmony_ci 8, 9, 10, 11, /* ADAT 2 */ 8268c2ecf20Sopenharmony_ci 12, 13, 14, 15, /* ADAT 3 */ 8278c2ecf20Sopenharmony_ci 16, 17, 18, 19, /* ADAT 4 */ 8288c2ecf20Sopenharmony_ci 0, 1, /* AES */ 8298c2ecf20Sopenharmony_ci 2, 3, /* SPDIF */ 8308c2ecf20Sopenharmony_ci -1, -1, -1, -1, 8318c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8328c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8338c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8348c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8358c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8368c2ecf20Sopenharmony_ci}; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic const char channel_map_raydat_qs[HDSPM_MAX_CHANNELS] = { 8398c2ecf20Sopenharmony_ci 4, 5, /* ADAT 1 */ 8408c2ecf20Sopenharmony_ci 6, 7, /* ADAT 2 */ 8418c2ecf20Sopenharmony_ci 8, 9, /* ADAT 3 */ 8428c2ecf20Sopenharmony_ci 10, 11, /* ADAT 4 */ 8438c2ecf20Sopenharmony_ci 0, 1, /* AES */ 8448c2ecf20Sopenharmony_ci 2, 3, /* SPDIF */ 8458c2ecf20Sopenharmony_ci -1, -1, -1, -1, 8468c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8478c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8488c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8498c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8508c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8518c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8528c2ecf20Sopenharmony_ci}; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_cistatic const char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = { 8558c2ecf20Sopenharmony_ci 0, 1, /* line in */ 8568c2ecf20Sopenharmony_ci 8, 9, /* aes in, */ 8578c2ecf20Sopenharmony_ci 10, 11, /* spdif in */ 8588c2ecf20Sopenharmony_ci 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */ 8598c2ecf20Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 8608c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, 8618c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8628c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8638c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8648c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8658c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8668c2ecf20Sopenharmony_ci}; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic const char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = { 8698c2ecf20Sopenharmony_ci 0, 1, /* line out */ 8708c2ecf20Sopenharmony_ci 8, 9, /* aes out */ 8718c2ecf20Sopenharmony_ci 10, 11, /* spdif out */ 8728c2ecf20Sopenharmony_ci 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */ 8738c2ecf20Sopenharmony_ci 6, 7, /* phone out */ 8748c2ecf20Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 8758c2ecf20Sopenharmony_ci -1, -1, -1, -1, 8768c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8778c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8788c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8798c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8808c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8818c2ecf20Sopenharmony_ci}; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic const char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = { 8848c2ecf20Sopenharmony_ci 0, 1, /* line in */ 8858c2ecf20Sopenharmony_ci 8, 9, /* aes in */ 8868c2ecf20Sopenharmony_ci 10, 11, /* spdif in */ 8878c2ecf20Sopenharmony_ci 12, 14, 16, 18, /* adat in */ 8888c2ecf20Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 8898c2ecf20Sopenharmony_ci -1, -1, 8908c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8918c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8928c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8938c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8948c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8958c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 8968c2ecf20Sopenharmony_ci}; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic const char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = { 8998c2ecf20Sopenharmony_ci 0, 1, /* line out */ 9008c2ecf20Sopenharmony_ci 8, 9, /* aes out */ 9018c2ecf20Sopenharmony_ci 10, 11, /* spdif out */ 9028c2ecf20Sopenharmony_ci 12, 14, 16, 18, /* adat out */ 9038c2ecf20Sopenharmony_ci 6, 7, /* phone out */ 9048c2ecf20Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 9058c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9068c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9078c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9088c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9098c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9108c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 9118c2ecf20Sopenharmony_ci}; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistatic const char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = { 9148c2ecf20Sopenharmony_ci 0, 1, /* line in */ 9158c2ecf20Sopenharmony_ci 8, 9, /* aes in */ 9168c2ecf20Sopenharmony_ci 10, 11, /* spdif in */ 9178c2ecf20Sopenharmony_ci 12, 16, /* adat in */ 9188c2ecf20Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 9198c2ecf20Sopenharmony_ci -1, -1, -1, -1, 9208c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9218c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9228c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9238c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9248c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9258c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 9268c2ecf20Sopenharmony_ci}; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic const char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = { 9298c2ecf20Sopenharmony_ci 0, 1, /* line out */ 9308c2ecf20Sopenharmony_ci 8, 9, /* aes out */ 9318c2ecf20Sopenharmony_ci 10, 11, /* spdif out */ 9328c2ecf20Sopenharmony_ci 12, 16, /* adat out */ 9338c2ecf20Sopenharmony_ci 6, 7, /* phone out */ 9348c2ecf20Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 9358c2ecf20Sopenharmony_ci -1, -1, 9368c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9378c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9388c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9398c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9408c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9418c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 9428c2ecf20Sopenharmony_ci}; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_cistatic const char channel_map_aes32[HDSPM_MAX_CHANNELS] = { 9458c2ecf20Sopenharmony_ci 0, 1, 2, 3, 4, 5, 6, 7, 9468c2ecf20Sopenharmony_ci 8, 9, 10, 11, 12, 13, 14, 15, 9478c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9488c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9498c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9508c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9518c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9528c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 9538c2ecf20Sopenharmony_ci}; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistruct hdspm_midi { 9568c2ecf20Sopenharmony_ci struct hdspm *hdspm; 9578c2ecf20Sopenharmony_ci int id; 9588c2ecf20Sopenharmony_ci struct snd_rawmidi *rmidi; 9598c2ecf20Sopenharmony_ci struct snd_rawmidi_substream *input; 9608c2ecf20Sopenharmony_ci struct snd_rawmidi_substream *output; 9618c2ecf20Sopenharmony_ci char istimer; /* timer in use */ 9628c2ecf20Sopenharmony_ci struct timer_list timer; 9638c2ecf20Sopenharmony_ci spinlock_t lock; 9648c2ecf20Sopenharmony_ci int pending; 9658c2ecf20Sopenharmony_ci int dataIn; 9668c2ecf20Sopenharmony_ci int statusIn; 9678c2ecf20Sopenharmony_ci int dataOut; 9688c2ecf20Sopenharmony_ci int statusOut; 9698c2ecf20Sopenharmony_ci int ie; 9708c2ecf20Sopenharmony_ci int irq; 9718c2ecf20Sopenharmony_ci}; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_cistruct hdspm_tco { 9748c2ecf20Sopenharmony_ci int input; /* 0: LTC, 1:Video, 2: WC*/ 9758c2ecf20Sopenharmony_ci int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */ 9768c2ecf20Sopenharmony_ci int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */ 9778c2ecf20Sopenharmony_ci int samplerate; /* 0=44.1, 1=48, 2= freq from app */ 9788c2ecf20Sopenharmony_ci int pull; /* 0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/ 9798c2ecf20Sopenharmony_ci int term; /* 0 = off, 1 = on */ 9808c2ecf20Sopenharmony_ci}; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistruct hdspm { 9838c2ecf20Sopenharmony_ci spinlock_t lock; 9848c2ecf20Sopenharmony_ci /* only one playback and/or capture stream */ 9858c2ecf20Sopenharmony_ci struct snd_pcm_substream *capture_substream; 9868c2ecf20Sopenharmony_ci struct snd_pcm_substream *playback_substream; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci char *card_name; /* for procinfo */ 9898c2ecf20Sopenharmony_ci unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/ 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci uint8_t io_type; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci int monitor_outs; /* set up monitoring outs init flag */ 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci u32 control_register; /* cached value */ 9968c2ecf20Sopenharmony_ci u32 control2_register; /* cached value */ 9978c2ecf20Sopenharmony_ci u32 settings_register; /* cached value for AIO / RayDat (sync reference, master/slave) */ 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci struct hdspm_midi midi[4]; 10008c2ecf20Sopenharmony_ci struct work_struct midi_work; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci size_t period_bytes; 10038c2ecf20Sopenharmony_ci unsigned char ss_in_channels; 10048c2ecf20Sopenharmony_ci unsigned char ds_in_channels; 10058c2ecf20Sopenharmony_ci unsigned char qs_in_channels; 10068c2ecf20Sopenharmony_ci unsigned char ss_out_channels; 10078c2ecf20Sopenharmony_ci unsigned char ds_out_channels; 10088c2ecf20Sopenharmony_ci unsigned char qs_out_channels; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci unsigned char max_channels_in; 10118c2ecf20Sopenharmony_ci unsigned char max_channels_out; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci const signed char *channel_map_in; 10148c2ecf20Sopenharmony_ci const signed char *channel_map_out; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci const signed char *channel_map_in_ss, *channel_map_in_ds, *channel_map_in_qs; 10178c2ecf20Sopenharmony_ci const signed char *channel_map_out_ss, *channel_map_out_ds, *channel_map_out_qs; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci const char * const *port_names_in; 10208c2ecf20Sopenharmony_ci const char * const *port_names_out; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci const char * const *port_names_in_ss; 10238c2ecf20Sopenharmony_ci const char * const *port_names_in_ds; 10248c2ecf20Sopenharmony_ci const char * const *port_names_in_qs; 10258c2ecf20Sopenharmony_ci const char * const *port_names_out_ss; 10268c2ecf20Sopenharmony_ci const char * const *port_names_out_ds; 10278c2ecf20Sopenharmony_ci const char * const *port_names_out_qs; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci unsigned char *playback_buffer; /* suitably aligned address */ 10308c2ecf20Sopenharmony_ci unsigned char *capture_buffer; /* suitably aligned address */ 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci pid_t capture_pid; /* process id which uses capture */ 10338c2ecf20Sopenharmony_ci pid_t playback_pid; /* process id which uses capture */ 10348c2ecf20Sopenharmony_ci int running; /* running status */ 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci int last_external_sample_rate; /* samplerate mystic ... */ 10378c2ecf20Sopenharmony_ci int last_internal_sample_rate; 10388c2ecf20Sopenharmony_ci int system_sample_rate; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci int dev; /* Hardware vars... */ 10418c2ecf20Sopenharmony_ci int irq; 10428c2ecf20Sopenharmony_ci unsigned long port; 10438c2ecf20Sopenharmony_ci void __iomem *iobase; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci int irq_count; /* for debug */ 10468c2ecf20Sopenharmony_ci int midiPorts; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci struct snd_card *card; /* one card */ 10498c2ecf20Sopenharmony_ci struct snd_pcm *pcm; /* has one pcm */ 10508c2ecf20Sopenharmony_ci struct snd_hwdep *hwdep; /* and a hwdep for additional ioctl */ 10518c2ecf20Sopenharmony_ci struct pci_dev *pci; /* and an pci info */ 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* Mixer vars */ 10548c2ecf20Sopenharmony_ci /* fast alsa mixer */ 10558c2ecf20Sopenharmony_ci struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; 10568c2ecf20Sopenharmony_ci /* but input to much, so not used */ 10578c2ecf20Sopenharmony_ci struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS]; 10588c2ecf20Sopenharmony_ci /* full mixer accessible over mixer ioctl or hwdep-device */ 10598c2ecf20Sopenharmony_ci struct hdspm_mixer *mixer; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci struct hdspm_tco *tco; /* NULL if no TCO detected */ 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci const char *const *texts_autosync; 10648c2ecf20Sopenharmony_ci int texts_autosync_items; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci cycles_t last_interrupt; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci unsigned int serial; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci struct hdspm_peak_rms peak_rms; 10718c2ecf20Sopenharmony_ci}; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_cistatic const struct pci_device_id snd_hdspm_ids[] = { 10758c2ecf20Sopenharmony_ci { 10768c2ecf20Sopenharmony_ci .vendor = PCI_VENDOR_ID_XILINX, 10778c2ecf20Sopenharmony_ci .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, 10788c2ecf20Sopenharmony_ci .subvendor = PCI_ANY_ID, 10798c2ecf20Sopenharmony_ci .subdevice = PCI_ANY_ID, 10808c2ecf20Sopenharmony_ci .class = 0, 10818c2ecf20Sopenharmony_ci .class_mask = 0, 10828c2ecf20Sopenharmony_ci .driver_data = 0}, 10838c2ecf20Sopenharmony_ci {0,} 10848c2ecf20Sopenharmony_ci}; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_hdspm_ids); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci/* prototypes */ 10898c2ecf20Sopenharmony_cistatic int snd_hdspm_create_alsa_devices(struct snd_card *card, 10908c2ecf20Sopenharmony_ci struct hdspm *hdspm); 10918c2ecf20Sopenharmony_cistatic int snd_hdspm_create_pcm(struct snd_card *card, 10928c2ecf20Sopenharmony_ci struct hdspm *hdspm); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm); 10958c2ecf20Sopenharmony_cistatic inline int hdspm_get_pll_freq(struct hdspm *hdspm); 10968c2ecf20Sopenharmony_cistatic int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); 10978c2ecf20Sopenharmony_cistatic int hdspm_autosync_ref(struct hdspm *hdspm); 10988c2ecf20Sopenharmony_cistatic int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out); 10998c2ecf20Sopenharmony_cistatic int snd_hdspm_set_defaults(struct hdspm *hdspm); 11008c2ecf20Sopenharmony_cistatic int hdspm_system_clock_mode(struct hdspm *hdspm); 11018c2ecf20Sopenharmony_cistatic void hdspm_set_channel_dma_addr(struct hdspm *hdspm, 11028c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, 11038c2ecf20Sopenharmony_ci unsigned int reg, int channels); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_cistatic int hdspm_aes_sync_check(struct hdspm *hdspm, int idx); 11068c2ecf20Sopenharmony_cistatic int hdspm_wc_sync_check(struct hdspm *hdspm); 11078c2ecf20Sopenharmony_cistatic int hdspm_tco_sync_check(struct hdspm *hdspm); 11088c2ecf20Sopenharmony_cistatic int hdspm_sync_in_sync_check(struct hdspm *hdspm); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_cistatic int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index); 11118c2ecf20Sopenharmony_cistatic int hdspm_get_tco_sample_rate(struct hdspm *hdspm); 11128c2ecf20Sopenharmony_cistatic int hdspm_get_wc_sample_rate(struct hdspm *hdspm); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic inline int HDSPM_bit2freq(int n) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci static const int bit2freq_tab[] = { 11198c2ecf20Sopenharmony_ci 0, 32000, 44100, 48000, 64000, 88200, 11208c2ecf20Sopenharmony_ci 96000, 128000, 176400, 192000 }; 11218c2ecf20Sopenharmony_ci if (n < 1 || n > 9) 11228c2ecf20Sopenharmony_ci return 0; 11238c2ecf20Sopenharmony_ci return bit2freq_tab[n]; 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic bool hdspm_is_raydat_or_aio(struct hdspm *hdspm) 11278c2ecf20Sopenharmony_ci{ 11288c2ecf20Sopenharmony_ci return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type)); 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci/* Write/read to/from HDSPM with Adresses in Bytes 11338c2ecf20Sopenharmony_ci not words but only 32Bit writes are allowed */ 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_cistatic inline void hdspm_write(struct hdspm * hdspm, unsigned int reg, 11368c2ecf20Sopenharmony_ci unsigned int val) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci writel(val, hdspm->iobase + reg); 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic inline unsigned int hdspm_read(struct hdspm * hdspm, unsigned int reg) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci return readl(hdspm->iobase + reg); 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci/* for each output channel (chan) I have an Input (in) and Playback (pb) Fader 11478c2ecf20Sopenharmony_ci mixer is write only on hardware so we have to cache him for read 11488c2ecf20Sopenharmony_ci each fader is a u32, but uses only the first 16 bit */ 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_cistatic inline int hdspm_read_in_gain(struct hdspm * hdspm, unsigned int chan, 11518c2ecf20Sopenharmony_ci unsigned int in) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) 11548c2ecf20Sopenharmony_ci return 0; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci return hdspm->mixer->ch[chan].in[in]; 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cistatic inline int hdspm_read_pb_gain(struct hdspm * hdspm, unsigned int chan, 11608c2ecf20Sopenharmony_ci unsigned int pb) 11618c2ecf20Sopenharmony_ci{ 11628c2ecf20Sopenharmony_ci if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) 11638c2ecf20Sopenharmony_ci return 0; 11648c2ecf20Sopenharmony_ci return hdspm->mixer->ch[chan].pb[pb]; 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_cistatic int hdspm_write_in_gain(struct hdspm *hdspm, unsigned int chan, 11688c2ecf20Sopenharmony_ci unsigned int in, unsigned short data) 11698c2ecf20Sopenharmony_ci{ 11708c2ecf20Sopenharmony_ci if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) 11718c2ecf20Sopenharmony_ci return -1; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci hdspm_write(hdspm, 11748c2ecf20Sopenharmony_ci HDSPM_MADI_mixerBase + 11758c2ecf20Sopenharmony_ci ((in + 128 * chan) * sizeof(u32)), 11768c2ecf20Sopenharmony_ci (hdspm->mixer->ch[chan].in[in] = data & 0xFFFF)); 11778c2ecf20Sopenharmony_ci return 0; 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_cistatic int hdspm_write_pb_gain(struct hdspm *hdspm, unsigned int chan, 11818c2ecf20Sopenharmony_ci unsigned int pb, unsigned short data) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) 11848c2ecf20Sopenharmony_ci return -1; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci hdspm_write(hdspm, 11878c2ecf20Sopenharmony_ci HDSPM_MADI_mixerBase + 11888c2ecf20Sopenharmony_ci ((64 + pb + 128 * chan) * sizeof(u32)), 11898c2ecf20Sopenharmony_ci (hdspm->mixer->ch[chan].pb[pb] = data & 0xFFFF)); 11908c2ecf20Sopenharmony_ci return 0; 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci/* enable DMA for specific channels, now available for DSP-MADI */ 11958c2ecf20Sopenharmony_cistatic inline void snd_hdspm_enable_in(struct hdspm * hdspm, int i, int v) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_inputEnableBase + (4 * i), v); 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_cistatic inline void snd_hdspm_enable_out(struct hdspm * hdspm, int i, int v) 12018c2ecf20Sopenharmony_ci{ 12028c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_outputEnableBase + (4 * i), v); 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci/* check if same process is writing and reading */ 12068c2ecf20Sopenharmony_cistatic int snd_hdspm_use_is_exclusive(struct hdspm *hdspm) 12078c2ecf20Sopenharmony_ci{ 12088c2ecf20Sopenharmony_ci unsigned long flags; 12098c2ecf20Sopenharmony_ci int ret = 1; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci spin_lock_irqsave(&hdspm->lock, flags); 12128c2ecf20Sopenharmony_ci if ((hdspm->playback_pid != hdspm->capture_pid) && 12138c2ecf20Sopenharmony_ci (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) { 12148c2ecf20Sopenharmony_ci ret = 0; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hdspm->lock, flags); 12178c2ecf20Sopenharmony_ci return ret; 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci/* round arbitrary sample rates to commonly known rates */ 12218c2ecf20Sopenharmony_cistatic int hdspm_round_frequency(int rate) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci if (rate < 38050) 12248c2ecf20Sopenharmony_ci return 32000; 12258c2ecf20Sopenharmony_ci if (rate < 46008) 12268c2ecf20Sopenharmony_ci return 44100; 12278c2ecf20Sopenharmony_ci else 12288c2ecf20Sopenharmony_ci return 48000; 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci/* QS and DS rates normally can not be detected 12328c2ecf20Sopenharmony_ci * automatically by the card. Only exception is MADI 12338c2ecf20Sopenharmony_ci * in 96k frame mode. 12348c2ecf20Sopenharmony_ci * 12358c2ecf20Sopenharmony_ci * So if we read SS values (32 .. 48k), check for 12368c2ecf20Sopenharmony_ci * user-provided DS/QS bits in the control register 12378c2ecf20Sopenharmony_ci * and multiply the base frequency accordingly. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_cistatic int hdspm_rate_multiplier(struct hdspm *hdspm, int rate) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci if (rate <= 48000) { 12428c2ecf20Sopenharmony_ci if (hdspm->control_register & HDSPM_QuadSpeed) 12438c2ecf20Sopenharmony_ci return rate * 4; 12448c2ecf20Sopenharmony_ci else if (hdspm->control_register & 12458c2ecf20Sopenharmony_ci HDSPM_DoubleSpeed) 12468c2ecf20Sopenharmony_ci return rate * 2; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci return rate; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci/* check for external sample rate, returns the sample rate in Hz*/ 12528c2ecf20Sopenharmony_cistatic int hdspm_external_sample_rate(struct hdspm *hdspm) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci unsigned int status, status2; 12558c2ecf20Sopenharmony_ci int syncref, rate = 0, rate_bits; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 12588c2ecf20Sopenharmony_ci case AES32: 12598c2ecf20Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 12608c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci syncref = hdspm_autosync_ref(hdspm); 12638c2ecf20Sopenharmony_ci switch (syncref) { 12648c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_WORD: 12658c2ecf20Sopenharmony_ci /* Check WC sync and get sample rate */ 12668c2ecf20Sopenharmony_ci if (hdspm_wc_sync_check(hdspm)) 12678c2ecf20Sopenharmony_ci return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm)); 12688c2ecf20Sopenharmony_ci break; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES1: 12718c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES2: 12728c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES3: 12738c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES4: 12748c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES5: 12758c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES6: 12768c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES7: 12778c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES8: 12788c2ecf20Sopenharmony_ci /* Check AES sync and get sample rate */ 12798c2ecf20Sopenharmony_ci if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)) 12808c2ecf20Sopenharmony_ci return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm, 12818c2ecf20Sopenharmony_ci syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)); 12828c2ecf20Sopenharmony_ci break; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_TCO: 12868c2ecf20Sopenharmony_ci /* Check TCO sync and get sample rate */ 12878c2ecf20Sopenharmony_ci if (hdspm_tco_sync_check(hdspm)) 12888c2ecf20Sopenharmony_ci return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm)); 12898c2ecf20Sopenharmony_ci break; 12908c2ecf20Sopenharmony_ci default: 12918c2ecf20Sopenharmony_ci return 0; 12928c2ecf20Sopenharmony_ci } /* end switch(syncref) */ 12938c2ecf20Sopenharmony_ci break; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci case MADIface: 12968c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci if (!(status & HDSPM_madiLock)) { 12998c2ecf20Sopenharmony_ci rate = 0; /* no lock */ 13008c2ecf20Sopenharmony_ci } else { 13018c2ecf20Sopenharmony_ci switch (status & (HDSPM_status1_freqMask)) { 13028c2ecf20Sopenharmony_ci case HDSPM_status1_F_0*1: 13038c2ecf20Sopenharmony_ci rate = 32000; break; 13048c2ecf20Sopenharmony_ci case HDSPM_status1_F_0*2: 13058c2ecf20Sopenharmony_ci rate = 44100; break; 13068c2ecf20Sopenharmony_ci case HDSPM_status1_F_0*3: 13078c2ecf20Sopenharmony_ci rate = 48000; break; 13088c2ecf20Sopenharmony_ci case HDSPM_status1_F_0*4: 13098c2ecf20Sopenharmony_ci rate = 64000; break; 13108c2ecf20Sopenharmony_ci case HDSPM_status1_F_0*5: 13118c2ecf20Sopenharmony_ci rate = 88200; break; 13128c2ecf20Sopenharmony_ci case HDSPM_status1_F_0*6: 13138c2ecf20Sopenharmony_ci rate = 96000; break; 13148c2ecf20Sopenharmony_ci case HDSPM_status1_F_0*7: 13158c2ecf20Sopenharmony_ci rate = 128000; break; 13168c2ecf20Sopenharmony_ci case HDSPM_status1_F_0*8: 13178c2ecf20Sopenharmony_ci rate = 176400; break; 13188c2ecf20Sopenharmony_ci case HDSPM_status1_F_0*9: 13198c2ecf20Sopenharmony_ci rate = 192000; break; 13208c2ecf20Sopenharmony_ci default: 13218c2ecf20Sopenharmony_ci rate = 0; break; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci break; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci case MADI: 13288c2ecf20Sopenharmony_ci case AIO: 13298c2ecf20Sopenharmony_ci case RayDAT: 13308c2ecf20Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 13318c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 13328c2ecf20Sopenharmony_ci rate = 0; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci /* if wordclock has synced freq and wordclock is valid */ 13358c2ecf20Sopenharmony_ci if ((status2 & HDSPM_wcLock) != 0 && 13368c2ecf20Sopenharmony_ci (status2 & HDSPM_SelSyncRef0) == 0) { 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci rate_bits = status2 & HDSPM_wcFreqMask; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci switch (rate_bits) { 13428c2ecf20Sopenharmony_ci case HDSPM_wcFreq32: 13438c2ecf20Sopenharmony_ci rate = 32000; 13448c2ecf20Sopenharmony_ci break; 13458c2ecf20Sopenharmony_ci case HDSPM_wcFreq44_1: 13468c2ecf20Sopenharmony_ci rate = 44100; 13478c2ecf20Sopenharmony_ci break; 13488c2ecf20Sopenharmony_ci case HDSPM_wcFreq48: 13498c2ecf20Sopenharmony_ci rate = 48000; 13508c2ecf20Sopenharmony_ci break; 13518c2ecf20Sopenharmony_ci case HDSPM_wcFreq64: 13528c2ecf20Sopenharmony_ci rate = 64000; 13538c2ecf20Sopenharmony_ci break; 13548c2ecf20Sopenharmony_ci case HDSPM_wcFreq88_2: 13558c2ecf20Sopenharmony_ci rate = 88200; 13568c2ecf20Sopenharmony_ci break; 13578c2ecf20Sopenharmony_ci case HDSPM_wcFreq96: 13588c2ecf20Sopenharmony_ci rate = 96000; 13598c2ecf20Sopenharmony_ci break; 13608c2ecf20Sopenharmony_ci case HDSPM_wcFreq128: 13618c2ecf20Sopenharmony_ci rate = 128000; 13628c2ecf20Sopenharmony_ci break; 13638c2ecf20Sopenharmony_ci case HDSPM_wcFreq176_4: 13648c2ecf20Sopenharmony_ci rate = 176400; 13658c2ecf20Sopenharmony_ci break; 13668c2ecf20Sopenharmony_ci case HDSPM_wcFreq192: 13678c2ecf20Sopenharmony_ci rate = 192000; 13688c2ecf20Sopenharmony_ci break; 13698c2ecf20Sopenharmony_ci default: 13708c2ecf20Sopenharmony_ci rate = 0; 13718c2ecf20Sopenharmony_ci break; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci /* if rate detected and Syncref is Word than have it, 13768c2ecf20Sopenharmony_ci * word has priority to MADI 13778c2ecf20Sopenharmony_ci */ 13788c2ecf20Sopenharmony_ci if (rate != 0 && 13798c2ecf20Sopenharmony_ci (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) 13808c2ecf20Sopenharmony_ci return hdspm_rate_multiplier(hdspm, rate); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci /* maybe a madi input (which is taken if sel sync is madi) */ 13838c2ecf20Sopenharmony_ci if (status & HDSPM_madiLock) { 13848c2ecf20Sopenharmony_ci rate_bits = status & HDSPM_madiFreqMask; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci switch (rate_bits) { 13878c2ecf20Sopenharmony_ci case HDSPM_madiFreq32: 13888c2ecf20Sopenharmony_ci rate = 32000; 13898c2ecf20Sopenharmony_ci break; 13908c2ecf20Sopenharmony_ci case HDSPM_madiFreq44_1: 13918c2ecf20Sopenharmony_ci rate = 44100; 13928c2ecf20Sopenharmony_ci break; 13938c2ecf20Sopenharmony_ci case HDSPM_madiFreq48: 13948c2ecf20Sopenharmony_ci rate = 48000; 13958c2ecf20Sopenharmony_ci break; 13968c2ecf20Sopenharmony_ci case HDSPM_madiFreq64: 13978c2ecf20Sopenharmony_ci rate = 64000; 13988c2ecf20Sopenharmony_ci break; 13998c2ecf20Sopenharmony_ci case HDSPM_madiFreq88_2: 14008c2ecf20Sopenharmony_ci rate = 88200; 14018c2ecf20Sopenharmony_ci break; 14028c2ecf20Sopenharmony_ci case HDSPM_madiFreq96: 14038c2ecf20Sopenharmony_ci rate = 96000; 14048c2ecf20Sopenharmony_ci break; 14058c2ecf20Sopenharmony_ci case HDSPM_madiFreq128: 14068c2ecf20Sopenharmony_ci rate = 128000; 14078c2ecf20Sopenharmony_ci break; 14088c2ecf20Sopenharmony_ci case HDSPM_madiFreq176_4: 14098c2ecf20Sopenharmony_ci rate = 176400; 14108c2ecf20Sopenharmony_ci break; 14118c2ecf20Sopenharmony_ci case HDSPM_madiFreq192: 14128c2ecf20Sopenharmony_ci rate = 192000; 14138c2ecf20Sopenharmony_ci break; 14148c2ecf20Sopenharmony_ci default: 14158c2ecf20Sopenharmony_ci rate = 0; 14168c2ecf20Sopenharmony_ci break; 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci } /* endif HDSPM_madiLock */ 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci /* check sample rate from TCO or SYNC_IN */ 14228c2ecf20Sopenharmony_ci { 14238c2ecf20Sopenharmony_ci bool is_valid_input = 0; 14248c2ecf20Sopenharmony_ci bool has_sync = 0; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci syncref = hdspm_autosync_ref(hdspm); 14278c2ecf20Sopenharmony_ci if (HDSPM_AUTOSYNC_FROM_TCO == syncref) { 14288c2ecf20Sopenharmony_ci is_valid_input = 1; 14298c2ecf20Sopenharmony_ci has_sync = (HDSPM_SYNC_CHECK_SYNC == 14308c2ecf20Sopenharmony_ci hdspm_tco_sync_check(hdspm)); 14318c2ecf20Sopenharmony_ci } else if (HDSPM_AUTOSYNC_FROM_SYNC_IN == syncref) { 14328c2ecf20Sopenharmony_ci is_valid_input = 1; 14338c2ecf20Sopenharmony_ci has_sync = (HDSPM_SYNC_CHECK_SYNC == 14348c2ecf20Sopenharmony_ci hdspm_sync_in_sync_check(hdspm)); 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci if (is_valid_input && has_sync) { 14388c2ecf20Sopenharmony_ci rate = hdspm_round_frequency( 14398c2ecf20Sopenharmony_ci hdspm_get_pll_freq(hdspm)); 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci rate = hdspm_rate_multiplier(hdspm, rate); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci break; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci return rate; 14498c2ecf20Sopenharmony_ci} 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci/* return latency in samples per period */ 14528c2ecf20Sopenharmony_cistatic int hdspm_get_latency(struct hdspm *hdspm) 14538c2ecf20Sopenharmony_ci{ 14548c2ecf20Sopenharmony_ci int n; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci n = hdspm_decode_latency(hdspm->control_register); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci /* Special case for new RME cards with 32 samples period size. 14598c2ecf20Sopenharmony_ci * The three latency bits in the control register 14608c2ecf20Sopenharmony_ci * (HDSP_LatencyMask) encode latency values of 64 samples as 14618c2ecf20Sopenharmony_ci * 0, 128 samples as 1 ... 4096 samples as 6. For old cards, 7 14628c2ecf20Sopenharmony_ci * denotes 8192 samples, but on new cards like RayDAT or AIO, 14638c2ecf20Sopenharmony_ci * it corresponds to 32 samples. 14648c2ecf20Sopenharmony_ci */ 14658c2ecf20Sopenharmony_ci if ((7 == n) && (RayDAT == hdspm->io_type || AIO == hdspm->io_type)) 14668c2ecf20Sopenharmony_ci n = -1; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci return 1 << (n + 6); 14698c2ecf20Sopenharmony_ci} 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci/* Latency function */ 14728c2ecf20Sopenharmony_cistatic inline void hdspm_compute_period_size(struct hdspm *hdspm) 14738c2ecf20Sopenharmony_ci{ 14748c2ecf20Sopenharmony_ci hdspm->period_bytes = 4 * hdspm_get_latency(hdspm); 14758c2ecf20Sopenharmony_ci} 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t hdspm_hw_pointer(struct hdspm *hdspm) 14798c2ecf20Sopenharmony_ci{ 14808c2ecf20Sopenharmony_ci int position; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci position = hdspm_read(hdspm, HDSPM_statusRegister); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 14858c2ecf20Sopenharmony_ci case RayDAT: 14868c2ecf20Sopenharmony_ci case AIO: 14878c2ecf20Sopenharmony_ci position &= HDSPM_BufferPositionMask; 14888c2ecf20Sopenharmony_ci position /= 4; /* Bytes per sample */ 14898c2ecf20Sopenharmony_ci break; 14908c2ecf20Sopenharmony_ci default: 14918c2ecf20Sopenharmony_ci position = (position & HDSPM_BufferID) ? 14928c2ecf20Sopenharmony_ci (hdspm->period_bytes / 4) : 0; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci return position; 14968c2ecf20Sopenharmony_ci} 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_cistatic inline void hdspm_start_audio(struct hdspm * s) 15008c2ecf20Sopenharmony_ci{ 15018c2ecf20Sopenharmony_ci s->control_register |= (HDSPM_AudioInterruptEnable | HDSPM_Start); 15028c2ecf20Sopenharmony_ci hdspm_write(s, HDSPM_controlRegister, s->control_register); 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_cistatic inline void hdspm_stop_audio(struct hdspm * s) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci s->control_register &= ~(HDSPM_Start | HDSPM_AudioInterruptEnable); 15088c2ecf20Sopenharmony_ci hdspm_write(s, HDSPM_controlRegister, s->control_register); 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci/* should I silence all or only opened ones ? doit all for first even is 4MB*/ 15128c2ecf20Sopenharmony_cistatic void hdspm_silence_playback(struct hdspm *hdspm) 15138c2ecf20Sopenharmony_ci{ 15148c2ecf20Sopenharmony_ci int i; 15158c2ecf20Sopenharmony_ci int n = hdspm->period_bytes; 15168c2ecf20Sopenharmony_ci void *buf = hdspm->playback_buffer; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci if (!buf) 15198c2ecf20Sopenharmony_ci return; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { 15228c2ecf20Sopenharmony_ci memset(buf, 0, n); 15238c2ecf20Sopenharmony_ci buf += HDSPM_CHANNEL_BUFFER_BYTES; 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci} 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_cistatic int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames) 15288c2ecf20Sopenharmony_ci{ 15298c2ecf20Sopenharmony_ci int n; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci spin_lock_irq(&s->lock); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (32 == frames) { 15348c2ecf20Sopenharmony_ci /* Special case for new RME cards like RayDAT/AIO which 15358c2ecf20Sopenharmony_ci * support period sizes of 32 samples. Since latency is 15368c2ecf20Sopenharmony_ci * encoded in the three bits of HDSP_LatencyMask, we can only 15378c2ecf20Sopenharmony_ci * have values from 0 .. 7. While 0 still means 64 samples and 15388c2ecf20Sopenharmony_ci * 6 represents 4096 samples on all cards, 7 represents 8192 15398c2ecf20Sopenharmony_ci * on older cards and 32 samples on new cards. 15408c2ecf20Sopenharmony_ci * 15418c2ecf20Sopenharmony_ci * In other words, period size in samples is calculated by 15428c2ecf20Sopenharmony_ci * 2^(n+6) with n ranging from 0 .. 7. 15438c2ecf20Sopenharmony_ci */ 15448c2ecf20Sopenharmony_ci n = 7; 15458c2ecf20Sopenharmony_ci } else { 15468c2ecf20Sopenharmony_ci frames >>= 7; 15478c2ecf20Sopenharmony_ci n = 0; 15488c2ecf20Sopenharmony_ci while (frames) { 15498c2ecf20Sopenharmony_ci n++; 15508c2ecf20Sopenharmony_ci frames >>= 1; 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci s->control_register &= ~HDSPM_LatencyMask; 15558c2ecf20Sopenharmony_ci s->control_register |= hdspm_encode_latency(n); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci hdspm_write(s, HDSPM_controlRegister, s->control_register); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci hdspm_compute_period_size(s); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci spin_unlock_irq(&s->lock); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci return 0; 15648c2ecf20Sopenharmony_ci} 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_cistatic u64 hdspm_calc_dds_value(struct hdspm *hdspm, u64 period) 15678c2ecf20Sopenharmony_ci{ 15688c2ecf20Sopenharmony_ci u64 freq_const; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (period == 0) 15718c2ecf20Sopenharmony_ci return 0; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 15748c2ecf20Sopenharmony_ci case MADI: 15758c2ecf20Sopenharmony_ci case AES32: 15768c2ecf20Sopenharmony_ci freq_const = 110069313433624ULL; 15778c2ecf20Sopenharmony_ci break; 15788c2ecf20Sopenharmony_ci case RayDAT: 15798c2ecf20Sopenharmony_ci case AIO: 15808c2ecf20Sopenharmony_ci freq_const = 104857600000000ULL; 15818c2ecf20Sopenharmony_ci break; 15828c2ecf20Sopenharmony_ci case MADIface: 15838c2ecf20Sopenharmony_ci freq_const = 131072000000000ULL; 15848c2ecf20Sopenharmony_ci break; 15858c2ecf20Sopenharmony_ci default: 15868c2ecf20Sopenharmony_ci snd_BUG(); 15878c2ecf20Sopenharmony_ci return 0; 15888c2ecf20Sopenharmony_ci } 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci return div_u64(freq_const, period); 15918c2ecf20Sopenharmony_ci} 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cistatic void hdspm_set_dds_value(struct hdspm *hdspm, int rate) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci u64 n; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci if (snd_BUG_ON(rate <= 0)) 15998c2ecf20Sopenharmony_ci return; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci if (rate >= 112000) 16028c2ecf20Sopenharmony_ci rate /= 4; 16038c2ecf20Sopenharmony_ci else if (rate >= 56000) 16048c2ecf20Sopenharmony_ci rate /= 2; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 16078c2ecf20Sopenharmony_ci case MADIface: 16088c2ecf20Sopenharmony_ci n = 131072000000000ULL; /* 125 MHz */ 16098c2ecf20Sopenharmony_ci break; 16108c2ecf20Sopenharmony_ci case MADI: 16118c2ecf20Sopenharmony_ci case AES32: 16128c2ecf20Sopenharmony_ci n = 110069313433624ULL; /* 105 MHz */ 16138c2ecf20Sopenharmony_ci break; 16148c2ecf20Sopenharmony_ci case RayDAT: 16158c2ecf20Sopenharmony_ci case AIO: 16168c2ecf20Sopenharmony_ci n = 104857600000000ULL; /* 100 MHz */ 16178c2ecf20Sopenharmony_ci break; 16188c2ecf20Sopenharmony_ci default: 16198c2ecf20Sopenharmony_ci snd_BUG(); 16208c2ecf20Sopenharmony_ci return; 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci n = div_u64(n, rate); 16248c2ecf20Sopenharmony_ci /* n should be less than 2^32 for being written to FREQ register */ 16258c2ecf20Sopenharmony_ci snd_BUG_ON(n >> 32); 16268c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_freqReg, (u32)n); 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci/* dummy set rate lets see what happens */ 16308c2ecf20Sopenharmony_cistatic int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) 16318c2ecf20Sopenharmony_ci{ 16328c2ecf20Sopenharmony_ci int current_rate; 16338c2ecf20Sopenharmony_ci int rate_bits; 16348c2ecf20Sopenharmony_ci int not_set = 0; 16358c2ecf20Sopenharmony_ci int current_speed, target_speed; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci /* ASSUMPTION: hdspm->lock is either set, or there is no need for 16388c2ecf20Sopenharmony_ci it (e.g. during module initialization). 16398c2ecf20Sopenharmony_ci */ 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci /* SLAVE --- */ 16448c2ecf20Sopenharmony_ci if (called_internally) { 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci /* request from ctl or card initialization 16478c2ecf20Sopenharmony_ci just make a warning an remember setting 16488c2ecf20Sopenharmony_ci for future master mode switching */ 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci dev_warn(hdspm->card->dev, 16518c2ecf20Sopenharmony_ci "Warning: device is not running as a clock master.\n"); 16528c2ecf20Sopenharmony_ci not_set = 1; 16538c2ecf20Sopenharmony_ci } else { 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci /* hw_param request while in AutoSync mode */ 16568c2ecf20Sopenharmony_ci int external_freq = 16578c2ecf20Sopenharmony_ci hdspm_external_sample_rate(hdspm); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci if (hdspm_autosync_ref(hdspm) == 16608c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_FROM_NONE) { 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci dev_warn(hdspm->card->dev, 16638c2ecf20Sopenharmony_ci "Detected no External Sync\n"); 16648c2ecf20Sopenharmony_ci not_set = 1; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci } else if (rate != external_freq) { 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci dev_warn(hdspm->card->dev, 16698c2ecf20Sopenharmony_ci "Warning: No AutoSync source for requested rate\n"); 16708c2ecf20Sopenharmony_ci not_set = 1; 16718c2ecf20Sopenharmony_ci } 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci current_rate = hdspm->system_sample_rate; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci /* Changing between Singe, Double and Quad speed is not 16788c2ecf20Sopenharmony_ci allowed if any substreams are open. This is because such a change 16798c2ecf20Sopenharmony_ci causes a shift in the location of the DMA buffers and a reduction 16808c2ecf20Sopenharmony_ci in the number of available buffers. 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci Note that a similar but essentially insoluble problem exists for 16838c2ecf20Sopenharmony_ci externally-driven rate changes. All we can do is to flag rate 16848c2ecf20Sopenharmony_ci changes in the read/write routines. 16858c2ecf20Sopenharmony_ci */ 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci if (current_rate <= 48000) 16888c2ecf20Sopenharmony_ci current_speed = HDSPM_SPEED_SINGLE; 16898c2ecf20Sopenharmony_ci else if (current_rate <= 96000) 16908c2ecf20Sopenharmony_ci current_speed = HDSPM_SPEED_DOUBLE; 16918c2ecf20Sopenharmony_ci else 16928c2ecf20Sopenharmony_ci current_speed = HDSPM_SPEED_QUAD; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci if (rate <= 48000) 16958c2ecf20Sopenharmony_ci target_speed = HDSPM_SPEED_SINGLE; 16968c2ecf20Sopenharmony_ci else if (rate <= 96000) 16978c2ecf20Sopenharmony_ci target_speed = HDSPM_SPEED_DOUBLE; 16988c2ecf20Sopenharmony_ci else 16998c2ecf20Sopenharmony_ci target_speed = HDSPM_SPEED_QUAD; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci switch (rate) { 17028c2ecf20Sopenharmony_ci case 32000: 17038c2ecf20Sopenharmony_ci rate_bits = HDSPM_Frequency32KHz; 17048c2ecf20Sopenharmony_ci break; 17058c2ecf20Sopenharmony_ci case 44100: 17068c2ecf20Sopenharmony_ci rate_bits = HDSPM_Frequency44_1KHz; 17078c2ecf20Sopenharmony_ci break; 17088c2ecf20Sopenharmony_ci case 48000: 17098c2ecf20Sopenharmony_ci rate_bits = HDSPM_Frequency48KHz; 17108c2ecf20Sopenharmony_ci break; 17118c2ecf20Sopenharmony_ci case 64000: 17128c2ecf20Sopenharmony_ci rate_bits = HDSPM_Frequency64KHz; 17138c2ecf20Sopenharmony_ci break; 17148c2ecf20Sopenharmony_ci case 88200: 17158c2ecf20Sopenharmony_ci rate_bits = HDSPM_Frequency88_2KHz; 17168c2ecf20Sopenharmony_ci break; 17178c2ecf20Sopenharmony_ci case 96000: 17188c2ecf20Sopenharmony_ci rate_bits = HDSPM_Frequency96KHz; 17198c2ecf20Sopenharmony_ci break; 17208c2ecf20Sopenharmony_ci case 128000: 17218c2ecf20Sopenharmony_ci rate_bits = HDSPM_Frequency128KHz; 17228c2ecf20Sopenharmony_ci break; 17238c2ecf20Sopenharmony_ci case 176400: 17248c2ecf20Sopenharmony_ci rate_bits = HDSPM_Frequency176_4KHz; 17258c2ecf20Sopenharmony_ci break; 17268c2ecf20Sopenharmony_ci case 192000: 17278c2ecf20Sopenharmony_ci rate_bits = HDSPM_Frequency192KHz; 17288c2ecf20Sopenharmony_ci break; 17298c2ecf20Sopenharmony_ci default: 17308c2ecf20Sopenharmony_ci return -EINVAL; 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci if (current_speed != target_speed 17348c2ecf20Sopenharmony_ci && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { 17358c2ecf20Sopenharmony_ci dev_err(hdspm->card->dev, 17368c2ecf20Sopenharmony_ci "cannot change from %s speed to %s speed mode (capture PID = %d, playback PID = %d)\n", 17378c2ecf20Sopenharmony_ci hdspm_speed_names[current_speed], 17388c2ecf20Sopenharmony_ci hdspm_speed_names[target_speed], 17398c2ecf20Sopenharmony_ci hdspm->capture_pid, hdspm->playback_pid); 17408c2ecf20Sopenharmony_ci return -EBUSY; 17418c2ecf20Sopenharmony_ci } 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci hdspm->control_register &= ~HDSPM_FrequencyMask; 17448c2ecf20Sopenharmony_ci hdspm->control_register |= rate_bits; 17458c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci /* For AES32, need to set DDS value in FREQ register 17488c2ecf20Sopenharmony_ci For MADI, also apparently */ 17498c2ecf20Sopenharmony_ci hdspm_set_dds_value(hdspm, rate); 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci if (AES32 == hdspm->io_type && rate != current_rate) 17528c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_eeprom_wr, 0); 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci hdspm->system_sample_rate = rate; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci if (rate <= 48000) { 17578c2ecf20Sopenharmony_ci hdspm->channel_map_in = hdspm->channel_map_in_ss; 17588c2ecf20Sopenharmony_ci hdspm->channel_map_out = hdspm->channel_map_out_ss; 17598c2ecf20Sopenharmony_ci hdspm->max_channels_in = hdspm->ss_in_channels; 17608c2ecf20Sopenharmony_ci hdspm->max_channels_out = hdspm->ss_out_channels; 17618c2ecf20Sopenharmony_ci hdspm->port_names_in = hdspm->port_names_in_ss; 17628c2ecf20Sopenharmony_ci hdspm->port_names_out = hdspm->port_names_out_ss; 17638c2ecf20Sopenharmony_ci } else if (rate <= 96000) { 17648c2ecf20Sopenharmony_ci hdspm->channel_map_in = hdspm->channel_map_in_ds; 17658c2ecf20Sopenharmony_ci hdspm->channel_map_out = hdspm->channel_map_out_ds; 17668c2ecf20Sopenharmony_ci hdspm->max_channels_in = hdspm->ds_in_channels; 17678c2ecf20Sopenharmony_ci hdspm->max_channels_out = hdspm->ds_out_channels; 17688c2ecf20Sopenharmony_ci hdspm->port_names_in = hdspm->port_names_in_ds; 17698c2ecf20Sopenharmony_ci hdspm->port_names_out = hdspm->port_names_out_ds; 17708c2ecf20Sopenharmony_ci } else { 17718c2ecf20Sopenharmony_ci hdspm->channel_map_in = hdspm->channel_map_in_qs; 17728c2ecf20Sopenharmony_ci hdspm->channel_map_out = hdspm->channel_map_out_qs; 17738c2ecf20Sopenharmony_ci hdspm->max_channels_in = hdspm->qs_in_channels; 17748c2ecf20Sopenharmony_ci hdspm->max_channels_out = hdspm->qs_out_channels; 17758c2ecf20Sopenharmony_ci hdspm->port_names_in = hdspm->port_names_in_qs; 17768c2ecf20Sopenharmony_ci hdspm->port_names_out = hdspm->port_names_out_qs; 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci if (not_set != 0) 17808c2ecf20Sopenharmony_ci return -1; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci return 0; 17838c2ecf20Sopenharmony_ci} 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci/* mainly for init to 0 on load */ 17868c2ecf20Sopenharmony_cistatic void all_in_all_mixer(struct hdspm * hdspm, int sgain) 17878c2ecf20Sopenharmony_ci{ 17888c2ecf20Sopenharmony_ci int i, j; 17898c2ecf20Sopenharmony_ci unsigned int gain; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci if (sgain > UNITY_GAIN) 17928c2ecf20Sopenharmony_ci gain = UNITY_GAIN; 17938c2ecf20Sopenharmony_ci else if (sgain < 0) 17948c2ecf20Sopenharmony_ci gain = 0; 17958c2ecf20Sopenharmony_ci else 17968c2ecf20Sopenharmony_ci gain = sgain; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) 17998c2ecf20Sopenharmony_ci for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) { 18008c2ecf20Sopenharmony_ci hdspm_write_in_gain(hdspm, i, j, gain); 18018c2ecf20Sopenharmony_ci hdspm_write_pb_gain(hdspm, i, j, gain); 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci} 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------- 18068c2ecf20Sopenharmony_ci MIDI 18078c2ecf20Sopenharmony_ci ----------------------------------------------------------------------------*/ 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_cistatic inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm, 18108c2ecf20Sopenharmony_ci int id) 18118c2ecf20Sopenharmony_ci{ 18128c2ecf20Sopenharmony_ci /* the hardware already does the relevant bit-mask with 0xff */ 18138c2ecf20Sopenharmony_ci return hdspm_read(hdspm, hdspm->midi[id].dataIn); 18148c2ecf20Sopenharmony_ci} 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_cistatic inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id, 18178c2ecf20Sopenharmony_ci int val) 18188c2ecf20Sopenharmony_ci{ 18198c2ecf20Sopenharmony_ci /* the hardware already does the relevant bit-mask with 0xff */ 18208c2ecf20Sopenharmony_ci return hdspm_write(hdspm, hdspm->midi[id].dataOut, val); 18218c2ecf20Sopenharmony_ci} 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_cistatic inline int snd_hdspm_midi_input_available (struct hdspm *hdspm, int id) 18248c2ecf20Sopenharmony_ci{ 18258c2ecf20Sopenharmony_ci return hdspm_read(hdspm, hdspm->midi[id].statusIn) & 0xFF; 18268c2ecf20Sopenharmony_ci} 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_cistatic inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id) 18298c2ecf20Sopenharmony_ci{ 18308c2ecf20Sopenharmony_ci int fifo_bytes_used; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci fifo_bytes_used = hdspm_read(hdspm, hdspm->midi[id].statusOut) & 0xFF; 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci if (fifo_bytes_used < 128) 18358c2ecf20Sopenharmony_ci return 128 - fifo_bytes_used; 18368c2ecf20Sopenharmony_ci else 18378c2ecf20Sopenharmony_ci return 0; 18388c2ecf20Sopenharmony_ci} 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_cistatic void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id) 18418c2ecf20Sopenharmony_ci{ 18428c2ecf20Sopenharmony_ci while (snd_hdspm_midi_input_available (hdspm, id)) 18438c2ecf20Sopenharmony_ci snd_hdspm_midi_read_byte (hdspm, id); 18448c2ecf20Sopenharmony_ci} 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_cistatic int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) 18478c2ecf20Sopenharmony_ci{ 18488c2ecf20Sopenharmony_ci unsigned long flags; 18498c2ecf20Sopenharmony_ci int n_pending; 18508c2ecf20Sopenharmony_ci int to_write; 18518c2ecf20Sopenharmony_ci int i; 18528c2ecf20Sopenharmony_ci unsigned char buf[128]; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci /* Output is not interrupt driven */ 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci spin_lock_irqsave (&hmidi->lock, flags); 18578c2ecf20Sopenharmony_ci if (hmidi->output && 18588c2ecf20Sopenharmony_ci !snd_rawmidi_transmit_empty (hmidi->output)) { 18598c2ecf20Sopenharmony_ci n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, 18608c2ecf20Sopenharmony_ci hmidi->id); 18618c2ecf20Sopenharmony_ci if (n_pending > 0) { 18628c2ecf20Sopenharmony_ci if (n_pending > (int)sizeof (buf)) 18638c2ecf20Sopenharmony_ci n_pending = sizeof (buf); 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci to_write = snd_rawmidi_transmit (hmidi->output, buf, 18668c2ecf20Sopenharmony_ci n_pending); 18678c2ecf20Sopenharmony_ci if (to_write > 0) { 18688c2ecf20Sopenharmony_ci for (i = 0; i < to_write; ++i) 18698c2ecf20Sopenharmony_ci snd_hdspm_midi_write_byte (hmidi->hdspm, 18708c2ecf20Sopenharmony_ci hmidi->id, 18718c2ecf20Sopenharmony_ci buf[i]); 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&hmidi->lock, flags); 18768c2ecf20Sopenharmony_ci return 0; 18778c2ecf20Sopenharmony_ci} 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_cistatic int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi) 18808c2ecf20Sopenharmony_ci{ 18818c2ecf20Sopenharmony_ci unsigned char buf[128]; /* this buffer is designed to match the MIDI 18828c2ecf20Sopenharmony_ci * input FIFO size 18838c2ecf20Sopenharmony_ci */ 18848c2ecf20Sopenharmony_ci unsigned long flags; 18858c2ecf20Sopenharmony_ci int n_pending; 18868c2ecf20Sopenharmony_ci int i; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci spin_lock_irqsave (&hmidi->lock, flags); 18898c2ecf20Sopenharmony_ci n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id); 18908c2ecf20Sopenharmony_ci if (n_pending > 0) { 18918c2ecf20Sopenharmony_ci if (hmidi->input) { 18928c2ecf20Sopenharmony_ci if (n_pending > (int)sizeof (buf)) 18938c2ecf20Sopenharmony_ci n_pending = sizeof (buf); 18948c2ecf20Sopenharmony_ci for (i = 0; i < n_pending; ++i) 18958c2ecf20Sopenharmony_ci buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, 18968c2ecf20Sopenharmony_ci hmidi->id); 18978c2ecf20Sopenharmony_ci if (n_pending) 18988c2ecf20Sopenharmony_ci snd_rawmidi_receive (hmidi->input, buf, 18998c2ecf20Sopenharmony_ci n_pending); 19008c2ecf20Sopenharmony_ci } else { 19018c2ecf20Sopenharmony_ci /* flush the MIDI input FIFO */ 19028c2ecf20Sopenharmony_ci while (n_pending--) 19038c2ecf20Sopenharmony_ci snd_hdspm_midi_read_byte (hmidi->hdspm, 19048c2ecf20Sopenharmony_ci hmidi->id); 19058c2ecf20Sopenharmony_ci } 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci hmidi->pending = 0; 19088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hmidi->lock, flags); 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci spin_lock_irqsave(&hmidi->hdspm->lock, flags); 19118c2ecf20Sopenharmony_ci hmidi->hdspm->control_register |= hmidi->ie; 19128c2ecf20Sopenharmony_ci hdspm_write(hmidi->hdspm, HDSPM_controlRegister, 19138c2ecf20Sopenharmony_ci hmidi->hdspm->control_register); 19148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hmidi->hdspm->lock, flags); 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci return snd_hdspm_midi_output_write (hmidi); 19178c2ecf20Sopenharmony_ci} 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_cistatic void 19208c2ecf20Sopenharmony_cisnd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) 19218c2ecf20Sopenharmony_ci{ 19228c2ecf20Sopenharmony_ci struct hdspm *hdspm; 19238c2ecf20Sopenharmony_ci struct hdspm_midi *hmidi; 19248c2ecf20Sopenharmony_ci unsigned long flags; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci hmidi = substream->rmidi->private_data; 19278c2ecf20Sopenharmony_ci hdspm = hmidi->hdspm; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci spin_lock_irqsave (&hdspm->lock, flags); 19308c2ecf20Sopenharmony_ci if (up) { 19318c2ecf20Sopenharmony_ci if (!(hdspm->control_register & hmidi->ie)) { 19328c2ecf20Sopenharmony_ci snd_hdspm_flush_midi_input (hdspm, hmidi->id); 19338c2ecf20Sopenharmony_ci hdspm->control_register |= hmidi->ie; 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci } else { 19368c2ecf20Sopenharmony_ci hdspm->control_register &= ~hmidi->ie; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 19408c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&hdspm->lock, flags); 19418c2ecf20Sopenharmony_ci} 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_cistatic void snd_hdspm_midi_output_timer(struct timer_list *t) 19448c2ecf20Sopenharmony_ci{ 19458c2ecf20Sopenharmony_ci struct hdspm_midi *hmidi = from_timer(hmidi, t, timer); 19468c2ecf20Sopenharmony_ci unsigned long flags; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci snd_hdspm_midi_output_write(hmidi); 19498c2ecf20Sopenharmony_ci spin_lock_irqsave (&hmidi->lock, flags); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci /* this does not bump hmidi->istimer, because the 19528c2ecf20Sopenharmony_ci kernel automatically removed the timer when it 19538c2ecf20Sopenharmony_ci expired, and we are now adding it back, thus 19548c2ecf20Sopenharmony_ci leaving istimer wherever it was set before. 19558c2ecf20Sopenharmony_ci */ 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci if (hmidi->istimer) 19588c2ecf20Sopenharmony_ci mod_timer(&hmidi->timer, 1 + jiffies); 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&hmidi->lock, flags); 19618c2ecf20Sopenharmony_ci} 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_cistatic void 19648c2ecf20Sopenharmony_cisnd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) 19658c2ecf20Sopenharmony_ci{ 19668c2ecf20Sopenharmony_ci struct hdspm_midi *hmidi; 19678c2ecf20Sopenharmony_ci unsigned long flags; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci hmidi = substream->rmidi->private_data; 19708c2ecf20Sopenharmony_ci spin_lock_irqsave (&hmidi->lock, flags); 19718c2ecf20Sopenharmony_ci if (up) { 19728c2ecf20Sopenharmony_ci if (!hmidi->istimer) { 19738c2ecf20Sopenharmony_ci timer_setup(&hmidi->timer, 19748c2ecf20Sopenharmony_ci snd_hdspm_midi_output_timer, 0); 19758c2ecf20Sopenharmony_ci mod_timer(&hmidi->timer, 1 + jiffies); 19768c2ecf20Sopenharmony_ci hmidi->istimer++; 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci } else { 19798c2ecf20Sopenharmony_ci if (hmidi->istimer && --hmidi->istimer <= 0) 19808c2ecf20Sopenharmony_ci del_timer (&hmidi->timer); 19818c2ecf20Sopenharmony_ci } 19828c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&hmidi->lock, flags); 19838c2ecf20Sopenharmony_ci if (up) 19848c2ecf20Sopenharmony_ci snd_hdspm_midi_output_write(hmidi); 19858c2ecf20Sopenharmony_ci} 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_cistatic int snd_hdspm_midi_input_open(struct snd_rawmidi_substream *substream) 19888c2ecf20Sopenharmony_ci{ 19898c2ecf20Sopenharmony_ci struct hdspm_midi *hmidi; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci hmidi = substream->rmidi->private_data; 19928c2ecf20Sopenharmony_ci spin_lock_irq (&hmidi->lock); 19938c2ecf20Sopenharmony_ci snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id); 19948c2ecf20Sopenharmony_ci hmidi->input = substream; 19958c2ecf20Sopenharmony_ci spin_unlock_irq (&hmidi->lock); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci return 0; 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_cistatic int snd_hdspm_midi_output_open(struct snd_rawmidi_substream *substream) 20018c2ecf20Sopenharmony_ci{ 20028c2ecf20Sopenharmony_ci struct hdspm_midi *hmidi; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci hmidi = substream->rmidi->private_data; 20058c2ecf20Sopenharmony_ci spin_lock_irq (&hmidi->lock); 20068c2ecf20Sopenharmony_ci hmidi->output = substream; 20078c2ecf20Sopenharmony_ci spin_unlock_irq (&hmidi->lock); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci return 0; 20108c2ecf20Sopenharmony_ci} 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_cistatic int snd_hdspm_midi_input_close(struct snd_rawmidi_substream *substream) 20138c2ecf20Sopenharmony_ci{ 20148c2ecf20Sopenharmony_ci struct hdspm_midi *hmidi; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci snd_hdspm_midi_input_trigger (substream, 0); 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci hmidi = substream->rmidi->private_data; 20198c2ecf20Sopenharmony_ci spin_lock_irq (&hmidi->lock); 20208c2ecf20Sopenharmony_ci hmidi->input = NULL; 20218c2ecf20Sopenharmony_ci spin_unlock_irq (&hmidi->lock); 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci return 0; 20248c2ecf20Sopenharmony_ci} 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_cistatic int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream) 20278c2ecf20Sopenharmony_ci{ 20288c2ecf20Sopenharmony_ci struct hdspm_midi *hmidi; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci snd_hdspm_midi_output_trigger (substream, 0); 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci hmidi = substream->rmidi->private_data; 20338c2ecf20Sopenharmony_ci spin_lock_irq (&hmidi->lock); 20348c2ecf20Sopenharmony_ci hmidi->output = NULL; 20358c2ecf20Sopenharmony_ci spin_unlock_irq (&hmidi->lock); 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci return 0; 20388c2ecf20Sopenharmony_ci} 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_cistatic const struct snd_rawmidi_ops snd_hdspm_midi_output = 20418c2ecf20Sopenharmony_ci{ 20428c2ecf20Sopenharmony_ci .open = snd_hdspm_midi_output_open, 20438c2ecf20Sopenharmony_ci .close = snd_hdspm_midi_output_close, 20448c2ecf20Sopenharmony_ci .trigger = snd_hdspm_midi_output_trigger, 20458c2ecf20Sopenharmony_ci}; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_cistatic const struct snd_rawmidi_ops snd_hdspm_midi_input = 20488c2ecf20Sopenharmony_ci{ 20498c2ecf20Sopenharmony_ci .open = snd_hdspm_midi_input_open, 20508c2ecf20Sopenharmony_ci .close = snd_hdspm_midi_input_close, 20518c2ecf20Sopenharmony_ci .trigger = snd_hdspm_midi_input_trigger, 20528c2ecf20Sopenharmony_ci}; 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_cistatic int snd_hdspm_create_midi(struct snd_card *card, 20558c2ecf20Sopenharmony_ci struct hdspm *hdspm, int id) 20568c2ecf20Sopenharmony_ci{ 20578c2ecf20Sopenharmony_ci int err; 20588c2ecf20Sopenharmony_ci char buf[64]; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci hdspm->midi[id].id = id; 20618c2ecf20Sopenharmony_ci hdspm->midi[id].hdspm = hdspm; 20628c2ecf20Sopenharmony_ci spin_lock_init (&hdspm->midi[id].lock); 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci if (0 == id) { 20658c2ecf20Sopenharmony_ci if (MADIface == hdspm->io_type) { 20668c2ecf20Sopenharmony_ci /* MIDI-over-MADI on HDSPe MADIface */ 20678c2ecf20Sopenharmony_ci hdspm->midi[0].dataIn = HDSPM_midiDataIn2; 20688c2ecf20Sopenharmony_ci hdspm->midi[0].statusIn = HDSPM_midiStatusIn2; 20698c2ecf20Sopenharmony_ci hdspm->midi[0].dataOut = HDSPM_midiDataOut2; 20708c2ecf20Sopenharmony_ci hdspm->midi[0].statusOut = HDSPM_midiStatusOut2; 20718c2ecf20Sopenharmony_ci hdspm->midi[0].ie = HDSPM_Midi2InterruptEnable; 20728c2ecf20Sopenharmony_ci hdspm->midi[0].irq = HDSPM_midi2IRQPending; 20738c2ecf20Sopenharmony_ci } else { 20748c2ecf20Sopenharmony_ci hdspm->midi[0].dataIn = HDSPM_midiDataIn0; 20758c2ecf20Sopenharmony_ci hdspm->midi[0].statusIn = HDSPM_midiStatusIn0; 20768c2ecf20Sopenharmony_ci hdspm->midi[0].dataOut = HDSPM_midiDataOut0; 20778c2ecf20Sopenharmony_ci hdspm->midi[0].statusOut = HDSPM_midiStatusOut0; 20788c2ecf20Sopenharmony_ci hdspm->midi[0].ie = HDSPM_Midi0InterruptEnable; 20798c2ecf20Sopenharmony_ci hdspm->midi[0].irq = HDSPM_midi0IRQPending; 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci } else if (1 == id) { 20828c2ecf20Sopenharmony_ci hdspm->midi[1].dataIn = HDSPM_midiDataIn1; 20838c2ecf20Sopenharmony_ci hdspm->midi[1].statusIn = HDSPM_midiStatusIn1; 20848c2ecf20Sopenharmony_ci hdspm->midi[1].dataOut = HDSPM_midiDataOut1; 20858c2ecf20Sopenharmony_ci hdspm->midi[1].statusOut = HDSPM_midiStatusOut1; 20868c2ecf20Sopenharmony_ci hdspm->midi[1].ie = HDSPM_Midi1InterruptEnable; 20878c2ecf20Sopenharmony_ci hdspm->midi[1].irq = HDSPM_midi1IRQPending; 20888c2ecf20Sopenharmony_ci } else if ((2 == id) && (MADI == hdspm->io_type)) { 20898c2ecf20Sopenharmony_ci /* MIDI-over-MADI on HDSPe MADI */ 20908c2ecf20Sopenharmony_ci hdspm->midi[2].dataIn = HDSPM_midiDataIn2; 20918c2ecf20Sopenharmony_ci hdspm->midi[2].statusIn = HDSPM_midiStatusIn2; 20928c2ecf20Sopenharmony_ci hdspm->midi[2].dataOut = HDSPM_midiDataOut2; 20938c2ecf20Sopenharmony_ci hdspm->midi[2].statusOut = HDSPM_midiStatusOut2; 20948c2ecf20Sopenharmony_ci hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable; 20958c2ecf20Sopenharmony_ci hdspm->midi[2].irq = HDSPM_midi2IRQPending; 20968c2ecf20Sopenharmony_ci } else if (2 == id) { 20978c2ecf20Sopenharmony_ci /* TCO MTC, read only */ 20988c2ecf20Sopenharmony_ci hdspm->midi[2].dataIn = HDSPM_midiDataIn2; 20998c2ecf20Sopenharmony_ci hdspm->midi[2].statusIn = HDSPM_midiStatusIn2; 21008c2ecf20Sopenharmony_ci hdspm->midi[2].dataOut = -1; 21018c2ecf20Sopenharmony_ci hdspm->midi[2].statusOut = -1; 21028c2ecf20Sopenharmony_ci hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable; 21038c2ecf20Sopenharmony_ci hdspm->midi[2].irq = HDSPM_midi2IRQPendingAES; 21048c2ecf20Sopenharmony_ci } else if (3 == id) { 21058c2ecf20Sopenharmony_ci /* TCO MTC on HDSPe MADI */ 21068c2ecf20Sopenharmony_ci hdspm->midi[3].dataIn = HDSPM_midiDataIn3; 21078c2ecf20Sopenharmony_ci hdspm->midi[3].statusIn = HDSPM_midiStatusIn3; 21088c2ecf20Sopenharmony_ci hdspm->midi[3].dataOut = -1; 21098c2ecf20Sopenharmony_ci hdspm->midi[3].statusOut = -1; 21108c2ecf20Sopenharmony_ci hdspm->midi[3].ie = HDSPM_Midi3InterruptEnable; 21118c2ecf20Sopenharmony_ci hdspm->midi[3].irq = HDSPM_midi3IRQPending; 21128c2ecf20Sopenharmony_ci } 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci if ((id < 2) || ((2 == id) && ((MADI == hdspm->io_type) || 21158c2ecf20Sopenharmony_ci (MADIface == hdspm->io_type)))) { 21168c2ecf20Sopenharmony_ci if ((id == 0) && (MADIface == hdspm->io_type)) { 21178c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%s MIDIoverMADI", 21188c2ecf20Sopenharmony_ci card->shortname); 21198c2ecf20Sopenharmony_ci } else if ((id == 2) && (MADI == hdspm->io_type)) { 21208c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%s MIDIoverMADI", 21218c2ecf20Sopenharmony_ci card->shortname); 21228c2ecf20Sopenharmony_ci } else { 21238c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%s MIDI %d", 21248c2ecf20Sopenharmony_ci card->shortname, id+1); 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci err = snd_rawmidi_new(card, buf, id, 1, 1, 21278c2ecf20Sopenharmony_ci &hdspm->midi[id].rmidi); 21288c2ecf20Sopenharmony_ci if (err < 0) 21298c2ecf20Sopenharmony_ci return err; 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci snprintf(hdspm->midi[id].rmidi->name, 21328c2ecf20Sopenharmony_ci sizeof(hdspm->midi[id].rmidi->name), 21338c2ecf20Sopenharmony_ci "%s MIDI %d", card->id, id+1); 21348c2ecf20Sopenharmony_ci hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 21378c2ecf20Sopenharmony_ci SNDRV_RAWMIDI_STREAM_OUTPUT, 21388c2ecf20Sopenharmony_ci &snd_hdspm_midi_output); 21398c2ecf20Sopenharmony_ci snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 21408c2ecf20Sopenharmony_ci SNDRV_RAWMIDI_STREAM_INPUT, 21418c2ecf20Sopenharmony_ci &snd_hdspm_midi_input); 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci hdspm->midi[id].rmidi->info_flags |= 21448c2ecf20Sopenharmony_ci SNDRV_RAWMIDI_INFO_OUTPUT | 21458c2ecf20Sopenharmony_ci SNDRV_RAWMIDI_INFO_INPUT | 21468c2ecf20Sopenharmony_ci SNDRV_RAWMIDI_INFO_DUPLEX; 21478c2ecf20Sopenharmony_ci } else { 21488c2ecf20Sopenharmony_ci /* TCO MTC, read only */ 21498c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%s MTC %d", 21508c2ecf20Sopenharmony_ci card->shortname, id+1); 21518c2ecf20Sopenharmony_ci err = snd_rawmidi_new(card, buf, id, 1, 1, 21528c2ecf20Sopenharmony_ci &hdspm->midi[id].rmidi); 21538c2ecf20Sopenharmony_ci if (err < 0) 21548c2ecf20Sopenharmony_ci return err; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci snprintf(hdspm->midi[id].rmidi->name, 21578c2ecf20Sopenharmony_ci sizeof(hdspm->midi[id].rmidi->name), 21588c2ecf20Sopenharmony_ci "%s MTC %d", card->id, id+1); 21598c2ecf20Sopenharmony_ci hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 21628c2ecf20Sopenharmony_ci SNDRV_RAWMIDI_STREAM_INPUT, 21638c2ecf20Sopenharmony_ci &snd_hdspm_midi_input); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; 21668c2ecf20Sopenharmony_ci } 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci return 0; 21698c2ecf20Sopenharmony_ci} 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_cistatic void hdspm_midi_work(struct work_struct *work) 21738c2ecf20Sopenharmony_ci{ 21748c2ecf20Sopenharmony_ci struct hdspm *hdspm = container_of(work, struct hdspm, midi_work); 21758c2ecf20Sopenharmony_ci int i = 0; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci while (i < hdspm->midiPorts) { 21788c2ecf20Sopenharmony_ci if (hdspm->midi[i].pending) 21798c2ecf20Sopenharmony_ci snd_hdspm_midi_input_read(&hdspm->midi[i]); 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci i++; 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci} 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------------- 21878c2ecf20Sopenharmony_ci Status Interface 21888c2ecf20Sopenharmony_ci ----------------------------------------------------------------------------*/ 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci/* get the system sample rate which is set */ 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_cistatic inline int hdspm_get_pll_freq(struct hdspm *hdspm) 21948c2ecf20Sopenharmony_ci{ 21958c2ecf20Sopenharmony_ci unsigned int period, rate; 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 21988c2ecf20Sopenharmony_ci rate = hdspm_calc_dds_value(hdspm, period); 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci return rate; 22018c2ecf20Sopenharmony_ci} 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci/* 22048c2ecf20Sopenharmony_ci * Calculate the real sample rate from the 22058c2ecf20Sopenharmony_ci * current DDS value. 22068c2ecf20Sopenharmony_ci */ 22078c2ecf20Sopenharmony_cistatic int hdspm_get_system_sample_rate(struct hdspm *hdspm) 22088c2ecf20Sopenharmony_ci{ 22098c2ecf20Sopenharmony_ci unsigned int rate; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci rate = hdspm_get_pll_freq(hdspm); 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci if (rate > 207000) { 22148c2ecf20Sopenharmony_ci /* Unreasonable high sample rate as seen on PCI MADI cards. */ 22158c2ecf20Sopenharmony_ci if (0 == hdspm_system_clock_mode(hdspm)) { 22168c2ecf20Sopenharmony_ci /* master mode, return internal sample rate */ 22178c2ecf20Sopenharmony_ci rate = hdspm->system_sample_rate; 22188c2ecf20Sopenharmony_ci } else { 22198c2ecf20Sopenharmony_ci /* slave mode, return external sample rate */ 22208c2ecf20Sopenharmony_ci rate = hdspm_external_sample_rate(hdspm); 22218c2ecf20Sopenharmony_ci if (!rate) 22228c2ecf20Sopenharmony_ci rate = hdspm->system_sample_rate; 22238c2ecf20Sopenharmony_ci } 22248c2ecf20Sopenharmony_ci } 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci return rate; 22278c2ecf20Sopenharmony_ci} 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci#define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \ 22318c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 22328c2ecf20Sopenharmony_ci .name = xname, \ 22338c2ecf20Sopenharmony_ci .index = xindex, \ 22348c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 22358c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 22368c2ecf20Sopenharmony_ci .info = snd_hdspm_info_system_sample_rate, \ 22378c2ecf20Sopenharmony_ci .put = snd_hdspm_put_system_sample_rate, \ 22388c2ecf20Sopenharmony_ci .get = snd_hdspm_get_system_sample_rate \ 22398c2ecf20Sopenharmony_ci} 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_cistatic int snd_hdspm_info_system_sample_rate(struct snd_kcontrol *kcontrol, 22428c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 22438c2ecf20Sopenharmony_ci{ 22448c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 22458c2ecf20Sopenharmony_ci uinfo->count = 1; 22468c2ecf20Sopenharmony_ci uinfo->value.integer.min = 27000; 22478c2ecf20Sopenharmony_ci uinfo->value.integer.max = 207000; 22488c2ecf20Sopenharmony_ci uinfo->value.integer.step = 1; 22498c2ecf20Sopenharmony_ci return 0; 22508c2ecf20Sopenharmony_ci} 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_cistatic int snd_hdspm_get_system_sample_rate(struct snd_kcontrol *kcontrol, 22548c2ecf20Sopenharmony_ci struct snd_ctl_elem_value * 22558c2ecf20Sopenharmony_ci ucontrol) 22568c2ecf20Sopenharmony_ci{ 22578c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = hdspm_get_system_sample_rate(hdspm); 22608c2ecf20Sopenharmony_ci return 0; 22618c2ecf20Sopenharmony_ci} 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_cistatic int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol, 22648c2ecf20Sopenharmony_ci struct snd_ctl_elem_value * 22658c2ecf20Sopenharmony_ci ucontrol) 22668c2ecf20Sopenharmony_ci{ 22678c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 22688c2ecf20Sopenharmony_ci int rate = ucontrol->value.integer.value[0]; 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci if (rate < 27000 || rate > 207000) 22718c2ecf20Sopenharmony_ci return -EINVAL; 22728c2ecf20Sopenharmony_ci hdspm_set_dds_value(hdspm, ucontrol->value.integer.value[0]); 22738c2ecf20Sopenharmony_ci return 0; 22748c2ecf20Sopenharmony_ci} 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci/* 22788c2ecf20Sopenharmony_ci * Returns the WordClock sample rate class for the given card. 22798c2ecf20Sopenharmony_ci */ 22808c2ecf20Sopenharmony_cistatic int hdspm_get_wc_sample_rate(struct hdspm *hdspm) 22818c2ecf20Sopenharmony_ci{ 22828c2ecf20Sopenharmony_ci int status; 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 22858c2ecf20Sopenharmony_ci case RayDAT: 22868c2ecf20Sopenharmony_ci case AIO: 22878c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 22888c2ecf20Sopenharmony_ci return (status >> 16) & 0xF; 22898c2ecf20Sopenharmony_ci break; 22908c2ecf20Sopenharmony_ci case AES32: 22918c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 22928c2ecf20Sopenharmony_ci return (status >> HDSPM_AES32_wcFreq_bit) & 0xF; 22938c2ecf20Sopenharmony_ci default: 22948c2ecf20Sopenharmony_ci break; 22958c2ecf20Sopenharmony_ci } 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci return 0; 22998c2ecf20Sopenharmony_ci} 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci/* 23038c2ecf20Sopenharmony_ci * Returns the TCO sample rate class for the given card. 23048c2ecf20Sopenharmony_ci */ 23058c2ecf20Sopenharmony_cistatic int hdspm_get_tco_sample_rate(struct hdspm *hdspm) 23068c2ecf20Sopenharmony_ci{ 23078c2ecf20Sopenharmony_ci int status; 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci if (hdspm->tco) { 23108c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 23118c2ecf20Sopenharmony_ci case RayDAT: 23128c2ecf20Sopenharmony_ci case AIO: 23138c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 23148c2ecf20Sopenharmony_ci return (status >> 20) & 0xF; 23158c2ecf20Sopenharmony_ci break; 23168c2ecf20Sopenharmony_ci case AES32: 23178c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 23188c2ecf20Sopenharmony_ci return (status >> 1) & 0xF; 23198c2ecf20Sopenharmony_ci default: 23208c2ecf20Sopenharmony_ci break; 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci } 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci return 0; 23258c2ecf20Sopenharmony_ci} 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci/* 23298c2ecf20Sopenharmony_ci * Returns the SYNC_IN sample rate class for the given card. 23308c2ecf20Sopenharmony_ci */ 23318c2ecf20Sopenharmony_cistatic int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) 23328c2ecf20Sopenharmony_ci{ 23338c2ecf20Sopenharmony_ci int status; 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci if (hdspm->tco) { 23368c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 23378c2ecf20Sopenharmony_ci case RayDAT: 23388c2ecf20Sopenharmony_ci case AIO: 23398c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_2); 23408c2ecf20Sopenharmony_ci return (status >> 12) & 0xF; 23418c2ecf20Sopenharmony_ci break; 23428c2ecf20Sopenharmony_ci default: 23438c2ecf20Sopenharmony_ci break; 23448c2ecf20Sopenharmony_ci } 23458c2ecf20Sopenharmony_ci } 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci return 0; 23488c2ecf20Sopenharmony_ci} 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci/* 23518c2ecf20Sopenharmony_ci * Returns the AES sample rate class for the given card. 23528c2ecf20Sopenharmony_ci */ 23538c2ecf20Sopenharmony_cistatic int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index) 23548c2ecf20Sopenharmony_ci{ 23558c2ecf20Sopenharmony_ci int timecode; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 23588c2ecf20Sopenharmony_ci case AES32: 23598c2ecf20Sopenharmony_ci timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); 23608c2ecf20Sopenharmony_ci return (timecode >> (4*index)) & 0xF; 23618c2ecf20Sopenharmony_ci break; 23628c2ecf20Sopenharmony_ci default: 23638c2ecf20Sopenharmony_ci break; 23648c2ecf20Sopenharmony_ci } 23658c2ecf20Sopenharmony_ci return 0; 23668c2ecf20Sopenharmony_ci} 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci/* 23698c2ecf20Sopenharmony_ci * Returns the sample rate class for input source <idx> for 23708c2ecf20Sopenharmony_ci * 'new style' cards like the AIO and RayDAT. 23718c2ecf20Sopenharmony_ci */ 23728c2ecf20Sopenharmony_cistatic int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) 23738c2ecf20Sopenharmony_ci{ 23748c2ecf20Sopenharmony_ci int status = hdspm_read(hdspm, HDSPM_RD_STATUS_2); 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci return (status >> (idx*4)) & 0xF; 23778c2ecf20Sopenharmony_ci} 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci#define ENUMERATED_CTL_INFO(info, texts) \ 23808c2ecf20Sopenharmony_ci snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts) 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci/* Helper function to query the external sample rate and return the 23848c2ecf20Sopenharmony_ci * corresponding enum to be returned to userspace. 23858c2ecf20Sopenharmony_ci */ 23868c2ecf20Sopenharmony_cistatic int hdspm_external_rate_to_enum(struct hdspm *hdspm) 23878c2ecf20Sopenharmony_ci{ 23888c2ecf20Sopenharmony_ci int rate = hdspm_external_sample_rate(hdspm); 23898c2ecf20Sopenharmony_ci int i, selected_rate = 0; 23908c2ecf20Sopenharmony_ci for (i = 1; i < 10; i++) 23918c2ecf20Sopenharmony_ci if (HDSPM_bit2freq(i) == rate) { 23928c2ecf20Sopenharmony_ci selected_rate = i; 23938c2ecf20Sopenharmony_ci break; 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci return selected_rate; 23968c2ecf20Sopenharmony_ci} 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci#define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ 24008c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 24018c2ecf20Sopenharmony_ci .name = xname, \ 24028c2ecf20Sopenharmony_ci .private_value = xindex, \ 24038c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, \ 24048c2ecf20Sopenharmony_ci .info = snd_hdspm_info_autosync_sample_rate, \ 24058c2ecf20Sopenharmony_ci .get = snd_hdspm_get_autosync_sample_rate \ 24068c2ecf20Sopenharmony_ci} 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_cistatic int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, 24108c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 24118c2ecf20Sopenharmony_ci{ 24128c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts_freq); 24138c2ecf20Sopenharmony_ci return 0; 24148c2ecf20Sopenharmony_ci} 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_cistatic int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, 24188c2ecf20Sopenharmony_ci struct snd_ctl_elem_value * 24198c2ecf20Sopenharmony_ci ucontrol) 24208c2ecf20Sopenharmony_ci{ 24218c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 24248c2ecf20Sopenharmony_ci case RayDAT: 24258c2ecf20Sopenharmony_ci switch (kcontrol->private_value) { 24268c2ecf20Sopenharmony_ci case 0: 24278c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24288c2ecf20Sopenharmony_ci hdspm_get_wc_sample_rate(hdspm); 24298c2ecf20Sopenharmony_ci break; 24308c2ecf20Sopenharmony_ci case 7: 24318c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24328c2ecf20Sopenharmony_ci hdspm_get_tco_sample_rate(hdspm); 24338c2ecf20Sopenharmony_ci break; 24348c2ecf20Sopenharmony_ci case 8: 24358c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24368c2ecf20Sopenharmony_ci hdspm_get_sync_in_sample_rate(hdspm); 24378c2ecf20Sopenharmony_ci break; 24388c2ecf20Sopenharmony_ci default: 24398c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24408c2ecf20Sopenharmony_ci hdspm_get_s1_sample_rate(hdspm, 24418c2ecf20Sopenharmony_ci kcontrol->private_value-1); 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci break; 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci case AIO: 24468c2ecf20Sopenharmony_ci switch (kcontrol->private_value) { 24478c2ecf20Sopenharmony_ci case 0: /* WC */ 24488c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24498c2ecf20Sopenharmony_ci hdspm_get_wc_sample_rate(hdspm); 24508c2ecf20Sopenharmony_ci break; 24518c2ecf20Sopenharmony_ci case 4: /* TCO */ 24528c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24538c2ecf20Sopenharmony_ci hdspm_get_tco_sample_rate(hdspm); 24548c2ecf20Sopenharmony_ci break; 24558c2ecf20Sopenharmony_ci case 5: /* SYNC_IN */ 24568c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24578c2ecf20Sopenharmony_ci hdspm_get_sync_in_sample_rate(hdspm); 24588c2ecf20Sopenharmony_ci break; 24598c2ecf20Sopenharmony_ci default: 24608c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24618c2ecf20Sopenharmony_ci hdspm_get_s1_sample_rate(hdspm, 24628c2ecf20Sopenharmony_ci kcontrol->private_value-1); 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci break; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci case AES32: 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci switch (kcontrol->private_value) { 24698c2ecf20Sopenharmony_ci case 0: /* WC */ 24708c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24718c2ecf20Sopenharmony_ci hdspm_get_wc_sample_rate(hdspm); 24728c2ecf20Sopenharmony_ci break; 24738c2ecf20Sopenharmony_ci case 9: /* TCO */ 24748c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24758c2ecf20Sopenharmony_ci hdspm_get_tco_sample_rate(hdspm); 24768c2ecf20Sopenharmony_ci break; 24778c2ecf20Sopenharmony_ci case 10: /* SYNC_IN */ 24788c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24798c2ecf20Sopenharmony_ci hdspm_get_sync_in_sample_rate(hdspm); 24808c2ecf20Sopenharmony_ci break; 24818c2ecf20Sopenharmony_ci case 11: /* External Rate */ 24828c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24838c2ecf20Sopenharmony_ci hdspm_external_rate_to_enum(hdspm); 24848c2ecf20Sopenharmony_ci break; 24858c2ecf20Sopenharmony_ci default: /* AES1 to AES8 */ 24868c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24878c2ecf20Sopenharmony_ci hdspm_get_aes_sample_rate(hdspm, 24888c2ecf20Sopenharmony_ci kcontrol->private_value - 24898c2ecf20Sopenharmony_ci HDSPM_AES32_AUTOSYNC_FROM_AES1); 24908c2ecf20Sopenharmony_ci break; 24918c2ecf20Sopenharmony_ci } 24928c2ecf20Sopenharmony_ci break; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci case MADI: 24958c2ecf20Sopenharmony_ci case MADIface: 24968c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 24978c2ecf20Sopenharmony_ci hdspm_external_rate_to_enum(hdspm); 24988c2ecf20Sopenharmony_ci break; 24998c2ecf20Sopenharmony_ci default: 25008c2ecf20Sopenharmony_ci break; 25018c2ecf20Sopenharmony_ci } 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci return 0; 25048c2ecf20Sopenharmony_ci} 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci#define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \ 25088c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 25098c2ecf20Sopenharmony_ci .name = xname, \ 25108c2ecf20Sopenharmony_ci .index = xindex, \ 25118c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 25128c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 25138c2ecf20Sopenharmony_ci .info = snd_hdspm_info_system_clock_mode, \ 25148c2ecf20Sopenharmony_ci .get = snd_hdspm_get_system_clock_mode, \ 25158c2ecf20Sopenharmony_ci .put = snd_hdspm_put_system_clock_mode, \ 25168c2ecf20Sopenharmony_ci} 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci/* 25208c2ecf20Sopenharmony_ci * Returns the system clock mode for the given card. 25218c2ecf20Sopenharmony_ci * @returns 0 - master, 1 - slave 25228c2ecf20Sopenharmony_ci */ 25238c2ecf20Sopenharmony_cistatic int hdspm_system_clock_mode(struct hdspm *hdspm) 25248c2ecf20Sopenharmony_ci{ 25258c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 25268c2ecf20Sopenharmony_ci case AIO: 25278c2ecf20Sopenharmony_ci case RayDAT: 25288c2ecf20Sopenharmony_ci if (hdspm->settings_register & HDSPM_c0Master) 25298c2ecf20Sopenharmony_ci return 0; 25308c2ecf20Sopenharmony_ci break; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci default: 25338c2ecf20Sopenharmony_ci if (hdspm->control_register & HDSPM_ClockModeMaster) 25348c2ecf20Sopenharmony_ci return 0; 25358c2ecf20Sopenharmony_ci } 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci return 1; 25388c2ecf20Sopenharmony_ci} 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci/* 25428c2ecf20Sopenharmony_ci * Sets the system clock mode. 25438c2ecf20Sopenharmony_ci * @param mode 0 - master, 1 - slave 25448c2ecf20Sopenharmony_ci */ 25458c2ecf20Sopenharmony_cistatic void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) 25468c2ecf20Sopenharmony_ci{ 25478c2ecf20Sopenharmony_ci hdspm_set_toggle_setting(hdspm, 25488c2ecf20Sopenharmony_ci (hdspm_is_raydat_or_aio(hdspm)) ? 25498c2ecf20Sopenharmony_ci HDSPM_c0Master : HDSPM_ClockModeMaster, 25508c2ecf20Sopenharmony_ci (0 == mode)); 25518c2ecf20Sopenharmony_ci} 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_cistatic int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, 25558c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 25568c2ecf20Sopenharmony_ci{ 25578c2ecf20Sopenharmony_ci static const char *const texts[] = { "Master", "AutoSync" }; 25588c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 25598c2ecf20Sopenharmony_ci return 0; 25608c2ecf20Sopenharmony_ci} 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_cistatic int snd_hdspm_get_system_clock_mode(struct snd_kcontrol *kcontrol, 25638c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 25648c2ecf20Sopenharmony_ci{ 25658c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_system_clock_mode(hdspm); 25688c2ecf20Sopenharmony_ci return 0; 25698c2ecf20Sopenharmony_ci} 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_cistatic int snd_hdspm_put_system_clock_mode(struct snd_kcontrol *kcontrol, 25728c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 25738c2ecf20Sopenharmony_ci{ 25748c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 25758c2ecf20Sopenharmony_ci int val; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 25788c2ecf20Sopenharmony_ci return -EBUSY; 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 25818c2ecf20Sopenharmony_ci if (val < 0) 25828c2ecf20Sopenharmony_ci val = 0; 25838c2ecf20Sopenharmony_ci else if (val > 1) 25848c2ecf20Sopenharmony_ci val = 1; 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci hdspm_set_system_clock_mode(hdspm, val); 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci return 0; 25898c2ecf20Sopenharmony_ci} 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci#define HDSPM_INTERNAL_CLOCK(xname, xindex) \ 25938c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 25948c2ecf20Sopenharmony_ci .name = xname, \ 25958c2ecf20Sopenharmony_ci .index = xindex, \ 25968c2ecf20Sopenharmony_ci .info = snd_hdspm_info_clock_source, \ 25978c2ecf20Sopenharmony_ci .get = snd_hdspm_get_clock_source, \ 25988c2ecf20Sopenharmony_ci .put = snd_hdspm_put_clock_source \ 25998c2ecf20Sopenharmony_ci} 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_cistatic int hdspm_clock_source(struct hdspm * hdspm) 26038c2ecf20Sopenharmony_ci{ 26048c2ecf20Sopenharmony_ci switch (hdspm->system_sample_rate) { 26058c2ecf20Sopenharmony_ci case 32000: return 0; 26068c2ecf20Sopenharmony_ci case 44100: return 1; 26078c2ecf20Sopenharmony_ci case 48000: return 2; 26088c2ecf20Sopenharmony_ci case 64000: return 3; 26098c2ecf20Sopenharmony_ci case 88200: return 4; 26108c2ecf20Sopenharmony_ci case 96000: return 5; 26118c2ecf20Sopenharmony_ci case 128000: return 6; 26128c2ecf20Sopenharmony_ci case 176400: return 7; 26138c2ecf20Sopenharmony_ci case 192000: return 8; 26148c2ecf20Sopenharmony_ci } 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci return -1; 26178c2ecf20Sopenharmony_ci} 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_cistatic int hdspm_set_clock_source(struct hdspm * hdspm, int mode) 26208c2ecf20Sopenharmony_ci{ 26218c2ecf20Sopenharmony_ci int rate; 26228c2ecf20Sopenharmony_ci switch (mode) { 26238c2ecf20Sopenharmony_ci case 0: 26248c2ecf20Sopenharmony_ci rate = 32000; break; 26258c2ecf20Sopenharmony_ci case 1: 26268c2ecf20Sopenharmony_ci rate = 44100; break; 26278c2ecf20Sopenharmony_ci case 2: 26288c2ecf20Sopenharmony_ci rate = 48000; break; 26298c2ecf20Sopenharmony_ci case 3: 26308c2ecf20Sopenharmony_ci rate = 64000; break; 26318c2ecf20Sopenharmony_ci case 4: 26328c2ecf20Sopenharmony_ci rate = 88200; break; 26338c2ecf20Sopenharmony_ci case 5: 26348c2ecf20Sopenharmony_ci rate = 96000; break; 26358c2ecf20Sopenharmony_ci case 6: 26368c2ecf20Sopenharmony_ci rate = 128000; break; 26378c2ecf20Sopenharmony_ci case 7: 26388c2ecf20Sopenharmony_ci rate = 176400; break; 26398c2ecf20Sopenharmony_ci case 8: 26408c2ecf20Sopenharmony_ci rate = 192000; break; 26418c2ecf20Sopenharmony_ci default: 26428c2ecf20Sopenharmony_ci rate = 48000; 26438c2ecf20Sopenharmony_ci } 26448c2ecf20Sopenharmony_ci hdspm_set_rate(hdspm, rate, 1); 26458c2ecf20Sopenharmony_ci return 0; 26468c2ecf20Sopenharmony_ci} 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_cistatic int snd_hdspm_info_clock_source(struct snd_kcontrol *kcontrol, 26498c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 26508c2ecf20Sopenharmony_ci{ 26518c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 9, texts_freq + 1); 26528c2ecf20Sopenharmony_ci} 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_cistatic int snd_hdspm_get_clock_source(struct snd_kcontrol *kcontrol, 26558c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 26568c2ecf20Sopenharmony_ci{ 26578c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_clock_source(hdspm); 26608c2ecf20Sopenharmony_ci return 0; 26618c2ecf20Sopenharmony_ci} 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_cistatic int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol, 26648c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 26658c2ecf20Sopenharmony_ci{ 26668c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 26678c2ecf20Sopenharmony_ci int change; 26688c2ecf20Sopenharmony_ci int val; 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 26718c2ecf20Sopenharmony_ci return -EBUSY; 26728c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 26738c2ecf20Sopenharmony_ci if (val < 0) 26748c2ecf20Sopenharmony_ci val = 0; 26758c2ecf20Sopenharmony_ci if (val > 9) 26768c2ecf20Sopenharmony_ci val = 9; 26778c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 26788c2ecf20Sopenharmony_ci if (val != hdspm_clock_source(hdspm)) 26798c2ecf20Sopenharmony_ci change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0; 26808c2ecf20Sopenharmony_ci else 26818c2ecf20Sopenharmony_ci change = 0; 26828c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 26838c2ecf20Sopenharmony_ci return change; 26848c2ecf20Sopenharmony_ci} 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci#define HDSPM_PREF_SYNC_REF(xname, xindex) \ 26888c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 26898c2ecf20Sopenharmony_ci .name = xname, \ 26908c2ecf20Sopenharmony_ci .index = xindex, \ 26918c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 26928c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 26938c2ecf20Sopenharmony_ci .info = snd_hdspm_info_pref_sync_ref, \ 26948c2ecf20Sopenharmony_ci .get = snd_hdspm_get_pref_sync_ref, \ 26958c2ecf20Sopenharmony_ci .put = snd_hdspm_put_pref_sync_ref \ 26968c2ecf20Sopenharmony_ci} 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci/* 27008c2ecf20Sopenharmony_ci * Returns the current preferred sync reference setting. 27018c2ecf20Sopenharmony_ci * The semantics of the return value are depending on the 27028c2ecf20Sopenharmony_ci * card, please see the comments for clarification. 27038c2ecf20Sopenharmony_ci */ 27048c2ecf20Sopenharmony_cistatic int hdspm_pref_sync_ref(struct hdspm * hdspm) 27058c2ecf20Sopenharmony_ci{ 27068c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 27078c2ecf20Sopenharmony_ci case AES32: 27088c2ecf20Sopenharmony_ci switch (hdspm->control_register & HDSPM_SyncRefMask) { 27098c2ecf20Sopenharmony_ci case 0: return 0; /* WC */ 27108c2ecf20Sopenharmony_ci case HDSPM_SyncRef0: return 1; /* AES 1 */ 27118c2ecf20Sopenharmony_ci case HDSPM_SyncRef1: return 2; /* AES 2 */ 27128c2ecf20Sopenharmony_ci case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3; /* AES 3 */ 27138c2ecf20Sopenharmony_ci case HDSPM_SyncRef2: return 4; /* AES 4 */ 27148c2ecf20Sopenharmony_ci case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5; /* AES 5 */ 27158c2ecf20Sopenharmony_ci case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6; /* AES 6 */ 27168c2ecf20Sopenharmony_ci case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0: 27178c2ecf20Sopenharmony_ci return 7; /* AES 7 */ 27188c2ecf20Sopenharmony_ci case HDSPM_SyncRef3: return 8; /* AES 8 */ 27198c2ecf20Sopenharmony_ci case HDSPM_SyncRef3+HDSPM_SyncRef0: return 9; /* TCO */ 27208c2ecf20Sopenharmony_ci } 27218c2ecf20Sopenharmony_ci break; 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci case MADI: 27248c2ecf20Sopenharmony_ci case MADIface: 27258c2ecf20Sopenharmony_ci if (hdspm->tco) { 27268c2ecf20Sopenharmony_ci switch (hdspm->control_register & HDSPM_SyncRefMask) { 27278c2ecf20Sopenharmony_ci case 0: return 0; /* WC */ 27288c2ecf20Sopenharmony_ci case HDSPM_SyncRef0: return 1; /* MADI */ 27298c2ecf20Sopenharmony_ci case HDSPM_SyncRef1: return 2; /* TCO */ 27308c2ecf20Sopenharmony_ci case HDSPM_SyncRef1+HDSPM_SyncRef0: 27318c2ecf20Sopenharmony_ci return 3; /* SYNC_IN */ 27328c2ecf20Sopenharmony_ci } 27338c2ecf20Sopenharmony_ci } else { 27348c2ecf20Sopenharmony_ci switch (hdspm->control_register & HDSPM_SyncRefMask) { 27358c2ecf20Sopenharmony_ci case 0: return 0; /* WC */ 27368c2ecf20Sopenharmony_ci case HDSPM_SyncRef0: return 1; /* MADI */ 27378c2ecf20Sopenharmony_ci case HDSPM_SyncRef1+HDSPM_SyncRef0: 27388c2ecf20Sopenharmony_ci return 2; /* SYNC_IN */ 27398c2ecf20Sopenharmony_ci } 27408c2ecf20Sopenharmony_ci } 27418c2ecf20Sopenharmony_ci break; 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci case RayDAT: 27448c2ecf20Sopenharmony_ci if (hdspm->tco) { 27458c2ecf20Sopenharmony_ci switch ((hdspm->settings_register & 27468c2ecf20Sopenharmony_ci HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 27478c2ecf20Sopenharmony_ci case 0: return 0; /* WC */ 27488c2ecf20Sopenharmony_ci case 3: return 1; /* ADAT 1 */ 27498c2ecf20Sopenharmony_ci case 4: return 2; /* ADAT 2 */ 27508c2ecf20Sopenharmony_ci case 5: return 3; /* ADAT 3 */ 27518c2ecf20Sopenharmony_ci case 6: return 4; /* ADAT 4 */ 27528c2ecf20Sopenharmony_ci case 1: return 5; /* AES */ 27538c2ecf20Sopenharmony_ci case 2: return 6; /* SPDIF */ 27548c2ecf20Sopenharmony_ci case 9: return 7; /* TCO */ 27558c2ecf20Sopenharmony_ci case 10: return 8; /* SYNC_IN */ 27568c2ecf20Sopenharmony_ci } 27578c2ecf20Sopenharmony_ci } else { 27588c2ecf20Sopenharmony_ci switch ((hdspm->settings_register & 27598c2ecf20Sopenharmony_ci HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 27608c2ecf20Sopenharmony_ci case 0: return 0; /* WC */ 27618c2ecf20Sopenharmony_ci case 3: return 1; /* ADAT 1 */ 27628c2ecf20Sopenharmony_ci case 4: return 2; /* ADAT 2 */ 27638c2ecf20Sopenharmony_ci case 5: return 3; /* ADAT 3 */ 27648c2ecf20Sopenharmony_ci case 6: return 4; /* ADAT 4 */ 27658c2ecf20Sopenharmony_ci case 1: return 5; /* AES */ 27668c2ecf20Sopenharmony_ci case 2: return 6; /* SPDIF */ 27678c2ecf20Sopenharmony_ci case 10: return 7; /* SYNC_IN */ 27688c2ecf20Sopenharmony_ci } 27698c2ecf20Sopenharmony_ci } 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci break; 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci case AIO: 27748c2ecf20Sopenharmony_ci if (hdspm->tco) { 27758c2ecf20Sopenharmony_ci switch ((hdspm->settings_register & 27768c2ecf20Sopenharmony_ci HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 27778c2ecf20Sopenharmony_ci case 0: return 0; /* WC */ 27788c2ecf20Sopenharmony_ci case 3: return 1; /* ADAT */ 27798c2ecf20Sopenharmony_ci case 1: return 2; /* AES */ 27808c2ecf20Sopenharmony_ci case 2: return 3; /* SPDIF */ 27818c2ecf20Sopenharmony_ci case 9: return 4; /* TCO */ 27828c2ecf20Sopenharmony_ci case 10: return 5; /* SYNC_IN */ 27838c2ecf20Sopenharmony_ci } 27848c2ecf20Sopenharmony_ci } else { 27858c2ecf20Sopenharmony_ci switch ((hdspm->settings_register & 27868c2ecf20Sopenharmony_ci HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 27878c2ecf20Sopenharmony_ci case 0: return 0; /* WC */ 27888c2ecf20Sopenharmony_ci case 3: return 1; /* ADAT */ 27898c2ecf20Sopenharmony_ci case 1: return 2; /* AES */ 27908c2ecf20Sopenharmony_ci case 2: return 3; /* SPDIF */ 27918c2ecf20Sopenharmony_ci case 10: return 4; /* SYNC_IN */ 27928c2ecf20Sopenharmony_ci } 27938c2ecf20Sopenharmony_ci } 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci break; 27968c2ecf20Sopenharmony_ci } 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci return -1; 27998c2ecf20Sopenharmony_ci} 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci/* 28038c2ecf20Sopenharmony_ci * Set the preferred sync reference to <pref>. The semantics 28048c2ecf20Sopenharmony_ci * of <pref> are depending on the card type, see the comments 28058c2ecf20Sopenharmony_ci * for clarification. 28068c2ecf20Sopenharmony_ci */ 28078c2ecf20Sopenharmony_cistatic int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref) 28088c2ecf20Sopenharmony_ci{ 28098c2ecf20Sopenharmony_ci int p = 0; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 28128c2ecf20Sopenharmony_ci case AES32: 28138c2ecf20Sopenharmony_ci hdspm->control_register &= ~HDSPM_SyncRefMask; 28148c2ecf20Sopenharmony_ci switch (pref) { 28158c2ecf20Sopenharmony_ci case 0: /* WC */ 28168c2ecf20Sopenharmony_ci break; 28178c2ecf20Sopenharmony_ci case 1: /* AES 1 */ 28188c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef0; 28198c2ecf20Sopenharmony_ci break; 28208c2ecf20Sopenharmony_ci case 2: /* AES 2 */ 28218c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef1; 28228c2ecf20Sopenharmony_ci break; 28238c2ecf20Sopenharmony_ci case 3: /* AES 3 */ 28248c2ecf20Sopenharmony_ci hdspm->control_register |= 28258c2ecf20Sopenharmony_ci HDSPM_SyncRef1+HDSPM_SyncRef0; 28268c2ecf20Sopenharmony_ci break; 28278c2ecf20Sopenharmony_ci case 4: /* AES 4 */ 28288c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef2; 28298c2ecf20Sopenharmony_ci break; 28308c2ecf20Sopenharmony_ci case 5: /* AES 5 */ 28318c2ecf20Sopenharmony_ci hdspm->control_register |= 28328c2ecf20Sopenharmony_ci HDSPM_SyncRef2+HDSPM_SyncRef0; 28338c2ecf20Sopenharmony_ci break; 28348c2ecf20Sopenharmony_ci case 6: /* AES 6 */ 28358c2ecf20Sopenharmony_ci hdspm->control_register |= 28368c2ecf20Sopenharmony_ci HDSPM_SyncRef2+HDSPM_SyncRef1; 28378c2ecf20Sopenharmony_ci break; 28388c2ecf20Sopenharmony_ci case 7: /* AES 7 */ 28398c2ecf20Sopenharmony_ci hdspm->control_register |= 28408c2ecf20Sopenharmony_ci HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0; 28418c2ecf20Sopenharmony_ci break; 28428c2ecf20Sopenharmony_ci case 8: /* AES 8 */ 28438c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef3; 28448c2ecf20Sopenharmony_ci break; 28458c2ecf20Sopenharmony_ci case 9: /* TCO */ 28468c2ecf20Sopenharmony_ci hdspm->control_register |= 28478c2ecf20Sopenharmony_ci HDSPM_SyncRef3+HDSPM_SyncRef0; 28488c2ecf20Sopenharmony_ci break; 28498c2ecf20Sopenharmony_ci default: 28508c2ecf20Sopenharmony_ci return -1; 28518c2ecf20Sopenharmony_ci } 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci break; 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci case MADI: 28568c2ecf20Sopenharmony_ci case MADIface: 28578c2ecf20Sopenharmony_ci hdspm->control_register &= ~HDSPM_SyncRefMask; 28588c2ecf20Sopenharmony_ci if (hdspm->tco) { 28598c2ecf20Sopenharmony_ci switch (pref) { 28608c2ecf20Sopenharmony_ci case 0: /* WC */ 28618c2ecf20Sopenharmony_ci break; 28628c2ecf20Sopenharmony_ci case 1: /* MADI */ 28638c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef0; 28648c2ecf20Sopenharmony_ci break; 28658c2ecf20Sopenharmony_ci case 2: /* TCO */ 28668c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef1; 28678c2ecf20Sopenharmony_ci break; 28688c2ecf20Sopenharmony_ci case 3: /* SYNC_IN */ 28698c2ecf20Sopenharmony_ci hdspm->control_register |= 28708c2ecf20Sopenharmony_ci HDSPM_SyncRef0+HDSPM_SyncRef1; 28718c2ecf20Sopenharmony_ci break; 28728c2ecf20Sopenharmony_ci default: 28738c2ecf20Sopenharmony_ci return -1; 28748c2ecf20Sopenharmony_ci } 28758c2ecf20Sopenharmony_ci } else { 28768c2ecf20Sopenharmony_ci switch (pref) { 28778c2ecf20Sopenharmony_ci case 0: /* WC */ 28788c2ecf20Sopenharmony_ci break; 28798c2ecf20Sopenharmony_ci case 1: /* MADI */ 28808c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef0; 28818c2ecf20Sopenharmony_ci break; 28828c2ecf20Sopenharmony_ci case 2: /* SYNC_IN */ 28838c2ecf20Sopenharmony_ci hdspm->control_register |= 28848c2ecf20Sopenharmony_ci HDSPM_SyncRef0+HDSPM_SyncRef1; 28858c2ecf20Sopenharmony_ci break; 28868c2ecf20Sopenharmony_ci default: 28878c2ecf20Sopenharmony_ci return -1; 28888c2ecf20Sopenharmony_ci } 28898c2ecf20Sopenharmony_ci } 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci break; 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci case RayDAT: 28948c2ecf20Sopenharmony_ci if (hdspm->tco) { 28958c2ecf20Sopenharmony_ci switch (pref) { 28968c2ecf20Sopenharmony_ci case 0: p = 0; break; /* WC */ 28978c2ecf20Sopenharmony_ci case 1: p = 3; break; /* ADAT 1 */ 28988c2ecf20Sopenharmony_ci case 2: p = 4; break; /* ADAT 2 */ 28998c2ecf20Sopenharmony_ci case 3: p = 5; break; /* ADAT 3 */ 29008c2ecf20Sopenharmony_ci case 4: p = 6; break; /* ADAT 4 */ 29018c2ecf20Sopenharmony_ci case 5: p = 1; break; /* AES */ 29028c2ecf20Sopenharmony_ci case 6: p = 2; break; /* SPDIF */ 29038c2ecf20Sopenharmony_ci case 7: p = 9; break; /* TCO */ 29048c2ecf20Sopenharmony_ci case 8: p = 10; break; /* SYNC_IN */ 29058c2ecf20Sopenharmony_ci default: return -1; 29068c2ecf20Sopenharmony_ci } 29078c2ecf20Sopenharmony_ci } else { 29088c2ecf20Sopenharmony_ci switch (pref) { 29098c2ecf20Sopenharmony_ci case 0: p = 0; break; /* WC */ 29108c2ecf20Sopenharmony_ci case 1: p = 3; break; /* ADAT 1 */ 29118c2ecf20Sopenharmony_ci case 2: p = 4; break; /* ADAT 2 */ 29128c2ecf20Sopenharmony_ci case 3: p = 5; break; /* ADAT 3 */ 29138c2ecf20Sopenharmony_ci case 4: p = 6; break; /* ADAT 4 */ 29148c2ecf20Sopenharmony_ci case 5: p = 1; break; /* AES */ 29158c2ecf20Sopenharmony_ci case 6: p = 2; break; /* SPDIF */ 29168c2ecf20Sopenharmony_ci case 7: p = 10; break; /* SYNC_IN */ 29178c2ecf20Sopenharmony_ci default: return -1; 29188c2ecf20Sopenharmony_ci } 29198c2ecf20Sopenharmony_ci } 29208c2ecf20Sopenharmony_ci break; 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci case AIO: 29238c2ecf20Sopenharmony_ci if (hdspm->tco) { 29248c2ecf20Sopenharmony_ci switch (pref) { 29258c2ecf20Sopenharmony_ci case 0: p = 0; break; /* WC */ 29268c2ecf20Sopenharmony_ci case 1: p = 3; break; /* ADAT */ 29278c2ecf20Sopenharmony_ci case 2: p = 1; break; /* AES */ 29288c2ecf20Sopenharmony_ci case 3: p = 2; break; /* SPDIF */ 29298c2ecf20Sopenharmony_ci case 4: p = 9; break; /* TCO */ 29308c2ecf20Sopenharmony_ci case 5: p = 10; break; /* SYNC_IN */ 29318c2ecf20Sopenharmony_ci default: return -1; 29328c2ecf20Sopenharmony_ci } 29338c2ecf20Sopenharmony_ci } else { 29348c2ecf20Sopenharmony_ci switch (pref) { 29358c2ecf20Sopenharmony_ci case 0: p = 0; break; /* WC */ 29368c2ecf20Sopenharmony_ci case 1: p = 3; break; /* ADAT */ 29378c2ecf20Sopenharmony_ci case 2: p = 1; break; /* AES */ 29388c2ecf20Sopenharmony_ci case 3: p = 2; break; /* SPDIF */ 29398c2ecf20Sopenharmony_ci case 4: p = 10; break; /* SYNC_IN */ 29408c2ecf20Sopenharmony_ci default: return -1; 29418c2ecf20Sopenharmony_ci } 29428c2ecf20Sopenharmony_ci } 29438c2ecf20Sopenharmony_ci break; 29448c2ecf20Sopenharmony_ci } 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 29478c2ecf20Sopenharmony_ci case RayDAT: 29488c2ecf20Sopenharmony_ci case AIO: 29498c2ecf20Sopenharmony_ci hdspm->settings_register &= ~HDSPM_c0_SyncRefMask; 29508c2ecf20Sopenharmony_ci hdspm->settings_register |= HDSPM_c0_SyncRef0 * p; 29518c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 29528c2ecf20Sopenharmony_ci break; 29538c2ecf20Sopenharmony_ci 29548c2ecf20Sopenharmony_ci case MADI: 29558c2ecf20Sopenharmony_ci case MADIface: 29568c2ecf20Sopenharmony_ci case AES32: 29578c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, 29588c2ecf20Sopenharmony_ci hdspm->control_register); 29598c2ecf20Sopenharmony_ci } 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci return 0; 29628c2ecf20Sopenharmony_ci} 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_cistatic int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, 29668c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 29678c2ecf20Sopenharmony_ci{ 29688c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync); 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci return 0; 29738c2ecf20Sopenharmony_ci} 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_cistatic int snd_hdspm_get_pref_sync_ref(struct snd_kcontrol *kcontrol, 29768c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 29778c2ecf20Sopenharmony_ci{ 29788c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 29798c2ecf20Sopenharmony_ci int psf = hdspm_pref_sync_ref(hdspm); 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci if (psf >= 0) { 29828c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = psf; 29838c2ecf20Sopenharmony_ci return 0; 29848c2ecf20Sopenharmony_ci } 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci return -1; 29878c2ecf20Sopenharmony_ci} 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_cistatic int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, 29908c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 29918c2ecf20Sopenharmony_ci{ 29928c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 29938c2ecf20Sopenharmony_ci int val, change = 0; 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 29968c2ecf20Sopenharmony_ci return -EBUSY; 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci if (val < 0) 30018c2ecf20Sopenharmony_ci val = 0; 30028c2ecf20Sopenharmony_ci else if (val >= hdspm->texts_autosync_items) 30038c2ecf20Sopenharmony_ci val = hdspm->texts_autosync_items-1; 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 30068c2ecf20Sopenharmony_ci if (val != hdspm_pref_sync_ref(hdspm)) 30078c2ecf20Sopenharmony_ci change = (0 == hdspm_set_pref_sync_ref(hdspm, val)) ? 1 : 0; 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 30108c2ecf20Sopenharmony_ci return change; 30118c2ecf20Sopenharmony_ci} 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci#define HDSPM_AUTOSYNC_REF(xname, xindex) \ 30158c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 30168c2ecf20Sopenharmony_ci .name = xname, \ 30178c2ecf20Sopenharmony_ci .index = xindex, \ 30188c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, \ 30198c2ecf20Sopenharmony_ci .info = snd_hdspm_info_autosync_ref, \ 30208c2ecf20Sopenharmony_ci .get = snd_hdspm_get_autosync_ref, \ 30218c2ecf20Sopenharmony_ci} 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_cistatic int hdspm_autosync_ref(struct hdspm *hdspm) 30248c2ecf20Sopenharmony_ci{ 30258c2ecf20Sopenharmony_ci /* This looks at the autosync selected sync reference */ 30268c2ecf20Sopenharmony_ci if (AES32 == hdspm->io_type) { 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); 30298c2ecf20Sopenharmony_ci unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; 30308c2ecf20Sopenharmony_ci /* syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD is always true */ 30318c2ecf20Sopenharmony_ci if (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN) { 30328c2ecf20Sopenharmony_ci return syncref; 30338c2ecf20Sopenharmony_ci } 30348c2ecf20Sopenharmony_ci return HDSPM_AES32_AUTOSYNC_FROM_NONE; 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci } else if (MADI == hdspm->io_type) { 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 30398c2ecf20Sopenharmony_ci switch (status2 & HDSPM_SelSyncRefMask) { 30408c2ecf20Sopenharmony_ci case HDSPM_SelSyncRef_WORD: 30418c2ecf20Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_WORD; 30428c2ecf20Sopenharmony_ci case HDSPM_SelSyncRef_MADI: 30438c2ecf20Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_MADI; 30448c2ecf20Sopenharmony_ci case HDSPM_SelSyncRef_TCO: 30458c2ecf20Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_TCO; 30468c2ecf20Sopenharmony_ci case HDSPM_SelSyncRef_SyncIn: 30478c2ecf20Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_SYNC_IN; 30488c2ecf20Sopenharmony_ci case HDSPM_SelSyncRef_NVALID: 30498c2ecf20Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_NONE; 30508c2ecf20Sopenharmony_ci default: 30518c2ecf20Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_NONE; 30528c2ecf20Sopenharmony_ci } 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci } 30558c2ecf20Sopenharmony_ci return 0; 30568c2ecf20Sopenharmony_ci} 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_cistatic int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, 30608c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 30618c2ecf20Sopenharmony_ci{ 30628c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_ci if (AES32 == hdspm->io_type) { 30658c2ecf20Sopenharmony_ci static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3", 30668c2ecf20Sopenharmony_ci "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"}; 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 30698c2ecf20Sopenharmony_ci } else if (MADI == hdspm->io_type) { 30708c2ecf20Sopenharmony_ci static const char *const texts[] = {"Word Clock", "MADI", "TCO", 30718c2ecf20Sopenharmony_ci "Sync In", "None" }; 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 30748c2ecf20Sopenharmony_ci } 30758c2ecf20Sopenharmony_ci return 0; 30768c2ecf20Sopenharmony_ci} 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_cistatic int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, 30798c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 30808c2ecf20Sopenharmony_ci{ 30818c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_autosync_ref(hdspm); 30848c2ecf20Sopenharmony_ci return 0; 30858c2ecf20Sopenharmony_ci} 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci#define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname, xindex) \ 30908c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 30918c2ecf20Sopenharmony_ci .name = xname, \ 30928c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ |\ 30938c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 30948c2ecf20Sopenharmony_ci .info = snd_hdspm_info_tco_video_input_format, \ 30958c2ecf20Sopenharmony_ci .get = snd_hdspm_get_tco_video_input_format, \ 30968c2ecf20Sopenharmony_ci} 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_cistatic int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol, 30998c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 31008c2ecf20Sopenharmony_ci{ 31018c2ecf20Sopenharmony_ci static const char *const texts[] = {"No video", "NTSC", "PAL"}; 31028c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 31038c2ecf20Sopenharmony_ci return 0; 31048c2ecf20Sopenharmony_ci} 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_cistatic int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol, 31078c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 31088c2ecf20Sopenharmony_ci{ 31098c2ecf20Sopenharmony_ci u32 status; 31108c2ecf20Sopenharmony_ci int ret = 0; 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 31138c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 31148c2ecf20Sopenharmony_ci switch (status & (HDSPM_TCO1_Video_Input_Format_NTSC | 31158c2ecf20Sopenharmony_ci HDSPM_TCO1_Video_Input_Format_PAL)) { 31168c2ecf20Sopenharmony_ci case HDSPM_TCO1_Video_Input_Format_NTSC: 31178c2ecf20Sopenharmony_ci /* ntsc */ 31188c2ecf20Sopenharmony_ci ret = 1; 31198c2ecf20Sopenharmony_ci break; 31208c2ecf20Sopenharmony_ci case HDSPM_TCO1_Video_Input_Format_PAL: 31218c2ecf20Sopenharmony_ci /* pal */ 31228c2ecf20Sopenharmony_ci ret = 2; 31238c2ecf20Sopenharmony_ci break; 31248c2ecf20Sopenharmony_ci default: 31258c2ecf20Sopenharmony_ci /* no video */ 31268c2ecf20Sopenharmony_ci ret = 0; 31278c2ecf20Sopenharmony_ci break; 31288c2ecf20Sopenharmony_ci } 31298c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = ret; 31308c2ecf20Sopenharmony_ci return 0; 31318c2ecf20Sopenharmony_ci} 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci#define HDSPM_TCO_LTC_FRAMES(xname, xindex) \ 31368c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 31378c2ecf20Sopenharmony_ci .name = xname, \ 31388c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ |\ 31398c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 31408c2ecf20Sopenharmony_ci .info = snd_hdspm_info_tco_ltc_frames, \ 31418c2ecf20Sopenharmony_ci .get = snd_hdspm_get_tco_ltc_frames, \ 31428c2ecf20Sopenharmony_ci} 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_cistatic int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol, 31458c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 31468c2ecf20Sopenharmony_ci{ 31478c2ecf20Sopenharmony_ci static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", 31488c2ecf20Sopenharmony_ci "30 fps"}; 31498c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 31508c2ecf20Sopenharmony_ci return 0; 31518c2ecf20Sopenharmony_ci} 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_cistatic int hdspm_tco_ltc_frames(struct hdspm *hdspm) 31548c2ecf20Sopenharmony_ci{ 31558c2ecf20Sopenharmony_ci u32 status; 31568c2ecf20Sopenharmony_ci int ret = 0; 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 31598c2ecf20Sopenharmony_ci if (status & HDSPM_TCO1_LTC_Input_valid) { 31608c2ecf20Sopenharmony_ci switch (status & (HDSPM_TCO1_LTC_Format_LSB | 31618c2ecf20Sopenharmony_ci HDSPM_TCO1_LTC_Format_MSB)) { 31628c2ecf20Sopenharmony_ci case 0: 31638c2ecf20Sopenharmony_ci /* 24 fps */ 31648c2ecf20Sopenharmony_ci ret = fps_24; 31658c2ecf20Sopenharmony_ci break; 31668c2ecf20Sopenharmony_ci case HDSPM_TCO1_LTC_Format_LSB: 31678c2ecf20Sopenharmony_ci /* 25 fps */ 31688c2ecf20Sopenharmony_ci ret = fps_25; 31698c2ecf20Sopenharmony_ci break; 31708c2ecf20Sopenharmony_ci case HDSPM_TCO1_LTC_Format_MSB: 31718c2ecf20Sopenharmony_ci /* 29.97 fps */ 31728c2ecf20Sopenharmony_ci ret = fps_2997; 31738c2ecf20Sopenharmony_ci break; 31748c2ecf20Sopenharmony_ci default: 31758c2ecf20Sopenharmony_ci /* 30 fps */ 31768c2ecf20Sopenharmony_ci ret = fps_30; 31778c2ecf20Sopenharmony_ci break; 31788c2ecf20Sopenharmony_ci } 31798c2ecf20Sopenharmony_ci } 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci return ret; 31828c2ecf20Sopenharmony_ci} 31838c2ecf20Sopenharmony_ci 31848c2ecf20Sopenharmony_cistatic int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol, 31858c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 31868c2ecf20Sopenharmony_ci{ 31878c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_tco_ltc_frames(hdspm); 31908c2ecf20Sopenharmony_ci return 0; 31918c2ecf20Sopenharmony_ci} 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci#define HDSPM_TOGGLE_SETTING(xname, xindex) \ 31948c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 31958c2ecf20Sopenharmony_ci .name = xname, \ 31968c2ecf20Sopenharmony_ci .private_value = xindex, \ 31978c2ecf20Sopenharmony_ci .info = snd_hdspm_info_toggle_setting, \ 31988c2ecf20Sopenharmony_ci .get = snd_hdspm_get_toggle_setting, \ 31998c2ecf20Sopenharmony_ci .put = snd_hdspm_put_toggle_setting \ 32008c2ecf20Sopenharmony_ci} 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_cistatic int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask) 32038c2ecf20Sopenharmony_ci{ 32048c2ecf20Sopenharmony_ci u32 reg; 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_ci if (hdspm_is_raydat_or_aio(hdspm)) 32078c2ecf20Sopenharmony_ci reg = hdspm->settings_register; 32088c2ecf20Sopenharmony_ci else 32098c2ecf20Sopenharmony_ci reg = hdspm->control_register; 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci return (reg & regmask) ? 1 : 0; 32128c2ecf20Sopenharmony_ci} 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_cistatic int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out) 32158c2ecf20Sopenharmony_ci{ 32168c2ecf20Sopenharmony_ci u32 *reg; 32178c2ecf20Sopenharmony_ci u32 target_reg; 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci if (hdspm_is_raydat_or_aio(hdspm)) { 32208c2ecf20Sopenharmony_ci reg = &(hdspm->settings_register); 32218c2ecf20Sopenharmony_ci target_reg = HDSPM_WR_SETTINGS; 32228c2ecf20Sopenharmony_ci } else { 32238c2ecf20Sopenharmony_ci reg = &(hdspm->control_register); 32248c2ecf20Sopenharmony_ci target_reg = HDSPM_controlRegister; 32258c2ecf20Sopenharmony_ci } 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci if (out) 32288c2ecf20Sopenharmony_ci *reg |= regmask; 32298c2ecf20Sopenharmony_ci else 32308c2ecf20Sopenharmony_ci *reg &= ~regmask; 32318c2ecf20Sopenharmony_ci 32328c2ecf20Sopenharmony_ci hdspm_write(hdspm, target_reg, *reg); 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci return 0; 32358c2ecf20Sopenharmony_ci} 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci#define snd_hdspm_info_toggle_setting snd_ctl_boolean_mono_info 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_cistatic int snd_hdspm_get_toggle_setting(struct snd_kcontrol *kcontrol, 32408c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 32418c2ecf20Sopenharmony_ci{ 32428c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 32438c2ecf20Sopenharmony_ci u32 regmask = kcontrol->private_value; 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 32468c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = hdspm_toggle_setting(hdspm, regmask); 32478c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 32488c2ecf20Sopenharmony_ci return 0; 32498c2ecf20Sopenharmony_ci} 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_cistatic int snd_hdspm_put_toggle_setting(struct snd_kcontrol *kcontrol, 32528c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 32538c2ecf20Sopenharmony_ci{ 32548c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 32558c2ecf20Sopenharmony_ci u32 regmask = kcontrol->private_value; 32568c2ecf20Sopenharmony_ci int change; 32578c2ecf20Sopenharmony_ci unsigned int val; 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 32608c2ecf20Sopenharmony_ci return -EBUSY; 32618c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0] & 1; 32628c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 32638c2ecf20Sopenharmony_ci change = (int) val != hdspm_toggle_setting(hdspm, regmask); 32648c2ecf20Sopenharmony_ci hdspm_set_toggle_setting(hdspm, regmask, val); 32658c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 32668c2ecf20Sopenharmony_ci return change; 32678c2ecf20Sopenharmony_ci} 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci#define HDSPM_INPUT_SELECT(xname, xindex) \ 32708c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 32718c2ecf20Sopenharmony_ci .name = xname, \ 32728c2ecf20Sopenharmony_ci .index = xindex, \ 32738c2ecf20Sopenharmony_ci .info = snd_hdspm_info_input_select, \ 32748c2ecf20Sopenharmony_ci .get = snd_hdspm_get_input_select, \ 32758c2ecf20Sopenharmony_ci .put = snd_hdspm_put_input_select \ 32768c2ecf20Sopenharmony_ci} 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_cistatic int hdspm_input_select(struct hdspm * hdspm) 32798c2ecf20Sopenharmony_ci{ 32808c2ecf20Sopenharmony_ci return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0; 32818c2ecf20Sopenharmony_ci} 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_cistatic int hdspm_set_input_select(struct hdspm * hdspm, int out) 32848c2ecf20Sopenharmony_ci{ 32858c2ecf20Sopenharmony_ci if (out) 32868c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_InputSelect0; 32878c2ecf20Sopenharmony_ci else 32888c2ecf20Sopenharmony_ci hdspm->control_register &= ~HDSPM_InputSelect0; 32898c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ci return 0; 32928c2ecf20Sopenharmony_ci} 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_cistatic int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, 32958c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 32968c2ecf20Sopenharmony_ci{ 32978c2ecf20Sopenharmony_ci static const char *const texts[] = { "optical", "coaxial" }; 32988c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 32998c2ecf20Sopenharmony_ci return 0; 33008c2ecf20Sopenharmony_ci} 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_cistatic int snd_hdspm_get_input_select(struct snd_kcontrol *kcontrol, 33038c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 33048c2ecf20Sopenharmony_ci{ 33058c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 33088c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm); 33098c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 33108c2ecf20Sopenharmony_ci return 0; 33118c2ecf20Sopenharmony_ci} 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_cistatic int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol, 33148c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 33158c2ecf20Sopenharmony_ci{ 33168c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 33178c2ecf20Sopenharmony_ci int change; 33188c2ecf20Sopenharmony_ci unsigned int val; 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 33218c2ecf20Sopenharmony_ci return -EBUSY; 33228c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0] & 1; 33238c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 33248c2ecf20Sopenharmony_ci change = (int) val != hdspm_input_select(hdspm); 33258c2ecf20Sopenharmony_ci hdspm_set_input_select(hdspm, val); 33268c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 33278c2ecf20Sopenharmony_ci return change; 33288c2ecf20Sopenharmony_ci} 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci#define HDSPM_DS_WIRE(xname, xindex) \ 33328c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 33338c2ecf20Sopenharmony_ci .name = xname, \ 33348c2ecf20Sopenharmony_ci .index = xindex, \ 33358c2ecf20Sopenharmony_ci .info = snd_hdspm_info_ds_wire, \ 33368c2ecf20Sopenharmony_ci .get = snd_hdspm_get_ds_wire, \ 33378c2ecf20Sopenharmony_ci .put = snd_hdspm_put_ds_wire \ 33388c2ecf20Sopenharmony_ci} 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_cistatic int hdspm_ds_wire(struct hdspm * hdspm) 33418c2ecf20Sopenharmony_ci{ 33428c2ecf20Sopenharmony_ci return (hdspm->control_register & HDSPM_DS_DoubleWire) ? 1 : 0; 33438c2ecf20Sopenharmony_ci} 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_cistatic int hdspm_set_ds_wire(struct hdspm * hdspm, int ds) 33468c2ecf20Sopenharmony_ci{ 33478c2ecf20Sopenharmony_ci if (ds) 33488c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_DS_DoubleWire; 33498c2ecf20Sopenharmony_ci else 33508c2ecf20Sopenharmony_ci hdspm->control_register &= ~HDSPM_DS_DoubleWire; 33518c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_ci return 0; 33548c2ecf20Sopenharmony_ci} 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_cistatic int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, 33578c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 33588c2ecf20Sopenharmony_ci{ 33598c2ecf20Sopenharmony_ci static const char *const texts[] = { "Single", "Double" }; 33608c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 33618c2ecf20Sopenharmony_ci return 0; 33628c2ecf20Sopenharmony_ci} 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_cistatic int snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol, 33658c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 33668c2ecf20Sopenharmony_ci{ 33678c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 33708c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm); 33718c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 33728c2ecf20Sopenharmony_ci return 0; 33738c2ecf20Sopenharmony_ci} 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_cistatic int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol, 33768c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 33778c2ecf20Sopenharmony_ci{ 33788c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 33798c2ecf20Sopenharmony_ci int change; 33808c2ecf20Sopenharmony_ci unsigned int val; 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 33838c2ecf20Sopenharmony_ci return -EBUSY; 33848c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0] & 1; 33858c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 33868c2ecf20Sopenharmony_ci change = (int) val != hdspm_ds_wire(hdspm); 33878c2ecf20Sopenharmony_ci hdspm_set_ds_wire(hdspm, val); 33888c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 33898c2ecf20Sopenharmony_ci return change; 33908c2ecf20Sopenharmony_ci} 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci#define HDSPM_QS_WIRE(xname, xindex) \ 33948c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 33958c2ecf20Sopenharmony_ci .name = xname, \ 33968c2ecf20Sopenharmony_ci .index = xindex, \ 33978c2ecf20Sopenharmony_ci .info = snd_hdspm_info_qs_wire, \ 33988c2ecf20Sopenharmony_ci .get = snd_hdspm_get_qs_wire, \ 33998c2ecf20Sopenharmony_ci .put = snd_hdspm_put_qs_wire \ 34008c2ecf20Sopenharmony_ci} 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_cistatic int hdspm_qs_wire(struct hdspm * hdspm) 34038c2ecf20Sopenharmony_ci{ 34048c2ecf20Sopenharmony_ci if (hdspm->control_register & HDSPM_QS_DoubleWire) 34058c2ecf20Sopenharmony_ci return 1; 34068c2ecf20Sopenharmony_ci if (hdspm->control_register & HDSPM_QS_QuadWire) 34078c2ecf20Sopenharmony_ci return 2; 34088c2ecf20Sopenharmony_ci return 0; 34098c2ecf20Sopenharmony_ci} 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_cistatic int hdspm_set_qs_wire(struct hdspm * hdspm, int mode) 34128c2ecf20Sopenharmony_ci{ 34138c2ecf20Sopenharmony_ci hdspm->control_register &= ~(HDSPM_QS_DoubleWire | HDSPM_QS_QuadWire); 34148c2ecf20Sopenharmony_ci switch (mode) { 34158c2ecf20Sopenharmony_ci case 0: 34168c2ecf20Sopenharmony_ci break; 34178c2ecf20Sopenharmony_ci case 1: 34188c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_QS_DoubleWire; 34198c2ecf20Sopenharmony_ci break; 34208c2ecf20Sopenharmony_ci case 2: 34218c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_QS_QuadWire; 34228c2ecf20Sopenharmony_ci break; 34238c2ecf20Sopenharmony_ci } 34248c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci return 0; 34278c2ecf20Sopenharmony_ci} 34288c2ecf20Sopenharmony_ci 34298c2ecf20Sopenharmony_cistatic int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, 34308c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 34318c2ecf20Sopenharmony_ci{ 34328c2ecf20Sopenharmony_ci static const char *const texts[] = { "Single", "Double", "Quad" }; 34338c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 34348c2ecf20Sopenharmony_ci return 0; 34358c2ecf20Sopenharmony_ci} 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_cistatic int snd_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol, 34388c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 34398c2ecf20Sopenharmony_ci{ 34408c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 34438c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm); 34448c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 34458c2ecf20Sopenharmony_ci return 0; 34468c2ecf20Sopenharmony_ci} 34478c2ecf20Sopenharmony_ci 34488c2ecf20Sopenharmony_cistatic int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, 34498c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 34508c2ecf20Sopenharmony_ci{ 34518c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 34528c2ecf20Sopenharmony_ci int change; 34538c2ecf20Sopenharmony_ci int val; 34548c2ecf20Sopenharmony_ci 34558c2ecf20Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 34568c2ecf20Sopenharmony_ci return -EBUSY; 34578c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 34588c2ecf20Sopenharmony_ci if (val < 0) 34598c2ecf20Sopenharmony_ci val = 0; 34608c2ecf20Sopenharmony_ci if (val > 2) 34618c2ecf20Sopenharmony_ci val = 2; 34628c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 34638c2ecf20Sopenharmony_ci change = val != hdspm_qs_wire(hdspm); 34648c2ecf20Sopenharmony_ci hdspm_set_qs_wire(hdspm, val); 34658c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 34668c2ecf20Sopenharmony_ci return change; 34678c2ecf20Sopenharmony_ci} 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci#define HDSPM_CONTROL_TRISTATE(xname, xindex) \ 34708c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 34718c2ecf20Sopenharmony_ci .name = xname, \ 34728c2ecf20Sopenharmony_ci .private_value = xindex, \ 34738c2ecf20Sopenharmony_ci .info = snd_hdspm_info_tristate, \ 34748c2ecf20Sopenharmony_ci .get = snd_hdspm_get_tristate, \ 34758c2ecf20Sopenharmony_ci .put = snd_hdspm_put_tristate \ 34768c2ecf20Sopenharmony_ci} 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_cistatic int hdspm_tristate(struct hdspm *hdspm, u32 regmask) 34798c2ecf20Sopenharmony_ci{ 34808c2ecf20Sopenharmony_ci u32 reg = hdspm->settings_register & (regmask * 3); 34818c2ecf20Sopenharmony_ci return reg / regmask; 34828c2ecf20Sopenharmony_ci} 34838c2ecf20Sopenharmony_ci 34848c2ecf20Sopenharmony_cistatic int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask) 34858c2ecf20Sopenharmony_ci{ 34868c2ecf20Sopenharmony_ci hdspm->settings_register &= ~(regmask * 3); 34878c2ecf20Sopenharmony_ci hdspm->settings_register |= (regmask * mode); 34888c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 34898c2ecf20Sopenharmony_ci 34908c2ecf20Sopenharmony_ci return 0; 34918c2ecf20Sopenharmony_ci} 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_cistatic int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol, 34948c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 34958c2ecf20Sopenharmony_ci{ 34968c2ecf20Sopenharmony_ci u32 regmask = kcontrol->private_value; 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_ci static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" }; 34998c2ecf20Sopenharmony_ci static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" }; 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci switch (regmask) { 35028c2ecf20Sopenharmony_ci case HDSPM_c0_Input0: 35038c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts_spdif); 35048c2ecf20Sopenharmony_ci break; 35058c2ecf20Sopenharmony_ci default: 35068c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts_levels); 35078c2ecf20Sopenharmony_ci break; 35088c2ecf20Sopenharmony_ci } 35098c2ecf20Sopenharmony_ci return 0; 35108c2ecf20Sopenharmony_ci} 35118c2ecf20Sopenharmony_ci 35128c2ecf20Sopenharmony_cistatic int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol, 35138c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 35148c2ecf20Sopenharmony_ci{ 35158c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 35168c2ecf20Sopenharmony_ci u32 regmask = kcontrol->private_value; 35178c2ecf20Sopenharmony_ci 35188c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 35198c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask); 35208c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 35218c2ecf20Sopenharmony_ci return 0; 35228c2ecf20Sopenharmony_ci} 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_cistatic int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol, 35258c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 35268c2ecf20Sopenharmony_ci{ 35278c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 35288c2ecf20Sopenharmony_ci u32 regmask = kcontrol->private_value; 35298c2ecf20Sopenharmony_ci int change; 35308c2ecf20Sopenharmony_ci int val; 35318c2ecf20Sopenharmony_ci 35328c2ecf20Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 35338c2ecf20Sopenharmony_ci return -EBUSY; 35348c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 35358c2ecf20Sopenharmony_ci if (val < 0) 35368c2ecf20Sopenharmony_ci val = 0; 35378c2ecf20Sopenharmony_ci if (val > 2) 35388c2ecf20Sopenharmony_ci val = 2; 35398c2ecf20Sopenharmony_ci 35408c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 35418c2ecf20Sopenharmony_ci change = val != hdspm_tristate(hdspm, regmask); 35428c2ecf20Sopenharmony_ci hdspm_set_tristate(hdspm, val, regmask); 35438c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 35448c2ecf20Sopenharmony_ci return change; 35458c2ecf20Sopenharmony_ci} 35468c2ecf20Sopenharmony_ci 35478c2ecf20Sopenharmony_ci#define HDSPM_MADI_SPEEDMODE(xname, xindex) \ 35488c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 35498c2ecf20Sopenharmony_ci .name = xname, \ 35508c2ecf20Sopenharmony_ci .index = xindex, \ 35518c2ecf20Sopenharmony_ci .info = snd_hdspm_info_madi_speedmode, \ 35528c2ecf20Sopenharmony_ci .get = snd_hdspm_get_madi_speedmode, \ 35538c2ecf20Sopenharmony_ci .put = snd_hdspm_put_madi_speedmode \ 35548c2ecf20Sopenharmony_ci} 35558c2ecf20Sopenharmony_ci 35568c2ecf20Sopenharmony_cistatic int hdspm_madi_speedmode(struct hdspm *hdspm) 35578c2ecf20Sopenharmony_ci{ 35588c2ecf20Sopenharmony_ci if (hdspm->control_register & HDSPM_QuadSpeed) 35598c2ecf20Sopenharmony_ci return 2; 35608c2ecf20Sopenharmony_ci if (hdspm->control_register & HDSPM_DoubleSpeed) 35618c2ecf20Sopenharmony_ci return 1; 35628c2ecf20Sopenharmony_ci return 0; 35638c2ecf20Sopenharmony_ci} 35648c2ecf20Sopenharmony_ci 35658c2ecf20Sopenharmony_cistatic int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode) 35668c2ecf20Sopenharmony_ci{ 35678c2ecf20Sopenharmony_ci hdspm->control_register &= ~(HDSPM_DoubleSpeed | HDSPM_QuadSpeed); 35688c2ecf20Sopenharmony_ci switch (mode) { 35698c2ecf20Sopenharmony_ci case 0: 35708c2ecf20Sopenharmony_ci break; 35718c2ecf20Sopenharmony_ci case 1: 35728c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_DoubleSpeed; 35738c2ecf20Sopenharmony_ci break; 35748c2ecf20Sopenharmony_ci case 2: 35758c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPM_QuadSpeed; 35768c2ecf20Sopenharmony_ci break; 35778c2ecf20Sopenharmony_ci } 35788c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 35798c2ecf20Sopenharmony_ci 35808c2ecf20Sopenharmony_ci return 0; 35818c2ecf20Sopenharmony_ci} 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_cistatic int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, 35848c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 35858c2ecf20Sopenharmony_ci{ 35868c2ecf20Sopenharmony_ci static const char *const texts[] = { "Single", "Double", "Quad" }; 35878c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 35888c2ecf20Sopenharmony_ci return 0; 35898c2ecf20Sopenharmony_ci} 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_cistatic int snd_hdspm_get_madi_speedmode(struct snd_kcontrol *kcontrol, 35928c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 35938c2ecf20Sopenharmony_ci{ 35948c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 35958c2ecf20Sopenharmony_ci 35968c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 35978c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_madi_speedmode(hdspm); 35988c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 35998c2ecf20Sopenharmony_ci return 0; 36008c2ecf20Sopenharmony_ci} 36018c2ecf20Sopenharmony_ci 36028c2ecf20Sopenharmony_cistatic int snd_hdspm_put_madi_speedmode(struct snd_kcontrol *kcontrol, 36038c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 36048c2ecf20Sopenharmony_ci{ 36058c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 36068c2ecf20Sopenharmony_ci int change; 36078c2ecf20Sopenharmony_ci int val; 36088c2ecf20Sopenharmony_ci 36098c2ecf20Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 36108c2ecf20Sopenharmony_ci return -EBUSY; 36118c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 36128c2ecf20Sopenharmony_ci if (val < 0) 36138c2ecf20Sopenharmony_ci val = 0; 36148c2ecf20Sopenharmony_ci if (val > 2) 36158c2ecf20Sopenharmony_ci val = 2; 36168c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 36178c2ecf20Sopenharmony_ci change = val != hdspm_madi_speedmode(hdspm); 36188c2ecf20Sopenharmony_ci hdspm_set_madi_speedmode(hdspm, val); 36198c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 36208c2ecf20Sopenharmony_ci return change; 36218c2ecf20Sopenharmony_ci} 36228c2ecf20Sopenharmony_ci 36238c2ecf20Sopenharmony_ci#define HDSPM_MIXER(xname, xindex) \ 36248c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ 36258c2ecf20Sopenharmony_ci .name = xname, \ 36268c2ecf20Sopenharmony_ci .index = xindex, \ 36278c2ecf20Sopenharmony_ci .device = 0, \ 36288c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 36298c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 36308c2ecf20Sopenharmony_ci .info = snd_hdspm_info_mixer, \ 36318c2ecf20Sopenharmony_ci .get = snd_hdspm_get_mixer, \ 36328c2ecf20Sopenharmony_ci .put = snd_hdspm_put_mixer \ 36338c2ecf20Sopenharmony_ci} 36348c2ecf20Sopenharmony_ci 36358c2ecf20Sopenharmony_cistatic int snd_hdspm_info_mixer(struct snd_kcontrol *kcontrol, 36368c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 36378c2ecf20Sopenharmony_ci{ 36388c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 36398c2ecf20Sopenharmony_ci uinfo->count = 3; 36408c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 36418c2ecf20Sopenharmony_ci uinfo->value.integer.max = 65535; 36428c2ecf20Sopenharmony_ci uinfo->value.integer.step = 1; 36438c2ecf20Sopenharmony_ci return 0; 36448c2ecf20Sopenharmony_ci} 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_cistatic int snd_hdspm_get_mixer(struct snd_kcontrol *kcontrol, 36478c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 36488c2ecf20Sopenharmony_ci{ 36498c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 36508c2ecf20Sopenharmony_ci int source; 36518c2ecf20Sopenharmony_ci int destination; 36528c2ecf20Sopenharmony_ci 36538c2ecf20Sopenharmony_ci source = ucontrol->value.integer.value[0]; 36548c2ecf20Sopenharmony_ci if (source < 0) 36558c2ecf20Sopenharmony_ci source = 0; 36568c2ecf20Sopenharmony_ci else if (source >= 2 * HDSPM_MAX_CHANNELS) 36578c2ecf20Sopenharmony_ci source = 2 * HDSPM_MAX_CHANNELS - 1; 36588c2ecf20Sopenharmony_ci 36598c2ecf20Sopenharmony_ci destination = ucontrol->value.integer.value[1]; 36608c2ecf20Sopenharmony_ci if (destination < 0) 36618c2ecf20Sopenharmony_ci destination = 0; 36628c2ecf20Sopenharmony_ci else if (destination >= HDSPM_MAX_CHANNELS) 36638c2ecf20Sopenharmony_ci destination = HDSPM_MAX_CHANNELS - 1; 36648c2ecf20Sopenharmony_ci 36658c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 36668c2ecf20Sopenharmony_ci if (source >= HDSPM_MAX_CHANNELS) 36678c2ecf20Sopenharmony_ci ucontrol->value.integer.value[2] = 36688c2ecf20Sopenharmony_ci hdspm_read_pb_gain(hdspm, destination, 36698c2ecf20Sopenharmony_ci source - HDSPM_MAX_CHANNELS); 36708c2ecf20Sopenharmony_ci else 36718c2ecf20Sopenharmony_ci ucontrol->value.integer.value[2] = 36728c2ecf20Sopenharmony_ci hdspm_read_in_gain(hdspm, destination, source); 36738c2ecf20Sopenharmony_ci 36748c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci return 0; 36778c2ecf20Sopenharmony_ci} 36788c2ecf20Sopenharmony_ci 36798c2ecf20Sopenharmony_cistatic int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol, 36808c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 36818c2ecf20Sopenharmony_ci{ 36828c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 36838c2ecf20Sopenharmony_ci int change; 36848c2ecf20Sopenharmony_ci int source; 36858c2ecf20Sopenharmony_ci int destination; 36868c2ecf20Sopenharmony_ci int gain; 36878c2ecf20Sopenharmony_ci 36888c2ecf20Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 36898c2ecf20Sopenharmony_ci return -EBUSY; 36908c2ecf20Sopenharmony_ci 36918c2ecf20Sopenharmony_ci source = ucontrol->value.integer.value[0]; 36928c2ecf20Sopenharmony_ci destination = ucontrol->value.integer.value[1]; 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_ci if (source < 0 || source >= 2 * HDSPM_MAX_CHANNELS) 36958c2ecf20Sopenharmony_ci return -1; 36968c2ecf20Sopenharmony_ci if (destination < 0 || destination >= HDSPM_MAX_CHANNELS) 36978c2ecf20Sopenharmony_ci return -1; 36988c2ecf20Sopenharmony_ci 36998c2ecf20Sopenharmony_ci gain = ucontrol->value.integer.value[2]; 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_ci if (source >= HDSPM_MAX_CHANNELS) 37048c2ecf20Sopenharmony_ci change = gain != hdspm_read_pb_gain(hdspm, destination, 37058c2ecf20Sopenharmony_ci source - 37068c2ecf20Sopenharmony_ci HDSPM_MAX_CHANNELS); 37078c2ecf20Sopenharmony_ci else 37088c2ecf20Sopenharmony_ci change = gain != hdspm_read_in_gain(hdspm, destination, 37098c2ecf20Sopenharmony_ci source); 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_ci if (change) { 37128c2ecf20Sopenharmony_ci if (source >= HDSPM_MAX_CHANNELS) 37138c2ecf20Sopenharmony_ci hdspm_write_pb_gain(hdspm, destination, 37148c2ecf20Sopenharmony_ci source - HDSPM_MAX_CHANNELS, 37158c2ecf20Sopenharmony_ci gain); 37168c2ecf20Sopenharmony_ci else 37178c2ecf20Sopenharmony_ci hdspm_write_in_gain(hdspm, destination, source, 37188c2ecf20Sopenharmony_ci gain); 37198c2ecf20Sopenharmony_ci } 37208c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_ci return change; 37238c2ecf20Sopenharmony_ci} 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci/* The simple mixer control(s) provide gain control for the 37268c2ecf20Sopenharmony_ci basic 1:1 mappings of playback streams to output 37278c2ecf20Sopenharmony_ci streams. 37288c2ecf20Sopenharmony_ci*/ 37298c2ecf20Sopenharmony_ci 37308c2ecf20Sopenharmony_ci#define HDSPM_PLAYBACK_MIXER \ 37318c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 37328c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ 37338c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 37348c2ecf20Sopenharmony_ci .info = snd_hdspm_info_playback_mixer, \ 37358c2ecf20Sopenharmony_ci .get = snd_hdspm_get_playback_mixer, \ 37368c2ecf20Sopenharmony_ci .put = snd_hdspm_put_playback_mixer \ 37378c2ecf20Sopenharmony_ci} 37388c2ecf20Sopenharmony_ci 37398c2ecf20Sopenharmony_cistatic int snd_hdspm_info_playback_mixer(struct snd_kcontrol *kcontrol, 37408c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 37418c2ecf20Sopenharmony_ci{ 37428c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 37438c2ecf20Sopenharmony_ci uinfo->count = 1; 37448c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 37458c2ecf20Sopenharmony_ci uinfo->value.integer.max = 64; 37468c2ecf20Sopenharmony_ci uinfo->value.integer.step = 1; 37478c2ecf20Sopenharmony_ci return 0; 37488c2ecf20Sopenharmony_ci} 37498c2ecf20Sopenharmony_ci 37508c2ecf20Sopenharmony_cistatic int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol, 37518c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 37528c2ecf20Sopenharmony_ci{ 37538c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 37548c2ecf20Sopenharmony_ci int channel; 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_ci channel = ucontrol->id.index - 1; 37578c2ecf20Sopenharmony_ci 37588c2ecf20Sopenharmony_ci if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS)) 37598c2ecf20Sopenharmony_ci return -EINVAL; 37608c2ecf20Sopenharmony_ci 37618c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 37628c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 37638c2ecf20Sopenharmony_ci (hdspm_read_pb_gain(hdspm, channel, channel)*64)/UNITY_GAIN; 37648c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 37658c2ecf20Sopenharmony_ci 37668c2ecf20Sopenharmony_ci return 0; 37678c2ecf20Sopenharmony_ci} 37688c2ecf20Sopenharmony_ci 37698c2ecf20Sopenharmony_cistatic int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, 37708c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 37718c2ecf20Sopenharmony_ci{ 37728c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 37738c2ecf20Sopenharmony_ci int change; 37748c2ecf20Sopenharmony_ci int channel; 37758c2ecf20Sopenharmony_ci int gain; 37768c2ecf20Sopenharmony_ci 37778c2ecf20Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 37788c2ecf20Sopenharmony_ci return -EBUSY; 37798c2ecf20Sopenharmony_ci 37808c2ecf20Sopenharmony_ci channel = ucontrol->id.index - 1; 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS)) 37838c2ecf20Sopenharmony_ci return -EINVAL; 37848c2ecf20Sopenharmony_ci 37858c2ecf20Sopenharmony_ci gain = ucontrol->value.integer.value[0]*UNITY_GAIN/64; 37868c2ecf20Sopenharmony_ci 37878c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 37888c2ecf20Sopenharmony_ci change = 37898c2ecf20Sopenharmony_ci gain != hdspm_read_pb_gain(hdspm, channel, 37908c2ecf20Sopenharmony_ci channel); 37918c2ecf20Sopenharmony_ci if (change) 37928c2ecf20Sopenharmony_ci hdspm_write_pb_gain(hdspm, channel, channel, 37938c2ecf20Sopenharmony_ci gain); 37948c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 37958c2ecf20Sopenharmony_ci return change; 37968c2ecf20Sopenharmony_ci} 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_ci#define HDSPM_SYNC_CHECK(xname, xindex) \ 37998c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 38008c2ecf20Sopenharmony_ci .name = xname, \ 38018c2ecf20Sopenharmony_ci .private_value = xindex, \ 38028c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 38038c2ecf20Sopenharmony_ci .info = snd_hdspm_info_sync_check, \ 38048c2ecf20Sopenharmony_ci .get = snd_hdspm_get_sync_check \ 38058c2ecf20Sopenharmony_ci} 38068c2ecf20Sopenharmony_ci 38078c2ecf20Sopenharmony_ci#define HDSPM_TCO_LOCK_CHECK(xname, xindex) \ 38088c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 38098c2ecf20Sopenharmony_ci .name = xname, \ 38108c2ecf20Sopenharmony_ci .private_value = xindex, \ 38118c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 38128c2ecf20Sopenharmony_ci .info = snd_hdspm_tco_info_lock_check, \ 38138c2ecf20Sopenharmony_ci .get = snd_hdspm_get_sync_check \ 38148c2ecf20Sopenharmony_ci} 38158c2ecf20Sopenharmony_ci 38168c2ecf20Sopenharmony_ci 38178c2ecf20Sopenharmony_ci 38188c2ecf20Sopenharmony_cistatic int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, 38198c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 38208c2ecf20Sopenharmony_ci{ 38218c2ecf20Sopenharmony_ci static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" }; 38228c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 38238c2ecf20Sopenharmony_ci return 0; 38248c2ecf20Sopenharmony_ci} 38258c2ecf20Sopenharmony_ci 38268c2ecf20Sopenharmony_cistatic int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol, 38278c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 38288c2ecf20Sopenharmony_ci{ 38298c2ecf20Sopenharmony_ci static const char *const texts[] = { "No Lock", "Lock" }; 38308c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 38318c2ecf20Sopenharmony_ci return 0; 38328c2ecf20Sopenharmony_ci} 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_cistatic int hdspm_wc_sync_check(struct hdspm *hdspm) 38358c2ecf20Sopenharmony_ci{ 38368c2ecf20Sopenharmony_ci int status, status2; 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 38398c2ecf20Sopenharmony_ci case AES32: 38408c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 38418c2ecf20Sopenharmony_ci if (status & HDSPM_AES32_wcLock) { 38428c2ecf20Sopenharmony_ci if (status & HDSPM_AES32_wcSync) 38438c2ecf20Sopenharmony_ci return 2; 38448c2ecf20Sopenharmony_ci else 38458c2ecf20Sopenharmony_ci return 1; 38468c2ecf20Sopenharmony_ci } 38478c2ecf20Sopenharmony_ci return 0; 38488c2ecf20Sopenharmony_ci break; 38498c2ecf20Sopenharmony_ci 38508c2ecf20Sopenharmony_ci case MADI: 38518c2ecf20Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 38528c2ecf20Sopenharmony_ci if (status2 & HDSPM_wcLock) { 38538c2ecf20Sopenharmony_ci if (status2 & HDSPM_wcSync) 38548c2ecf20Sopenharmony_ci return 2; 38558c2ecf20Sopenharmony_ci else 38568c2ecf20Sopenharmony_ci return 1; 38578c2ecf20Sopenharmony_ci } 38588c2ecf20Sopenharmony_ci return 0; 38598c2ecf20Sopenharmony_ci break; 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci case RayDAT: 38628c2ecf20Sopenharmony_ci case AIO: 38638c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 38648c2ecf20Sopenharmony_ci 38658c2ecf20Sopenharmony_ci if (status & 0x2000000) 38668c2ecf20Sopenharmony_ci return 2; 38678c2ecf20Sopenharmony_ci else if (status & 0x1000000) 38688c2ecf20Sopenharmony_ci return 1; 38698c2ecf20Sopenharmony_ci return 0; 38708c2ecf20Sopenharmony_ci 38718c2ecf20Sopenharmony_ci break; 38728c2ecf20Sopenharmony_ci 38738c2ecf20Sopenharmony_ci case MADIface: 38748c2ecf20Sopenharmony_ci break; 38758c2ecf20Sopenharmony_ci } 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_ci 38788c2ecf20Sopenharmony_ci return 3; 38798c2ecf20Sopenharmony_ci} 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_cistatic int hdspm_madi_sync_check(struct hdspm *hdspm) 38838c2ecf20Sopenharmony_ci{ 38848c2ecf20Sopenharmony_ci int status = hdspm_read(hdspm, HDSPM_statusRegister); 38858c2ecf20Sopenharmony_ci if (status & HDSPM_madiLock) { 38868c2ecf20Sopenharmony_ci if (status & HDSPM_madiSync) 38878c2ecf20Sopenharmony_ci return 2; 38888c2ecf20Sopenharmony_ci else 38898c2ecf20Sopenharmony_ci return 1; 38908c2ecf20Sopenharmony_ci } 38918c2ecf20Sopenharmony_ci return 0; 38928c2ecf20Sopenharmony_ci} 38938c2ecf20Sopenharmony_ci 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_cistatic int hdspm_s1_sync_check(struct hdspm *hdspm, int idx) 38968c2ecf20Sopenharmony_ci{ 38978c2ecf20Sopenharmony_ci int status, lock, sync; 38988c2ecf20Sopenharmony_ci 38998c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 39008c2ecf20Sopenharmony_ci 39018c2ecf20Sopenharmony_ci lock = (status & (0x1<<idx)) ? 1 : 0; 39028c2ecf20Sopenharmony_ci sync = (status & (0x100<<idx)) ? 1 : 0; 39038c2ecf20Sopenharmony_ci 39048c2ecf20Sopenharmony_ci if (lock && sync) 39058c2ecf20Sopenharmony_ci return 2; 39068c2ecf20Sopenharmony_ci else if (lock) 39078c2ecf20Sopenharmony_ci return 1; 39088c2ecf20Sopenharmony_ci return 0; 39098c2ecf20Sopenharmony_ci} 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_cistatic int hdspm_sync_in_sync_check(struct hdspm *hdspm) 39138c2ecf20Sopenharmony_ci{ 39148c2ecf20Sopenharmony_ci int status, lock = 0, sync = 0; 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 39178c2ecf20Sopenharmony_ci case RayDAT: 39188c2ecf20Sopenharmony_ci case AIO: 39198c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_3); 39208c2ecf20Sopenharmony_ci lock = (status & 0x400) ? 1 : 0; 39218c2ecf20Sopenharmony_ci sync = (status & 0x800) ? 1 : 0; 39228c2ecf20Sopenharmony_ci break; 39238c2ecf20Sopenharmony_ci 39248c2ecf20Sopenharmony_ci case MADI: 39258c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 39268c2ecf20Sopenharmony_ci lock = (status & HDSPM_syncInLock) ? 1 : 0; 39278c2ecf20Sopenharmony_ci sync = (status & HDSPM_syncInSync) ? 1 : 0; 39288c2ecf20Sopenharmony_ci break; 39298c2ecf20Sopenharmony_ci 39308c2ecf20Sopenharmony_ci case AES32: 39318c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister2); 39328c2ecf20Sopenharmony_ci lock = (status & 0x100000) ? 1 : 0; 39338c2ecf20Sopenharmony_ci sync = (status & 0x200000) ? 1 : 0; 39348c2ecf20Sopenharmony_ci break; 39358c2ecf20Sopenharmony_ci 39368c2ecf20Sopenharmony_ci case MADIface: 39378c2ecf20Sopenharmony_ci break; 39388c2ecf20Sopenharmony_ci } 39398c2ecf20Sopenharmony_ci 39408c2ecf20Sopenharmony_ci if (lock && sync) 39418c2ecf20Sopenharmony_ci return 2; 39428c2ecf20Sopenharmony_ci else if (lock) 39438c2ecf20Sopenharmony_ci return 1; 39448c2ecf20Sopenharmony_ci 39458c2ecf20Sopenharmony_ci return 0; 39468c2ecf20Sopenharmony_ci} 39478c2ecf20Sopenharmony_ci 39488c2ecf20Sopenharmony_cistatic int hdspm_aes_sync_check(struct hdspm *hdspm, int idx) 39498c2ecf20Sopenharmony_ci{ 39508c2ecf20Sopenharmony_ci int status2, lock, sync; 39518c2ecf20Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci lock = (status2 & (0x0080 >> idx)) ? 1 : 0; 39548c2ecf20Sopenharmony_ci sync = (status2 & (0x8000 >> idx)) ? 1 : 0; 39558c2ecf20Sopenharmony_ci 39568c2ecf20Sopenharmony_ci if (sync) 39578c2ecf20Sopenharmony_ci return 2; 39588c2ecf20Sopenharmony_ci else if (lock) 39598c2ecf20Sopenharmony_ci return 1; 39608c2ecf20Sopenharmony_ci return 0; 39618c2ecf20Sopenharmony_ci} 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_cistatic int hdspm_tco_input_check(struct hdspm *hdspm, u32 mask) 39648c2ecf20Sopenharmony_ci{ 39658c2ecf20Sopenharmony_ci u32 status; 39668c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci return (status & mask) ? 1 : 0; 39698c2ecf20Sopenharmony_ci} 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci 39728c2ecf20Sopenharmony_cistatic int hdspm_tco_sync_check(struct hdspm *hdspm) 39738c2ecf20Sopenharmony_ci{ 39748c2ecf20Sopenharmony_ci int status; 39758c2ecf20Sopenharmony_ci 39768c2ecf20Sopenharmony_ci if (hdspm->tco) { 39778c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 39788c2ecf20Sopenharmony_ci case MADI: 39798c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 39808c2ecf20Sopenharmony_ci if (status & HDSPM_tcoLockMadi) { 39818c2ecf20Sopenharmony_ci if (status & HDSPM_tcoSync) 39828c2ecf20Sopenharmony_ci return 2; 39838c2ecf20Sopenharmony_ci else 39848c2ecf20Sopenharmony_ci return 1; 39858c2ecf20Sopenharmony_ci } 39868c2ecf20Sopenharmony_ci return 0; 39878c2ecf20Sopenharmony_ci case AES32: 39888c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 39898c2ecf20Sopenharmony_ci if (status & HDSPM_tcoLockAes) { 39908c2ecf20Sopenharmony_ci if (status & HDSPM_tcoSync) 39918c2ecf20Sopenharmony_ci return 2; 39928c2ecf20Sopenharmony_ci else 39938c2ecf20Sopenharmony_ci return 1; 39948c2ecf20Sopenharmony_ci } 39958c2ecf20Sopenharmony_ci return 0; 39968c2ecf20Sopenharmony_ci case RayDAT: 39978c2ecf20Sopenharmony_ci case AIO: 39988c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 39998c2ecf20Sopenharmony_ci 40008c2ecf20Sopenharmony_ci if (status & 0x8000000) 40018c2ecf20Sopenharmony_ci return 2; /* Sync */ 40028c2ecf20Sopenharmony_ci if (status & 0x4000000) 40038c2ecf20Sopenharmony_ci return 1; /* Lock */ 40048c2ecf20Sopenharmony_ci return 0; /* No signal */ 40058c2ecf20Sopenharmony_ci 40068c2ecf20Sopenharmony_ci default: 40078c2ecf20Sopenharmony_ci break; 40088c2ecf20Sopenharmony_ci } 40098c2ecf20Sopenharmony_ci } 40108c2ecf20Sopenharmony_ci 40118c2ecf20Sopenharmony_ci return 3; /* N/A */ 40128c2ecf20Sopenharmony_ci} 40138c2ecf20Sopenharmony_ci 40148c2ecf20Sopenharmony_ci 40158c2ecf20Sopenharmony_cistatic int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, 40168c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 40178c2ecf20Sopenharmony_ci{ 40188c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 40198c2ecf20Sopenharmony_ci int val = -1; 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 40228c2ecf20Sopenharmony_ci case RayDAT: 40238c2ecf20Sopenharmony_ci switch (kcontrol->private_value) { 40248c2ecf20Sopenharmony_ci case 0: /* WC */ 40258c2ecf20Sopenharmony_ci val = hdspm_wc_sync_check(hdspm); break; 40268c2ecf20Sopenharmony_ci case 7: /* TCO */ 40278c2ecf20Sopenharmony_ci val = hdspm_tco_sync_check(hdspm); break; 40288c2ecf20Sopenharmony_ci case 8: /* SYNC IN */ 40298c2ecf20Sopenharmony_ci val = hdspm_sync_in_sync_check(hdspm); break; 40308c2ecf20Sopenharmony_ci default: 40318c2ecf20Sopenharmony_ci val = hdspm_s1_sync_check(hdspm, 40328c2ecf20Sopenharmony_ci kcontrol->private_value-1); 40338c2ecf20Sopenharmony_ci } 40348c2ecf20Sopenharmony_ci break; 40358c2ecf20Sopenharmony_ci 40368c2ecf20Sopenharmony_ci case AIO: 40378c2ecf20Sopenharmony_ci switch (kcontrol->private_value) { 40388c2ecf20Sopenharmony_ci case 0: /* WC */ 40398c2ecf20Sopenharmony_ci val = hdspm_wc_sync_check(hdspm); break; 40408c2ecf20Sopenharmony_ci case 4: /* TCO */ 40418c2ecf20Sopenharmony_ci val = hdspm_tco_sync_check(hdspm); break; 40428c2ecf20Sopenharmony_ci case 5: /* SYNC IN */ 40438c2ecf20Sopenharmony_ci val = hdspm_sync_in_sync_check(hdspm); break; 40448c2ecf20Sopenharmony_ci default: 40458c2ecf20Sopenharmony_ci val = hdspm_s1_sync_check(hdspm, 40468c2ecf20Sopenharmony_ci kcontrol->private_value-1); 40478c2ecf20Sopenharmony_ci } 40488c2ecf20Sopenharmony_ci break; 40498c2ecf20Sopenharmony_ci 40508c2ecf20Sopenharmony_ci case MADI: 40518c2ecf20Sopenharmony_ci switch (kcontrol->private_value) { 40528c2ecf20Sopenharmony_ci case 0: /* WC */ 40538c2ecf20Sopenharmony_ci val = hdspm_wc_sync_check(hdspm); break; 40548c2ecf20Sopenharmony_ci case 1: /* MADI */ 40558c2ecf20Sopenharmony_ci val = hdspm_madi_sync_check(hdspm); break; 40568c2ecf20Sopenharmony_ci case 2: /* TCO */ 40578c2ecf20Sopenharmony_ci val = hdspm_tco_sync_check(hdspm); break; 40588c2ecf20Sopenharmony_ci case 3: /* SYNC_IN */ 40598c2ecf20Sopenharmony_ci val = hdspm_sync_in_sync_check(hdspm); break; 40608c2ecf20Sopenharmony_ci } 40618c2ecf20Sopenharmony_ci break; 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_ci case MADIface: 40648c2ecf20Sopenharmony_ci val = hdspm_madi_sync_check(hdspm); /* MADI */ 40658c2ecf20Sopenharmony_ci break; 40668c2ecf20Sopenharmony_ci 40678c2ecf20Sopenharmony_ci case AES32: 40688c2ecf20Sopenharmony_ci switch (kcontrol->private_value) { 40698c2ecf20Sopenharmony_ci case 0: /* WC */ 40708c2ecf20Sopenharmony_ci val = hdspm_wc_sync_check(hdspm); break; 40718c2ecf20Sopenharmony_ci case 9: /* TCO */ 40728c2ecf20Sopenharmony_ci val = hdspm_tco_sync_check(hdspm); break; 40738c2ecf20Sopenharmony_ci case 10 /* SYNC IN */: 40748c2ecf20Sopenharmony_ci val = hdspm_sync_in_sync_check(hdspm); break; 40758c2ecf20Sopenharmony_ci default: /* AES1 to AES8 */ 40768c2ecf20Sopenharmony_ci val = hdspm_aes_sync_check(hdspm, 40778c2ecf20Sopenharmony_ci kcontrol->private_value-1); 40788c2ecf20Sopenharmony_ci } 40798c2ecf20Sopenharmony_ci break; 40808c2ecf20Sopenharmony_ci 40818c2ecf20Sopenharmony_ci } 40828c2ecf20Sopenharmony_ci 40838c2ecf20Sopenharmony_ci if (hdspm->tco) { 40848c2ecf20Sopenharmony_ci switch (kcontrol->private_value) { 40858c2ecf20Sopenharmony_ci case 11: 40868c2ecf20Sopenharmony_ci /* Check TCO for lock state of its current input */ 40878c2ecf20Sopenharmony_ci val = hdspm_tco_input_check(hdspm, HDSPM_TCO1_TCO_lock); 40888c2ecf20Sopenharmony_ci break; 40898c2ecf20Sopenharmony_ci case 12: 40908c2ecf20Sopenharmony_ci /* Check TCO for valid time code on LTC input. */ 40918c2ecf20Sopenharmony_ci val = hdspm_tco_input_check(hdspm, 40928c2ecf20Sopenharmony_ci HDSPM_TCO1_LTC_Input_valid); 40938c2ecf20Sopenharmony_ci break; 40948c2ecf20Sopenharmony_ci default: 40958c2ecf20Sopenharmony_ci break; 40968c2ecf20Sopenharmony_ci } 40978c2ecf20Sopenharmony_ci } 40988c2ecf20Sopenharmony_ci 40998c2ecf20Sopenharmony_ci if (-1 == val) 41008c2ecf20Sopenharmony_ci val = 3; 41018c2ecf20Sopenharmony_ci 41028c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = val; 41038c2ecf20Sopenharmony_ci return 0; 41048c2ecf20Sopenharmony_ci} 41058c2ecf20Sopenharmony_ci 41068c2ecf20Sopenharmony_ci 41078c2ecf20Sopenharmony_ci 41088c2ecf20Sopenharmony_ci/* 41098c2ecf20Sopenharmony_ci * TCO controls 41108c2ecf20Sopenharmony_ci */ 41118c2ecf20Sopenharmony_cistatic void hdspm_tco_write(struct hdspm *hdspm) 41128c2ecf20Sopenharmony_ci{ 41138c2ecf20Sopenharmony_ci unsigned int tc[4] = { 0, 0, 0, 0}; 41148c2ecf20Sopenharmony_ci 41158c2ecf20Sopenharmony_ci switch (hdspm->tco->input) { 41168c2ecf20Sopenharmony_ci case 0: 41178c2ecf20Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_input_MSB; 41188c2ecf20Sopenharmony_ci break; 41198c2ecf20Sopenharmony_ci case 1: 41208c2ecf20Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_input_LSB; 41218c2ecf20Sopenharmony_ci break; 41228c2ecf20Sopenharmony_ci default: 41238c2ecf20Sopenharmony_ci break; 41248c2ecf20Sopenharmony_ci } 41258c2ecf20Sopenharmony_ci 41268c2ecf20Sopenharmony_ci switch (hdspm->tco->framerate) { 41278c2ecf20Sopenharmony_ci case 1: 41288c2ecf20Sopenharmony_ci tc[1] |= HDSPM_TCO1_LTC_Format_LSB; 41298c2ecf20Sopenharmony_ci break; 41308c2ecf20Sopenharmony_ci case 2: 41318c2ecf20Sopenharmony_ci tc[1] |= HDSPM_TCO1_LTC_Format_MSB; 41328c2ecf20Sopenharmony_ci break; 41338c2ecf20Sopenharmony_ci case 3: 41348c2ecf20Sopenharmony_ci tc[1] |= HDSPM_TCO1_LTC_Format_MSB + 41358c2ecf20Sopenharmony_ci HDSPM_TCO1_set_drop_frame_flag; 41368c2ecf20Sopenharmony_ci break; 41378c2ecf20Sopenharmony_ci case 4: 41388c2ecf20Sopenharmony_ci tc[1] |= HDSPM_TCO1_LTC_Format_LSB + 41398c2ecf20Sopenharmony_ci HDSPM_TCO1_LTC_Format_MSB; 41408c2ecf20Sopenharmony_ci break; 41418c2ecf20Sopenharmony_ci case 5: 41428c2ecf20Sopenharmony_ci tc[1] |= HDSPM_TCO1_LTC_Format_LSB + 41438c2ecf20Sopenharmony_ci HDSPM_TCO1_LTC_Format_MSB + 41448c2ecf20Sopenharmony_ci HDSPM_TCO1_set_drop_frame_flag; 41458c2ecf20Sopenharmony_ci break; 41468c2ecf20Sopenharmony_ci default: 41478c2ecf20Sopenharmony_ci break; 41488c2ecf20Sopenharmony_ci } 41498c2ecf20Sopenharmony_ci 41508c2ecf20Sopenharmony_ci switch (hdspm->tco->wordclock) { 41518c2ecf20Sopenharmony_ci case 1: 41528c2ecf20Sopenharmony_ci tc[2] |= HDSPM_TCO2_WCK_IO_ratio_LSB; 41538c2ecf20Sopenharmony_ci break; 41548c2ecf20Sopenharmony_ci case 2: 41558c2ecf20Sopenharmony_ci tc[2] |= HDSPM_TCO2_WCK_IO_ratio_MSB; 41568c2ecf20Sopenharmony_ci break; 41578c2ecf20Sopenharmony_ci default: 41588c2ecf20Sopenharmony_ci break; 41598c2ecf20Sopenharmony_ci } 41608c2ecf20Sopenharmony_ci 41618c2ecf20Sopenharmony_ci switch (hdspm->tco->samplerate) { 41628c2ecf20Sopenharmony_ci case 1: 41638c2ecf20Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_freq; 41648c2ecf20Sopenharmony_ci break; 41658c2ecf20Sopenharmony_ci case 2: 41668c2ecf20Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_freq_from_app; 41678c2ecf20Sopenharmony_ci break; 41688c2ecf20Sopenharmony_ci default: 41698c2ecf20Sopenharmony_ci break; 41708c2ecf20Sopenharmony_ci } 41718c2ecf20Sopenharmony_ci 41728c2ecf20Sopenharmony_ci switch (hdspm->tco->pull) { 41738c2ecf20Sopenharmony_ci case 1: 41748c2ecf20Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_pull_up; 41758c2ecf20Sopenharmony_ci break; 41768c2ecf20Sopenharmony_ci case 2: 41778c2ecf20Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_pull_down; 41788c2ecf20Sopenharmony_ci break; 41798c2ecf20Sopenharmony_ci case 3: 41808c2ecf20Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_pull_up + HDSPM_TCO2_set_01_4; 41818c2ecf20Sopenharmony_ci break; 41828c2ecf20Sopenharmony_ci case 4: 41838c2ecf20Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_pull_down + HDSPM_TCO2_set_01_4; 41848c2ecf20Sopenharmony_ci break; 41858c2ecf20Sopenharmony_ci default: 41868c2ecf20Sopenharmony_ci break; 41878c2ecf20Sopenharmony_ci } 41888c2ecf20Sopenharmony_ci 41898c2ecf20Sopenharmony_ci if (1 == hdspm->tco->term) { 41908c2ecf20Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_term_75R; 41918c2ecf20Sopenharmony_ci } 41928c2ecf20Sopenharmony_ci 41938c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_TCO, tc[0]); 41948c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_TCO+4, tc[1]); 41958c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_TCO+8, tc[2]); 41968c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_TCO+12, tc[3]); 41978c2ecf20Sopenharmony_ci} 41988c2ecf20Sopenharmony_ci 41998c2ecf20Sopenharmony_ci 42008c2ecf20Sopenharmony_ci#define HDSPM_TCO_SAMPLE_RATE(xname, xindex) \ 42018c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 42028c2ecf20Sopenharmony_ci .name = xname, \ 42038c2ecf20Sopenharmony_ci .index = xindex, \ 42048c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 42058c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 42068c2ecf20Sopenharmony_ci .info = snd_hdspm_info_tco_sample_rate, \ 42078c2ecf20Sopenharmony_ci .get = snd_hdspm_get_tco_sample_rate, \ 42088c2ecf20Sopenharmony_ci .put = snd_hdspm_put_tco_sample_rate \ 42098c2ecf20Sopenharmony_ci} 42108c2ecf20Sopenharmony_ci 42118c2ecf20Sopenharmony_cistatic int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, 42128c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 42138c2ecf20Sopenharmony_ci{ 42148c2ecf20Sopenharmony_ci /* TODO freq from app could be supported here, see tco->samplerate */ 42158c2ecf20Sopenharmony_ci static const char *const texts[] = { "44.1 kHz", "48 kHz" }; 42168c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 42178c2ecf20Sopenharmony_ci return 0; 42188c2ecf20Sopenharmony_ci} 42198c2ecf20Sopenharmony_ci 42208c2ecf20Sopenharmony_cistatic int snd_hdspm_get_tco_sample_rate(struct snd_kcontrol *kcontrol, 42218c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 42228c2ecf20Sopenharmony_ci{ 42238c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 42248c2ecf20Sopenharmony_ci 42258c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm->tco->samplerate; 42268c2ecf20Sopenharmony_ci 42278c2ecf20Sopenharmony_ci return 0; 42288c2ecf20Sopenharmony_ci} 42298c2ecf20Sopenharmony_ci 42308c2ecf20Sopenharmony_cistatic int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol, 42318c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 42328c2ecf20Sopenharmony_ci{ 42338c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 42348c2ecf20Sopenharmony_ci 42358c2ecf20Sopenharmony_ci if (hdspm->tco->samplerate != ucontrol->value.enumerated.item[0]) { 42368c2ecf20Sopenharmony_ci hdspm->tco->samplerate = ucontrol->value.enumerated.item[0]; 42378c2ecf20Sopenharmony_ci 42388c2ecf20Sopenharmony_ci hdspm_tco_write(hdspm); 42398c2ecf20Sopenharmony_ci 42408c2ecf20Sopenharmony_ci return 1; 42418c2ecf20Sopenharmony_ci } 42428c2ecf20Sopenharmony_ci 42438c2ecf20Sopenharmony_ci return 0; 42448c2ecf20Sopenharmony_ci} 42458c2ecf20Sopenharmony_ci 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci#define HDSPM_TCO_PULL(xname, xindex) \ 42488c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 42498c2ecf20Sopenharmony_ci .name = xname, \ 42508c2ecf20Sopenharmony_ci .index = xindex, \ 42518c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 42528c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 42538c2ecf20Sopenharmony_ci .info = snd_hdspm_info_tco_pull, \ 42548c2ecf20Sopenharmony_ci .get = snd_hdspm_get_tco_pull, \ 42558c2ecf20Sopenharmony_ci .put = snd_hdspm_put_tco_pull \ 42568c2ecf20Sopenharmony_ci} 42578c2ecf20Sopenharmony_ci 42588c2ecf20Sopenharmony_cistatic int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, 42598c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 42608c2ecf20Sopenharmony_ci{ 42618c2ecf20Sopenharmony_ci static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %", 42628c2ecf20Sopenharmony_ci "+ 4 %", "- 4 %" }; 42638c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 42648c2ecf20Sopenharmony_ci return 0; 42658c2ecf20Sopenharmony_ci} 42668c2ecf20Sopenharmony_ci 42678c2ecf20Sopenharmony_cistatic int snd_hdspm_get_tco_pull(struct snd_kcontrol *kcontrol, 42688c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 42698c2ecf20Sopenharmony_ci{ 42708c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 42718c2ecf20Sopenharmony_ci 42728c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm->tco->pull; 42738c2ecf20Sopenharmony_ci 42748c2ecf20Sopenharmony_ci return 0; 42758c2ecf20Sopenharmony_ci} 42768c2ecf20Sopenharmony_ci 42778c2ecf20Sopenharmony_cistatic int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol, 42788c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 42798c2ecf20Sopenharmony_ci{ 42808c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 42818c2ecf20Sopenharmony_ci 42828c2ecf20Sopenharmony_ci if (hdspm->tco->pull != ucontrol->value.enumerated.item[0]) { 42838c2ecf20Sopenharmony_ci hdspm->tco->pull = ucontrol->value.enumerated.item[0]; 42848c2ecf20Sopenharmony_ci 42858c2ecf20Sopenharmony_ci hdspm_tco_write(hdspm); 42868c2ecf20Sopenharmony_ci 42878c2ecf20Sopenharmony_ci return 1; 42888c2ecf20Sopenharmony_ci } 42898c2ecf20Sopenharmony_ci 42908c2ecf20Sopenharmony_ci return 0; 42918c2ecf20Sopenharmony_ci} 42928c2ecf20Sopenharmony_ci 42938c2ecf20Sopenharmony_ci#define HDSPM_TCO_WCK_CONVERSION(xname, xindex) \ 42948c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 42958c2ecf20Sopenharmony_ci .name = xname, \ 42968c2ecf20Sopenharmony_ci .index = xindex, \ 42978c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 42988c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 42998c2ecf20Sopenharmony_ci .info = snd_hdspm_info_tco_wck_conversion, \ 43008c2ecf20Sopenharmony_ci .get = snd_hdspm_get_tco_wck_conversion, \ 43018c2ecf20Sopenharmony_ci .put = snd_hdspm_put_tco_wck_conversion \ 43028c2ecf20Sopenharmony_ci} 43038c2ecf20Sopenharmony_ci 43048c2ecf20Sopenharmony_cistatic int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, 43058c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 43068c2ecf20Sopenharmony_ci{ 43078c2ecf20Sopenharmony_ci static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; 43088c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 43098c2ecf20Sopenharmony_ci return 0; 43108c2ecf20Sopenharmony_ci} 43118c2ecf20Sopenharmony_ci 43128c2ecf20Sopenharmony_cistatic int snd_hdspm_get_tco_wck_conversion(struct snd_kcontrol *kcontrol, 43138c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 43148c2ecf20Sopenharmony_ci{ 43158c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 43168c2ecf20Sopenharmony_ci 43178c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm->tco->wordclock; 43188c2ecf20Sopenharmony_ci 43198c2ecf20Sopenharmony_ci return 0; 43208c2ecf20Sopenharmony_ci} 43218c2ecf20Sopenharmony_ci 43228c2ecf20Sopenharmony_cistatic int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol, 43238c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 43248c2ecf20Sopenharmony_ci{ 43258c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 43268c2ecf20Sopenharmony_ci 43278c2ecf20Sopenharmony_ci if (hdspm->tco->wordclock != ucontrol->value.enumerated.item[0]) { 43288c2ecf20Sopenharmony_ci hdspm->tco->wordclock = ucontrol->value.enumerated.item[0]; 43298c2ecf20Sopenharmony_ci 43308c2ecf20Sopenharmony_ci hdspm_tco_write(hdspm); 43318c2ecf20Sopenharmony_ci 43328c2ecf20Sopenharmony_ci return 1; 43338c2ecf20Sopenharmony_ci } 43348c2ecf20Sopenharmony_ci 43358c2ecf20Sopenharmony_ci return 0; 43368c2ecf20Sopenharmony_ci} 43378c2ecf20Sopenharmony_ci 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci#define HDSPM_TCO_FRAME_RATE(xname, xindex) \ 43408c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 43418c2ecf20Sopenharmony_ci .name = xname, \ 43428c2ecf20Sopenharmony_ci .index = xindex, \ 43438c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 43448c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 43458c2ecf20Sopenharmony_ci .info = snd_hdspm_info_tco_frame_rate, \ 43468c2ecf20Sopenharmony_ci .get = snd_hdspm_get_tco_frame_rate, \ 43478c2ecf20Sopenharmony_ci .put = snd_hdspm_put_tco_frame_rate \ 43488c2ecf20Sopenharmony_ci} 43498c2ecf20Sopenharmony_ci 43508c2ecf20Sopenharmony_cistatic int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, 43518c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 43528c2ecf20Sopenharmony_ci{ 43538c2ecf20Sopenharmony_ci static const char *const texts[] = { "24 fps", "25 fps", "29.97fps", 43548c2ecf20Sopenharmony_ci "29.97 dfps", "30 fps", "30 dfps" }; 43558c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 43568c2ecf20Sopenharmony_ci return 0; 43578c2ecf20Sopenharmony_ci} 43588c2ecf20Sopenharmony_ci 43598c2ecf20Sopenharmony_cistatic int snd_hdspm_get_tco_frame_rate(struct snd_kcontrol *kcontrol, 43608c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 43618c2ecf20Sopenharmony_ci{ 43628c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 43638c2ecf20Sopenharmony_ci 43648c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm->tco->framerate; 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_ci return 0; 43678c2ecf20Sopenharmony_ci} 43688c2ecf20Sopenharmony_ci 43698c2ecf20Sopenharmony_cistatic int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol, 43708c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 43718c2ecf20Sopenharmony_ci{ 43728c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 43738c2ecf20Sopenharmony_ci 43748c2ecf20Sopenharmony_ci if (hdspm->tco->framerate != ucontrol->value.enumerated.item[0]) { 43758c2ecf20Sopenharmony_ci hdspm->tco->framerate = ucontrol->value.enumerated.item[0]; 43768c2ecf20Sopenharmony_ci 43778c2ecf20Sopenharmony_ci hdspm_tco_write(hdspm); 43788c2ecf20Sopenharmony_ci 43798c2ecf20Sopenharmony_ci return 1; 43808c2ecf20Sopenharmony_ci } 43818c2ecf20Sopenharmony_ci 43828c2ecf20Sopenharmony_ci return 0; 43838c2ecf20Sopenharmony_ci} 43848c2ecf20Sopenharmony_ci 43858c2ecf20Sopenharmony_ci 43868c2ecf20Sopenharmony_ci#define HDSPM_TCO_SYNC_SOURCE(xname, xindex) \ 43878c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 43888c2ecf20Sopenharmony_ci .name = xname, \ 43898c2ecf20Sopenharmony_ci .index = xindex, \ 43908c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 43918c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 43928c2ecf20Sopenharmony_ci .info = snd_hdspm_info_tco_sync_source, \ 43938c2ecf20Sopenharmony_ci .get = snd_hdspm_get_tco_sync_source, \ 43948c2ecf20Sopenharmony_ci .put = snd_hdspm_put_tco_sync_source \ 43958c2ecf20Sopenharmony_ci} 43968c2ecf20Sopenharmony_ci 43978c2ecf20Sopenharmony_cistatic int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, 43988c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 43998c2ecf20Sopenharmony_ci{ 44008c2ecf20Sopenharmony_ci static const char *const texts[] = { "LTC", "Video", "WCK" }; 44018c2ecf20Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 44028c2ecf20Sopenharmony_ci return 0; 44038c2ecf20Sopenharmony_ci} 44048c2ecf20Sopenharmony_ci 44058c2ecf20Sopenharmony_cistatic int snd_hdspm_get_tco_sync_source(struct snd_kcontrol *kcontrol, 44068c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 44078c2ecf20Sopenharmony_ci{ 44088c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 44098c2ecf20Sopenharmony_ci 44108c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm->tco->input; 44118c2ecf20Sopenharmony_ci 44128c2ecf20Sopenharmony_ci return 0; 44138c2ecf20Sopenharmony_ci} 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_cistatic int snd_hdspm_put_tco_sync_source(struct snd_kcontrol *kcontrol, 44168c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 44178c2ecf20Sopenharmony_ci{ 44188c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 44198c2ecf20Sopenharmony_ci 44208c2ecf20Sopenharmony_ci if (hdspm->tco->input != ucontrol->value.enumerated.item[0]) { 44218c2ecf20Sopenharmony_ci hdspm->tco->input = ucontrol->value.enumerated.item[0]; 44228c2ecf20Sopenharmony_ci 44238c2ecf20Sopenharmony_ci hdspm_tco_write(hdspm); 44248c2ecf20Sopenharmony_ci 44258c2ecf20Sopenharmony_ci return 1; 44268c2ecf20Sopenharmony_ci } 44278c2ecf20Sopenharmony_ci 44288c2ecf20Sopenharmony_ci return 0; 44298c2ecf20Sopenharmony_ci} 44308c2ecf20Sopenharmony_ci 44318c2ecf20Sopenharmony_ci 44328c2ecf20Sopenharmony_ci#define HDSPM_TCO_WORD_TERM(xname, xindex) \ 44338c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 44348c2ecf20Sopenharmony_ci .name = xname, \ 44358c2ecf20Sopenharmony_ci .index = xindex, \ 44368c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 44378c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 44388c2ecf20Sopenharmony_ci .info = snd_hdspm_info_tco_word_term, \ 44398c2ecf20Sopenharmony_ci .get = snd_hdspm_get_tco_word_term, \ 44408c2ecf20Sopenharmony_ci .put = snd_hdspm_put_tco_word_term \ 44418c2ecf20Sopenharmony_ci} 44428c2ecf20Sopenharmony_ci 44438c2ecf20Sopenharmony_cistatic int snd_hdspm_info_tco_word_term(struct snd_kcontrol *kcontrol, 44448c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 44458c2ecf20Sopenharmony_ci{ 44468c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 44478c2ecf20Sopenharmony_ci uinfo->count = 1; 44488c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 44498c2ecf20Sopenharmony_ci uinfo->value.integer.max = 1; 44508c2ecf20Sopenharmony_ci 44518c2ecf20Sopenharmony_ci return 0; 44528c2ecf20Sopenharmony_ci} 44538c2ecf20Sopenharmony_ci 44548c2ecf20Sopenharmony_ci 44558c2ecf20Sopenharmony_cistatic int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol, 44568c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 44578c2ecf20Sopenharmony_ci{ 44588c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 44598c2ecf20Sopenharmony_ci 44608c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = hdspm->tco->term; 44618c2ecf20Sopenharmony_ci 44628c2ecf20Sopenharmony_ci return 0; 44638c2ecf20Sopenharmony_ci} 44648c2ecf20Sopenharmony_ci 44658c2ecf20Sopenharmony_ci 44668c2ecf20Sopenharmony_cistatic int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol, 44678c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 44688c2ecf20Sopenharmony_ci{ 44698c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_ci if (hdspm->tco->term != ucontrol->value.integer.value[0]) { 44728c2ecf20Sopenharmony_ci hdspm->tco->term = ucontrol->value.integer.value[0]; 44738c2ecf20Sopenharmony_ci 44748c2ecf20Sopenharmony_ci hdspm_tco_write(hdspm); 44758c2ecf20Sopenharmony_ci 44768c2ecf20Sopenharmony_ci return 1; 44778c2ecf20Sopenharmony_ci } 44788c2ecf20Sopenharmony_ci 44798c2ecf20Sopenharmony_ci return 0; 44808c2ecf20Sopenharmony_ci} 44818c2ecf20Sopenharmony_ci 44828c2ecf20Sopenharmony_ci 44838c2ecf20Sopenharmony_ci 44848c2ecf20Sopenharmony_ci 44858c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_madi[] = { 44868c2ecf20Sopenharmony_ci HDSPM_MIXER("Mixer", 0), 44878c2ecf20Sopenharmony_ci HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 44888c2ecf20Sopenharmony_ci HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 44898c2ecf20Sopenharmony_ci HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 44908c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), 44918c2ecf20Sopenharmony_ci HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 44928c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 44938c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("WC SyncCheck", 0), 44948c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("MADI SyncCheck", 1), 44958c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("TCO SyncCheck", 2), 44968c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3), 44978c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut), 44988c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch), 44998c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Disable 96K frames", HDSPM_SMUX), 45008c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), 45018c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp), 45028c2ecf20Sopenharmony_ci HDSPM_INPUT_SELECT("Input Select", 0), 45038c2ecf20Sopenharmony_ci HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) 45048c2ecf20Sopenharmony_ci}; 45058c2ecf20Sopenharmony_ci 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_madiface[] = { 45088c2ecf20Sopenharmony_ci HDSPM_MIXER("Mixer", 0), 45098c2ecf20Sopenharmony_ci HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 45108c2ecf20Sopenharmony_ci HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 45118c2ecf20Sopenharmony_ci HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 45128c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 45138c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("MADI SyncCheck", 0), 45148c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch), 45158c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), 45168c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp), 45178c2ecf20Sopenharmony_ci HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) 45188c2ecf20Sopenharmony_ci}; 45198c2ecf20Sopenharmony_ci 45208c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_aio[] = { 45218c2ecf20Sopenharmony_ci HDSPM_MIXER("Mixer", 0), 45228c2ecf20Sopenharmony_ci HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 45238c2ecf20Sopenharmony_ci HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 45248c2ecf20Sopenharmony_ci HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 45258c2ecf20Sopenharmony_ci HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 45268c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 45278c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("WC SyncCheck", 0), 45288c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("AES SyncCheck", 1), 45298c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2), 45308c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("ADAT SyncCheck", 3), 45318c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("TCO SyncCheck", 4), 45328c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 5), 45338c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 45348c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1), 45358c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), 45368c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), 45378c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), 45388c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5), 45398c2ecf20Sopenharmony_ci HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0), 45408c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt), 45418c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), 45428c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1), 45438c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db), 45448c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48), 45458c2ecf20Sopenharmony_ci HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0), 45468c2ecf20Sopenharmony_ci HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0), 45478c2ecf20Sopenharmony_ci HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0) 45488c2ecf20Sopenharmony_ci 45498c2ecf20Sopenharmony_ci /* 45508c2ecf20Sopenharmony_ci HDSPM_INPUT_SELECT("Input Select", 0), 45518c2ecf20Sopenharmony_ci HDSPM_SPDIF_OPTICAL("SPDIF Out Optical", 0), 45528c2ecf20Sopenharmony_ci HDSPM_PROFESSIONAL("SPDIF Out Professional", 0); 45538c2ecf20Sopenharmony_ci HDSPM_SPDIF_IN("SPDIF In", 0); 45548c2ecf20Sopenharmony_ci HDSPM_BREAKOUT_CABLE("Breakout Cable", 0); 45558c2ecf20Sopenharmony_ci HDSPM_INPUT_LEVEL("Input Level", 0); 45568c2ecf20Sopenharmony_ci HDSPM_OUTPUT_LEVEL("Output Level", 0); 45578c2ecf20Sopenharmony_ci HDSPM_PHONES("Phones", 0); 45588c2ecf20Sopenharmony_ci */ 45598c2ecf20Sopenharmony_ci}; 45608c2ecf20Sopenharmony_ci 45618c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_raydat[] = { 45628c2ecf20Sopenharmony_ci HDSPM_MIXER("Mixer", 0), 45638c2ecf20Sopenharmony_ci HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 45648c2ecf20Sopenharmony_ci HDSPM_SYSTEM_CLOCK_MODE("Clock Mode", 0), 45658c2ecf20Sopenharmony_ci HDSPM_PREF_SYNC_REF("Pref Sync Ref", 0), 45668c2ecf20Sopenharmony_ci HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 45678c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("WC SyncCheck", 0), 45688c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("AES SyncCheck", 1), 45698c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2), 45708c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("ADAT1 SyncCheck", 3), 45718c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("ADAT2 SyncCheck", 4), 45728c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("ADAT3 SyncCheck", 5), 45738c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("ADAT4 SyncCheck", 6), 45748c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("TCO SyncCheck", 7), 45758c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 8), 45768c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 45778c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1), 45788c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), 45798c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT1 Frequency", 3), 45808c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT2 Frequency", 4), 45818c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5), 45828c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6), 45838c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7), 45848c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8), 45858c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), 45868c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48) 45878c2ecf20Sopenharmony_ci}; 45888c2ecf20Sopenharmony_ci 45898c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { 45908c2ecf20Sopenharmony_ci HDSPM_MIXER("Mixer", 0), 45918c2ecf20Sopenharmony_ci HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 45928c2ecf20Sopenharmony_ci HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 45938c2ecf20Sopenharmony_ci HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 45948c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), 45958c2ecf20Sopenharmony_ci HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 45968c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11), 45978c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("WC Sync Check", 0), 45988c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("AES1 Sync Check", 1), 45998c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("AES2 Sync Check", 2), 46008c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("AES3 Sync Check", 3), 46018c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("AES4 Sync Check", 4), 46028c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("AES5 Sync Check", 5), 46038c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("AES6 Sync Check", 6), 46048c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("AES7 Sync Check", 7), 46058c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("AES8 Sync Check", 8), 46068c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("TCO Sync Check", 9), 46078c2ecf20Sopenharmony_ci HDSPM_SYNC_CHECK("SYNC IN Sync Check", 10), 46088c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 46098c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES1 Frequency", 1), 46108c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES2 Frequency", 2), 46118c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES3 Frequency", 3), 46128c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES4 Frequency", 4), 46138c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES5 Frequency", 5), 46148c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES6 Frequency", 6), 46158c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES7 Frequency", 7), 46168c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES8 Frequency", 8), 46178c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 9), 46188c2ecf20Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 10), 46198c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut), 46208c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Emphasis", HDSPM_Emphasis), 46218c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Non Audio", HDSPM_Dolby), 46228c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Professional", HDSPM_Professional), 46238c2ecf20Sopenharmony_ci HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), 46248c2ecf20Sopenharmony_ci HDSPM_DS_WIRE("Double Speed Wire Mode", 0), 46258c2ecf20Sopenharmony_ci HDSPM_QS_WIRE("Quad Speed Wire Mode", 0), 46268c2ecf20Sopenharmony_ci}; 46278c2ecf20Sopenharmony_ci 46288c2ecf20Sopenharmony_ci 46298c2ecf20Sopenharmony_ci 46308c2ecf20Sopenharmony_ci/* Control elements for the optional TCO module */ 46318c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_tco[] = { 46328c2ecf20Sopenharmony_ci HDSPM_TCO_SAMPLE_RATE("TCO Sample Rate", 0), 46338c2ecf20Sopenharmony_ci HDSPM_TCO_PULL("TCO Pull", 0), 46348c2ecf20Sopenharmony_ci HDSPM_TCO_WCK_CONVERSION("TCO WCK Conversion", 0), 46358c2ecf20Sopenharmony_ci HDSPM_TCO_FRAME_RATE("TCO Frame Rate", 0), 46368c2ecf20Sopenharmony_ci HDSPM_TCO_SYNC_SOURCE("TCO Sync Source", 0), 46378c2ecf20Sopenharmony_ci HDSPM_TCO_WORD_TERM("TCO Word Term", 0), 46388c2ecf20Sopenharmony_ci HDSPM_TCO_LOCK_CHECK("TCO Input Check", 11), 46398c2ecf20Sopenharmony_ci HDSPM_TCO_LOCK_CHECK("TCO LTC Valid", 12), 46408c2ecf20Sopenharmony_ci HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate", 0), 46418c2ecf20Sopenharmony_ci HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format", 0) 46428c2ecf20Sopenharmony_ci}; 46438c2ecf20Sopenharmony_ci 46448c2ecf20Sopenharmony_ci 46458c2ecf20Sopenharmony_cistatic struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER; 46468c2ecf20Sopenharmony_ci 46478c2ecf20Sopenharmony_ci 46488c2ecf20Sopenharmony_cistatic int hdspm_update_simple_mixer_controls(struct hdspm * hdspm) 46498c2ecf20Sopenharmony_ci{ 46508c2ecf20Sopenharmony_ci int i; 46518c2ecf20Sopenharmony_ci 46528c2ecf20Sopenharmony_ci for (i = hdspm->ds_out_channels; i < hdspm->ss_out_channels; ++i) { 46538c2ecf20Sopenharmony_ci if (hdspm->system_sample_rate > 48000) { 46548c2ecf20Sopenharmony_ci hdspm->playback_mixer_ctls[i]->vd[0].access = 46558c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_INACTIVE | 46568c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_READ | 46578c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE; 46588c2ecf20Sopenharmony_ci } else { 46598c2ecf20Sopenharmony_ci hdspm->playback_mixer_ctls[i]->vd[0].access = 46608c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_READWRITE | 46618c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE; 46628c2ecf20Sopenharmony_ci } 46638c2ecf20Sopenharmony_ci snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE | 46648c2ecf20Sopenharmony_ci SNDRV_CTL_EVENT_MASK_INFO, 46658c2ecf20Sopenharmony_ci &hdspm->playback_mixer_ctls[i]->id); 46668c2ecf20Sopenharmony_ci } 46678c2ecf20Sopenharmony_ci 46688c2ecf20Sopenharmony_ci return 0; 46698c2ecf20Sopenharmony_ci} 46708c2ecf20Sopenharmony_ci 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_cistatic int snd_hdspm_create_controls(struct snd_card *card, 46738c2ecf20Sopenharmony_ci struct hdspm *hdspm) 46748c2ecf20Sopenharmony_ci{ 46758c2ecf20Sopenharmony_ci unsigned int idx, limit; 46768c2ecf20Sopenharmony_ci int err; 46778c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 46788c2ecf20Sopenharmony_ci const struct snd_kcontrol_new *list = NULL; 46798c2ecf20Sopenharmony_ci 46808c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 46818c2ecf20Sopenharmony_ci case MADI: 46828c2ecf20Sopenharmony_ci list = snd_hdspm_controls_madi; 46838c2ecf20Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_madi); 46848c2ecf20Sopenharmony_ci break; 46858c2ecf20Sopenharmony_ci case MADIface: 46868c2ecf20Sopenharmony_ci list = snd_hdspm_controls_madiface; 46878c2ecf20Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_madiface); 46888c2ecf20Sopenharmony_ci break; 46898c2ecf20Sopenharmony_ci case AIO: 46908c2ecf20Sopenharmony_ci list = snd_hdspm_controls_aio; 46918c2ecf20Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_aio); 46928c2ecf20Sopenharmony_ci break; 46938c2ecf20Sopenharmony_ci case RayDAT: 46948c2ecf20Sopenharmony_ci list = snd_hdspm_controls_raydat; 46958c2ecf20Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_raydat); 46968c2ecf20Sopenharmony_ci break; 46978c2ecf20Sopenharmony_ci case AES32: 46988c2ecf20Sopenharmony_ci list = snd_hdspm_controls_aes32; 46998c2ecf20Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_aes32); 47008c2ecf20Sopenharmony_ci break; 47018c2ecf20Sopenharmony_ci } 47028c2ecf20Sopenharmony_ci 47038c2ecf20Sopenharmony_ci if (list) { 47048c2ecf20Sopenharmony_ci for (idx = 0; idx < limit; idx++) { 47058c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 47068c2ecf20Sopenharmony_ci snd_ctl_new1(&list[idx], hdspm)); 47078c2ecf20Sopenharmony_ci if (err < 0) 47088c2ecf20Sopenharmony_ci return err; 47098c2ecf20Sopenharmony_ci } 47108c2ecf20Sopenharmony_ci } 47118c2ecf20Sopenharmony_ci 47128c2ecf20Sopenharmony_ci 47138c2ecf20Sopenharmony_ci /* create simple 1:1 playback mixer controls */ 47148c2ecf20Sopenharmony_ci snd_hdspm_playback_mixer.name = "Chn"; 47158c2ecf20Sopenharmony_ci if (hdspm->system_sample_rate >= 128000) { 47168c2ecf20Sopenharmony_ci limit = hdspm->qs_out_channels; 47178c2ecf20Sopenharmony_ci } else if (hdspm->system_sample_rate >= 64000) { 47188c2ecf20Sopenharmony_ci limit = hdspm->ds_out_channels; 47198c2ecf20Sopenharmony_ci } else { 47208c2ecf20Sopenharmony_ci limit = hdspm->ss_out_channels; 47218c2ecf20Sopenharmony_ci } 47228c2ecf20Sopenharmony_ci for (idx = 0; idx < limit; ++idx) { 47238c2ecf20Sopenharmony_ci snd_hdspm_playback_mixer.index = idx + 1; 47248c2ecf20Sopenharmony_ci kctl = snd_ctl_new1(&snd_hdspm_playback_mixer, hdspm); 47258c2ecf20Sopenharmony_ci err = snd_ctl_add(card, kctl); 47268c2ecf20Sopenharmony_ci if (err < 0) 47278c2ecf20Sopenharmony_ci return err; 47288c2ecf20Sopenharmony_ci hdspm->playback_mixer_ctls[idx] = kctl; 47298c2ecf20Sopenharmony_ci } 47308c2ecf20Sopenharmony_ci 47318c2ecf20Sopenharmony_ci 47328c2ecf20Sopenharmony_ci if (hdspm->tco) { 47338c2ecf20Sopenharmony_ci /* add tco control elements */ 47348c2ecf20Sopenharmony_ci list = snd_hdspm_controls_tco; 47358c2ecf20Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_tco); 47368c2ecf20Sopenharmony_ci for (idx = 0; idx < limit; idx++) { 47378c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 47388c2ecf20Sopenharmony_ci snd_ctl_new1(&list[idx], hdspm)); 47398c2ecf20Sopenharmony_ci if (err < 0) 47408c2ecf20Sopenharmony_ci return err; 47418c2ecf20Sopenharmony_ci } 47428c2ecf20Sopenharmony_ci } 47438c2ecf20Sopenharmony_ci 47448c2ecf20Sopenharmony_ci return 0; 47458c2ecf20Sopenharmony_ci} 47468c2ecf20Sopenharmony_ci 47478c2ecf20Sopenharmony_ci/*------------------------------------------------------------ 47488c2ecf20Sopenharmony_ci /proc interface 47498c2ecf20Sopenharmony_ci ------------------------------------------------------------*/ 47508c2ecf20Sopenharmony_ci 47518c2ecf20Sopenharmony_cistatic void 47528c2ecf20Sopenharmony_cisnd_hdspm_proc_read_tco(struct snd_info_entry *entry, 47538c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 47548c2ecf20Sopenharmony_ci{ 47558c2ecf20Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 47568c2ecf20Sopenharmony_ci unsigned int status, control; 47578c2ecf20Sopenharmony_ci int a, ltc, frames, seconds, minutes, hours; 47588c2ecf20Sopenharmony_ci unsigned int period; 47598c2ecf20Sopenharmony_ci u64 freq_const = 0; 47608c2ecf20Sopenharmony_ci u32 rate; 47618c2ecf20Sopenharmony_ci 47628c2ecf20Sopenharmony_ci snd_iprintf(buffer, "--- TCO ---\n"); 47638c2ecf20Sopenharmony_ci 47648c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 47658c2ecf20Sopenharmony_ci control = hdspm->control_register; 47668c2ecf20Sopenharmony_ci 47678c2ecf20Sopenharmony_ci 47688c2ecf20Sopenharmony_ci if (status & HDSPM_tco_detect) { 47698c2ecf20Sopenharmony_ci snd_iprintf(buffer, "TCO module detected.\n"); 47708c2ecf20Sopenharmony_ci a = hdspm_read(hdspm, HDSPM_RD_TCO+4); 47718c2ecf20Sopenharmony_ci if (a & HDSPM_TCO1_LTC_Input_valid) { 47728c2ecf20Sopenharmony_ci snd_iprintf(buffer, " LTC valid, "); 47738c2ecf20Sopenharmony_ci switch (a & (HDSPM_TCO1_LTC_Format_LSB | 47748c2ecf20Sopenharmony_ci HDSPM_TCO1_LTC_Format_MSB)) { 47758c2ecf20Sopenharmony_ci case 0: 47768c2ecf20Sopenharmony_ci snd_iprintf(buffer, "24 fps, "); 47778c2ecf20Sopenharmony_ci break; 47788c2ecf20Sopenharmony_ci case HDSPM_TCO1_LTC_Format_LSB: 47798c2ecf20Sopenharmony_ci snd_iprintf(buffer, "25 fps, "); 47808c2ecf20Sopenharmony_ci break; 47818c2ecf20Sopenharmony_ci case HDSPM_TCO1_LTC_Format_MSB: 47828c2ecf20Sopenharmony_ci snd_iprintf(buffer, "29.97 fps, "); 47838c2ecf20Sopenharmony_ci break; 47848c2ecf20Sopenharmony_ci default: 47858c2ecf20Sopenharmony_ci snd_iprintf(buffer, "30 fps, "); 47868c2ecf20Sopenharmony_ci break; 47878c2ecf20Sopenharmony_ci } 47888c2ecf20Sopenharmony_ci if (a & HDSPM_TCO1_set_drop_frame_flag) { 47898c2ecf20Sopenharmony_ci snd_iprintf(buffer, "drop frame\n"); 47908c2ecf20Sopenharmony_ci } else { 47918c2ecf20Sopenharmony_ci snd_iprintf(buffer, "full frame\n"); 47928c2ecf20Sopenharmony_ci } 47938c2ecf20Sopenharmony_ci } else { 47948c2ecf20Sopenharmony_ci snd_iprintf(buffer, " no LTC\n"); 47958c2ecf20Sopenharmony_ci } 47968c2ecf20Sopenharmony_ci if (a & HDSPM_TCO1_Video_Input_Format_NTSC) { 47978c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Video: NTSC\n"); 47988c2ecf20Sopenharmony_ci } else if (a & HDSPM_TCO1_Video_Input_Format_PAL) { 47998c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Video: PAL\n"); 48008c2ecf20Sopenharmony_ci } else { 48018c2ecf20Sopenharmony_ci snd_iprintf(buffer, " No video\n"); 48028c2ecf20Sopenharmony_ci } 48038c2ecf20Sopenharmony_ci if (a & HDSPM_TCO1_TCO_lock) { 48048c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Sync: lock\n"); 48058c2ecf20Sopenharmony_ci } else { 48068c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Sync: no lock\n"); 48078c2ecf20Sopenharmony_ci } 48088c2ecf20Sopenharmony_ci 48098c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 48108c2ecf20Sopenharmony_ci case MADI: 48118c2ecf20Sopenharmony_ci case AES32: 48128c2ecf20Sopenharmony_ci freq_const = 110069313433624ULL; 48138c2ecf20Sopenharmony_ci break; 48148c2ecf20Sopenharmony_ci case RayDAT: 48158c2ecf20Sopenharmony_ci case AIO: 48168c2ecf20Sopenharmony_ci freq_const = 104857600000000ULL; 48178c2ecf20Sopenharmony_ci break; 48188c2ecf20Sopenharmony_ci case MADIface: 48198c2ecf20Sopenharmony_ci break; /* no TCO possible */ 48208c2ecf20Sopenharmony_ci } 48218c2ecf20Sopenharmony_ci 48228c2ecf20Sopenharmony_ci period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 48238c2ecf20Sopenharmony_ci snd_iprintf(buffer, " period: %u\n", period); 48248c2ecf20Sopenharmony_ci 48258c2ecf20Sopenharmony_ci 48268c2ecf20Sopenharmony_ci /* rate = freq_const/period; */ 48278c2ecf20Sopenharmony_ci rate = div_u64(freq_const, period); 48288c2ecf20Sopenharmony_ci 48298c2ecf20Sopenharmony_ci if (control & HDSPM_QuadSpeed) { 48308c2ecf20Sopenharmony_ci rate *= 4; 48318c2ecf20Sopenharmony_ci } else if (control & HDSPM_DoubleSpeed) { 48328c2ecf20Sopenharmony_ci rate *= 2; 48338c2ecf20Sopenharmony_ci } 48348c2ecf20Sopenharmony_ci 48358c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Frequency: %u Hz\n", 48368c2ecf20Sopenharmony_ci (unsigned int) rate); 48378c2ecf20Sopenharmony_ci 48388c2ecf20Sopenharmony_ci ltc = hdspm_read(hdspm, HDSPM_RD_TCO); 48398c2ecf20Sopenharmony_ci frames = ltc & 0xF; 48408c2ecf20Sopenharmony_ci ltc >>= 4; 48418c2ecf20Sopenharmony_ci frames += (ltc & 0x3) * 10; 48428c2ecf20Sopenharmony_ci ltc >>= 4; 48438c2ecf20Sopenharmony_ci seconds = ltc & 0xF; 48448c2ecf20Sopenharmony_ci ltc >>= 4; 48458c2ecf20Sopenharmony_ci seconds += (ltc & 0x7) * 10; 48468c2ecf20Sopenharmony_ci ltc >>= 4; 48478c2ecf20Sopenharmony_ci minutes = ltc & 0xF; 48488c2ecf20Sopenharmony_ci ltc >>= 4; 48498c2ecf20Sopenharmony_ci minutes += (ltc & 0x7) * 10; 48508c2ecf20Sopenharmony_ci ltc >>= 4; 48518c2ecf20Sopenharmony_ci hours = ltc & 0xF; 48528c2ecf20Sopenharmony_ci ltc >>= 4; 48538c2ecf20Sopenharmony_ci hours += (ltc & 0x3) * 10; 48548c2ecf20Sopenharmony_ci snd_iprintf(buffer, 48558c2ecf20Sopenharmony_ci " LTC In: %02d:%02d:%02d:%02d\n", 48568c2ecf20Sopenharmony_ci hours, minutes, seconds, frames); 48578c2ecf20Sopenharmony_ci 48588c2ecf20Sopenharmony_ci } else { 48598c2ecf20Sopenharmony_ci snd_iprintf(buffer, "No TCO module detected.\n"); 48608c2ecf20Sopenharmony_ci } 48618c2ecf20Sopenharmony_ci} 48628c2ecf20Sopenharmony_ci 48638c2ecf20Sopenharmony_cistatic void 48648c2ecf20Sopenharmony_cisnd_hdspm_proc_read_madi(struct snd_info_entry *entry, 48658c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 48668c2ecf20Sopenharmony_ci{ 48678c2ecf20Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 48688c2ecf20Sopenharmony_ci unsigned int status, status2; 48698c2ecf20Sopenharmony_ci 48708c2ecf20Sopenharmony_ci char *pref_sync_ref; 48718c2ecf20Sopenharmony_ci char *autosync_ref; 48728c2ecf20Sopenharmony_ci char *system_clock_mode; 48738c2ecf20Sopenharmony_ci int x, x2; 48748c2ecf20Sopenharmony_ci 48758c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 48768c2ecf20Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 48778c2ecf20Sopenharmony_ci 48788c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", 48798c2ecf20Sopenharmony_ci hdspm->card_name, hdspm->card->number + 1, 48808c2ecf20Sopenharmony_ci hdspm->firmware_rev, 48818c2ecf20Sopenharmony_ci (status2 & HDSPM_version0) | 48828c2ecf20Sopenharmony_ci (status2 & HDSPM_version1) | (status2 & 48838c2ecf20Sopenharmony_ci HDSPM_version2)); 48848c2ecf20Sopenharmony_ci 48858c2ecf20Sopenharmony_ci snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", 48868c2ecf20Sopenharmony_ci (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, 48878c2ecf20Sopenharmony_ci hdspm->serial); 48888c2ecf20Sopenharmony_ci 48898c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", 48908c2ecf20Sopenharmony_ci hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); 48918c2ecf20Sopenharmony_ci 48928c2ecf20Sopenharmony_ci snd_iprintf(buffer, "--- System ---\n"); 48938c2ecf20Sopenharmony_ci 48948c2ecf20Sopenharmony_ci snd_iprintf(buffer, 48958c2ecf20Sopenharmony_ci "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", 48968c2ecf20Sopenharmony_ci status & HDSPM_audioIRQPending, 48978c2ecf20Sopenharmony_ci (status & HDSPM_midi0IRQPending) ? 1 : 0, 48988c2ecf20Sopenharmony_ci (status & HDSPM_midi1IRQPending) ? 1 : 0, 48998c2ecf20Sopenharmony_ci hdspm->irq_count); 49008c2ecf20Sopenharmony_ci snd_iprintf(buffer, 49018c2ecf20Sopenharmony_ci "HW pointer: id = %d, rawptr = %d (%d->%d) " 49028c2ecf20Sopenharmony_ci "estimated= %ld (bytes)\n", 49038c2ecf20Sopenharmony_ci ((status & HDSPM_BufferID) ? 1 : 0), 49048c2ecf20Sopenharmony_ci (status & HDSPM_BufferPositionMask), 49058c2ecf20Sopenharmony_ci (status & HDSPM_BufferPositionMask) % 49068c2ecf20Sopenharmony_ci (2 * (int)hdspm->period_bytes), 49078c2ecf20Sopenharmony_ci ((status & HDSPM_BufferPositionMask) - 64) % 49088c2ecf20Sopenharmony_ci (2 * (int)hdspm->period_bytes), 49098c2ecf20Sopenharmony_ci (long) hdspm_hw_pointer(hdspm) * 4); 49108c2ecf20Sopenharmony_ci 49118c2ecf20Sopenharmony_ci snd_iprintf(buffer, 49128c2ecf20Sopenharmony_ci "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", 49138c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, 49148c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, 49158c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, 49168c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); 49178c2ecf20Sopenharmony_ci snd_iprintf(buffer, 49188c2ecf20Sopenharmony_ci "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", 49198c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, 49208c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); 49218c2ecf20Sopenharmony_ci snd_iprintf(buffer, 49228c2ecf20Sopenharmony_ci "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " 49238c2ecf20Sopenharmony_ci "status2=0x%x\n", 49248c2ecf20Sopenharmony_ci hdspm->control_register, hdspm->control2_register, 49258c2ecf20Sopenharmony_ci status, status2); 49268c2ecf20Sopenharmony_ci 49278c2ecf20Sopenharmony_ci 49288c2ecf20Sopenharmony_ci snd_iprintf(buffer, "--- Settings ---\n"); 49298c2ecf20Sopenharmony_ci 49308c2ecf20Sopenharmony_ci x = hdspm_get_latency(hdspm); 49318c2ecf20Sopenharmony_ci 49328c2ecf20Sopenharmony_ci snd_iprintf(buffer, 49338c2ecf20Sopenharmony_ci "Size (Latency): %d samples (2 periods of %lu bytes)\n", 49348c2ecf20Sopenharmony_ci x, (unsigned long) hdspm->period_bytes); 49358c2ecf20Sopenharmony_ci 49368c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Line out: %s\n", 49378c2ecf20Sopenharmony_ci (hdspm->control_register & HDSPM_LineOut) ? "on " : "off"); 49388c2ecf20Sopenharmony_ci 49398c2ecf20Sopenharmony_ci snd_iprintf(buffer, 49408c2ecf20Sopenharmony_ci "ClearTrackMarker = %s, Transmit in %s Channel Mode, " 49418c2ecf20Sopenharmony_ci "Auto Input %s\n", 49428c2ecf20Sopenharmony_ci (hdspm->control_register & HDSPM_clr_tms) ? "on" : "off", 49438c2ecf20Sopenharmony_ci (hdspm->control_register & HDSPM_TX_64ch) ? "64" : "56", 49448c2ecf20Sopenharmony_ci (hdspm->control_register & HDSPM_AutoInp) ? "on" : "off"); 49458c2ecf20Sopenharmony_ci 49468c2ecf20Sopenharmony_ci 49478c2ecf20Sopenharmony_ci if (!(hdspm->control_register & HDSPM_ClockModeMaster)) 49488c2ecf20Sopenharmony_ci system_clock_mode = "AutoSync"; 49498c2ecf20Sopenharmony_ci else 49508c2ecf20Sopenharmony_ci system_clock_mode = "Master"; 49518c2ecf20Sopenharmony_ci snd_iprintf(buffer, "AutoSync Reference: %s\n", system_clock_mode); 49528c2ecf20Sopenharmony_ci 49538c2ecf20Sopenharmony_ci switch (hdspm_pref_sync_ref(hdspm)) { 49548c2ecf20Sopenharmony_ci case HDSPM_SYNC_FROM_WORD: 49558c2ecf20Sopenharmony_ci pref_sync_ref = "Word Clock"; 49568c2ecf20Sopenharmony_ci break; 49578c2ecf20Sopenharmony_ci case HDSPM_SYNC_FROM_MADI: 49588c2ecf20Sopenharmony_ci pref_sync_ref = "MADI Sync"; 49598c2ecf20Sopenharmony_ci break; 49608c2ecf20Sopenharmony_ci case HDSPM_SYNC_FROM_TCO: 49618c2ecf20Sopenharmony_ci pref_sync_ref = "TCO"; 49628c2ecf20Sopenharmony_ci break; 49638c2ecf20Sopenharmony_ci case HDSPM_SYNC_FROM_SYNC_IN: 49648c2ecf20Sopenharmony_ci pref_sync_ref = "Sync In"; 49658c2ecf20Sopenharmony_ci break; 49668c2ecf20Sopenharmony_ci default: 49678c2ecf20Sopenharmony_ci pref_sync_ref = "XXXX Clock"; 49688c2ecf20Sopenharmony_ci break; 49698c2ecf20Sopenharmony_ci } 49708c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Preferred Sync Reference: %s\n", 49718c2ecf20Sopenharmony_ci pref_sync_ref); 49728c2ecf20Sopenharmony_ci 49738c2ecf20Sopenharmony_ci snd_iprintf(buffer, "System Clock Frequency: %d\n", 49748c2ecf20Sopenharmony_ci hdspm->system_sample_rate); 49758c2ecf20Sopenharmony_ci 49768c2ecf20Sopenharmony_ci 49778c2ecf20Sopenharmony_ci snd_iprintf(buffer, "--- Status:\n"); 49788c2ecf20Sopenharmony_ci 49798c2ecf20Sopenharmony_ci x = status & HDSPM_madiSync; 49808c2ecf20Sopenharmony_ci x2 = status2 & HDSPM_wcSync; 49818c2ecf20Sopenharmony_ci 49828c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Inputs MADI=%s, WordClock=%s\n", 49838c2ecf20Sopenharmony_ci (status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") : 49848c2ecf20Sopenharmony_ci "NoLock", 49858c2ecf20Sopenharmony_ci (status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") : 49868c2ecf20Sopenharmony_ci "NoLock"); 49878c2ecf20Sopenharmony_ci 49888c2ecf20Sopenharmony_ci switch (hdspm_autosync_ref(hdspm)) { 49898c2ecf20Sopenharmony_ci case HDSPM_AUTOSYNC_FROM_SYNC_IN: 49908c2ecf20Sopenharmony_ci autosync_ref = "Sync In"; 49918c2ecf20Sopenharmony_ci break; 49928c2ecf20Sopenharmony_ci case HDSPM_AUTOSYNC_FROM_TCO: 49938c2ecf20Sopenharmony_ci autosync_ref = "TCO"; 49948c2ecf20Sopenharmony_ci break; 49958c2ecf20Sopenharmony_ci case HDSPM_AUTOSYNC_FROM_WORD: 49968c2ecf20Sopenharmony_ci autosync_ref = "Word Clock"; 49978c2ecf20Sopenharmony_ci break; 49988c2ecf20Sopenharmony_ci case HDSPM_AUTOSYNC_FROM_MADI: 49998c2ecf20Sopenharmony_ci autosync_ref = "MADI Sync"; 50008c2ecf20Sopenharmony_ci break; 50018c2ecf20Sopenharmony_ci case HDSPM_AUTOSYNC_FROM_NONE: 50028c2ecf20Sopenharmony_ci autosync_ref = "Input not valid"; 50038c2ecf20Sopenharmony_ci break; 50048c2ecf20Sopenharmony_ci default: 50058c2ecf20Sopenharmony_ci autosync_ref = "---"; 50068c2ecf20Sopenharmony_ci break; 50078c2ecf20Sopenharmony_ci } 50088c2ecf20Sopenharmony_ci snd_iprintf(buffer, 50098c2ecf20Sopenharmony_ci "AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n", 50108c2ecf20Sopenharmony_ci autosync_ref, hdspm_external_sample_rate(hdspm), 50118c2ecf20Sopenharmony_ci (status & HDSPM_madiFreqMask) >> 22, 50128c2ecf20Sopenharmony_ci (status2 & HDSPM_wcFreqMask) >> 5); 50138c2ecf20Sopenharmony_ci 50148c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Input: %s, Mode=%s\n", 50158c2ecf20Sopenharmony_ci (status & HDSPM_AB_int) ? "Coax" : "Optical", 50168c2ecf20Sopenharmony_ci (status & HDSPM_RX_64ch) ? "64 channels" : 50178c2ecf20Sopenharmony_ci "56 channels"); 50188c2ecf20Sopenharmony_ci 50198c2ecf20Sopenharmony_ci /* call readout function for TCO specific status */ 50208c2ecf20Sopenharmony_ci snd_hdspm_proc_read_tco(entry, buffer); 50218c2ecf20Sopenharmony_ci 50228c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 50238c2ecf20Sopenharmony_ci} 50248c2ecf20Sopenharmony_ci 50258c2ecf20Sopenharmony_cistatic void 50268c2ecf20Sopenharmony_cisnd_hdspm_proc_read_aes32(struct snd_info_entry * entry, 50278c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 50288c2ecf20Sopenharmony_ci{ 50298c2ecf20Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 50308c2ecf20Sopenharmony_ci unsigned int status; 50318c2ecf20Sopenharmony_ci unsigned int status2; 50328c2ecf20Sopenharmony_ci unsigned int timecode; 50338c2ecf20Sopenharmony_ci unsigned int wcLock, wcSync; 50348c2ecf20Sopenharmony_ci int pref_syncref; 50358c2ecf20Sopenharmony_ci char *autosync_ref; 50368c2ecf20Sopenharmony_ci int x; 50378c2ecf20Sopenharmony_ci 50388c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 50398c2ecf20Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 50408c2ecf20Sopenharmony_ci timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); 50418c2ecf20Sopenharmony_ci 50428c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%s (Card #%d) Rev.%x\n", 50438c2ecf20Sopenharmony_ci hdspm->card_name, hdspm->card->number + 1, 50448c2ecf20Sopenharmony_ci hdspm->firmware_rev); 50458c2ecf20Sopenharmony_ci 50468c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", 50478c2ecf20Sopenharmony_ci hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); 50488c2ecf20Sopenharmony_ci 50498c2ecf20Sopenharmony_ci snd_iprintf(buffer, "--- System ---\n"); 50508c2ecf20Sopenharmony_ci 50518c2ecf20Sopenharmony_ci snd_iprintf(buffer, 50528c2ecf20Sopenharmony_ci "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", 50538c2ecf20Sopenharmony_ci status & HDSPM_audioIRQPending, 50548c2ecf20Sopenharmony_ci (status & HDSPM_midi0IRQPending) ? 1 : 0, 50558c2ecf20Sopenharmony_ci (status & HDSPM_midi1IRQPending) ? 1 : 0, 50568c2ecf20Sopenharmony_ci hdspm->irq_count); 50578c2ecf20Sopenharmony_ci snd_iprintf(buffer, 50588c2ecf20Sopenharmony_ci "HW pointer: id = %d, rawptr = %d (%d->%d) " 50598c2ecf20Sopenharmony_ci "estimated= %ld (bytes)\n", 50608c2ecf20Sopenharmony_ci ((status & HDSPM_BufferID) ? 1 : 0), 50618c2ecf20Sopenharmony_ci (status & HDSPM_BufferPositionMask), 50628c2ecf20Sopenharmony_ci (status & HDSPM_BufferPositionMask) % 50638c2ecf20Sopenharmony_ci (2 * (int)hdspm->period_bytes), 50648c2ecf20Sopenharmony_ci ((status & HDSPM_BufferPositionMask) - 64) % 50658c2ecf20Sopenharmony_ci (2 * (int)hdspm->period_bytes), 50668c2ecf20Sopenharmony_ci (long) hdspm_hw_pointer(hdspm) * 4); 50678c2ecf20Sopenharmony_ci 50688c2ecf20Sopenharmony_ci snd_iprintf(buffer, 50698c2ecf20Sopenharmony_ci "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", 50708c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, 50718c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, 50728c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, 50738c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); 50748c2ecf20Sopenharmony_ci snd_iprintf(buffer, 50758c2ecf20Sopenharmony_ci "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", 50768c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, 50778c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); 50788c2ecf20Sopenharmony_ci snd_iprintf(buffer, 50798c2ecf20Sopenharmony_ci "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " 50808c2ecf20Sopenharmony_ci "status2=0x%x\n", 50818c2ecf20Sopenharmony_ci hdspm->control_register, hdspm->control2_register, 50828c2ecf20Sopenharmony_ci status, status2); 50838c2ecf20Sopenharmony_ci 50848c2ecf20Sopenharmony_ci snd_iprintf(buffer, "--- Settings ---\n"); 50858c2ecf20Sopenharmony_ci 50868c2ecf20Sopenharmony_ci x = hdspm_get_latency(hdspm); 50878c2ecf20Sopenharmony_ci 50888c2ecf20Sopenharmony_ci snd_iprintf(buffer, 50898c2ecf20Sopenharmony_ci "Size (Latency): %d samples (2 periods of %lu bytes)\n", 50908c2ecf20Sopenharmony_ci x, (unsigned long) hdspm->period_bytes); 50918c2ecf20Sopenharmony_ci 50928c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Line out: %s\n", 50938c2ecf20Sopenharmony_ci (hdspm-> 50948c2ecf20Sopenharmony_ci control_register & HDSPM_LineOut) ? "on " : "off"); 50958c2ecf20Sopenharmony_ci 50968c2ecf20Sopenharmony_ci snd_iprintf(buffer, 50978c2ecf20Sopenharmony_ci "ClearTrackMarker %s, Emphasis %s, Dolby %s\n", 50988c2ecf20Sopenharmony_ci (hdspm-> 50998c2ecf20Sopenharmony_ci control_register & HDSPM_clr_tms) ? "on" : "off", 51008c2ecf20Sopenharmony_ci (hdspm-> 51018c2ecf20Sopenharmony_ci control_register & HDSPM_Emphasis) ? "on" : "off", 51028c2ecf20Sopenharmony_ci (hdspm-> 51038c2ecf20Sopenharmony_ci control_register & HDSPM_Dolby) ? "on" : "off"); 51048c2ecf20Sopenharmony_ci 51058c2ecf20Sopenharmony_ci 51068c2ecf20Sopenharmony_ci pref_syncref = hdspm_pref_sync_ref(hdspm); 51078c2ecf20Sopenharmony_ci if (pref_syncref == 0) 51088c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Preferred Sync Reference: Word Clock\n"); 51098c2ecf20Sopenharmony_ci else 51108c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Preferred Sync Reference: AES%d\n", 51118c2ecf20Sopenharmony_ci pref_syncref); 51128c2ecf20Sopenharmony_ci 51138c2ecf20Sopenharmony_ci snd_iprintf(buffer, "System Clock Frequency: %d\n", 51148c2ecf20Sopenharmony_ci hdspm->system_sample_rate); 51158c2ecf20Sopenharmony_ci 51168c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Double speed: %s\n", 51178c2ecf20Sopenharmony_ci hdspm->control_register & HDSPM_DS_DoubleWire? 51188c2ecf20Sopenharmony_ci "Double wire" : "Single wire"); 51198c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Quad speed: %s\n", 51208c2ecf20Sopenharmony_ci hdspm->control_register & HDSPM_QS_DoubleWire? 51218c2ecf20Sopenharmony_ci "Double wire" : 51228c2ecf20Sopenharmony_ci hdspm->control_register & HDSPM_QS_QuadWire? 51238c2ecf20Sopenharmony_ci "Quad wire" : "Single wire"); 51248c2ecf20Sopenharmony_ci 51258c2ecf20Sopenharmony_ci snd_iprintf(buffer, "--- Status:\n"); 51268c2ecf20Sopenharmony_ci 51278c2ecf20Sopenharmony_ci wcLock = status & HDSPM_AES32_wcLock; 51288c2ecf20Sopenharmony_ci wcSync = wcLock && (status & HDSPM_AES32_wcSync); 51298c2ecf20Sopenharmony_ci 51308c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Word: %s Frequency: %d\n", 51318c2ecf20Sopenharmony_ci (wcLock) ? (wcSync ? "Sync " : "Lock ") : "No Lock", 51328c2ecf20Sopenharmony_ci HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); 51338c2ecf20Sopenharmony_ci 51348c2ecf20Sopenharmony_ci for (x = 0; x < 8; x++) { 51358c2ecf20Sopenharmony_ci snd_iprintf(buffer, "AES%d: %s Frequency: %d\n", 51368c2ecf20Sopenharmony_ci x+1, 51378c2ecf20Sopenharmony_ci (status2 & (HDSPM_LockAES >> x)) ? 51388c2ecf20Sopenharmony_ci "Sync " : "No Lock", 51398c2ecf20Sopenharmony_ci HDSPM_bit2freq((timecode >> (4*x)) & 0xF)); 51408c2ecf20Sopenharmony_ci } 51418c2ecf20Sopenharmony_ci 51428c2ecf20Sopenharmony_ci switch (hdspm_autosync_ref(hdspm)) { 51438c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_NONE: 51448c2ecf20Sopenharmony_ci autosync_ref = "None"; break; 51458c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_WORD: 51468c2ecf20Sopenharmony_ci autosync_ref = "Word Clock"; break; 51478c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES1: 51488c2ecf20Sopenharmony_ci autosync_ref = "AES1"; break; 51498c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES2: 51508c2ecf20Sopenharmony_ci autosync_ref = "AES2"; break; 51518c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES3: 51528c2ecf20Sopenharmony_ci autosync_ref = "AES3"; break; 51538c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES4: 51548c2ecf20Sopenharmony_ci autosync_ref = "AES4"; break; 51558c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES5: 51568c2ecf20Sopenharmony_ci autosync_ref = "AES5"; break; 51578c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES6: 51588c2ecf20Sopenharmony_ci autosync_ref = "AES6"; break; 51598c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES7: 51608c2ecf20Sopenharmony_ci autosync_ref = "AES7"; break; 51618c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES8: 51628c2ecf20Sopenharmony_ci autosync_ref = "AES8"; break; 51638c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_TCO: 51648c2ecf20Sopenharmony_ci autosync_ref = "TCO"; break; 51658c2ecf20Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN: 51668c2ecf20Sopenharmony_ci autosync_ref = "Sync In"; break; 51678c2ecf20Sopenharmony_ci default: 51688c2ecf20Sopenharmony_ci autosync_ref = "---"; break; 51698c2ecf20Sopenharmony_ci } 51708c2ecf20Sopenharmony_ci snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); 51718c2ecf20Sopenharmony_ci 51728c2ecf20Sopenharmony_ci /* call readout function for TCO specific status */ 51738c2ecf20Sopenharmony_ci snd_hdspm_proc_read_tco(entry, buffer); 51748c2ecf20Sopenharmony_ci 51758c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 51768c2ecf20Sopenharmony_ci} 51778c2ecf20Sopenharmony_ci 51788c2ecf20Sopenharmony_cistatic void 51798c2ecf20Sopenharmony_cisnd_hdspm_proc_read_raydat(struct snd_info_entry *entry, 51808c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 51818c2ecf20Sopenharmony_ci{ 51828c2ecf20Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 51838c2ecf20Sopenharmony_ci unsigned int status1, status2, status3, i; 51848c2ecf20Sopenharmony_ci unsigned int lock, sync; 51858c2ecf20Sopenharmony_ci 51868c2ecf20Sopenharmony_ci status1 = hdspm_read(hdspm, HDSPM_RD_STATUS_1); /* s1 */ 51878c2ecf20Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_RD_STATUS_2); /* freq */ 51888c2ecf20Sopenharmony_ci status3 = hdspm_read(hdspm, HDSPM_RD_STATUS_3); /* s2 */ 51898c2ecf20Sopenharmony_ci 51908c2ecf20Sopenharmony_ci snd_iprintf(buffer, "STATUS1: 0x%08x\n", status1); 51918c2ecf20Sopenharmony_ci snd_iprintf(buffer, "STATUS2: 0x%08x\n", status2); 51928c2ecf20Sopenharmony_ci snd_iprintf(buffer, "STATUS3: 0x%08x\n", status3); 51938c2ecf20Sopenharmony_ci 51948c2ecf20Sopenharmony_ci 51958c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n*** CLOCK MODE\n\n"); 51968c2ecf20Sopenharmony_ci 51978c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Clock mode : %s\n", 51988c2ecf20Sopenharmony_ci (hdspm_system_clock_mode(hdspm) == 0) ? "master" : "slave"); 51998c2ecf20Sopenharmony_ci snd_iprintf(buffer, "System frequency: %d Hz\n", 52008c2ecf20Sopenharmony_ci hdspm_get_system_sample_rate(hdspm)); 52018c2ecf20Sopenharmony_ci 52028c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n*** INPUT STATUS\n\n"); 52038c2ecf20Sopenharmony_ci 52048c2ecf20Sopenharmony_ci lock = 0x1; 52058c2ecf20Sopenharmony_ci sync = 0x100; 52068c2ecf20Sopenharmony_ci 52078c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 52088c2ecf20Sopenharmony_ci snd_iprintf(buffer, "s1_input %d: Lock %d, Sync %d, Freq %s\n", 52098c2ecf20Sopenharmony_ci i, 52108c2ecf20Sopenharmony_ci (status1 & lock) ? 1 : 0, 52118c2ecf20Sopenharmony_ci (status1 & sync) ? 1 : 0, 52128c2ecf20Sopenharmony_ci texts_freq[(status2 >> (i * 4)) & 0xF]); 52138c2ecf20Sopenharmony_ci 52148c2ecf20Sopenharmony_ci lock = lock<<1; 52158c2ecf20Sopenharmony_ci sync = sync<<1; 52168c2ecf20Sopenharmony_ci } 52178c2ecf20Sopenharmony_ci 52188c2ecf20Sopenharmony_ci snd_iprintf(buffer, "WC input: Lock %d, Sync %d, Freq %s\n", 52198c2ecf20Sopenharmony_ci (status1 & 0x1000000) ? 1 : 0, 52208c2ecf20Sopenharmony_ci (status1 & 0x2000000) ? 1 : 0, 52218c2ecf20Sopenharmony_ci texts_freq[(status1 >> 16) & 0xF]); 52228c2ecf20Sopenharmony_ci 52238c2ecf20Sopenharmony_ci snd_iprintf(buffer, "TCO input: Lock %d, Sync %d, Freq %s\n", 52248c2ecf20Sopenharmony_ci (status1 & 0x4000000) ? 1 : 0, 52258c2ecf20Sopenharmony_ci (status1 & 0x8000000) ? 1 : 0, 52268c2ecf20Sopenharmony_ci texts_freq[(status1 >> 20) & 0xF]); 52278c2ecf20Sopenharmony_ci 52288c2ecf20Sopenharmony_ci snd_iprintf(buffer, "SYNC IN: Lock %d, Sync %d, Freq %s\n", 52298c2ecf20Sopenharmony_ci (status3 & 0x400) ? 1 : 0, 52308c2ecf20Sopenharmony_ci (status3 & 0x800) ? 1 : 0, 52318c2ecf20Sopenharmony_ci texts_freq[(status2 >> 12) & 0xF]); 52328c2ecf20Sopenharmony_ci 52338c2ecf20Sopenharmony_ci} 52348c2ecf20Sopenharmony_ci 52358c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_DEBUG 52368c2ecf20Sopenharmony_cistatic void 52378c2ecf20Sopenharmony_cisnd_hdspm_proc_read_debug(struct snd_info_entry *entry, 52388c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 52398c2ecf20Sopenharmony_ci{ 52408c2ecf20Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 52418c2ecf20Sopenharmony_ci 52428c2ecf20Sopenharmony_ci int j,i; 52438c2ecf20Sopenharmony_ci 52448c2ecf20Sopenharmony_ci for (i = 0; i < 256 /* 1024*64 */; i += j) { 52458c2ecf20Sopenharmony_ci snd_iprintf(buffer, "0x%08X: ", i); 52468c2ecf20Sopenharmony_ci for (j = 0; j < 16; j += 4) 52478c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j)); 52488c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 52498c2ecf20Sopenharmony_ci } 52508c2ecf20Sopenharmony_ci} 52518c2ecf20Sopenharmony_ci#endif 52528c2ecf20Sopenharmony_ci 52538c2ecf20Sopenharmony_ci 52548c2ecf20Sopenharmony_cistatic void snd_hdspm_proc_ports_in(struct snd_info_entry *entry, 52558c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 52568c2ecf20Sopenharmony_ci{ 52578c2ecf20Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 52588c2ecf20Sopenharmony_ci int i; 52598c2ecf20Sopenharmony_ci 52608c2ecf20Sopenharmony_ci snd_iprintf(buffer, "# generated by hdspm\n"); 52618c2ecf20Sopenharmony_ci 52628c2ecf20Sopenharmony_ci for (i = 0; i < hdspm->max_channels_in; i++) { 52638c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_in[i]); 52648c2ecf20Sopenharmony_ci } 52658c2ecf20Sopenharmony_ci} 52668c2ecf20Sopenharmony_ci 52678c2ecf20Sopenharmony_cistatic void snd_hdspm_proc_ports_out(struct snd_info_entry *entry, 52688c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 52698c2ecf20Sopenharmony_ci{ 52708c2ecf20Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 52718c2ecf20Sopenharmony_ci int i; 52728c2ecf20Sopenharmony_ci 52738c2ecf20Sopenharmony_ci snd_iprintf(buffer, "# generated by hdspm\n"); 52748c2ecf20Sopenharmony_ci 52758c2ecf20Sopenharmony_ci for (i = 0; i < hdspm->max_channels_out; i++) { 52768c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_out[i]); 52778c2ecf20Sopenharmony_ci } 52788c2ecf20Sopenharmony_ci} 52798c2ecf20Sopenharmony_ci 52808c2ecf20Sopenharmony_ci 52818c2ecf20Sopenharmony_cistatic void snd_hdspm_proc_init(struct hdspm *hdspm) 52828c2ecf20Sopenharmony_ci{ 52838c2ecf20Sopenharmony_ci void (*read)(struct snd_info_entry *, struct snd_info_buffer *) = NULL; 52848c2ecf20Sopenharmony_ci 52858c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 52868c2ecf20Sopenharmony_ci case AES32: 52878c2ecf20Sopenharmony_ci read = snd_hdspm_proc_read_aes32; 52888c2ecf20Sopenharmony_ci break; 52898c2ecf20Sopenharmony_ci case MADI: 52908c2ecf20Sopenharmony_ci read = snd_hdspm_proc_read_madi; 52918c2ecf20Sopenharmony_ci break; 52928c2ecf20Sopenharmony_ci case MADIface: 52938c2ecf20Sopenharmony_ci /* read = snd_hdspm_proc_read_madiface; */ 52948c2ecf20Sopenharmony_ci break; 52958c2ecf20Sopenharmony_ci case RayDAT: 52968c2ecf20Sopenharmony_ci read = snd_hdspm_proc_read_raydat; 52978c2ecf20Sopenharmony_ci break; 52988c2ecf20Sopenharmony_ci case AIO: 52998c2ecf20Sopenharmony_ci break; 53008c2ecf20Sopenharmony_ci } 53018c2ecf20Sopenharmony_ci 53028c2ecf20Sopenharmony_ci snd_card_ro_proc_new(hdspm->card, "hdspm", hdspm, read); 53038c2ecf20Sopenharmony_ci snd_card_ro_proc_new(hdspm->card, "ports.in", hdspm, 53048c2ecf20Sopenharmony_ci snd_hdspm_proc_ports_in); 53058c2ecf20Sopenharmony_ci snd_card_ro_proc_new(hdspm->card, "ports.out", hdspm, 53068c2ecf20Sopenharmony_ci snd_hdspm_proc_ports_out); 53078c2ecf20Sopenharmony_ci 53088c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_DEBUG 53098c2ecf20Sopenharmony_ci /* debug file to read all hdspm registers */ 53108c2ecf20Sopenharmony_ci snd_card_ro_proc_new(hdspm->card, "debug", hdspm, 53118c2ecf20Sopenharmony_ci snd_hdspm_proc_read_debug); 53128c2ecf20Sopenharmony_ci#endif 53138c2ecf20Sopenharmony_ci} 53148c2ecf20Sopenharmony_ci 53158c2ecf20Sopenharmony_ci/*------------------------------------------------------------ 53168c2ecf20Sopenharmony_ci hdspm intitialize 53178c2ecf20Sopenharmony_ci ------------------------------------------------------------*/ 53188c2ecf20Sopenharmony_ci 53198c2ecf20Sopenharmony_cistatic int snd_hdspm_set_defaults(struct hdspm * hdspm) 53208c2ecf20Sopenharmony_ci{ 53218c2ecf20Sopenharmony_ci /* ASSUMPTION: hdspm->lock is either held, or there is no need to 53228c2ecf20Sopenharmony_ci hold it (e.g. during module initialization). 53238c2ecf20Sopenharmony_ci */ 53248c2ecf20Sopenharmony_ci 53258c2ecf20Sopenharmony_ci /* set defaults: */ 53268c2ecf20Sopenharmony_ci 53278c2ecf20Sopenharmony_ci hdspm->settings_register = 0; 53288c2ecf20Sopenharmony_ci 53298c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 53308c2ecf20Sopenharmony_ci case MADI: 53318c2ecf20Sopenharmony_ci case MADIface: 53328c2ecf20Sopenharmony_ci hdspm->control_register = 53338c2ecf20Sopenharmony_ci 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000; 53348c2ecf20Sopenharmony_ci break; 53358c2ecf20Sopenharmony_ci 53368c2ecf20Sopenharmony_ci case RayDAT: 53378c2ecf20Sopenharmony_ci case AIO: 53388c2ecf20Sopenharmony_ci hdspm->settings_register = 0x1 + 0x1000; 53398c2ecf20Sopenharmony_ci /* Magic values are: LAT_0, LAT_2, Master, freq1, tx64ch, inp_0, 53408c2ecf20Sopenharmony_ci * line_out */ 53418c2ecf20Sopenharmony_ci hdspm->control_register = 53428c2ecf20Sopenharmony_ci 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000; 53438c2ecf20Sopenharmony_ci break; 53448c2ecf20Sopenharmony_ci 53458c2ecf20Sopenharmony_ci case AES32: 53468c2ecf20Sopenharmony_ci hdspm->control_register = 53478c2ecf20Sopenharmony_ci HDSPM_ClockModeMaster | /* Master Clock Mode on */ 53488c2ecf20Sopenharmony_ci hdspm_encode_latency(7) | /* latency max=8192samples */ 53498c2ecf20Sopenharmony_ci HDSPM_SyncRef0 | /* AES1 is syncclock */ 53508c2ecf20Sopenharmony_ci HDSPM_LineOut | /* Analog output in */ 53518c2ecf20Sopenharmony_ci HDSPM_Professional; /* Professional mode */ 53528c2ecf20Sopenharmony_ci break; 53538c2ecf20Sopenharmony_ci } 53548c2ecf20Sopenharmony_ci 53558c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 53568c2ecf20Sopenharmony_ci 53578c2ecf20Sopenharmony_ci if (AES32 == hdspm->io_type) { 53588c2ecf20Sopenharmony_ci /* No control2 register for AES32 */ 53598c2ecf20Sopenharmony_ci#ifdef SNDRV_BIG_ENDIAN 53608c2ecf20Sopenharmony_ci hdspm->control2_register = HDSPM_BIGENDIAN_MODE; 53618c2ecf20Sopenharmony_ci#else 53628c2ecf20Sopenharmony_ci hdspm->control2_register = 0; 53638c2ecf20Sopenharmony_ci#endif 53648c2ecf20Sopenharmony_ci 53658c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register); 53668c2ecf20Sopenharmony_ci } 53678c2ecf20Sopenharmony_ci hdspm_compute_period_size(hdspm); 53688c2ecf20Sopenharmony_ci 53698c2ecf20Sopenharmony_ci /* silence everything */ 53708c2ecf20Sopenharmony_ci 53718c2ecf20Sopenharmony_ci all_in_all_mixer(hdspm, 0 * UNITY_GAIN); 53728c2ecf20Sopenharmony_ci 53738c2ecf20Sopenharmony_ci if (hdspm_is_raydat_or_aio(hdspm)) 53748c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 53758c2ecf20Sopenharmony_ci 53768c2ecf20Sopenharmony_ci /* set a default rate so that the channel map is set up. */ 53778c2ecf20Sopenharmony_ci hdspm_set_rate(hdspm, 48000, 1); 53788c2ecf20Sopenharmony_ci 53798c2ecf20Sopenharmony_ci return 0; 53808c2ecf20Sopenharmony_ci} 53818c2ecf20Sopenharmony_ci 53828c2ecf20Sopenharmony_ci 53838c2ecf20Sopenharmony_ci/*------------------------------------------------------------ 53848c2ecf20Sopenharmony_ci interrupt 53858c2ecf20Sopenharmony_ci ------------------------------------------------------------*/ 53868c2ecf20Sopenharmony_ci 53878c2ecf20Sopenharmony_cistatic irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) 53888c2ecf20Sopenharmony_ci{ 53898c2ecf20Sopenharmony_ci struct hdspm *hdspm = (struct hdspm *) dev_id; 53908c2ecf20Sopenharmony_ci unsigned int status; 53918c2ecf20Sopenharmony_ci int i, audio, midi, schedule = 0; 53928c2ecf20Sopenharmony_ci /* cycles_t now; */ 53938c2ecf20Sopenharmony_ci 53948c2ecf20Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 53958c2ecf20Sopenharmony_ci 53968c2ecf20Sopenharmony_ci audio = status & HDSPM_audioIRQPending; 53978c2ecf20Sopenharmony_ci midi = status & (HDSPM_midi0IRQPending | HDSPM_midi1IRQPending | 53988c2ecf20Sopenharmony_ci HDSPM_midi2IRQPending | HDSPM_midi3IRQPending); 53998c2ecf20Sopenharmony_ci 54008c2ecf20Sopenharmony_ci /* now = get_cycles(); */ 54018c2ecf20Sopenharmony_ci /* 54028c2ecf20Sopenharmony_ci * LAT_2..LAT_0 period counter (win) counter (mac) 54038c2ecf20Sopenharmony_ci * 6 4096 ~256053425 ~514672358 54048c2ecf20Sopenharmony_ci * 5 2048 ~128024983 ~257373821 54058c2ecf20Sopenharmony_ci * 4 1024 ~64023706 ~128718089 54068c2ecf20Sopenharmony_ci * 3 512 ~32005945 ~64385999 54078c2ecf20Sopenharmony_ci * 2 256 ~16003039 ~32260176 54088c2ecf20Sopenharmony_ci * 1 128 ~7998738 ~16194507 54098c2ecf20Sopenharmony_ci * 0 64 ~3998231 ~8191558 54108c2ecf20Sopenharmony_ci */ 54118c2ecf20Sopenharmony_ci /* 54128c2ecf20Sopenharmony_ci dev_info(hdspm->card->dev, "snd_hdspm_interrupt %llu @ %llx\n", 54138c2ecf20Sopenharmony_ci now-hdspm->last_interrupt, status & 0xFFC0); 54148c2ecf20Sopenharmony_ci hdspm->last_interrupt = now; 54158c2ecf20Sopenharmony_ci */ 54168c2ecf20Sopenharmony_ci 54178c2ecf20Sopenharmony_ci if (!audio && !midi) 54188c2ecf20Sopenharmony_ci return IRQ_NONE; 54198c2ecf20Sopenharmony_ci 54208c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_interruptConfirmation, 0); 54218c2ecf20Sopenharmony_ci hdspm->irq_count++; 54228c2ecf20Sopenharmony_ci 54238c2ecf20Sopenharmony_ci 54248c2ecf20Sopenharmony_ci if (audio) { 54258c2ecf20Sopenharmony_ci if (hdspm->capture_substream) 54268c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(hdspm->capture_substream); 54278c2ecf20Sopenharmony_ci 54288c2ecf20Sopenharmony_ci if (hdspm->playback_substream) 54298c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(hdspm->playback_substream); 54308c2ecf20Sopenharmony_ci } 54318c2ecf20Sopenharmony_ci 54328c2ecf20Sopenharmony_ci if (midi) { 54338c2ecf20Sopenharmony_ci i = 0; 54348c2ecf20Sopenharmony_ci while (i < hdspm->midiPorts) { 54358c2ecf20Sopenharmony_ci if ((hdspm_read(hdspm, 54368c2ecf20Sopenharmony_ci hdspm->midi[i].statusIn) & 0xff) && 54378c2ecf20Sopenharmony_ci (status & hdspm->midi[i].irq)) { 54388c2ecf20Sopenharmony_ci /* we disable interrupts for this input until 54398c2ecf20Sopenharmony_ci * processing is done 54408c2ecf20Sopenharmony_ci */ 54418c2ecf20Sopenharmony_ci hdspm->control_register &= ~hdspm->midi[i].ie; 54428c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, 54438c2ecf20Sopenharmony_ci hdspm->control_register); 54448c2ecf20Sopenharmony_ci hdspm->midi[i].pending = 1; 54458c2ecf20Sopenharmony_ci schedule = 1; 54468c2ecf20Sopenharmony_ci } 54478c2ecf20Sopenharmony_ci 54488c2ecf20Sopenharmony_ci i++; 54498c2ecf20Sopenharmony_ci } 54508c2ecf20Sopenharmony_ci 54518c2ecf20Sopenharmony_ci if (schedule) 54528c2ecf20Sopenharmony_ci queue_work(system_highpri_wq, &hdspm->midi_work); 54538c2ecf20Sopenharmony_ci } 54548c2ecf20Sopenharmony_ci 54558c2ecf20Sopenharmony_ci return IRQ_HANDLED; 54568c2ecf20Sopenharmony_ci} 54578c2ecf20Sopenharmony_ci 54588c2ecf20Sopenharmony_ci/*------------------------------------------------------------ 54598c2ecf20Sopenharmony_ci pcm interface 54608c2ecf20Sopenharmony_ci ------------------------------------------------------------*/ 54618c2ecf20Sopenharmony_ci 54628c2ecf20Sopenharmony_ci 54638c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t snd_hdspm_hw_pointer(struct snd_pcm_substream 54648c2ecf20Sopenharmony_ci *substream) 54658c2ecf20Sopenharmony_ci{ 54668c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 54678c2ecf20Sopenharmony_ci return hdspm_hw_pointer(hdspm); 54688c2ecf20Sopenharmony_ci} 54698c2ecf20Sopenharmony_ci 54708c2ecf20Sopenharmony_ci 54718c2ecf20Sopenharmony_cistatic int snd_hdspm_reset(struct snd_pcm_substream *substream) 54728c2ecf20Sopenharmony_ci{ 54738c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 54748c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 54758c2ecf20Sopenharmony_ci struct snd_pcm_substream *other; 54768c2ecf20Sopenharmony_ci 54778c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 54788c2ecf20Sopenharmony_ci other = hdspm->capture_substream; 54798c2ecf20Sopenharmony_ci else 54808c2ecf20Sopenharmony_ci other = hdspm->playback_substream; 54818c2ecf20Sopenharmony_ci 54828c2ecf20Sopenharmony_ci if (hdspm->running) 54838c2ecf20Sopenharmony_ci runtime->status->hw_ptr = hdspm_hw_pointer(hdspm); 54848c2ecf20Sopenharmony_ci else 54858c2ecf20Sopenharmony_ci runtime->status->hw_ptr = 0; 54868c2ecf20Sopenharmony_ci if (other) { 54878c2ecf20Sopenharmony_ci struct snd_pcm_substream *s; 54888c2ecf20Sopenharmony_ci struct snd_pcm_runtime *oruntime = other->runtime; 54898c2ecf20Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 54908c2ecf20Sopenharmony_ci if (s == other) { 54918c2ecf20Sopenharmony_ci oruntime->status->hw_ptr = 54928c2ecf20Sopenharmony_ci runtime->status->hw_ptr; 54938c2ecf20Sopenharmony_ci break; 54948c2ecf20Sopenharmony_ci } 54958c2ecf20Sopenharmony_ci } 54968c2ecf20Sopenharmony_ci } 54978c2ecf20Sopenharmony_ci return 0; 54988c2ecf20Sopenharmony_ci} 54998c2ecf20Sopenharmony_ci 55008c2ecf20Sopenharmony_cistatic int snd_hdspm_hw_params(struct snd_pcm_substream *substream, 55018c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 55028c2ecf20Sopenharmony_ci{ 55038c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 55048c2ecf20Sopenharmony_ci int err; 55058c2ecf20Sopenharmony_ci int i; 55068c2ecf20Sopenharmony_ci pid_t this_pid; 55078c2ecf20Sopenharmony_ci pid_t other_pid; 55088c2ecf20Sopenharmony_ci 55098c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 55108c2ecf20Sopenharmony_ci 55118c2ecf20Sopenharmony_ci if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { 55128c2ecf20Sopenharmony_ci this_pid = hdspm->playback_pid; 55138c2ecf20Sopenharmony_ci other_pid = hdspm->capture_pid; 55148c2ecf20Sopenharmony_ci } else { 55158c2ecf20Sopenharmony_ci this_pid = hdspm->capture_pid; 55168c2ecf20Sopenharmony_ci other_pid = hdspm->playback_pid; 55178c2ecf20Sopenharmony_ci } 55188c2ecf20Sopenharmony_ci 55198c2ecf20Sopenharmony_ci if (other_pid > 0 && this_pid != other_pid) { 55208c2ecf20Sopenharmony_ci 55218c2ecf20Sopenharmony_ci /* The other stream is open, and not by the same 55228c2ecf20Sopenharmony_ci task as this one. Make sure that the parameters 55238c2ecf20Sopenharmony_ci that matter are the same. 55248c2ecf20Sopenharmony_ci */ 55258c2ecf20Sopenharmony_ci 55268c2ecf20Sopenharmony_ci if (params_rate(params) != hdspm->system_sample_rate) { 55278c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 55288c2ecf20Sopenharmony_ci _snd_pcm_hw_param_setempty(params, 55298c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE); 55308c2ecf20Sopenharmony_ci return -EBUSY; 55318c2ecf20Sopenharmony_ci } 55328c2ecf20Sopenharmony_ci 55338c2ecf20Sopenharmony_ci if (params_period_size(params) != hdspm->period_bytes / 4) { 55348c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 55358c2ecf20Sopenharmony_ci _snd_pcm_hw_param_setempty(params, 55368c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 55378c2ecf20Sopenharmony_ci return -EBUSY; 55388c2ecf20Sopenharmony_ci } 55398c2ecf20Sopenharmony_ci 55408c2ecf20Sopenharmony_ci } 55418c2ecf20Sopenharmony_ci /* We're fine. */ 55428c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 55438c2ecf20Sopenharmony_ci 55448c2ecf20Sopenharmony_ci /* how to make sure that the rate matches an externally-set one ? */ 55458c2ecf20Sopenharmony_ci 55468c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 55478c2ecf20Sopenharmony_ci err = hdspm_set_rate(hdspm, params_rate(params), 0); 55488c2ecf20Sopenharmony_ci if (err < 0) { 55498c2ecf20Sopenharmony_ci dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err); 55508c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 55518c2ecf20Sopenharmony_ci _snd_pcm_hw_param_setempty(params, 55528c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE); 55538c2ecf20Sopenharmony_ci return err; 55548c2ecf20Sopenharmony_ci } 55558c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 55568c2ecf20Sopenharmony_ci 55578c2ecf20Sopenharmony_ci err = hdspm_set_interrupt_interval(hdspm, 55588c2ecf20Sopenharmony_ci params_period_size(params)); 55598c2ecf20Sopenharmony_ci if (err < 0) { 55608c2ecf20Sopenharmony_ci dev_info(hdspm->card->dev, 55618c2ecf20Sopenharmony_ci "err on hdspm_set_interrupt_interval: %d\n", err); 55628c2ecf20Sopenharmony_ci _snd_pcm_hw_param_setempty(params, 55638c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 55648c2ecf20Sopenharmony_ci return err; 55658c2ecf20Sopenharmony_ci } 55668c2ecf20Sopenharmony_ci 55678c2ecf20Sopenharmony_ci /* Memory allocation, takashi's method, dont know if we should 55688c2ecf20Sopenharmony_ci * spinlock 55698c2ecf20Sopenharmony_ci */ 55708c2ecf20Sopenharmony_ci /* malloc all buffer even if not enabled to get sure */ 55718c2ecf20Sopenharmony_ci /* Update for MADI rev 204: we need to allocate for all channels, 55728c2ecf20Sopenharmony_ci * otherwise it doesn't work at 96kHz */ 55738c2ecf20Sopenharmony_ci 55748c2ecf20Sopenharmony_ci err = 55758c2ecf20Sopenharmony_ci snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES); 55768c2ecf20Sopenharmony_ci if (err < 0) { 55778c2ecf20Sopenharmony_ci dev_info(hdspm->card->dev, 55788c2ecf20Sopenharmony_ci "err on snd_pcm_lib_malloc_pages: %d\n", err); 55798c2ecf20Sopenharmony_ci return err; 55808c2ecf20Sopenharmony_ci } 55818c2ecf20Sopenharmony_ci 55828c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 55838c2ecf20Sopenharmony_ci 55848c2ecf20Sopenharmony_ci for (i = 0; i < params_channels(params); ++i) { 55858c2ecf20Sopenharmony_ci int c = hdspm->channel_map_out[i]; 55868c2ecf20Sopenharmony_ci 55878c2ecf20Sopenharmony_ci if (c < 0) 55888c2ecf20Sopenharmony_ci continue; /* just make sure */ 55898c2ecf20Sopenharmony_ci hdspm_set_channel_dma_addr(hdspm, substream, 55908c2ecf20Sopenharmony_ci HDSPM_pageAddressBufferOut, 55918c2ecf20Sopenharmony_ci c); 55928c2ecf20Sopenharmony_ci snd_hdspm_enable_out(hdspm, c, 1); 55938c2ecf20Sopenharmony_ci } 55948c2ecf20Sopenharmony_ci 55958c2ecf20Sopenharmony_ci hdspm->playback_buffer = 55968c2ecf20Sopenharmony_ci (unsigned char *) substream->runtime->dma_area; 55978c2ecf20Sopenharmony_ci dev_dbg(hdspm->card->dev, 55988c2ecf20Sopenharmony_ci "Allocated sample buffer for playback at %p\n", 55998c2ecf20Sopenharmony_ci hdspm->playback_buffer); 56008c2ecf20Sopenharmony_ci } else { 56018c2ecf20Sopenharmony_ci for (i = 0; i < params_channels(params); ++i) { 56028c2ecf20Sopenharmony_ci int c = hdspm->channel_map_in[i]; 56038c2ecf20Sopenharmony_ci 56048c2ecf20Sopenharmony_ci if (c < 0) 56058c2ecf20Sopenharmony_ci continue; 56068c2ecf20Sopenharmony_ci hdspm_set_channel_dma_addr(hdspm, substream, 56078c2ecf20Sopenharmony_ci HDSPM_pageAddressBufferIn, 56088c2ecf20Sopenharmony_ci c); 56098c2ecf20Sopenharmony_ci snd_hdspm_enable_in(hdspm, c, 1); 56108c2ecf20Sopenharmony_ci } 56118c2ecf20Sopenharmony_ci 56128c2ecf20Sopenharmony_ci hdspm->capture_buffer = 56138c2ecf20Sopenharmony_ci (unsigned char *) substream->runtime->dma_area; 56148c2ecf20Sopenharmony_ci dev_dbg(hdspm->card->dev, 56158c2ecf20Sopenharmony_ci "Allocated sample buffer for capture at %p\n", 56168c2ecf20Sopenharmony_ci hdspm->capture_buffer); 56178c2ecf20Sopenharmony_ci } 56188c2ecf20Sopenharmony_ci 56198c2ecf20Sopenharmony_ci /* 56208c2ecf20Sopenharmony_ci dev_dbg(hdspm->card->dev, 56218c2ecf20Sopenharmony_ci "Allocated sample buffer for %s at 0x%08X\n", 56228c2ecf20Sopenharmony_ci substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 56238c2ecf20Sopenharmony_ci "playback" : "capture", 56248c2ecf20Sopenharmony_ci snd_pcm_sgbuf_get_addr(substream, 0)); 56258c2ecf20Sopenharmony_ci */ 56268c2ecf20Sopenharmony_ci /* 56278c2ecf20Sopenharmony_ci dev_dbg(hdspm->card->dev, 56288c2ecf20Sopenharmony_ci "set_hwparams: %s %d Hz, %d channels, bs = %d\n", 56298c2ecf20Sopenharmony_ci substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 56308c2ecf20Sopenharmony_ci "playback" : "capture", 56318c2ecf20Sopenharmony_ci params_rate(params), params_channels(params), 56328c2ecf20Sopenharmony_ci params_buffer_size(params)); 56338c2ecf20Sopenharmony_ci */ 56348c2ecf20Sopenharmony_ci 56358c2ecf20Sopenharmony_ci 56368c2ecf20Sopenharmony_ci /* For AES cards, the float format bit is the same as the 56378c2ecf20Sopenharmony_ci * preferred sync reference. Since we don't want to break 56388c2ecf20Sopenharmony_ci * sync settings, we have to skip the remaining part of this 56398c2ecf20Sopenharmony_ci * function. 56408c2ecf20Sopenharmony_ci */ 56418c2ecf20Sopenharmony_ci if (hdspm->io_type == AES32) { 56428c2ecf20Sopenharmony_ci return 0; 56438c2ecf20Sopenharmony_ci } 56448c2ecf20Sopenharmony_ci 56458c2ecf20Sopenharmony_ci 56468c2ecf20Sopenharmony_ci /* Switch to native float format if requested */ 56478c2ecf20Sopenharmony_ci if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) { 56488c2ecf20Sopenharmony_ci if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT)) 56498c2ecf20Sopenharmony_ci dev_info(hdspm->card->dev, 56508c2ecf20Sopenharmony_ci "Switching to native 32bit LE float format.\n"); 56518c2ecf20Sopenharmony_ci 56528c2ecf20Sopenharmony_ci hdspm->control_register |= HDSPe_FLOAT_FORMAT; 56538c2ecf20Sopenharmony_ci } else if (SNDRV_PCM_FORMAT_S32_LE == params_format(params)) { 56548c2ecf20Sopenharmony_ci if (hdspm->control_register & HDSPe_FLOAT_FORMAT) 56558c2ecf20Sopenharmony_ci dev_info(hdspm->card->dev, 56568c2ecf20Sopenharmony_ci "Switching to native 32bit LE integer format.\n"); 56578c2ecf20Sopenharmony_ci 56588c2ecf20Sopenharmony_ci hdspm->control_register &= ~HDSPe_FLOAT_FORMAT; 56598c2ecf20Sopenharmony_ci } 56608c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 56618c2ecf20Sopenharmony_ci 56628c2ecf20Sopenharmony_ci return 0; 56638c2ecf20Sopenharmony_ci} 56648c2ecf20Sopenharmony_ci 56658c2ecf20Sopenharmony_cistatic int snd_hdspm_hw_free(struct snd_pcm_substream *substream) 56668c2ecf20Sopenharmony_ci{ 56678c2ecf20Sopenharmony_ci int i; 56688c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 56698c2ecf20Sopenharmony_ci 56708c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 56718c2ecf20Sopenharmony_ci /* Just disable all channels. The saving when disabling a */ 56728c2ecf20Sopenharmony_ci /* smaller set is not worth the trouble. */ 56738c2ecf20Sopenharmony_ci for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) 56748c2ecf20Sopenharmony_ci snd_hdspm_enable_out(hdspm, i, 0); 56758c2ecf20Sopenharmony_ci 56768c2ecf20Sopenharmony_ci hdspm->playback_buffer = NULL; 56778c2ecf20Sopenharmony_ci } else { 56788c2ecf20Sopenharmony_ci for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) 56798c2ecf20Sopenharmony_ci snd_hdspm_enable_in(hdspm, i, 0); 56808c2ecf20Sopenharmony_ci 56818c2ecf20Sopenharmony_ci hdspm->capture_buffer = NULL; 56828c2ecf20Sopenharmony_ci } 56838c2ecf20Sopenharmony_ci 56848c2ecf20Sopenharmony_ci snd_pcm_lib_free_pages(substream); 56858c2ecf20Sopenharmony_ci 56868c2ecf20Sopenharmony_ci return 0; 56878c2ecf20Sopenharmony_ci} 56888c2ecf20Sopenharmony_ci 56898c2ecf20Sopenharmony_ci 56908c2ecf20Sopenharmony_cistatic int snd_hdspm_channel_info(struct snd_pcm_substream *substream, 56918c2ecf20Sopenharmony_ci struct snd_pcm_channel_info *info) 56928c2ecf20Sopenharmony_ci{ 56938c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 56948c2ecf20Sopenharmony_ci unsigned int channel = info->channel; 56958c2ecf20Sopenharmony_ci 56968c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 56978c2ecf20Sopenharmony_ci if (snd_BUG_ON(channel >= hdspm->max_channels_out)) { 56988c2ecf20Sopenharmony_ci dev_info(hdspm->card->dev, 56998c2ecf20Sopenharmony_ci "snd_hdspm_channel_info: output channel out of range (%d)\n", 57008c2ecf20Sopenharmony_ci channel); 57018c2ecf20Sopenharmony_ci return -EINVAL; 57028c2ecf20Sopenharmony_ci } 57038c2ecf20Sopenharmony_ci 57048c2ecf20Sopenharmony_ci channel = array_index_nospec(channel, hdspm->max_channels_out); 57058c2ecf20Sopenharmony_ci if (hdspm->channel_map_out[channel] < 0) { 57068c2ecf20Sopenharmony_ci dev_info(hdspm->card->dev, 57078c2ecf20Sopenharmony_ci "snd_hdspm_channel_info: output channel %d mapped out\n", 57088c2ecf20Sopenharmony_ci channel); 57098c2ecf20Sopenharmony_ci return -EINVAL; 57108c2ecf20Sopenharmony_ci } 57118c2ecf20Sopenharmony_ci 57128c2ecf20Sopenharmony_ci info->offset = hdspm->channel_map_out[channel] * 57138c2ecf20Sopenharmony_ci HDSPM_CHANNEL_BUFFER_BYTES; 57148c2ecf20Sopenharmony_ci } else { 57158c2ecf20Sopenharmony_ci if (snd_BUG_ON(channel >= hdspm->max_channels_in)) { 57168c2ecf20Sopenharmony_ci dev_info(hdspm->card->dev, 57178c2ecf20Sopenharmony_ci "snd_hdspm_channel_info: input channel out of range (%d)\n", 57188c2ecf20Sopenharmony_ci channel); 57198c2ecf20Sopenharmony_ci return -EINVAL; 57208c2ecf20Sopenharmony_ci } 57218c2ecf20Sopenharmony_ci 57228c2ecf20Sopenharmony_ci channel = array_index_nospec(channel, hdspm->max_channels_in); 57238c2ecf20Sopenharmony_ci if (hdspm->channel_map_in[channel] < 0) { 57248c2ecf20Sopenharmony_ci dev_info(hdspm->card->dev, 57258c2ecf20Sopenharmony_ci "snd_hdspm_channel_info: input channel %d mapped out\n", 57268c2ecf20Sopenharmony_ci channel); 57278c2ecf20Sopenharmony_ci return -EINVAL; 57288c2ecf20Sopenharmony_ci } 57298c2ecf20Sopenharmony_ci 57308c2ecf20Sopenharmony_ci info->offset = hdspm->channel_map_in[channel] * 57318c2ecf20Sopenharmony_ci HDSPM_CHANNEL_BUFFER_BYTES; 57328c2ecf20Sopenharmony_ci } 57338c2ecf20Sopenharmony_ci 57348c2ecf20Sopenharmony_ci info->first = 0; 57358c2ecf20Sopenharmony_ci info->step = 32; 57368c2ecf20Sopenharmony_ci return 0; 57378c2ecf20Sopenharmony_ci} 57388c2ecf20Sopenharmony_ci 57398c2ecf20Sopenharmony_ci 57408c2ecf20Sopenharmony_cistatic int snd_hdspm_ioctl(struct snd_pcm_substream *substream, 57418c2ecf20Sopenharmony_ci unsigned int cmd, void *arg) 57428c2ecf20Sopenharmony_ci{ 57438c2ecf20Sopenharmony_ci switch (cmd) { 57448c2ecf20Sopenharmony_ci case SNDRV_PCM_IOCTL1_RESET: 57458c2ecf20Sopenharmony_ci return snd_hdspm_reset(substream); 57468c2ecf20Sopenharmony_ci 57478c2ecf20Sopenharmony_ci case SNDRV_PCM_IOCTL1_CHANNEL_INFO: 57488c2ecf20Sopenharmony_ci { 57498c2ecf20Sopenharmony_ci struct snd_pcm_channel_info *info = arg; 57508c2ecf20Sopenharmony_ci return snd_hdspm_channel_info(substream, info); 57518c2ecf20Sopenharmony_ci } 57528c2ecf20Sopenharmony_ci default: 57538c2ecf20Sopenharmony_ci break; 57548c2ecf20Sopenharmony_ci } 57558c2ecf20Sopenharmony_ci 57568c2ecf20Sopenharmony_ci return snd_pcm_lib_ioctl(substream, cmd, arg); 57578c2ecf20Sopenharmony_ci} 57588c2ecf20Sopenharmony_ci 57598c2ecf20Sopenharmony_cistatic int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd) 57608c2ecf20Sopenharmony_ci{ 57618c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 57628c2ecf20Sopenharmony_ci struct snd_pcm_substream *other; 57638c2ecf20Sopenharmony_ci int running; 57648c2ecf20Sopenharmony_ci 57658c2ecf20Sopenharmony_ci spin_lock(&hdspm->lock); 57668c2ecf20Sopenharmony_ci running = hdspm->running; 57678c2ecf20Sopenharmony_ci switch (cmd) { 57688c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 57698c2ecf20Sopenharmony_ci running |= 1 << substream->stream; 57708c2ecf20Sopenharmony_ci break; 57718c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 57728c2ecf20Sopenharmony_ci running &= ~(1 << substream->stream); 57738c2ecf20Sopenharmony_ci break; 57748c2ecf20Sopenharmony_ci default: 57758c2ecf20Sopenharmony_ci snd_BUG(); 57768c2ecf20Sopenharmony_ci spin_unlock(&hdspm->lock); 57778c2ecf20Sopenharmony_ci return -EINVAL; 57788c2ecf20Sopenharmony_ci } 57798c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 57808c2ecf20Sopenharmony_ci other = hdspm->capture_substream; 57818c2ecf20Sopenharmony_ci else 57828c2ecf20Sopenharmony_ci other = hdspm->playback_substream; 57838c2ecf20Sopenharmony_ci 57848c2ecf20Sopenharmony_ci if (other) { 57858c2ecf20Sopenharmony_ci struct snd_pcm_substream *s; 57868c2ecf20Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 57878c2ecf20Sopenharmony_ci if (s == other) { 57888c2ecf20Sopenharmony_ci snd_pcm_trigger_done(s, substream); 57898c2ecf20Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) 57908c2ecf20Sopenharmony_ci running |= 1 << s->stream; 57918c2ecf20Sopenharmony_ci else 57928c2ecf20Sopenharmony_ci running &= ~(1 << s->stream); 57938c2ecf20Sopenharmony_ci goto _ok; 57948c2ecf20Sopenharmony_ci } 57958c2ecf20Sopenharmony_ci } 57968c2ecf20Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) { 57978c2ecf20Sopenharmony_ci if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) 57988c2ecf20Sopenharmony_ci && substream->stream == 57998c2ecf20Sopenharmony_ci SNDRV_PCM_STREAM_CAPTURE) 58008c2ecf20Sopenharmony_ci hdspm_silence_playback(hdspm); 58018c2ecf20Sopenharmony_ci } else { 58028c2ecf20Sopenharmony_ci if (running && 58038c2ecf20Sopenharmony_ci substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 58048c2ecf20Sopenharmony_ci hdspm_silence_playback(hdspm); 58058c2ecf20Sopenharmony_ci } 58068c2ecf20Sopenharmony_ci } else { 58078c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 58088c2ecf20Sopenharmony_ci hdspm_silence_playback(hdspm); 58098c2ecf20Sopenharmony_ci } 58108c2ecf20Sopenharmony_ci_ok: 58118c2ecf20Sopenharmony_ci snd_pcm_trigger_done(substream, substream); 58128c2ecf20Sopenharmony_ci if (!hdspm->running && running) 58138c2ecf20Sopenharmony_ci hdspm_start_audio(hdspm); 58148c2ecf20Sopenharmony_ci else if (hdspm->running && !running) 58158c2ecf20Sopenharmony_ci hdspm_stop_audio(hdspm); 58168c2ecf20Sopenharmony_ci hdspm->running = running; 58178c2ecf20Sopenharmony_ci spin_unlock(&hdspm->lock); 58188c2ecf20Sopenharmony_ci 58198c2ecf20Sopenharmony_ci return 0; 58208c2ecf20Sopenharmony_ci} 58218c2ecf20Sopenharmony_ci 58228c2ecf20Sopenharmony_cistatic int snd_hdspm_prepare(struct snd_pcm_substream *substream) 58238c2ecf20Sopenharmony_ci{ 58248c2ecf20Sopenharmony_ci return 0; 58258c2ecf20Sopenharmony_ci} 58268c2ecf20Sopenharmony_ci 58278c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_hdspm_playback_subinfo = { 58288c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 58298c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 58308c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_NONINTERLEAVED | 58318c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_DOUBLE), 58328c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 58338c2ecf20Sopenharmony_ci .rates = (SNDRV_PCM_RATE_32000 | 58348c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_44100 | 58358c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | 58368c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_64000 | 58378c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 58388c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ), 58398c2ecf20Sopenharmony_ci .rate_min = 32000, 58408c2ecf20Sopenharmony_ci .rate_max = 192000, 58418c2ecf20Sopenharmony_ci .channels_min = 1, 58428c2ecf20Sopenharmony_ci .channels_max = HDSPM_MAX_CHANNELS, 58438c2ecf20Sopenharmony_ci .buffer_bytes_max = 58448c2ecf20Sopenharmony_ci HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, 58458c2ecf20Sopenharmony_ci .period_bytes_min = (32 * 4), 58468c2ecf20Sopenharmony_ci .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, 58478c2ecf20Sopenharmony_ci .periods_min = 2, 58488c2ecf20Sopenharmony_ci .periods_max = 512, 58498c2ecf20Sopenharmony_ci .fifo_size = 0 58508c2ecf20Sopenharmony_ci}; 58518c2ecf20Sopenharmony_ci 58528c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_hdspm_capture_subinfo = { 58538c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 58548c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 58558c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_NONINTERLEAVED | 58568c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START), 58578c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 58588c2ecf20Sopenharmony_ci .rates = (SNDRV_PCM_RATE_32000 | 58598c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_44100 | 58608c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | 58618c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_64000 | 58628c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 58638c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000), 58648c2ecf20Sopenharmony_ci .rate_min = 32000, 58658c2ecf20Sopenharmony_ci .rate_max = 192000, 58668c2ecf20Sopenharmony_ci .channels_min = 1, 58678c2ecf20Sopenharmony_ci .channels_max = HDSPM_MAX_CHANNELS, 58688c2ecf20Sopenharmony_ci .buffer_bytes_max = 58698c2ecf20Sopenharmony_ci HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, 58708c2ecf20Sopenharmony_ci .period_bytes_min = (32 * 4), 58718c2ecf20Sopenharmony_ci .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, 58728c2ecf20Sopenharmony_ci .periods_min = 2, 58738c2ecf20Sopenharmony_ci .periods_max = 512, 58748c2ecf20Sopenharmony_ci .fifo_size = 0 58758c2ecf20Sopenharmony_ci}; 58768c2ecf20Sopenharmony_ci 58778c2ecf20Sopenharmony_cistatic int snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params, 58788c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 58798c2ecf20Sopenharmony_ci{ 58808c2ecf20Sopenharmony_ci struct hdspm *hdspm = rule->private; 58818c2ecf20Sopenharmony_ci struct snd_interval *c = 58828c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 58838c2ecf20Sopenharmony_ci struct snd_interval *r = 58848c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 58858c2ecf20Sopenharmony_ci 58868c2ecf20Sopenharmony_ci if (r->min > 96000 && r->max <= 192000) { 58878c2ecf20Sopenharmony_ci struct snd_interval t = { 58888c2ecf20Sopenharmony_ci .min = hdspm->qs_in_channels, 58898c2ecf20Sopenharmony_ci .max = hdspm->qs_in_channels, 58908c2ecf20Sopenharmony_ci .integer = 1, 58918c2ecf20Sopenharmony_ci }; 58928c2ecf20Sopenharmony_ci return snd_interval_refine(c, &t); 58938c2ecf20Sopenharmony_ci } else if (r->min > 48000 && r->max <= 96000) { 58948c2ecf20Sopenharmony_ci struct snd_interval t = { 58958c2ecf20Sopenharmony_ci .min = hdspm->ds_in_channels, 58968c2ecf20Sopenharmony_ci .max = hdspm->ds_in_channels, 58978c2ecf20Sopenharmony_ci .integer = 1, 58988c2ecf20Sopenharmony_ci }; 58998c2ecf20Sopenharmony_ci return snd_interval_refine(c, &t); 59008c2ecf20Sopenharmony_ci } else if (r->max < 64000) { 59018c2ecf20Sopenharmony_ci struct snd_interval t = { 59028c2ecf20Sopenharmony_ci .min = hdspm->ss_in_channels, 59038c2ecf20Sopenharmony_ci .max = hdspm->ss_in_channels, 59048c2ecf20Sopenharmony_ci .integer = 1, 59058c2ecf20Sopenharmony_ci }; 59068c2ecf20Sopenharmony_ci return snd_interval_refine(c, &t); 59078c2ecf20Sopenharmony_ci } 59088c2ecf20Sopenharmony_ci 59098c2ecf20Sopenharmony_ci return 0; 59108c2ecf20Sopenharmony_ci} 59118c2ecf20Sopenharmony_ci 59128c2ecf20Sopenharmony_cistatic int snd_hdspm_hw_rule_out_channels_rate(struct snd_pcm_hw_params *params, 59138c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule * rule) 59148c2ecf20Sopenharmony_ci{ 59158c2ecf20Sopenharmony_ci struct hdspm *hdspm = rule->private; 59168c2ecf20Sopenharmony_ci struct snd_interval *c = 59178c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 59188c2ecf20Sopenharmony_ci struct snd_interval *r = 59198c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 59208c2ecf20Sopenharmony_ci 59218c2ecf20Sopenharmony_ci if (r->min > 96000 && r->max <= 192000) { 59228c2ecf20Sopenharmony_ci struct snd_interval t = { 59238c2ecf20Sopenharmony_ci .min = hdspm->qs_out_channels, 59248c2ecf20Sopenharmony_ci .max = hdspm->qs_out_channels, 59258c2ecf20Sopenharmony_ci .integer = 1, 59268c2ecf20Sopenharmony_ci }; 59278c2ecf20Sopenharmony_ci return snd_interval_refine(c, &t); 59288c2ecf20Sopenharmony_ci } else if (r->min > 48000 && r->max <= 96000) { 59298c2ecf20Sopenharmony_ci struct snd_interval t = { 59308c2ecf20Sopenharmony_ci .min = hdspm->ds_out_channels, 59318c2ecf20Sopenharmony_ci .max = hdspm->ds_out_channels, 59328c2ecf20Sopenharmony_ci .integer = 1, 59338c2ecf20Sopenharmony_ci }; 59348c2ecf20Sopenharmony_ci return snd_interval_refine(c, &t); 59358c2ecf20Sopenharmony_ci } else if (r->max < 64000) { 59368c2ecf20Sopenharmony_ci struct snd_interval t = { 59378c2ecf20Sopenharmony_ci .min = hdspm->ss_out_channels, 59388c2ecf20Sopenharmony_ci .max = hdspm->ss_out_channels, 59398c2ecf20Sopenharmony_ci .integer = 1, 59408c2ecf20Sopenharmony_ci }; 59418c2ecf20Sopenharmony_ci return snd_interval_refine(c, &t); 59428c2ecf20Sopenharmony_ci } else { 59438c2ecf20Sopenharmony_ci } 59448c2ecf20Sopenharmony_ci return 0; 59458c2ecf20Sopenharmony_ci} 59468c2ecf20Sopenharmony_ci 59478c2ecf20Sopenharmony_cistatic int snd_hdspm_hw_rule_rate_in_channels(struct snd_pcm_hw_params *params, 59488c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule * rule) 59498c2ecf20Sopenharmony_ci{ 59508c2ecf20Sopenharmony_ci struct hdspm *hdspm = rule->private; 59518c2ecf20Sopenharmony_ci struct snd_interval *c = 59528c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 59538c2ecf20Sopenharmony_ci struct snd_interval *r = 59548c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 59558c2ecf20Sopenharmony_ci 59568c2ecf20Sopenharmony_ci if (c->min >= hdspm->ss_in_channels) { 59578c2ecf20Sopenharmony_ci struct snd_interval t = { 59588c2ecf20Sopenharmony_ci .min = 32000, 59598c2ecf20Sopenharmony_ci .max = 48000, 59608c2ecf20Sopenharmony_ci .integer = 1, 59618c2ecf20Sopenharmony_ci }; 59628c2ecf20Sopenharmony_ci return snd_interval_refine(r, &t); 59638c2ecf20Sopenharmony_ci } else if (c->max <= hdspm->qs_in_channels) { 59648c2ecf20Sopenharmony_ci struct snd_interval t = { 59658c2ecf20Sopenharmony_ci .min = 128000, 59668c2ecf20Sopenharmony_ci .max = 192000, 59678c2ecf20Sopenharmony_ci .integer = 1, 59688c2ecf20Sopenharmony_ci }; 59698c2ecf20Sopenharmony_ci return snd_interval_refine(r, &t); 59708c2ecf20Sopenharmony_ci } else if (c->max <= hdspm->ds_in_channels) { 59718c2ecf20Sopenharmony_ci struct snd_interval t = { 59728c2ecf20Sopenharmony_ci .min = 64000, 59738c2ecf20Sopenharmony_ci .max = 96000, 59748c2ecf20Sopenharmony_ci .integer = 1, 59758c2ecf20Sopenharmony_ci }; 59768c2ecf20Sopenharmony_ci return snd_interval_refine(r, &t); 59778c2ecf20Sopenharmony_ci } 59788c2ecf20Sopenharmony_ci 59798c2ecf20Sopenharmony_ci return 0; 59808c2ecf20Sopenharmony_ci} 59818c2ecf20Sopenharmony_cistatic int snd_hdspm_hw_rule_rate_out_channels(struct snd_pcm_hw_params *params, 59828c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 59838c2ecf20Sopenharmony_ci{ 59848c2ecf20Sopenharmony_ci struct hdspm *hdspm = rule->private; 59858c2ecf20Sopenharmony_ci struct snd_interval *c = 59868c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 59878c2ecf20Sopenharmony_ci struct snd_interval *r = 59888c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 59898c2ecf20Sopenharmony_ci 59908c2ecf20Sopenharmony_ci if (c->min >= hdspm->ss_out_channels) { 59918c2ecf20Sopenharmony_ci struct snd_interval t = { 59928c2ecf20Sopenharmony_ci .min = 32000, 59938c2ecf20Sopenharmony_ci .max = 48000, 59948c2ecf20Sopenharmony_ci .integer = 1, 59958c2ecf20Sopenharmony_ci }; 59968c2ecf20Sopenharmony_ci return snd_interval_refine(r, &t); 59978c2ecf20Sopenharmony_ci } else if (c->max <= hdspm->qs_out_channels) { 59988c2ecf20Sopenharmony_ci struct snd_interval t = { 59998c2ecf20Sopenharmony_ci .min = 128000, 60008c2ecf20Sopenharmony_ci .max = 192000, 60018c2ecf20Sopenharmony_ci .integer = 1, 60028c2ecf20Sopenharmony_ci }; 60038c2ecf20Sopenharmony_ci return snd_interval_refine(r, &t); 60048c2ecf20Sopenharmony_ci } else if (c->max <= hdspm->ds_out_channels) { 60058c2ecf20Sopenharmony_ci struct snd_interval t = { 60068c2ecf20Sopenharmony_ci .min = 64000, 60078c2ecf20Sopenharmony_ci .max = 96000, 60088c2ecf20Sopenharmony_ci .integer = 1, 60098c2ecf20Sopenharmony_ci }; 60108c2ecf20Sopenharmony_ci return snd_interval_refine(r, &t); 60118c2ecf20Sopenharmony_ci } 60128c2ecf20Sopenharmony_ci 60138c2ecf20Sopenharmony_ci return 0; 60148c2ecf20Sopenharmony_ci} 60158c2ecf20Sopenharmony_ci 60168c2ecf20Sopenharmony_cistatic int snd_hdspm_hw_rule_in_channels(struct snd_pcm_hw_params *params, 60178c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 60188c2ecf20Sopenharmony_ci{ 60198c2ecf20Sopenharmony_ci unsigned int list[3]; 60208c2ecf20Sopenharmony_ci struct hdspm *hdspm = rule->private; 60218c2ecf20Sopenharmony_ci struct snd_interval *c = hw_param_interval(params, 60228c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS); 60238c2ecf20Sopenharmony_ci 60248c2ecf20Sopenharmony_ci list[0] = hdspm->qs_in_channels; 60258c2ecf20Sopenharmony_ci list[1] = hdspm->ds_in_channels; 60268c2ecf20Sopenharmony_ci list[2] = hdspm->ss_in_channels; 60278c2ecf20Sopenharmony_ci return snd_interval_list(c, 3, list, 0); 60288c2ecf20Sopenharmony_ci} 60298c2ecf20Sopenharmony_ci 60308c2ecf20Sopenharmony_cistatic int snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params *params, 60318c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 60328c2ecf20Sopenharmony_ci{ 60338c2ecf20Sopenharmony_ci unsigned int list[3]; 60348c2ecf20Sopenharmony_ci struct hdspm *hdspm = rule->private; 60358c2ecf20Sopenharmony_ci struct snd_interval *c = hw_param_interval(params, 60368c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS); 60378c2ecf20Sopenharmony_ci 60388c2ecf20Sopenharmony_ci list[0] = hdspm->qs_out_channels; 60398c2ecf20Sopenharmony_ci list[1] = hdspm->ds_out_channels; 60408c2ecf20Sopenharmony_ci list[2] = hdspm->ss_out_channels; 60418c2ecf20Sopenharmony_ci return snd_interval_list(c, 3, list, 0); 60428c2ecf20Sopenharmony_ci} 60438c2ecf20Sopenharmony_ci 60448c2ecf20Sopenharmony_ci 60458c2ecf20Sopenharmony_cistatic const unsigned int hdspm_aes32_sample_rates[] = { 60468c2ecf20Sopenharmony_ci 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 60478c2ecf20Sopenharmony_ci}; 60488c2ecf20Sopenharmony_ci 60498c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list 60508c2ecf20Sopenharmony_cihdspm_hw_constraints_aes32_sample_rates = { 60518c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(hdspm_aes32_sample_rates), 60528c2ecf20Sopenharmony_ci .list = hdspm_aes32_sample_rates, 60538c2ecf20Sopenharmony_ci .mask = 0 60548c2ecf20Sopenharmony_ci}; 60558c2ecf20Sopenharmony_ci 60568c2ecf20Sopenharmony_cistatic int snd_hdspm_open(struct snd_pcm_substream *substream) 60578c2ecf20Sopenharmony_ci{ 60588c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 60598c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 60608c2ecf20Sopenharmony_ci bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 60618c2ecf20Sopenharmony_ci 60628c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 60638c2ecf20Sopenharmony_ci snd_pcm_set_sync(substream); 60648c2ecf20Sopenharmony_ci runtime->hw = (playback) ? snd_hdspm_playback_subinfo : 60658c2ecf20Sopenharmony_ci snd_hdspm_capture_subinfo; 60668c2ecf20Sopenharmony_ci 60678c2ecf20Sopenharmony_ci if (playback) { 60688c2ecf20Sopenharmony_ci if (!hdspm->capture_substream) 60698c2ecf20Sopenharmony_ci hdspm_stop_audio(hdspm); 60708c2ecf20Sopenharmony_ci 60718c2ecf20Sopenharmony_ci hdspm->playback_pid = current->pid; 60728c2ecf20Sopenharmony_ci hdspm->playback_substream = substream; 60738c2ecf20Sopenharmony_ci } else { 60748c2ecf20Sopenharmony_ci if (!hdspm->playback_substream) 60758c2ecf20Sopenharmony_ci hdspm_stop_audio(hdspm); 60768c2ecf20Sopenharmony_ci 60778c2ecf20Sopenharmony_ci hdspm->capture_pid = current->pid; 60788c2ecf20Sopenharmony_ci hdspm->capture_substream = substream; 60798c2ecf20Sopenharmony_ci } 60808c2ecf20Sopenharmony_ci 60818c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 60828c2ecf20Sopenharmony_ci 60838c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 60848c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 60858c2ecf20Sopenharmony_ci 60868c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 60878c2ecf20Sopenharmony_ci case AIO: 60888c2ecf20Sopenharmony_ci case RayDAT: 60898c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_minmax(runtime, 60908c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 60918c2ecf20Sopenharmony_ci 32, 4096); 60928c2ecf20Sopenharmony_ci /* RayDAT & AIO have a fixed buffer of 16384 samples per channel */ 60938c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_single(runtime, 60948c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 60958c2ecf20Sopenharmony_ci 16384); 60968c2ecf20Sopenharmony_ci break; 60978c2ecf20Sopenharmony_ci 60988c2ecf20Sopenharmony_ci default: 60998c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_minmax(runtime, 61008c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 61018c2ecf20Sopenharmony_ci 64, 8192); 61028c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_single(runtime, 61038c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS, 2); 61048c2ecf20Sopenharmony_ci break; 61058c2ecf20Sopenharmony_ci } 61068c2ecf20Sopenharmony_ci 61078c2ecf20Sopenharmony_ci if (AES32 == hdspm->io_type) { 61088c2ecf20Sopenharmony_ci runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; 61098c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 61108c2ecf20Sopenharmony_ci &hdspm_hw_constraints_aes32_sample_rates); 61118c2ecf20Sopenharmony_ci } else { 61128c2ecf20Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 61138c2ecf20Sopenharmony_ci (playback ? 61148c2ecf20Sopenharmony_ci snd_hdspm_hw_rule_rate_out_channels : 61158c2ecf20Sopenharmony_ci snd_hdspm_hw_rule_rate_in_channels), hdspm, 61168c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 61178c2ecf20Sopenharmony_ci } 61188c2ecf20Sopenharmony_ci 61198c2ecf20Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 61208c2ecf20Sopenharmony_ci (playback ? snd_hdspm_hw_rule_out_channels : 61218c2ecf20Sopenharmony_ci snd_hdspm_hw_rule_in_channels), hdspm, 61228c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 61238c2ecf20Sopenharmony_ci 61248c2ecf20Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 61258c2ecf20Sopenharmony_ci (playback ? snd_hdspm_hw_rule_out_channels_rate : 61268c2ecf20Sopenharmony_ci snd_hdspm_hw_rule_in_channels_rate), hdspm, 61278c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, -1); 61288c2ecf20Sopenharmony_ci 61298c2ecf20Sopenharmony_ci return 0; 61308c2ecf20Sopenharmony_ci} 61318c2ecf20Sopenharmony_ci 61328c2ecf20Sopenharmony_cistatic int snd_hdspm_release(struct snd_pcm_substream *substream) 61338c2ecf20Sopenharmony_ci{ 61348c2ecf20Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 61358c2ecf20Sopenharmony_ci bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 61368c2ecf20Sopenharmony_ci 61378c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 61388c2ecf20Sopenharmony_ci 61398c2ecf20Sopenharmony_ci if (playback) { 61408c2ecf20Sopenharmony_ci hdspm->playback_pid = -1; 61418c2ecf20Sopenharmony_ci hdspm->playback_substream = NULL; 61428c2ecf20Sopenharmony_ci } else { 61438c2ecf20Sopenharmony_ci hdspm->capture_pid = -1; 61448c2ecf20Sopenharmony_ci hdspm->capture_substream = NULL; 61458c2ecf20Sopenharmony_ci } 61468c2ecf20Sopenharmony_ci 61478c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 61488c2ecf20Sopenharmony_ci 61498c2ecf20Sopenharmony_ci return 0; 61508c2ecf20Sopenharmony_ci} 61518c2ecf20Sopenharmony_ci 61528c2ecf20Sopenharmony_cistatic int snd_hdspm_hwdep_dummy_op(struct snd_hwdep *hw, struct file *file) 61538c2ecf20Sopenharmony_ci{ 61548c2ecf20Sopenharmony_ci /* we have nothing to initialize but the call is required */ 61558c2ecf20Sopenharmony_ci return 0; 61568c2ecf20Sopenharmony_ci} 61578c2ecf20Sopenharmony_ci 61588c2ecf20Sopenharmony_cistatic inline int copy_u32_le(void __user *dest, void __iomem *src) 61598c2ecf20Sopenharmony_ci{ 61608c2ecf20Sopenharmony_ci u32 val = readl(src); 61618c2ecf20Sopenharmony_ci return copy_to_user(dest, &val, 4); 61628c2ecf20Sopenharmony_ci} 61638c2ecf20Sopenharmony_ci 61648c2ecf20Sopenharmony_cistatic int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, 61658c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 61668c2ecf20Sopenharmony_ci{ 61678c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 61688c2ecf20Sopenharmony_ci struct hdspm *hdspm = hw->private_data; 61698c2ecf20Sopenharmony_ci struct hdspm_mixer_ioctl mixer; 61708c2ecf20Sopenharmony_ci struct hdspm_config info; 61718c2ecf20Sopenharmony_ci struct hdspm_status status; 61728c2ecf20Sopenharmony_ci struct hdspm_version hdspm_version; 61738c2ecf20Sopenharmony_ci struct hdspm_peak_rms *levels; 61748c2ecf20Sopenharmony_ci struct hdspm_ltc ltc; 61758c2ecf20Sopenharmony_ci unsigned int statusregister; 61768c2ecf20Sopenharmony_ci long unsigned int s; 61778c2ecf20Sopenharmony_ci int i = 0; 61788c2ecf20Sopenharmony_ci 61798c2ecf20Sopenharmony_ci switch (cmd) { 61808c2ecf20Sopenharmony_ci 61818c2ecf20Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS: 61828c2ecf20Sopenharmony_ci levels = &hdspm->peak_rms; 61838c2ecf20Sopenharmony_ci for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { 61848c2ecf20Sopenharmony_ci levels->input_peaks[i] = 61858c2ecf20Sopenharmony_ci readl(hdspm->iobase + 61868c2ecf20Sopenharmony_ci HDSPM_MADI_INPUT_PEAK + i*4); 61878c2ecf20Sopenharmony_ci levels->playback_peaks[i] = 61888c2ecf20Sopenharmony_ci readl(hdspm->iobase + 61898c2ecf20Sopenharmony_ci HDSPM_MADI_PLAYBACK_PEAK + i*4); 61908c2ecf20Sopenharmony_ci levels->output_peaks[i] = 61918c2ecf20Sopenharmony_ci readl(hdspm->iobase + 61928c2ecf20Sopenharmony_ci HDSPM_MADI_OUTPUT_PEAK + i*4); 61938c2ecf20Sopenharmony_ci 61948c2ecf20Sopenharmony_ci levels->input_rms[i] = 61958c2ecf20Sopenharmony_ci ((uint64_t) readl(hdspm->iobase + 61968c2ecf20Sopenharmony_ci HDSPM_MADI_INPUT_RMS_H + i*4) << 32) | 61978c2ecf20Sopenharmony_ci (uint64_t) readl(hdspm->iobase + 61988c2ecf20Sopenharmony_ci HDSPM_MADI_INPUT_RMS_L + i*4); 61998c2ecf20Sopenharmony_ci levels->playback_rms[i] = 62008c2ecf20Sopenharmony_ci ((uint64_t)readl(hdspm->iobase + 62018c2ecf20Sopenharmony_ci HDSPM_MADI_PLAYBACK_RMS_H+i*4) << 32) | 62028c2ecf20Sopenharmony_ci (uint64_t)readl(hdspm->iobase + 62038c2ecf20Sopenharmony_ci HDSPM_MADI_PLAYBACK_RMS_L + i*4); 62048c2ecf20Sopenharmony_ci levels->output_rms[i] = 62058c2ecf20Sopenharmony_ci ((uint64_t)readl(hdspm->iobase + 62068c2ecf20Sopenharmony_ci HDSPM_MADI_OUTPUT_RMS_H + i*4) << 32) | 62078c2ecf20Sopenharmony_ci (uint64_t)readl(hdspm->iobase + 62088c2ecf20Sopenharmony_ci HDSPM_MADI_OUTPUT_RMS_L + i*4); 62098c2ecf20Sopenharmony_ci } 62108c2ecf20Sopenharmony_ci 62118c2ecf20Sopenharmony_ci if (hdspm->system_sample_rate > 96000) { 62128c2ecf20Sopenharmony_ci levels->speed = qs; 62138c2ecf20Sopenharmony_ci } else if (hdspm->system_sample_rate > 48000) { 62148c2ecf20Sopenharmony_ci levels->speed = ds; 62158c2ecf20Sopenharmony_ci } else { 62168c2ecf20Sopenharmony_ci levels->speed = ss; 62178c2ecf20Sopenharmony_ci } 62188c2ecf20Sopenharmony_ci levels->status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 62198c2ecf20Sopenharmony_ci 62208c2ecf20Sopenharmony_ci s = copy_to_user(argp, levels, sizeof(*levels)); 62218c2ecf20Sopenharmony_ci if (0 != s) { 62228c2ecf20Sopenharmony_ci /* dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu 62238c2ecf20Sopenharmony_ci [Levels]\n", sizeof(struct hdspm_peak_rms), s); 62248c2ecf20Sopenharmony_ci */ 62258c2ecf20Sopenharmony_ci return -EFAULT; 62268c2ecf20Sopenharmony_ci } 62278c2ecf20Sopenharmony_ci break; 62288c2ecf20Sopenharmony_ci 62298c2ecf20Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_LTC: 62308c2ecf20Sopenharmony_ci ltc.ltc = hdspm_read(hdspm, HDSPM_RD_TCO); 62318c2ecf20Sopenharmony_ci i = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 62328c2ecf20Sopenharmony_ci if (i & HDSPM_TCO1_LTC_Input_valid) { 62338c2ecf20Sopenharmony_ci switch (i & (HDSPM_TCO1_LTC_Format_LSB | 62348c2ecf20Sopenharmony_ci HDSPM_TCO1_LTC_Format_MSB)) { 62358c2ecf20Sopenharmony_ci case 0: 62368c2ecf20Sopenharmony_ci ltc.format = fps_24; 62378c2ecf20Sopenharmony_ci break; 62388c2ecf20Sopenharmony_ci case HDSPM_TCO1_LTC_Format_LSB: 62398c2ecf20Sopenharmony_ci ltc.format = fps_25; 62408c2ecf20Sopenharmony_ci break; 62418c2ecf20Sopenharmony_ci case HDSPM_TCO1_LTC_Format_MSB: 62428c2ecf20Sopenharmony_ci ltc.format = fps_2997; 62438c2ecf20Sopenharmony_ci break; 62448c2ecf20Sopenharmony_ci default: 62458c2ecf20Sopenharmony_ci ltc.format = fps_30; 62468c2ecf20Sopenharmony_ci break; 62478c2ecf20Sopenharmony_ci } 62488c2ecf20Sopenharmony_ci if (i & HDSPM_TCO1_set_drop_frame_flag) { 62498c2ecf20Sopenharmony_ci ltc.frame = drop_frame; 62508c2ecf20Sopenharmony_ci } else { 62518c2ecf20Sopenharmony_ci ltc.frame = full_frame; 62528c2ecf20Sopenharmony_ci } 62538c2ecf20Sopenharmony_ci } else { 62548c2ecf20Sopenharmony_ci ltc.format = format_invalid; 62558c2ecf20Sopenharmony_ci ltc.frame = frame_invalid; 62568c2ecf20Sopenharmony_ci } 62578c2ecf20Sopenharmony_ci if (i & HDSPM_TCO1_Video_Input_Format_NTSC) { 62588c2ecf20Sopenharmony_ci ltc.input_format = ntsc; 62598c2ecf20Sopenharmony_ci } else if (i & HDSPM_TCO1_Video_Input_Format_PAL) { 62608c2ecf20Sopenharmony_ci ltc.input_format = pal; 62618c2ecf20Sopenharmony_ci } else { 62628c2ecf20Sopenharmony_ci ltc.input_format = no_video; 62638c2ecf20Sopenharmony_ci } 62648c2ecf20Sopenharmony_ci 62658c2ecf20Sopenharmony_ci s = copy_to_user(argp, <c, sizeof(ltc)); 62668c2ecf20Sopenharmony_ci if (0 != s) { 62678c2ecf20Sopenharmony_ci /* 62688c2ecf20Sopenharmony_ci dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */ 62698c2ecf20Sopenharmony_ci return -EFAULT; 62708c2ecf20Sopenharmony_ci } 62718c2ecf20Sopenharmony_ci 62728c2ecf20Sopenharmony_ci break; 62738c2ecf20Sopenharmony_ci 62748c2ecf20Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_CONFIG: 62758c2ecf20Sopenharmony_ci 62768c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(info)); 62778c2ecf20Sopenharmony_ci spin_lock_irq(&hdspm->lock); 62788c2ecf20Sopenharmony_ci info.pref_sync_ref = hdspm_pref_sync_ref(hdspm); 62798c2ecf20Sopenharmony_ci info.wordclock_sync_check = hdspm_wc_sync_check(hdspm); 62808c2ecf20Sopenharmony_ci 62818c2ecf20Sopenharmony_ci info.system_sample_rate = hdspm->system_sample_rate; 62828c2ecf20Sopenharmony_ci info.autosync_sample_rate = 62838c2ecf20Sopenharmony_ci hdspm_external_sample_rate(hdspm); 62848c2ecf20Sopenharmony_ci info.system_clock_mode = hdspm_system_clock_mode(hdspm); 62858c2ecf20Sopenharmony_ci info.clock_source = hdspm_clock_source(hdspm); 62868c2ecf20Sopenharmony_ci info.autosync_ref = hdspm_autosync_ref(hdspm); 62878c2ecf20Sopenharmony_ci info.line_out = hdspm_toggle_setting(hdspm, HDSPM_LineOut); 62888c2ecf20Sopenharmony_ci info.passthru = 0; 62898c2ecf20Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 62908c2ecf20Sopenharmony_ci if (copy_to_user(argp, &info, sizeof(info))) 62918c2ecf20Sopenharmony_ci return -EFAULT; 62928c2ecf20Sopenharmony_ci break; 62938c2ecf20Sopenharmony_ci 62948c2ecf20Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_STATUS: 62958c2ecf20Sopenharmony_ci memset(&status, 0, sizeof(status)); 62968c2ecf20Sopenharmony_ci 62978c2ecf20Sopenharmony_ci status.card_type = hdspm->io_type; 62988c2ecf20Sopenharmony_ci 62998c2ecf20Sopenharmony_ci status.autosync_source = hdspm_autosync_ref(hdspm); 63008c2ecf20Sopenharmony_ci 63018c2ecf20Sopenharmony_ci status.card_clock = 110069313433624ULL; 63028c2ecf20Sopenharmony_ci status.master_period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 63038c2ecf20Sopenharmony_ci 63048c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 63058c2ecf20Sopenharmony_ci case MADI: 63068c2ecf20Sopenharmony_ci case MADIface: 63078c2ecf20Sopenharmony_ci status.card_specific.madi.sync_wc = 63088c2ecf20Sopenharmony_ci hdspm_wc_sync_check(hdspm); 63098c2ecf20Sopenharmony_ci status.card_specific.madi.sync_madi = 63108c2ecf20Sopenharmony_ci hdspm_madi_sync_check(hdspm); 63118c2ecf20Sopenharmony_ci status.card_specific.madi.sync_tco = 63128c2ecf20Sopenharmony_ci hdspm_tco_sync_check(hdspm); 63138c2ecf20Sopenharmony_ci status.card_specific.madi.sync_in = 63148c2ecf20Sopenharmony_ci hdspm_sync_in_sync_check(hdspm); 63158c2ecf20Sopenharmony_ci 63168c2ecf20Sopenharmony_ci statusregister = 63178c2ecf20Sopenharmony_ci hdspm_read(hdspm, HDSPM_statusRegister); 63188c2ecf20Sopenharmony_ci status.card_specific.madi.madi_input = 63198c2ecf20Sopenharmony_ci (statusregister & HDSPM_AB_int) ? 1 : 0; 63208c2ecf20Sopenharmony_ci status.card_specific.madi.channel_format = 63218c2ecf20Sopenharmony_ci (statusregister & HDSPM_RX_64ch) ? 1 : 0; 63228c2ecf20Sopenharmony_ci /* TODO: Mac driver sets it when f_s>48kHz */ 63238c2ecf20Sopenharmony_ci status.card_specific.madi.frame_format = 0; 63248c2ecf20Sopenharmony_ci 63258c2ecf20Sopenharmony_ci default: 63268c2ecf20Sopenharmony_ci break; 63278c2ecf20Sopenharmony_ci } 63288c2ecf20Sopenharmony_ci 63298c2ecf20Sopenharmony_ci if (copy_to_user(argp, &status, sizeof(status))) 63308c2ecf20Sopenharmony_ci return -EFAULT; 63318c2ecf20Sopenharmony_ci 63328c2ecf20Sopenharmony_ci 63338c2ecf20Sopenharmony_ci break; 63348c2ecf20Sopenharmony_ci 63358c2ecf20Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_VERSION: 63368c2ecf20Sopenharmony_ci memset(&hdspm_version, 0, sizeof(hdspm_version)); 63378c2ecf20Sopenharmony_ci 63388c2ecf20Sopenharmony_ci hdspm_version.card_type = hdspm->io_type; 63398c2ecf20Sopenharmony_ci strlcpy(hdspm_version.cardname, hdspm->card_name, 63408c2ecf20Sopenharmony_ci sizeof(hdspm_version.cardname)); 63418c2ecf20Sopenharmony_ci hdspm_version.serial = hdspm->serial; 63428c2ecf20Sopenharmony_ci hdspm_version.firmware_rev = hdspm->firmware_rev; 63438c2ecf20Sopenharmony_ci hdspm_version.addons = 0; 63448c2ecf20Sopenharmony_ci if (hdspm->tco) 63458c2ecf20Sopenharmony_ci hdspm_version.addons |= HDSPM_ADDON_TCO; 63468c2ecf20Sopenharmony_ci 63478c2ecf20Sopenharmony_ci if (copy_to_user(argp, &hdspm_version, 63488c2ecf20Sopenharmony_ci sizeof(hdspm_version))) 63498c2ecf20Sopenharmony_ci return -EFAULT; 63508c2ecf20Sopenharmony_ci break; 63518c2ecf20Sopenharmony_ci 63528c2ecf20Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_MIXER: 63538c2ecf20Sopenharmony_ci if (copy_from_user(&mixer, argp, sizeof(mixer))) 63548c2ecf20Sopenharmony_ci return -EFAULT; 63558c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer, 63568c2ecf20Sopenharmony_ci sizeof(*mixer.mixer))) 63578c2ecf20Sopenharmony_ci return -EFAULT; 63588c2ecf20Sopenharmony_ci break; 63598c2ecf20Sopenharmony_ci 63608c2ecf20Sopenharmony_ci default: 63618c2ecf20Sopenharmony_ci return -EINVAL; 63628c2ecf20Sopenharmony_ci } 63638c2ecf20Sopenharmony_ci return 0; 63648c2ecf20Sopenharmony_ci} 63658c2ecf20Sopenharmony_ci 63668c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_hdspm_ops = { 63678c2ecf20Sopenharmony_ci .open = snd_hdspm_open, 63688c2ecf20Sopenharmony_ci .close = snd_hdspm_release, 63698c2ecf20Sopenharmony_ci .ioctl = snd_hdspm_ioctl, 63708c2ecf20Sopenharmony_ci .hw_params = snd_hdspm_hw_params, 63718c2ecf20Sopenharmony_ci .hw_free = snd_hdspm_hw_free, 63728c2ecf20Sopenharmony_ci .prepare = snd_hdspm_prepare, 63738c2ecf20Sopenharmony_ci .trigger = snd_hdspm_trigger, 63748c2ecf20Sopenharmony_ci .pointer = snd_hdspm_hw_pointer, 63758c2ecf20Sopenharmony_ci}; 63768c2ecf20Sopenharmony_ci 63778c2ecf20Sopenharmony_cistatic int snd_hdspm_create_hwdep(struct snd_card *card, 63788c2ecf20Sopenharmony_ci struct hdspm *hdspm) 63798c2ecf20Sopenharmony_ci{ 63808c2ecf20Sopenharmony_ci struct snd_hwdep *hw; 63818c2ecf20Sopenharmony_ci int err; 63828c2ecf20Sopenharmony_ci 63838c2ecf20Sopenharmony_ci err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw); 63848c2ecf20Sopenharmony_ci if (err < 0) 63858c2ecf20Sopenharmony_ci return err; 63868c2ecf20Sopenharmony_ci 63878c2ecf20Sopenharmony_ci hdspm->hwdep = hw; 63888c2ecf20Sopenharmony_ci hw->private_data = hdspm; 63898c2ecf20Sopenharmony_ci strcpy(hw->name, "HDSPM hwdep interface"); 63908c2ecf20Sopenharmony_ci 63918c2ecf20Sopenharmony_ci hw->ops.open = snd_hdspm_hwdep_dummy_op; 63928c2ecf20Sopenharmony_ci hw->ops.ioctl = snd_hdspm_hwdep_ioctl; 63938c2ecf20Sopenharmony_ci hw->ops.ioctl_compat = snd_hdspm_hwdep_ioctl; 63948c2ecf20Sopenharmony_ci hw->ops.release = snd_hdspm_hwdep_dummy_op; 63958c2ecf20Sopenharmony_ci 63968c2ecf20Sopenharmony_ci return 0; 63978c2ecf20Sopenharmony_ci} 63988c2ecf20Sopenharmony_ci 63998c2ecf20Sopenharmony_ci 64008c2ecf20Sopenharmony_ci/*------------------------------------------------------------ 64018c2ecf20Sopenharmony_ci memory interface 64028c2ecf20Sopenharmony_ci ------------------------------------------------------------*/ 64038c2ecf20Sopenharmony_cistatic int snd_hdspm_preallocate_memory(struct hdspm *hdspm) 64048c2ecf20Sopenharmony_ci{ 64058c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 64068c2ecf20Sopenharmony_ci size_t wanted; 64078c2ecf20Sopenharmony_ci 64088c2ecf20Sopenharmony_ci pcm = hdspm->pcm; 64098c2ecf20Sopenharmony_ci 64108c2ecf20Sopenharmony_ci wanted = HDSPM_DMA_AREA_BYTES; 64118c2ecf20Sopenharmony_ci 64128c2ecf20Sopenharmony_ci snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, 64138c2ecf20Sopenharmony_ci &hdspm->pci->dev, 64148c2ecf20Sopenharmony_ci wanted, wanted); 64158c2ecf20Sopenharmony_ci dev_dbg(hdspm->card->dev, " Preallocated %zd Bytes\n", wanted); 64168c2ecf20Sopenharmony_ci return 0; 64178c2ecf20Sopenharmony_ci} 64188c2ecf20Sopenharmony_ci 64198c2ecf20Sopenharmony_ci/* Inform the card what DMA addresses to use for the indicated channel. */ 64208c2ecf20Sopenharmony_ci/* Each channel got 16 4K pages allocated for DMA transfers. */ 64218c2ecf20Sopenharmony_cistatic void hdspm_set_channel_dma_addr(struct hdspm *hdspm, 64228c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, 64238c2ecf20Sopenharmony_ci unsigned int reg, int channel) 64248c2ecf20Sopenharmony_ci{ 64258c2ecf20Sopenharmony_ci int i; 64268c2ecf20Sopenharmony_ci 64278c2ecf20Sopenharmony_ci for (i = channel * 16; i < channel * 16 + 16; i++) 64288c2ecf20Sopenharmony_ci hdspm_write(hdspm, reg + 4 * i, 64298c2ecf20Sopenharmony_ci snd_pcm_sgbuf_get_addr(substream, 4096 * i)); 64308c2ecf20Sopenharmony_ci} 64318c2ecf20Sopenharmony_ci 64328c2ecf20Sopenharmony_ci 64338c2ecf20Sopenharmony_ci/* ------------- ALSA Devices ---------------------------- */ 64348c2ecf20Sopenharmony_cistatic int snd_hdspm_create_pcm(struct snd_card *card, 64358c2ecf20Sopenharmony_ci struct hdspm *hdspm) 64368c2ecf20Sopenharmony_ci{ 64378c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 64388c2ecf20Sopenharmony_ci int err; 64398c2ecf20Sopenharmony_ci 64408c2ecf20Sopenharmony_ci err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm); 64418c2ecf20Sopenharmony_ci if (err < 0) 64428c2ecf20Sopenharmony_ci return err; 64438c2ecf20Sopenharmony_ci 64448c2ecf20Sopenharmony_ci hdspm->pcm = pcm; 64458c2ecf20Sopenharmony_ci pcm->private_data = hdspm; 64468c2ecf20Sopenharmony_ci strcpy(pcm->name, hdspm->card_name); 64478c2ecf20Sopenharmony_ci 64488c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 64498c2ecf20Sopenharmony_ci &snd_hdspm_ops); 64508c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 64518c2ecf20Sopenharmony_ci &snd_hdspm_ops); 64528c2ecf20Sopenharmony_ci 64538c2ecf20Sopenharmony_ci pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; 64548c2ecf20Sopenharmony_ci 64558c2ecf20Sopenharmony_ci err = snd_hdspm_preallocate_memory(hdspm); 64568c2ecf20Sopenharmony_ci if (err < 0) 64578c2ecf20Sopenharmony_ci return err; 64588c2ecf20Sopenharmony_ci 64598c2ecf20Sopenharmony_ci return 0; 64608c2ecf20Sopenharmony_ci} 64618c2ecf20Sopenharmony_ci 64628c2ecf20Sopenharmony_cistatic inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm) 64638c2ecf20Sopenharmony_ci{ 64648c2ecf20Sopenharmony_ci int i; 64658c2ecf20Sopenharmony_ci 64668c2ecf20Sopenharmony_ci for (i = 0; i < hdspm->midiPorts; i++) 64678c2ecf20Sopenharmony_ci snd_hdspm_flush_midi_input(hdspm, i); 64688c2ecf20Sopenharmony_ci} 64698c2ecf20Sopenharmony_ci 64708c2ecf20Sopenharmony_cistatic int snd_hdspm_create_alsa_devices(struct snd_card *card, 64718c2ecf20Sopenharmony_ci struct hdspm *hdspm) 64728c2ecf20Sopenharmony_ci{ 64738c2ecf20Sopenharmony_ci int err, i; 64748c2ecf20Sopenharmony_ci 64758c2ecf20Sopenharmony_ci dev_dbg(card->dev, "Create card...\n"); 64768c2ecf20Sopenharmony_ci err = snd_hdspm_create_pcm(card, hdspm); 64778c2ecf20Sopenharmony_ci if (err < 0) 64788c2ecf20Sopenharmony_ci return err; 64798c2ecf20Sopenharmony_ci 64808c2ecf20Sopenharmony_ci i = 0; 64818c2ecf20Sopenharmony_ci while (i < hdspm->midiPorts) { 64828c2ecf20Sopenharmony_ci err = snd_hdspm_create_midi(card, hdspm, i); 64838c2ecf20Sopenharmony_ci if (err < 0) { 64848c2ecf20Sopenharmony_ci return err; 64858c2ecf20Sopenharmony_ci } 64868c2ecf20Sopenharmony_ci i++; 64878c2ecf20Sopenharmony_ci } 64888c2ecf20Sopenharmony_ci 64898c2ecf20Sopenharmony_ci err = snd_hdspm_create_controls(card, hdspm); 64908c2ecf20Sopenharmony_ci if (err < 0) 64918c2ecf20Sopenharmony_ci return err; 64928c2ecf20Sopenharmony_ci 64938c2ecf20Sopenharmony_ci err = snd_hdspm_create_hwdep(card, hdspm); 64948c2ecf20Sopenharmony_ci if (err < 0) 64958c2ecf20Sopenharmony_ci return err; 64968c2ecf20Sopenharmony_ci 64978c2ecf20Sopenharmony_ci dev_dbg(card->dev, "proc init...\n"); 64988c2ecf20Sopenharmony_ci snd_hdspm_proc_init(hdspm); 64998c2ecf20Sopenharmony_ci 65008c2ecf20Sopenharmony_ci hdspm->system_sample_rate = -1; 65018c2ecf20Sopenharmony_ci hdspm->last_external_sample_rate = -1; 65028c2ecf20Sopenharmony_ci hdspm->last_internal_sample_rate = -1; 65038c2ecf20Sopenharmony_ci hdspm->playback_pid = -1; 65048c2ecf20Sopenharmony_ci hdspm->capture_pid = -1; 65058c2ecf20Sopenharmony_ci hdspm->capture_substream = NULL; 65068c2ecf20Sopenharmony_ci hdspm->playback_substream = NULL; 65078c2ecf20Sopenharmony_ci 65088c2ecf20Sopenharmony_ci dev_dbg(card->dev, "Set defaults...\n"); 65098c2ecf20Sopenharmony_ci err = snd_hdspm_set_defaults(hdspm); 65108c2ecf20Sopenharmony_ci if (err < 0) 65118c2ecf20Sopenharmony_ci return err; 65128c2ecf20Sopenharmony_ci 65138c2ecf20Sopenharmony_ci dev_dbg(card->dev, "Update mixer controls...\n"); 65148c2ecf20Sopenharmony_ci hdspm_update_simple_mixer_controls(hdspm); 65158c2ecf20Sopenharmony_ci 65168c2ecf20Sopenharmony_ci dev_dbg(card->dev, "Initializing complete?\n"); 65178c2ecf20Sopenharmony_ci 65188c2ecf20Sopenharmony_ci err = snd_card_register(card); 65198c2ecf20Sopenharmony_ci if (err < 0) { 65208c2ecf20Sopenharmony_ci dev_err(card->dev, "error registering card\n"); 65218c2ecf20Sopenharmony_ci return err; 65228c2ecf20Sopenharmony_ci } 65238c2ecf20Sopenharmony_ci 65248c2ecf20Sopenharmony_ci dev_dbg(card->dev, "... yes now\n"); 65258c2ecf20Sopenharmony_ci 65268c2ecf20Sopenharmony_ci return 0; 65278c2ecf20Sopenharmony_ci} 65288c2ecf20Sopenharmony_ci 65298c2ecf20Sopenharmony_cistatic int snd_hdspm_create(struct snd_card *card, 65308c2ecf20Sopenharmony_ci struct hdspm *hdspm) 65318c2ecf20Sopenharmony_ci{ 65328c2ecf20Sopenharmony_ci 65338c2ecf20Sopenharmony_ci struct pci_dev *pci = hdspm->pci; 65348c2ecf20Sopenharmony_ci int err; 65358c2ecf20Sopenharmony_ci unsigned long io_extent; 65368c2ecf20Sopenharmony_ci 65378c2ecf20Sopenharmony_ci hdspm->irq = -1; 65388c2ecf20Sopenharmony_ci hdspm->card = card; 65398c2ecf20Sopenharmony_ci 65408c2ecf20Sopenharmony_ci spin_lock_init(&hdspm->lock); 65418c2ecf20Sopenharmony_ci INIT_WORK(&hdspm->midi_work, hdspm_midi_work); 65428c2ecf20Sopenharmony_ci 65438c2ecf20Sopenharmony_ci pci_read_config_word(hdspm->pci, 65448c2ecf20Sopenharmony_ci PCI_CLASS_REVISION, &hdspm->firmware_rev); 65458c2ecf20Sopenharmony_ci 65468c2ecf20Sopenharmony_ci strcpy(card->mixername, "Xilinx FPGA"); 65478c2ecf20Sopenharmony_ci strcpy(card->driver, "HDSPM"); 65488c2ecf20Sopenharmony_ci 65498c2ecf20Sopenharmony_ci switch (hdspm->firmware_rev) { 65508c2ecf20Sopenharmony_ci case HDSPM_RAYDAT_REV: 65518c2ecf20Sopenharmony_ci hdspm->io_type = RayDAT; 65528c2ecf20Sopenharmony_ci hdspm->card_name = "RME RayDAT"; 65538c2ecf20Sopenharmony_ci hdspm->midiPorts = 2; 65548c2ecf20Sopenharmony_ci break; 65558c2ecf20Sopenharmony_ci case HDSPM_AIO_REV: 65568c2ecf20Sopenharmony_ci hdspm->io_type = AIO; 65578c2ecf20Sopenharmony_ci hdspm->card_name = "RME AIO"; 65588c2ecf20Sopenharmony_ci hdspm->midiPorts = 1; 65598c2ecf20Sopenharmony_ci break; 65608c2ecf20Sopenharmony_ci case HDSPM_MADIFACE_REV: 65618c2ecf20Sopenharmony_ci hdspm->io_type = MADIface; 65628c2ecf20Sopenharmony_ci hdspm->card_name = "RME MADIface"; 65638c2ecf20Sopenharmony_ci hdspm->midiPorts = 1; 65648c2ecf20Sopenharmony_ci break; 65658c2ecf20Sopenharmony_ci default: 65668c2ecf20Sopenharmony_ci if ((hdspm->firmware_rev == 0xf0) || 65678c2ecf20Sopenharmony_ci ((hdspm->firmware_rev >= 0xe6) && 65688c2ecf20Sopenharmony_ci (hdspm->firmware_rev <= 0xea))) { 65698c2ecf20Sopenharmony_ci hdspm->io_type = AES32; 65708c2ecf20Sopenharmony_ci hdspm->card_name = "RME AES32"; 65718c2ecf20Sopenharmony_ci hdspm->midiPorts = 2; 65728c2ecf20Sopenharmony_ci } else if ((hdspm->firmware_rev == 0xd2) || 65738c2ecf20Sopenharmony_ci ((hdspm->firmware_rev >= 0xc8) && 65748c2ecf20Sopenharmony_ci (hdspm->firmware_rev <= 0xcf))) { 65758c2ecf20Sopenharmony_ci hdspm->io_type = MADI; 65768c2ecf20Sopenharmony_ci hdspm->card_name = "RME MADI"; 65778c2ecf20Sopenharmony_ci hdspm->midiPorts = 3; 65788c2ecf20Sopenharmony_ci } else { 65798c2ecf20Sopenharmony_ci dev_err(card->dev, 65808c2ecf20Sopenharmony_ci "unknown firmware revision %x\n", 65818c2ecf20Sopenharmony_ci hdspm->firmware_rev); 65828c2ecf20Sopenharmony_ci return -ENODEV; 65838c2ecf20Sopenharmony_ci } 65848c2ecf20Sopenharmony_ci } 65858c2ecf20Sopenharmony_ci 65868c2ecf20Sopenharmony_ci err = pci_enable_device(pci); 65878c2ecf20Sopenharmony_ci if (err < 0) 65888c2ecf20Sopenharmony_ci return err; 65898c2ecf20Sopenharmony_ci 65908c2ecf20Sopenharmony_ci pci_set_master(hdspm->pci); 65918c2ecf20Sopenharmony_ci 65928c2ecf20Sopenharmony_ci err = pci_request_regions(pci, "hdspm"); 65938c2ecf20Sopenharmony_ci if (err < 0) 65948c2ecf20Sopenharmony_ci return err; 65958c2ecf20Sopenharmony_ci 65968c2ecf20Sopenharmony_ci hdspm->port = pci_resource_start(pci, 0); 65978c2ecf20Sopenharmony_ci io_extent = pci_resource_len(pci, 0); 65988c2ecf20Sopenharmony_ci 65998c2ecf20Sopenharmony_ci dev_dbg(card->dev, "grabbed memory region 0x%lx-0x%lx\n", 66008c2ecf20Sopenharmony_ci hdspm->port, hdspm->port + io_extent - 1); 66018c2ecf20Sopenharmony_ci 66028c2ecf20Sopenharmony_ci hdspm->iobase = ioremap(hdspm->port, io_extent); 66038c2ecf20Sopenharmony_ci if (!hdspm->iobase) { 66048c2ecf20Sopenharmony_ci dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n", 66058c2ecf20Sopenharmony_ci hdspm->port, hdspm->port + io_extent - 1); 66068c2ecf20Sopenharmony_ci return -EBUSY; 66078c2ecf20Sopenharmony_ci } 66088c2ecf20Sopenharmony_ci dev_dbg(card->dev, "remapped region (0x%lx) 0x%lx-0x%lx\n", 66098c2ecf20Sopenharmony_ci (unsigned long)hdspm->iobase, hdspm->port, 66108c2ecf20Sopenharmony_ci hdspm->port + io_extent - 1); 66118c2ecf20Sopenharmony_ci 66128c2ecf20Sopenharmony_ci if (request_irq(pci->irq, snd_hdspm_interrupt, 66138c2ecf20Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, hdspm)) { 66148c2ecf20Sopenharmony_ci dev_err(card->dev, "unable to use IRQ %d\n", pci->irq); 66158c2ecf20Sopenharmony_ci return -EBUSY; 66168c2ecf20Sopenharmony_ci } 66178c2ecf20Sopenharmony_ci 66188c2ecf20Sopenharmony_ci dev_dbg(card->dev, "use IRQ %d\n", pci->irq); 66198c2ecf20Sopenharmony_ci 66208c2ecf20Sopenharmony_ci hdspm->irq = pci->irq; 66218c2ecf20Sopenharmony_ci card->sync_irq = hdspm->irq; 66228c2ecf20Sopenharmony_ci 66238c2ecf20Sopenharmony_ci dev_dbg(card->dev, "kmalloc Mixer memory of %zd Bytes\n", 66248c2ecf20Sopenharmony_ci sizeof(*hdspm->mixer)); 66258c2ecf20Sopenharmony_ci hdspm->mixer = kzalloc(sizeof(*hdspm->mixer), GFP_KERNEL); 66268c2ecf20Sopenharmony_ci if (!hdspm->mixer) 66278c2ecf20Sopenharmony_ci return -ENOMEM; 66288c2ecf20Sopenharmony_ci 66298c2ecf20Sopenharmony_ci hdspm->port_names_in = NULL; 66308c2ecf20Sopenharmony_ci hdspm->port_names_out = NULL; 66318c2ecf20Sopenharmony_ci 66328c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 66338c2ecf20Sopenharmony_ci case AES32: 66348c2ecf20Sopenharmony_ci hdspm->ss_in_channels = hdspm->ss_out_channels = AES32_CHANNELS; 66358c2ecf20Sopenharmony_ci hdspm->ds_in_channels = hdspm->ds_out_channels = AES32_CHANNELS; 66368c2ecf20Sopenharmony_ci hdspm->qs_in_channels = hdspm->qs_out_channels = AES32_CHANNELS; 66378c2ecf20Sopenharmony_ci 66388c2ecf20Sopenharmony_ci hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 66398c2ecf20Sopenharmony_ci channel_map_aes32; 66408c2ecf20Sopenharmony_ci hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 66418c2ecf20Sopenharmony_ci channel_map_aes32; 66428c2ecf20Sopenharmony_ci hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 66438c2ecf20Sopenharmony_ci channel_map_aes32; 66448c2ecf20Sopenharmony_ci hdspm->port_names_in_ss = hdspm->port_names_out_ss = 66458c2ecf20Sopenharmony_ci texts_ports_aes32; 66468c2ecf20Sopenharmony_ci hdspm->port_names_in_ds = hdspm->port_names_out_ds = 66478c2ecf20Sopenharmony_ci texts_ports_aes32; 66488c2ecf20Sopenharmony_ci hdspm->port_names_in_qs = hdspm->port_names_out_qs = 66498c2ecf20Sopenharmony_ci texts_ports_aes32; 66508c2ecf20Sopenharmony_ci 66518c2ecf20Sopenharmony_ci hdspm->max_channels_out = hdspm->max_channels_in = 66528c2ecf20Sopenharmony_ci AES32_CHANNELS; 66538c2ecf20Sopenharmony_ci hdspm->port_names_in = hdspm->port_names_out = 66548c2ecf20Sopenharmony_ci texts_ports_aes32; 66558c2ecf20Sopenharmony_ci hdspm->channel_map_in = hdspm->channel_map_out = 66568c2ecf20Sopenharmony_ci channel_map_aes32; 66578c2ecf20Sopenharmony_ci 66588c2ecf20Sopenharmony_ci break; 66598c2ecf20Sopenharmony_ci 66608c2ecf20Sopenharmony_ci case MADI: 66618c2ecf20Sopenharmony_ci case MADIface: 66628c2ecf20Sopenharmony_ci hdspm->ss_in_channels = hdspm->ss_out_channels = 66638c2ecf20Sopenharmony_ci MADI_SS_CHANNELS; 66648c2ecf20Sopenharmony_ci hdspm->ds_in_channels = hdspm->ds_out_channels = 66658c2ecf20Sopenharmony_ci MADI_DS_CHANNELS; 66668c2ecf20Sopenharmony_ci hdspm->qs_in_channels = hdspm->qs_out_channels = 66678c2ecf20Sopenharmony_ci MADI_QS_CHANNELS; 66688c2ecf20Sopenharmony_ci 66698c2ecf20Sopenharmony_ci hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 66708c2ecf20Sopenharmony_ci channel_map_unity_ss; 66718c2ecf20Sopenharmony_ci hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 66728c2ecf20Sopenharmony_ci channel_map_unity_ss; 66738c2ecf20Sopenharmony_ci hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 66748c2ecf20Sopenharmony_ci channel_map_unity_ss; 66758c2ecf20Sopenharmony_ci 66768c2ecf20Sopenharmony_ci hdspm->port_names_in_ss = hdspm->port_names_out_ss = 66778c2ecf20Sopenharmony_ci texts_ports_madi; 66788c2ecf20Sopenharmony_ci hdspm->port_names_in_ds = hdspm->port_names_out_ds = 66798c2ecf20Sopenharmony_ci texts_ports_madi; 66808c2ecf20Sopenharmony_ci hdspm->port_names_in_qs = hdspm->port_names_out_qs = 66818c2ecf20Sopenharmony_ci texts_ports_madi; 66828c2ecf20Sopenharmony_ci break; 66838c2ecf20Sopenharmony_ci 66848c2ecf20Sopenharmony_ci case AIO: 66858c2ecf20Sopenharmony_ci hdspm->ss_in_channels = AIO_IN_SS_CHANNELS; 66868c2ecf20Sopenharmony_ci hdspm->ds_in_channels = AIO_IN_DS_CHANNELS; 66878c2ecf20Sopenharmony_ci hdspm->qs_in_channels = AIO_IN_QS_CHANNELS; 66888c2ecf20Sopenharmony_ci hdspm->ss_out_channels = AIO_OUT_SS_CHANNELS; 66898c2ecf20Sopenharmony_ci hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS; 66908c2ecf20Sopenharmony_ci hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS; 66918c2ecf20Sopenharmony_ci 66928c2ecf20Sopenharmony_ci if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { 66938c2ecf20Sopenharmony_ci dev_info(card->dev, "AEB input board found\n"); 66948c2ecf20Sopenharmony_ci hdspm->ss_in_channels += 4; 66958c2ecf20Sopenharmony_ci hdspm->ds_in_channels += 4; 66968c2ecf20Sopenharmony_ci hdspm->qs_in_channels += 4; 66978c2ecf20Sopenharmony_ci } 66988c2ecf20Sopenharmony_ci 66998c2ecf20Sopenharmony_ci if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) { 67008c2ecf20Sopenharmony_ci dev_info(card->dev, "AEB output board found\n"); 67018c2ecf20Sopenharmony_ci hdspm->ss_out_channels += 4; 67028c2ecf20Sopenharmony_ci hdspm->ds_out_channels += 4; 67038c2ecf20Sopenharmony_ci hdspm->qs_out_channels += 4; 67048c2ecf20Sopenharmony_ci } 67058c2ecf20Sopenharmony_ci 67068c2ecf20Sopenharmony_ci hdspm->channel_map_out_ss = channel_map_aio_out_ss; 67078c2ecf20Sopenharmony_ci hdspm->channel_map_out_ds = channel_map_aio_out_ds; 67088c2ecf20Sopenharmony_ci hdspm->channel_map_out_qs = channel_map_aio_out_qs; 67098c2ecf20Sopenharmony_ci 67108c2ecf20Sopenharmony_ci hdspm->channel_map_in_ss = channel_map_aio_in_ss; 67118c2ecf20Sopenharmony_ci hdspm->channel_map_in_ds = channel_map_aio_in_ds; 67128c2ecf20Sopenharmony_ci hdspm->channel_map_in_qs = channel_map_aio_in_qs; 67138c2ecf20Sopenharmony_ci 67148c2ecf20Sopenharmony_ci hdspm->port_names_in_ss = texts_ports_aio_in_ss; 67158c2ecf20Sopenharmony_ci hdspm->port_names_out_ss = texts_ports_aio_out_ss; 67168c2ecf20Sopenharmony_ci hdspm->port_names_in_ds = texts_ports_aio_in_ds; 67178c2ecf20Sopenharmony_ci hdspm->port_names_out_ds = texts_ports_aio_out_ds; 67188c2ecf20Sopenharmony_ci hdspm->port_names_in_qs = texts_ports_aio_in_qs; 67198c2ecf20Sopenharmony_ci hdspm->port_names_out_qs = texts_ports_aio_out_qs; 67208c2ecf20Sopenharmony_ci 67218c2ecf20Sopenharmony_ci break; 67228c2ecf20Sopenharmony_ci 67238c2ecf20Sopenharmony_ci case RayDAT: 67248c2ecf20Sopenharmony_ci hdspm->ss_in_channels = hdspm->ss_out_channels = 67258c2ecf20Sopenharmony_ci RAYDAT_SS_CHANNELS; 67268c2ecf20Sopenharmony_ci hdspm->ds_in_channels = hdspm->ds_out_channels = 67278c2ecf20Sopenharmony_ci RAYDAT_DS_CHANNELS; 67288c2ecf20Sopenharmony_ci hdspm->qs_in_channels = hdspm->qs_out_channels = 67298c2ecf20Sopenharmony_ci RAYDAT_QS_CHANNELS; 67308c2ecf20Sopenharmony_ci 67318c2ecf20Sopenharmony_ci hdspm->max_channels_in = RAYDAT_SS_CHANNELS; 67328c2ecf20Sopenharmony_ci hdspm->max_channels_out = RAYDAT_SS_CHANNELS; 67338c2ecf20Sopenharmony_ci 67348c2ecf20Sopenharmony_ci hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 67358c2ecf20Sopenharmony_ci channel_map_raydat_ss; 67368c2ecf20Sopenharmony_ci hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 67378c2ecf20Sopenharmony_ci channel_map_raydat_ds; 67388c2ecf20Sopenharmony_ci hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 67398c2ecf20Sopenharmony_ci channel_map_raydat_qs; 67408c2ecf20Sopenharmony_ci hdspm->channel_map_in = hdspm->channel_map_out = 67418c2ecf20Sopenharmony_ci channel_map_raydat_ss; 67428c2ecf20Sopenharmony_ci 67438c2ecf20Sopenharmony_ci hdspm->port_names_in_ss = hdspm->port_names_out_ss = 67448c2ecf20Sopenharmony_ci texts_ports_raydat_ss; 67458c2ecf20Sopenharmony_ci hdspm->port_names_in_ds = hdspm->port_names_out_ds = 67468c2ecf20Sopenharmony_ci texts_ports_raydat_ds; 67478c2ecf20Sopenharmony_ci hdspm->port_names_in_qs = hdspm->port_names_out_qs = 67488c2ecf20Sopenharmony_ci texts_ports_raydat_qs; 67498c2ecf20Sopenharmony_ci 67508c2ecf20Sopenharmony_ci 67518c2ecf20Sopenharmony_ci break; 67528c2ecf20Sopenharmony_ci 67538c2ecf20Sopenharmony_ci } 67548c2ecf20Sopenharmony_ci 67558c2ecf20Sopenharmony_ci /* TCO detection */ 67568c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 67578c2ecf20Sopenharmony_ci case AIO: 67588c2ecf20Sopenharmony_ci case RayDAT: 67598c2ecf20Sopenharmony_ci if (hdspm_read(hdspm, HDSPM_statusRegister2) & 67608c2ecf20Sopenharmony_ci HDSPM_s2_tco_detect) { 67618c2ecf20Sopenharmony_ci hdspm->midiPorts++; 67628c2ecf20Sopenharmony_ci hdspm->tco = kzalloc(sizeof(*hdspm->tco), GFP_KERNEL); 67638c2ecf20Sopenharmony_ci if (hdspm->tco) 67648c2ecf20Sopenharmony_ci hdspm_tco_write(hdspm); 67658c2ecf20Sopenharmony_ci 67668c2ecf20Sopenharmony_ci dev_info(card->dev, "AIO/RayDAT TCO module found\n"); 67678c2ecf20Sopenharmony_ci } else { 67688c2ecf20Sopenharmony_ci hdspm->tco = NULL; 67698c2ecf20Sopenharmony_ci } 67708c2ecf20Sopenharmony_ci break; 67718c2ecf20Sopenharmony_ci 67728c2ecf20Sopenharmony_ci case MADI: 67738c2ecf20Sopenharmony_ci case AES32: 67748c2ecf20Sopenharmony_ci if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) { 67758c2ecf20Sopenharmony_ci hdspm->midiPorts++; 67768c2ecf20Sopenharmony_ci hdspm->tco = kzalloc(sizeof(*hdspm->tco), GFP_KERNEL); 67778c2ecf20Sopenharmony_ci if (hdspm->tco) 67788c2ecf20Sopenharmony_ci hdspm_tco_write(hdspm); 67798c2ecf20Sopenharmony_ci 67808c2ecf20Sopenharmony_ci dev_info(card->dev, "MADI/AES TCO module found\n"); 67818c2ecf20Sopenharmony_ci } else { 67828c2ecf20Sopenharmony_ci hdspm->tco = NULL; 67838c2ecf20Sopenharmony_ci } 67848c2ecf20Sopenharmony_ci break; 67858c2ecf20Sopenharmony_ci 67868c2ecf20Sopenharmony_ci default: 67878c2ecf20Sopenharmony_ci hdspm->tco = NULL; 67888c2ecf20Sopenharmony_ci } 67898c2ecf20Sopenharmony_ci 67908c2ecf20Sopenharmony_ci /* texts */ 67918c2ecf20Sopenharmony_ci switch (hdspm->io_type) { 67928c2ecf20Sopenharmony_ci case AES32: 67938c2ecf20Sopenharmony_ci if (hdspm->tco) { 67948c2ecf20Sopenharmony_ci hdspm->texts_autosync = texts_autosync_aes_tco; 67958c2ecf20Sopenharmony_ci hdspm->texts_autosync_items = 67968c2ecf20Sopenharmony_ci ARRAY_SIZE(texts_autosync_aes_tco); 67978c2ecf20Sopenharmony_ci } else { 67988c2ecf20Sopenharmony_ci hdspm->texts_autosync = texts_autosync_aes; 67998c2ecf20Sopenharmony_ci hdspm->texts_autosync_items = 68008c2ecf20Sopenharmony_ci ARRAY_SIZE(texts_autosync_aes); 68018c2ecf20Sopenharmony_ci } 68028c2ecf20Sopenharmony_ci break; 68038c2ecf20Sopenharmony_ci 68048c2ecf20Sopenharmony_ci case MADI: 68058c2ecf20Sopenharmony_ci if (hdspm->tco) { 68068c2ecf20Sopenharmony_ci hdspm->texts_autosync = texts_autosync_madi_tco; 68078c2ecf20Sopenharmony_ci hdspm->texts_autosync_items = 4; 68088c2ecf20Sopenharmony_ci } else { 68098c2ecf20Sopenharmony_ci hdspm->texts_autosync = texts_autosync_madi; 68108c2ecf20Sopenharmony_ci hdspm->texts_autosync_items = 3; 68118c2ecf20Sopenharmony_ci } 68128c2ecf20Sopenharmony_ci break; 68138c2ecf20Sopenharmony_ci 68148c2ecf20Sopenharmony_ci case MADIface: 68158c2ecf20Sopenharmony_ci 68168c2ecf20Sopenharmony_ci break; 68178c2ecf20Sopenharmony_ci 68188c2ecf20Sopenharmony_ci case RayDAT: 68198c2ecf20Sopenharmony_ci if (hdspm->tco) { 68208c2ecf20Sopenharmony_ci hdspm->texts_autosync = texts_autosync_raydat_tco; 68218c2ecf20Sopenharmony_ci hdspm->texts_autosync_items = 9; 68228c2ecf20Sopenharmony_ci } else { 68238c2ecf20Sopenharmony_ci hdspm->texts_autosync = texts_autosync_raydat; 68248c2ecf20Sopenharmony_ci hdspm->texts_autosync_items = 8; 68258c2ecf20Sopenharmony_ci } 68268c2ecf20Sopenharmony_ci break; 68278c2ecf20Sopenharmony_ci 68288c2ecf20Sopenharmony_ci case AIO: 68298c2ecf20Sopenharmony_ci if (hdspm->tco) { 68308c2ecf20Sopenharmony_ci hdspm->texts_autosync = texts_autosync_aio_tco; 68318c2ecf20Sopenharmony_ci hdspm->texts_autosync_items = 6; 68328c2ecf20Sopenharmony_ci } else { 68338c2ecf20Sopenharmony_ci hdspm->texts_autosync = texts_autosync_aio; 68348c2ecf20Sopenharmony_ci hdspm->texts_autosync_items = 5; 68358c2ecf20Sopenharmony_ci } 68368c2ecf20Sopenharmony_ci break; 68378c2ecf20Sopenharmony_ci 68388c2ecf20Sopenharmony_ci } 68398c2ecf20Sopenharmony_ci 68408c2ecf20Sopenharmony_ci if (hdspm->io_type != MADIface) { 68418c2ecf20Sopenharmony_ci hdspm->serial = (hdspm_read(hdspm, 68428c2ecf20Sopenharmony_ci HDSPM_midiStatusIn0)>>8) & 0xFFFFFF; 68438c2ecf20Sopenharmony_ci /* id contains either a user-provided value or the default 68448c2ecf20Sopenharmony_ci * NULL. If it's the default, we're safe to 68458c2ecf20Sopenharmony_ci * fill card->id with the serial number. 68468c2ecf20Sopenharmony_ci * 68478c2ecf20Sopenharmony_ci * If the serial number is 0xFFFFFF, then we're dealing with 68488c2ecf20Sopenharmony_ci * an old PCI revision that comes without a sane number. In 68498c2ecf20Sopenharmony_ci * this case, we don't set card->id to avoid collisions 68508c2ecf20Sopenharmony_ci * when running with multiple cards. 68518c2ecf20Sopenharmony_ci */ 68528c2ecf20Sopenharmony_ci if (!id[hdspm->dev] && hdspm->serial != 0xFFFFFF) { 68538c2ecf20Sopenharmony_ci snprintf(card->id, sizeof(card->id), 68548c2ecf20Sopenharmony_ci "HDSPMx%06x", hdspm->serial); 68558c2ecf20Sopenharmony_ci snd_card_set_id(card, card->id); 68568c2ecf20Sopenharmony_ci } 68578c2ecf20Sopenharmony_ci } 68588c2ecf20Sopenharmony_ci 68598c2ecf20Sopenharmony_ci dev_dbg(card->dev, "create alsa devices.\n"); 68608c2ecf20Sopenharmony_ci err = snd_hdspm_create_alsa_devices(card, hdspm); 68618c2ecf20Sopenharmony_ci if (err < 0) 68628c2ecf20Sopenharmony_ci return err; 68638c2ecf20Sopenharmony_ci 68648c2ecf20Sopenharmony_ci snd_hdspm_initialize_midi_flush(hdspm); 68658c2ecf20Sopenharmony_ci 68668c2ecf20Sopenharmony_ci return 0; 68678c2ecf20Sopenharmony_ci} 68688c2ecf20Sopenharmony_ci 68698c2ecf20Sopenharmony_ci 68708c2ecf20Sopenharmony_cistatic int snd_hdspm_free(struct hdspm * hdspm) 68718c2ecf20Sopenharmony_ci{ 68728c2ecf20Sopenharmony_ci 68738c2ecf20Sopenharmony_ci if (hdspm->port) { 68748c2ecf20Sopenharmony_ci cancel_work_sync(&hdspm->midi_work); 68758c2ecf20Sopenharmony_ci 68768c2ecf20Sopenharmony_ci /* stop th audio, and cancel all interrupts */ 68778c2ecf20Sopenharmony_ci hdspm->control_register &= 68788c2ecf20Sopenharmony_ci ~(HDSPM_Start | HDSPM_AudioInterruptEnable | 68798c2ecf20Sopenharmony_ci HDSPM_Midi0InterruptEnable | HDSPM_Midi1InterruptEnable | 68808c2ecf20Sopenharmony_ci HDSPM_Midi2InterruptEnable | HDSPM_Midi3InterruptEnable); 68818c2ecf20Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, 68828c2ecf20Sopenharmony_ci hdspm->control_register); 68838c2ecf20Sopenharmony_ci } 68848c2ecf20Sopenharmony_ci 68858c2ecf20Sopenharmony_ci if (hdspm->irq >= 0) 68868c2ecf20Sopenharmony_ci free_irq(hdspm->irq, (void *) hdspm); 68878c2ecf20Sopenharmony_ci 68888c2ecf20Sopenharmony_ci kfree(hdspm->mixer); 68898c2ecf20Sopenharmony_ci iounmap(hdspm->iobase); 68908c2ecf20Sopenharmony_ci 68918c2ecf20Sopenharmony_ci if (hdspm->port) 68928c2ecf20Sopenharmony_ci pci_release_regions(hdspm->pci); 68938c2ecf20Sopenharmony_ci 68948c2ecf20Sopenharmony_ci if (pci_is_enabled(hdspm->pci)) 68958c2ecf20Sopenharmony_ci pci_disable_device(hdspm->pci); 68968c2ecf20Sopenharmony_ci return 0; 68978c2ecf20Sopenharmony_ci} 68988c2ecf20Sopenharmony_ci 68998c2ecf20Sopenharmony_ci 69008c2ecf20Sopenharmony_cistatic void snd_hdspm_card_free(struct snd_card *card) 69018c2ecf20Sopenharmony_ci{ 69028c2ecf20Sopenharmony_ci struct hdspm *hdspm = card->private_data; 69038c2ecf20Sopenharmony_ci 69048c2ecf20Sopenharmony_ci if (hdspm) 69058c2ecf20Sopenharmony_ci snd_hdspm_free(hdspm); 69068c2ecf20Sopenharmony_ci} 69078c2ecf20Sopenharmony_ci 69088c2ecf20Sopenharmony_ci 69098c2ecf20Sopenharmony_cistatic int snd_hdspm_probe(struct pci_dev *pci, 69108c2ecf20Sopenharmony_ci const struct pci_device_id *pci_id) 69118c2ecf20Sopenharmony_ci{ 69128c2ecf20Sopenharmony_ci static int dev; 69138c2ecf20Sopenharmony_ci struct hdspm *hdspm; 69148c2ecf20Sopenharmony_ci struct snd_card *card; 69158c2ecf20Sopenharmony_ci int err; 69168c2ecf20Sopenharmony_ci 69178c2ecf20Sopenharmony_ci if (dev >= SNDRV_CARDS) 69188c2ecf20Sopenharmony_ci return -ENODEV; 69198c2ecf20Sopenharmony_ci if (!enable[dev]) { 69208c2ecf20Sopenharmony_ci dev++; 69218c2ecf20Sopenharmony_ci return -ENOENT; 69228c2ecf20Sopenharmony_ci } 69238c2ecf20Sopenharmony_ci 69248c2ecf20Sopenharmony_ci err = snd_card_new(&pci->dev, index[dev], id[dev], 69258c2ecf20Sopenharmony_ci THIS_MODULE, sizeof(*hdspm), &card); 69268c2ecf20Sopenharmony_ci if (err < 0) 69278c2ecf20Sopenharmony_ci return err; 69288c2ecf20Sopenharmony_ci 69298c2ecf20Sopenharmony_ci hdspm = card->private_data; 69308c2ecf20Sopenharmony_ci card->private_free = snd_hdspm_card_free; 69318c2ecf20Sopenharmony_ci hdspm->dev = dev; 69328c2ecf20Sopenharmony_ci hdspm->pci = pci; 69338c2ecf20Sopenharmony_ci 69348c2ecf20Sopenharmony_ci err = snd_hdspm_create(card, hdspm); 69358c2ecf20Sopenharmony_ci if (err < 0) 69368c2ecf20Sopenharmony_ci goto free_card; 69378c2ecf20Sopenharmony_ci 69388c2ecf20Sopenharmony_ci if (hdspm->io_type != MADIface) { 69398c2ecf20Sopenharmony_ci snprintf(card->shortname, sizeof(card->shortname), "%s_%x", 69408c2ecf20Sopenharmony_ci hdspm->card_name, hdspm->serial); 69418c2ecf20Sopenharmony_ci snprintf(card->longname, sizeof(card->longname), 69428c2ecf20Sopenharmony_ci "%s S/N 0x%x at 0x%lx, irq %d", 69438c2ecf20Sopenharmony_ci hdspm->card_name, hdspm->serial, 69448c2ecf20Sopenharmony_ci hdspm->port, hdspm->irq); 69458c2ecf20Sopenharmony_ci } else { 69468c2ecf20Sopenharmony_ci snprintf(card->shortname, sizeof(card->shortname), "%s", 69478c2ecf20Sopenharmony_ci hdspm->card_name); 69488c2ecf20Sopenharmony_ci snprintf(card->longname, sizeof(card->longname), 69498c2ecf20Sopenharmony_ci "%s at 0x%lx, irq %d", 69508c2ecf20Sopenharmony_ci hdspm->card_name, hdspm->port, hdspm->irq); 69518c2ecf20Sopenharmony_ci } 69528c2ecf20Sopenharmony_ci 69538c2ecf20Sopenharmony_ci err = snd_card_register(card); 69548c2ecf20Sopenharmony_ci if (err < 0) 69558c2ecf20Sopenharmony_ci goto free_card; 69568c2ecf20Sopenharmony_ci 69578c2ecf20Sopenharmony_ci pci_set_drvdata(pci, card); 69588c2ecf20Sopenharmony_ci 69598c2ecf20Sopenharmony_ci dev++; 69608c2ecf20Sopenharmony_ci return 0; 69618c2ecf20Sopenharmony_ci 69628c2ecf20Sopenharmony_cifree_card: 69638c2ecf20Sopenharmony_ci snd_card_free(card); 69648c2ecf20Sopenharmony_ci return err; 69658c2ecf20Sopenharmony_ci} 69668c2ecf20Sopenharmony_ci 69678c2ecf20Sopenharmony_cistatic void snd_hdspm_remove(struct pci_dev *pci) 69688c2ecf20Sopenharmony_ci{ 69698c2ecf20Sopenharmony_ci snd_card_free(pci_get_drvdata(pci)); 69708c2ecf20Sopenharmony_ci} 69718c2ecf20Sopenharmony_ci 69728c2ecf20Sopenharmony_cistatic struct pci_driver hdspm_driver = { 69738c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 69748c2ecf20Sopenharmony_ci .id_table = snd_hdspm_ids, 69758c2ecf20Sopenharmony_ci .probe = snd_hdspm_probe, 69768c2ecf20Sopenharmony_ci .remove = snd_hdspm_remove, 69778c2ecf20Sopenharmony_ci}; 69788c2ecf20Sopenharmony_ci 69798c2ecf20Sopenharmony_cimodule_pci_driver(hdspm_driver); 6980