1ef5fa1a4STakashi Iwai /* 2763f356cSTakashi Iwai * ALSA driver for RME Hammerfall DSP MADI audio interface(s) 3763f356cSTakashi Iwai * 4763f356cSTakashi Iwai * Copyright (c) 2003 Winfried Ritsch (IEM) 5763f356cSTakashi Iwai * code based on hdsp.c Paul Davis 6763f356cSTakashi Iwai * Marcus Andersson 7763f356cSTakashi Iwai * Thomas Charbonnel 83cee5a60SRemy Bruno * Modified 2006-06-01 for AES32 support by Remy Bruno 93cee5a60SRemy Bruno * <remy.bruno@trinnov.com> 10763f356cSTakashi Iwai * 110dca1793SAdrian Knoth * Modified 2009-04-13 for proper metering by Florian Faber 120dca1793SAdrian Knoth * <faber@faberman.de> 130dca1793SAdrian Knoth * 140dca1793SAdrian Knoth * Modified 2009-04-14 for native float support by Florian Faber 150dca1793SAdrian Knoth * <faber@faberman.de> 160dca1793SAdrian Knoth * 170dca1793SAdrian Knoth * Modified 2009-04-26 fixed bug in rms metering by Florian Faber 180dca1793SAdrian Knoth * <faber@faberman.de> 190dca1793SAdrian Knoth * 200dca1793SAdrian Knoth * Modified 2009-04-30 added hw serial number support by Florian Faber 210dca1793SAdrian Knoth * 220dca1793SAdrian Knoth * Modified 2011-01-14 added S/PDIF input on RayDATs by Adrian Knoth 230dca1793SAdrian Knoth * 240dca1793SAdrian Knoth * Modified 2011-01-25 variable period sizes on RayDAT/AIO by Adrian Knoth 250dca1793SAdrian Knoth * 26763f356cSTakashi Iwai * This program is free software; you can redistribute it and/or modify 27763f356cSTakashi Iwai * it under the terms of the GNU General Public License as published by 28763f356cSTakashi Iwai * the Free Software Foundation; either version 2 of the License, or 29763f356cSTakashi Iwai * (at your option) any later version. 30763f356cSTakashi Iwai * 31763f356cSTakashi Iwai * This program is distributed in the hope that it will be useful, 32763f356cSTakashi Iwai * but WITHOUT ANY WARRANTY; without even the implied warranty of 33763f356cSTakashi Iwai * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 34763f356cSTakashi Iwai * GNU General Public License for more details. 35763f356cSTakashi Iwai * 36763f356cSTakashi Iwai * You should have received a copy of the GNU General Public License 37763f356cSTakashi Iwai * along with this program; if not, write to the Free Software 38763f356cSTakashi Iwai * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 39763f356cSTakashi Iwai * 40763f356cSTakashi Iwai */ 41*69358fcaSMartin Dausel 42*69358fcaSMartin Dausel /* ************* Register Documentation ******************************************************* 43*69358fcaSMartin Dausel * 44*69358fcaSMartin Dausel * Work in progress! Documentation is based on the code in this file. 45*69358fcaSMartin Dausel * 46*69358fcaSMartin Dausel * --------- HDSPM_controlRegister --------- 47*69358fcaSMartin Dausel * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte 48*69358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||: 49*69358fcaSMartin Dausel * :3322.2222:2222.1111:1111.1100:0000.0000: bit number 50*69358fcaSMartin Dausel * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 51*69358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||: 52*69358fcaSMartin Dausel * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit 53*69358fcaSMartin Dausel * : . : . : . : x . : HDSPM_AudioInterruptEnable \_ setting both bits 54*69358fcaSMartin Dausel * : . : . : . : . x: HDSPM_Start / enables audio IO 55*69358fcaSMartin Dausel * : . : . : . : x. : HDSPM_ClockModeMaster - 1: Master, 0: Slave 56*69358fcaSMartin Dausel * : . : . : . : .210 : HDSPM_LatencyMask - 3 Bit value for latency 57*69358fcaSMartin Dausel * : . : . : . : . : 0:64, 1:128, 2:256, 3:512, 58*69358fcaSMartin Dausel * : . : . : . : . : 4:1024, 5:2048, 6:4096, 7:8192 59*69358fcaSMartin Dausel * :x . : . : . x:xx . : HDSPM_FrequencyMask 60*69358fcaSMartin Dausel * : . : . : . :10 . : HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=?? 61*69358fcaSMartin Dausel * : . : . : . x: . : <MADI> HDSPM_DoubleSpeed 62*69358fcaSMartin Dausel * :x . : . : . : . : <MADI> HDSPM_QuadSpeed 63*69358fcaSMartin Dausel * : . 3 : . 10: 2 . : . : HDSPM_SyncRefMask : 64*69358fcaSMartin Dausel * : . : . x: . : . : HDSPM_SyncRef0 65*69358fcaSMartin Dausel * : . : . x : . : . : HDSPM_SyncRef1 66*69358fcaSMartin Dausel * : . : . : x . : . : <AES32> HDSPM_SyncRef2 67*69358fcaSMartin Dausel * : . x : . : . : . : <AES32> HDSPM_SyncRef3 68*69358fcaSMartin Dausel * : . : . 10: . : . : <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn 69*69358fcaSMartin Dausel * : . 3 : . 10: 2 . : . : <AES32> 0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn? 70*69358fcaSMartin Dausel * : . x : . : . : . : <MADIe> HDSPe_FLOAT_FORMAT 71*69358fcaSMartin Dausel * : . : . : x . : . : <MADI> HDSPM_InputSelect0 : 0=optical,1=coax 72*69358fcaSMartin Dausel * : . : . :x . : . : <MADI> HDSPM_InputSelect1 73*69358fcaSMartin Dausel * : . : .x : . : . : <MADI> HDSPM_clr_tms 74*69358fcaSMartin Dausel * : . : . : . x : . : <MADI> HDSPM_TX_64ch 75*69358fcaSMartin Dausel * : . : . : . x : . : <AES32> HDSPM_Emphasis 76*69358fcaSMartin Dausel * : . : . : .x : . : <MADI> HDSPM_AutoInp 77*69358fcaSMartin Dausel * : . : . x : . : . : <MADI> HDSPM_SMUX 78*69358fcaSMartin Dausel * : . : .x : . : . : <MADI> HDSPM_clr_tms 79*69358fcaSMartin Dausel * : . : x. : . : . : <MADI> HDSPM_taxi_reset 80*69358fcaSMartin Dausel * : . x: . : . : . : <MADI> HDSPM_LineOut 81*69358fcaSMartin Dausel * : . x: . : . : . : <AES32> ?????????????????? 82*69358fcaSMartin Dausel * : . : x. : . : . : <AES32> HDSPM_WCK48 83*69358fcaSMartin Dausel * : . : . : .x : . : <AES32> HDSPM_Dolby 84*69358fcaSMartin Dausel * : . : x . : . : . : HDSPM_Midi0InterruptEnable 85*69358fcaSMartin Dausel * : . :x . : . : . : HDSPM_Midi1InterruptEnable 86*69358fcaSMartin Dausel * : . : x . : . : . : HDSPM_Midi2InterruptEnable 87*69358fcaSMartin Dausel * : . x : . : . : . : <MADI> HDSPM_Midi3InterruptEnable 88*69358fcaSMartin Dausel * : . x : . : . : . : <AES32> HDSPM_DS_DoubleWire 89*69358fcaSMartin Dausel * : .x : . : . : . : <AES32> HDSPM_QS_DoubleWire 90*69358fcaSMartin Dausel * : x. : . : . : . : <AES32> HDSPM_QS_QuadWire 91*69358fcaSMartin Dausel * : . : . : . x : . : <AES32> HDSPM_Professional 92*69358fcaSMartin Dausel * : x . : . : . : . : HDSPM_wclk_sel 93*69358fcaSMartin Dausel * : . : . : . : . : 94*69358fcaSMartin Dausel * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte 95*69358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||: 96*69358fcaSMartin Dausel * :3322.2222:2222.1111:1111.1100:0000.0000: bit number 97*69358fcaSMartin Dausel * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 98*69358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||: 99*69358fcaSMartin Dausel * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit 100*69358fcaSMartin Dausel * 101*69358fcaSMartin Dausel * 102*69358fcaSMartin Dausel * 103*69358fcaSMartin Dausel * AIO / RayDAT only 104*69358fcaSMartin Dausel * 105*69358fcaSMartin Dausel * ------------ HDSPM_WR_SETTINGS ---------- 106*69358fcaSMartin Dausel * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte 107*69358fcaSMartin Dausel * :1098.7654:3210.9876:5432.1098:7654.3210: 108*69358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||: bit number 109*69358fcaSMartin Dausel * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 110*69358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||: 111*69358fcaSMartin Dausel * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit 112*69358fcaSMartin Dausel * : . : . : . : . x: HDSPM_c0Master 1: Master, 0: Slave 113*69358fcaSMartin Dausel * : . : . : . : . x : HDSPM_c0_SyncRef0 114*69358fcaSMartin Dausel * : . : . : . : . x : HDSPM_c0_SyncRef1 115*69358fcaSMartin Dausel * : . : . : . : .x : HDSPM_c0_SyncRef2 116*69358fcaSMartin Dausel * : . : . : . : x. : HDSPM_c0_SyncRef3 117*69358fcaSMartin Dausel * : . : . : . : 3.210 : HDSPM_c0_SyncRefMask: 118*69358fcaSMartin Dausel * : . : . : . : . : RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4, 119*69358fcaSMartin Dausel * : . : . : . : . : 9:TCO, 10:SyncIn 120*69358fcaSMartin Dausel * : . : . : . : . : AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT, 121*69358fcaSMartin Dausel * : . : . : . : . : 9:TCO, 10:SyncIn 122*69358fcaSMartin Dausel * : . : . : . : . : 123*69358fcaSMartin Dausel * : . : . : . : . : 124*69358fcaSMartin Dausel * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte 125*69358fcaSMartin Dausel * :1098.7654:3210.9876:5432.1098:7654.3210: 126*69358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||: bit number 127*69358fcaSMartin Dausel * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 128*69358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||: 129*69358fcaSMartin Dausel * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit 130*69358fcaSMartin Dausel * 131*69358fcaSMartin Dausel */ 132763f356cSTakashi Iwai #include <linux/init.h> 133763f356cSTakashi Iwai #include <linux/delay.h> 134763f356cSTakashi Iwai #include <linux/interrupt.h> 13565a77217SPaul Gortmaker #include <linux/module.h> 136763f356cSTakashi Iwai #include <linux/slab.h> 137763f356cSTakashi Iwai #include <linux/pci.h> 1383f7440a6STakashi Iwai #include <linux/math64.h> 139763f356cSTakashi Iwai #include <asm/io.h> 140763f356cSTakashi Iwai 141763f356cSTakashi Iwai #include <sound/core.h> 142763f356cSTakashi Iwai #include <sound/control.h> 143763f356cSTakashi Iwai #include <sound/pcm.h> 1440dca1793SAdrian Knoth #include <sound/pcm_params.h> 145763f356cSTakashi Iwai #include <sound/info.h> 146763f356cSTakashi Iwai #include <sound/asoundef.h> 147763f356cSTakashi Iwai #include <sound/rawmidi.h> 148763f356cSTakashi Iwai #include <sound/hwdep.h> 149763f356cSTakashi Iwai #include <sound/initval.h> 150763f356cSTakashi Iwai 151763f356cSTakashi Iwai #include <sound/hdspm.h> 152763f356cSTakashi Iwai 153763f356cSTakashi Iwai static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 154763f356cSTakashi Iwai static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 155a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ 156763f356cSTakashi Iwai 157763f356cSTakashi Iwai module_param_array(index, int, NULL, 0444); 158763f356cSTakashi Iwai MODULE_PARM_DESC(index, "Index value for RME HDSPM interface."); 159763f356cSTakashi Iwai 160763f356cSTakashi Iwai module_param_array(id, charp, NULL, 0444); 161763f356cSTakashi Iwai MODULE_PARM_DESC(id, "ID string for RME HDSPM interface."); 162763f356cSTakashi Iwai 163763f356cSTakashi Iwai module_param_array(enable, bool, NULL, 0444); 164763f356cSTakashi Iwai MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards."); 165763f356cSTakashi Iwai 166763f356cSTakashi Iwai 167763f356cSTakashi Iwai MODULE_AUTHOR 1680dca1793SAdrian Knoth ( 1690dca1793SAdrian Knoth "Winfried Ritsch <ritsch_AT_iem.at>, " 170ef5fa1a4STakashi Iwai "Paul Davis <paul@linuxaudiosystems.com>, " 1713cee5a60SRemy Bruno "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, " 1720dca1793SAdrian Knoth "Remy Bruno <remy.bruno@trinnov.com>, " 1730dca1793SAdrian Knoth "Florian Faber <faberman@linuxproaudio.org>, " 1740dca1793SAdrian Knoth "Adrian Knoth <adi@drcomp.erfurt.thur.de>" 1750dca1793SAdrian Knoth ); 176763f356cSTakashi Iwai MODULE_DESCRIPTION("RME HDSPM"); 177763f356cSTakashi Iwai MODULE_LICENSE("GPL"); 178763f356cSTakashi Iwai MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); 179763f356cSTakashi Iwai 180763f356cSTakashi Iwai /* --- Write registers. --- 181763f356cSTakashi Iwai These are defined as byte-offsets from the iobase value. */ 182763f356cSTakashi Iwai 1830dca1793SAdrian Knoth #define HDSPM_WR_SETTINGS 0 1840dca1793SAdrian Knoth #define HDSPM_outputBufferAddress 32 1850dca1793SAdrian Knoth #define HDSPM_inputBufferAddress 36 186763f356cSTakashi Iwai #define HDSPM_controlRegister 64 187763f356cSTakashi Iwai #define HDSPM_interruptConfirmation 96 188763f356cSTakashi Iwai #define HDSPM_control2Reg 256 /* not in specs ???????? */ 189*69358fcaSMartin Dausel #define HDSPM_freqReg 256 /* for setting arbitrary clock values (DDS feature) */ 190763f356cSTakashi Iwai #define HDSPM_midiDataOut0 352 /* just believe in old code */ 191763f356cSTakashi Iwai #define HDSPM_midiDataOut1 356 192ffb2c3c0SRemy Bruno #define HDSPM_eeprom_wr 384 /* for AES32 */ 193763f356cSTakashi Iwai 194763f356cSTakashi Iwai /* DMA enable for 64 channels, only Bit 0 is relevant */ 195763f356cSTakashi Iwai #define HDSPM_outputEnableBase 512 /* 512-767 input DMA */ 196763f356cSTakashi Iwai #define HDSPM_inputEnableBase 768 /* 768-1023 output DMA */ 197763f356cSTakashi Iwai 198763f356cSTakashi Iwai /* 16 page addresses for each of the 64 channels DMA buffer in and out 199763f356cSTakashi Iwai (each 64k=16*4k) Buffer must be 4k aligned (which is default i386 ????) */ 200763f356cSTakashi Iwai #define HDSPM_pageAddressBufferOut 8192 201763f356cSTakashi Iwai #define HDSPM_pageAddressBufferIn (HDSPM_pageAddressBufferOut+64*16*4) 202763f356cSTakashi Iwai 203763f356cSTakashi Iwai #define HDSPM_MADI_mixerBase 32768 /* 32768-65535 for 2x64x64 Fader */ 204763f356cSTakashi Iwai 205763f356cSTakashi Iwai #define HDSPM_MATRIX_MIXER_SIZE 8192 /* = 2*64*64 * 4 Byte => 32kB */ 206763f356cSTakashi Iwai 207763f356cSTakashi Iwai /* --- Read registers. --- 208763f356cSTakashi Iwai These are defined as byte-offsets from the iobase value */ 209763f356cSTakashi Iwai #define HDSPM_statusRegister 0 2103cee5a60SRemy Bruno /*#define HDSPM_statusRegister2 96 */ 2113cee5a60SRemy Bruno /* after RME Windows driver sources, status2 is 4-byte word # 48 = word at 2123cee5a60SRemy Bruno * offset 192, for AES32 *and* MADI 2133cee5a60SRemy Bruno * => need to check that offset 192 is working on MADI */ 2143cee5a60SRemy Bruno #define HDSPM_statusRegister2 192 2153cee5a60SRemy Bruno #define HDSPM_timecodeRegister 128 216763f356cSTakashi Iwai 2170dca1793SAdrian Knoth /* AIO, RayDAT */ 2180dca1793SAdrian Knoth #define HDSPM_RD_STATUS_0 0 2190dca1793SAdrian Knoth #define HDSPM_RD_STATUS_1 64 2200dca1793SAdrian Knoth #define HDSPM_RD_STATUS_2 128 2210dca1793SAdrian Knoth #define HDSPM_RD_STATUS_3 192 2220dca1793SAdrian Knoth 2230dca1793SAdrian Knoth #define HDSPM_RD_TCO 256 2240dca1793SAdrian Knoth #define HDSPM_RD_PLL_FREQ 512 2250dca1793SAdrian Knoth #define HDSPM_WR_TCO 128 2260dca1793SAdrian Knoth 2270dca1793SAdrian Knoth #define HDSPM_TCO1_TCO_lock 0x00000001 2280dca1793SAdrian Knoth #define HDSPM_TCO1_WCK_Input_Range_LSB 0x00000002 2290dca1793SAdrian Knoth #define HDSPM_TCO1_WCK_Input_Range_MSB 0x00000004 2300dca1793SAdrian Knoth #define HDSPM_TCO1_LTC_Input_valid 0x00000008 2310dca1793SAdrian Knoth #define HDSPM_TCO1_WCK_Input_valid 0x00000010 2320dca1793SAdrian Knoth #define HDSPM_TCO1_Video_Input_Format_NTSC 0x00000020 2330dca1793SAdrian Knoth #define HDSPM_TCO1_Video_Input_Format_PAL 0x00000040 2340dca1793SAdrian Knoth 2350dca1793SAdrian Knoth #define HDSPM_TCO1_set_TC 0x00000100 2360dca1793SAdrian Knoth #define HDSPM_TCO1_set_drop_frame_flag 0x00000200 2370dca1793SAdrian Knoth #define HDSPM_TCO1_LTC_Format_LSB 0x00000400 2380dca1793SAdrian Knoth #define HDSPM_TCO1_LTC_Format_MSB 0x00000800 2390dca1793SAdrian Knoth 2400dca1793SAdrian Knoth #define HDSPM_TCO2_TC_run 0x00010000 2410dca1793SAdrian Knoth #define HDSPM_TCO2_WCK_IO_ratio_LSB 0x00020000 2420dca1793SAdrian Knoth #define HDSPM_TCO2_WCK_IO_ratio_MSB 0x00040000 2430dca1793SAdrian Knoth #define HDSPM_TCO2_set_num_drop_frames_LSB 0x00080000 2440dca1793SAdrian Knoth #define HDSPM_TCO2_set_num_drop_frames_MSB 0x00100000 2450dca1793SAdrian Knoth #define HDSPM_TCO2_set_jam_sync 0x00200000 2460dca1793SAdrian Knoth #define HDSPM_TCO2_set_flywheel 0x00400000 2470dca1793SAdrian Knoth 2480dca1793SAdrian Knoth #define HDSPM_TCO2_set_01_4 0x01000000 2490dca1793SAdrian Knoth #define HDSPM_TCO2_set_pull_down 0x02000000 2500dca1793SAdrian Knoth #define HDSPM_TCO2_set_pull_up 0x04000000 2510dca1793SAdrian Knoth #define HDSPM_TCO2_set_freq 0x08000000 2520dca1793SAdrian Knoth #define HDSPM_TCO2_set_term_75R 0x10000000 2530dca1793SAdrian Knoth #define HDSPM_TCO2_set_input_LSB 0x20000000 2540dca1793SAdrian Knoth #define HDSPM_TCO2_set_input_MSB 0x40000000 2550dca1793SAdrian Knoth #define HDSPM_TCO2_set_freq_from_app 0x80000000 2560dca1793SAdrian Knoth 2570dca1793SAdrian Knoth 2580dca1793SAdrian Knoth #define HDSPM_midiDataOut0 352 2590dca1793SAdrian Knoth #define HDSPM_midiDataOut1 356 2600dca1793SAdrian Knoth #define HDSPM_midiDataOut2 368 2610dca1793SAdrian Knoth 262763f356cSTakashi Iwai #define HDSPM_midiDataIn0 360 263763f356cSTakashi Iwai #define HDSPM_midiDataIn1 364 2640dca1793SAdrian Knoth #define HDSPM_midiDataIn2 372 2650dca1793SAdrian Knoth #define HDSPM_midiDataIn3 376 266763f356cSTakashi Iwai 267763f356cSTakashi Iwai /* status is data bytes in MIDI-FIFO (0-128) */ 268763f356cSTakashi Iwai #define HDSPM_midiStatusOut0 384 269763f356cSTakashi Iwai #define HDSPM_midiStatusOut1 388 2700dca1793SAdrian Knoth #define HDSPM_midiStatusOut2 400 2710dca1793SAdrian Knoth 272763f356cSTakashi Iwai #define HDSPM_midiStatusIn0 392 273763f356cSTakashi Iwai #define HDSPM_midiStatusIn1 396 2740dca1793SAdrian Knoth #define HDSPM_midiStatusIn2 404 2750dca1793SAdrian Knoth #define HDSPM_midiStatusIn3 408 276763f356cSTakashi Iwai 277763f356cSTakashi Iwai 278763f356cSTakashi Iwai /* the meters are regular i/o-mapped registers, but offset 279763f356cSTakashi Iwai considerably from the rest. the peak registers are reset 280763f356cSTakashi Iwai when read; the least-significant 4 bits are full-scale counters; 281763f356cSTakashi Iwai the actual peak value is in the most-significant 24 bits. 282763f356cSTakashi Iwai */ 2830dca1793SAdrian Knoth 2840dca1793SAdrian Knoth #define HDSPM_MADI_INPUT_PEAK 4096 2850dca1793SAdrian Knoth #define HDSPM_MADI_PLAYBACK_PEAK 4352 2860dca1793SAdrian Knoth #define HDSPM_MADI_OUTPUT_PEAK 4608 2870dca1793SAdrian Knoth 2880dca1793SAdrian Knoth #define HDSPM_MADI_INPUT_RMS_L 6144 2890dca1793SAdrian Knoth #define HDSPM_MADI_PLAYBACK_RMS_L 6400 2900dca1793SAdrian Knoth #define HDSPM_MADI_OUTPUT_RMS_L 6656 2910dca1793SAdrian Knoth 2920dca1793SAdrian Knoth #define HDSPM_MADI_INPUT_RMS_H 7168 2930dca1793SAdrian Knoth #define HDSPM_MADI_PLAYBACK_RMS_H 7424 2940dca1793SAdrian Knoth #define HDSPM_MADI_OUTPUT_RMS_H 7680 295763f356cSTakashi Iwai 296763f356cSTakashi Iwai /* --- Control Register bits --------- */ 297763f356cSTakashi Iwai #define HDSPM_Start (1<<0) /* start engine */ 298763f356cSTakashi Iwai 299763f356cSTakashi Iwai #define HDSPM_Latency0 (1<<1) /* buffer size = 2^n */ 300763f356cSTakashi Iwai #define HDSPM_Latency1 (1<<2) /* where n is defined */ 301763f356cSTakashi Iwai #define HDSPM_Latency2 (1<<3) /* by Latency{2,1,0} */ 302763f356cSTakashi Iwai 3030dca1793SAdrian Knoth #define HDSPM_ClockModeMaster (1<<4) /* 1=Master, 0=Autosync */ 3040dca1793SAdrian Knoth #define HDSPM_c0Master 0x1 /* Master clock bit in settings 3050dca1793SAdrian Knoth register [RayDAT, AIO] */ 306763f356cSTakashi Iwai 307763f356cSTakashi Iwai #define HDSPM_AudioInterruptEnable (1<<5) /* what do you think ? */ 308763f356cSTakashi Iwai 309763f356cSTakashi Iwai #define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ 310763f356cSTakashi Iwai #define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */ 311763f356cSTakashi Iwai #define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ 3123cee5a60SRemy Bruno #define HDSPM_QuadSpeed (1<<31) /* quad speed bit */ 313763f356cSTakashi Iwai 3143cee5a60SRemy Bruno #define HDSPM_Professional (1<<9) /* Professional */ /* AES32 ONLY */ 315763f356cSTakashi Iwai #define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1, 3163cee5a60SRemy Bruno 56channelMODE=0 */ /* MADI ONLY*/ 3173cee5a60SRemy Bruno #define HDSPM_Emphasis (1<<10) /* Emphasis */ /* AES32 ONLY */ 318763f356cSTakashi Iwai 319763f356cSTakashi Iwai #define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode, 3203cee5a60SRemy Bruno 0=off, 1=on */ /* MADI ONLY */ 3213cee5a60SRemy Bruno #define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */ 322763f356cSTakashi Iwai 323ef5fa1a4STakashi Iwai #define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax 324ef5fa1a4STakashi Iwai * -- MADI ONLY 325ef5fa1a4STakashi Iwai */ 326763f356cSTakashi Iwai #define HDSPM_InputSelect1 (1<<15) /* should be 0 */ 327763f356cSTakashi Iwai 3283cee5a60SRemy Bruno #define HDSPM_SyncRef2 (1<<13) 3293cee5a60SRemy Bruno #define HDSPM_SyncRef3 (1<<25) 330763f356cSTakashi Iwai 3313cee5a60SRemy Bruno #define HDSPM_SMUX (1<<18) /* Frame ??? */ /* MADI ONY */ 332763f356cSTakashi Iwai #define HDSPM_clr_tms (1<<19) /* clear track marker, do not use 333763f356cSTakashi Iwai AES additional bits in 334763f356cSTakashi Iwai lower 5 Audiodatabits ??? */ 3353cee5a60SRemy Bruno #define HDSPM_taxi_reset (1<<20) /* ??? */ /* MADI ONLY ? */ 3363cee5a60SRemy Bruno #define HDSPM_WCK48 (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */ 337763f356cSTakashi Iwai 3380dca1793SAdrian Knoth #define HDSPM_Midi0InterruptEnable 0x0400000 3390dca1793SAdrian Knoth #define HDSPM_Midi1InterruptEnable 0x0800000 3400dca1793SAdrian Knoth #define HDSPM_Midi2InterruptEnable 0x0200000 3410dca1793SAdrian Knoth #define HDSPM_Midi3InterruptEnable 0x4000000 342763f356cSTakashi Iwai 343763f356cSTakashi Iwai #define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */ 3440dca1793SAdrian Knoth #define HDSPe_FLOAT_FORMAT 0x2000000 345763f356cSTakashi Iwai 3463cee5a60SRemy Bruno #define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */ 3473cee5a60SRemy Bruno #define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */ 3483cee5a60SRemy Bruno #define HDSPM_QS_QuadWire (1<<28) /* AES32 ONLY */ 3493cee5a60SRemy Bruno 3503cee5a60SRemy Bruno #define HDSPM_wclk_sel (1<<30) 351763f356cSTakashi Iwai 352384f778fSAdrian Knoth /* additional control register bits for AIO*/ 353384f778fSAdrian Knoth #define HDSPM_c0_Wck48 0x20 /* also RayDAT */ 354384f778fSAdrian Knoth #define HDSPM_c0_Input0 0x1000 355384f778fSAdrian Knoth #define HDSPM_c0_Input1 0x2000 356384f778fSAdrian Knoth #define HDSPM_c0_Spdif_Opt 0x4000 357384f778fSAdrian Knoth #define HDSPM_c0_Pro 0x8000 358384f778fSAdrian Knoth #define HDSPM_c0_clr_tms 0x10000 359384f778fSAdrian Knoth #define HDSPM_c0_AEB1 0x20000 360384f778fSAdrian Knoth #define HDSPM_c0_AEB2 0x40000 361384f778fSAdrian Knoth #define HDSPM_c0_LineOut 0x80000 362384f778fSAdrian Knoth #define HDSPM_c0_AD_GAIN0 0x100000 363384f778fSAdrian Knoth #define HDSPM_c0_AD_GAIN1 0x200000 364384f778fSAdrian Knoth #define HDSPM_c0_DA_GAIN0 0x400000 365384f778fSAdrian Knoth #define HDSPM_c0_DA_GAIN1 0x800000 366384f778fSAdrian Knoth #define HDSPM_c0_PH_GAIN0 0x1000000 367384f778fSAdrian Knoth #define HDSPM_c0_PH_GAIN1 0x2000000 368384f778fSAdrian Knoth #define HDSPM_c0_Sym6db 0x4000000 369384f778fSAdrian Knoth 370384f778fSAdrian Knoth 371763f356cSTakashi Iwai /* --- bit helper defines */ 372763f356cSTakashi Iwai #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) 373ef5fa1a4STakashi Iwai #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ 374ef5fa1a4STakashi Iwai HDSPM_DoubleSpeed|HDSPM_QuadSpeed) 375763f356cSTakashi Iwai #define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) 376763f356cSTakashi Iwai #define HDSPM_InputOptical 0 377763f356cSTakashi Iwai #define HDSPM_InputCoaxial (HDSPM_InputSelect0) 378ef5fa1a4STakashi Iwai #define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|\ 379ef5fa1a4STakashi Iwai HDSPM_SyncRef2|HDSPM_SyncRef3) 3800dca1793SAdrian Knoth 3810dca1793SAdrian Knoth #define HDSPM_c0_SyncRef0 0x2 3820dca1793SAdrian Knoth #define HDSPM_c0_SyncRef1 0x4 3830dca1793SAdrian Knoth #define HDSPM_c0_SyncRef2 0x8 3840dca1793SAdrian Knoth #define HDSPM_c0_SyncRef3 0x10 3850dca1793SAdrian Knoth #define HDSPM_c0_SyncRefMask (HDSPM_c0_SyncRef0 | HDSPM_c0_SyncRef1 |\ 3860dca1793SAdrian Knoth HDSPM_c0_SyncRef2 | HDSPM_c0_SyncRef3) 387763f356cSTakashi Iwai 388763f356cSTakashi Iwai #define HDSPM_SYNC_FROM_WORD 0 /* Preferred sync reference */ 389763f356cSTakashi Iwai #define HDSPM_SYNC_FROM_MADI 1 /* choices - used by "pref_sync_ref" */ 3900dca1793SAdrian Knoth #define HDSPM_SYNC_FROM_TCO 2 3910dca1793SAdrian Knoth #define HDSPM_SYNC_FROM_SYNC_IN 3 392763f356cSTakashi Iwai 393763f356cSTakashi Iwai #define HDSPM_Frequency32KHz HDSPM_Frequency0 394763f356cSTakashi Iwai #define HDSPM_Frequency44_1KHz HDSPM_Frequency1 395763f356cSTakashi Iwai #define HDSPM_Frequency48KHz (HDSPM_Frequency1|HDSPM_Frequency0) 396763f356cSTakashi Iwai #define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) 397763f356cSTakashi Iwai #define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) 398ef5fa1a4STakashi Iwai #define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|\ 399ef5fa1a4STakashi Iwai HDSPM_Frequency0) 4003cee5a60SRemy Bruno #define HDSPM_Frequency128KHz (HDSPM_QuadSpeed|HDSPM_Frequency0) 4013cee5a60SRemy Bruno #define HDSPM_Frequency176_4KHz (HDSPM_QuadSpeed|HDSPM_Frequency1) 402ef5fa1a4STakashi Iwai #define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|\ 403ef5fa1a4STakashi Iwai HDSPM_Frequency0) 404763f356cSTakashi Iwai 405763f356cSTakashi Iwai 406763f356cSTakashi Iwai /* Synccheck Status */ 407763f356cSTakashi Iwai #define HDSPM_SYNC_CHECK_NO_LOCK 0 408763f356cSTakashi Iwai #define HDSPM_SYNC_CHECK_LOCK 1 409763f356cSTakashi Iwai #define HDSPM_SYNC_CHECK_SYNC 2 410763f356cSTakashi Iwai 411763f356cSTakashi Iwai /* AutoSync References - used by "autosync_ref" control switch */ 412763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_FROM_WORD 0 413763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_FROM_MADI 1 4140dca1793SAdrian Knoth #define HDSPM_AUTOSYNC_FROM_TCO 2 4150dca1793SAdrian Knoth #define HDSPM_AUTOSYNC_FROM_SYNC_IN 3 4160dca1793SAdrian Knoth #define HDSPM_AUTOSYNC_FROM_NONE 4 417763f356cSTakashi Iwai 418763f356cSTakashi Iwai /* Possible sources of MADI input */ 419763f356cSTakashi Iwai #define HDSPM_OPTICAL 0 /* optical */ 420763f356cSTakashi Iwai #define HDSPM_COAXIAL 1 /* BNC */ 421763f356cSTakashi Iwai 422763f356cSTakashi Iwai #define hdspm_encode_latency(x) (((x)<<1) & HDSPM_LatencyMask) 4230dca1793SAdrian Knoth #define hdspm_decode_latency(x) ((((x) & HDSPM_LatencyMask)>>1)) 424763f356cSTakashi Iwai 425763f356cSTakashi Iwai #define hdspm_encode_in(x) (((x)&0x3)<<14) 426763f356cSTakashi Iwai #define hdspm_decode_in(x) (((x)>>14)&0x3) 427763f356cSTakashi Iwai 428763f356cSTakashi Iwai /* --- control2 register bits --- */ 429763f356cSTakashi Iwai #define HDSPM_TMS (1<<0) 430763f356cSTakashi Iwai #define HDSPM_TCK (1<<1) 431763f356cSTakashi Iwai #define HDSPM_TDI (1<<2) 432763f356cSTakashi Iwai #define HDSPM_JTAG (1<<3) 433763f356cSTakashi Iwai #define HDSPM_PWDN (1<<4) 434763f356cSTakashi Iwai #define HDSPM_PROGRAM (1<<5) 435763f356cSTakashi Iwai #define HDSPM_CONFIG_MODE_0 (1<<6) 436763f356cSTakashi Iwai #define HDSPM_CONFIG_MODE_1 (1<<7) 437763f356cSTakashi Iwai /*#define HDSPM_VERSION_BIT (1<<8) not defined any more*/ 438763f356cSTakashi Iwai #define HDSPM_BIGENDIAN_MODE (1<<9) 439763f356cSTakashi Iwai #define HDSPM_RD_MULTIPLE (1<<10) 440763f356cSTakashi Iwai 4413cee5a60SRemy Bruno /* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and 442ef5fa1a4STakashi Iwai that do not conflict with specific bits for AES32 seem to be valid also 443ef5fa1a4STakashi Iwai for the AES32 444ef5fa1a4STakashi Iwai */ 445763f356cSTakashi Iwai #define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ 446ef5fa1a4STakashi Iwai #define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn MODE=0 */ 447ef5fa1a4STakashi Iwai #define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 448ef5fa1a4STakashi Iwai * (like inp0) 449ef5fa1a4STakashi Iwai */ 4500dca1793SAdrian Knoth 451763f356cSTakashi Iwai #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ 4520dca1793SAdrian Knoth #define HDSPM_madiSync (1<<18) /* MADI is in sync */ 4530dca1793SAdrian Knoth 454b0bf5504SAdrian Knoth #define HDSPM_tcoLockMadi 0x00000020 /* Optional TCO locked status for HDSPe MADI*/ 455b0bf5504SAdrian Knoth #define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/ 4560dca1793SAdrian Knoth 457b0bf5504SAdrian Knoth #define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */ 458b0bf5504SAdrian Knoth #define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */ 459763f356cSTakashi Iwai 460763f356cSTakashi Iwai #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ 4610dca1793SAdrian Knoth /* since 64byte accurate, last 6 bits are not used */ 462763f356cSTakashi Iwai 4630dca1793SAdrian Knoth 4640dca1793SAdrian Knoth 465763f356cSTakashi Iwai #define HDSPM_DoubleSpeedStatus (1<<19) /* (input) card in double speed */ 466763f356cSTakashi Iwai 467763f356cSTakashi Iwai #define HDSPM_madiFreq0 (1<<22) /* system freq 0=error */ 468763f356cSTakashi Iwai #define HDSPM_madiFreq1 (1<<23) /* 1=32, 2=44.1 3=48 */ 469763f356cSTakashi Iwai #define HDSPM_madiFreq2 (1<<24) /* 4=64, 5=88.2 6=96 */ 470763f356cSTakashi Iwai #define HDSPM_madiFreq3 (1<<25) /* 7=128, 8=176.4 9=192 */ 471763f356cSTakashi Iwai 472ef5fa1a4STakashi Iwai #define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with 473ef5fa1a4STakashi Iwai * Interrupt 474ef5fa1a4STakashi Iwai */ 4750dca1793SAdrian Knoth #define HDSPM_tco_detect 0x08000000 476b0bf5504SAdrian Knoth #define HDSPM_tcoLockAes 0x20000000 /* Optional TCO locked status for HDSPe AES */ 4770dca1793SAdrian Knoth 4780dca1793SAdrian Knoth #define HDSPM_s2_tco_detect 0x00000040 4790dca1793SAdrian Knoth #define HDSPM_s2_AEBO_D 0x00000080 4800dca1793SAdrian Knoth #define HDSPM_s2_AEBI_D 0x00000100 4810dca1793SAdrian Knoth 4820dca1793SAdrian Knoth 4830dca1793SAdrian Knoth #define HDSPM_midi0IRQPending 0x40000000 4840dca1793SAdrian Knoth #define HDSPM_midi1IRQPending 0x80000000 4850dca1793SAdrian Knoth #define HDSPM_midi2IRQPending 0x20000000 4860dca1793SAdrian Knoth #define HDSPM_midi2IRQPendingAES 0x00000020 4870dca1793SAdrian Knoth #define HDSPM_midi3IRQPending 0x00200000 488763f356cSTakashi Iwai 489763f356cSTakashi Iwai /* --- status bit helpers */ 490ef5fa1a4STakashi Iwai #define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|\ 491ef5fa1a4STakashi Iwai HDSPM_madiFreq2|HDSPM_madiFreq3) 492763f356cSTakashi Iwai #define HDSPM_madiFreq32 (HDSPM_madiFreq0) 493763f356cSTakashi Iwai #define HDSPM_madiFreq44_1 (HDSPM_madiFreq1) 494763f356cSTakashi Iwai #define HDSPM_madiFreq48 (HDSPM_madiFreq0|HDSPM_madiFreq1) 495763f356cSTakashi Iwai #define HDSPM_madiFreq64 (HDSPM_madiFreq2) 496763f356cSTakashi Iwai #define HDSPM_madiFreq88_2 (HDSPM_madiFreq0|HDSPM_madiFreq2) 497763f356cSTakashi Iwai #define HDSPM_madiFreq96 (HDSPM_madiFreq1|HDSPM_madiFreq2) 498763f356cSTakashi Iwai #define HDSPM_madiFreq128 (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2) 499763f356cSTakashi Iwai #define HDSPM_madiFreq176_4 (HDSPM_madiFreq3) 500763f356cSTakashi Iwai #define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0) 501763f356cSTakashi Iwai 5023cee5a60SRemy Bruno /* Status2 Register bits */ /* MADI ONLY */ 503763f356cSTakashi Iwai 50425985edcSLucas De Marchi #define HDSPM_version0 (1<<0) /* not really defined but I guess */ 505763f356cSTakashi Iwai #define HDSPM_version1 (1<<1) /* in former cards it was ??? */ 506763f356cSTakashi Iwai #define HDSPM_version2 (1<<2) 507763f356cSTakashi Iwai 508763f356cSTakashi Iwai #define HDSPM_wcLock (1<<3) /* Wordclock is detected and locked */ 509763f356cSTakashi Iwai #define HDSPM_wcSync (1<<4) /* Wordclock is in sync with systemclock */ 510763f356cSTakashi Iwai 511763f356cSTakashi Iwai #define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */ 512763f356cSTakashi Iwai #define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */ 513a8cd7148SAdrian Knoth #define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, 111=128 */ 514a8cd7148SAdrian Knoth #define HDSPM_wc_freq3 0x800 /* 1000=176.4, 1001=192 */ 515763f356cSTakashi Iwai 5160dca1793SAdrian Knoth #define HDSPM_SyncRef0 0x10000 /* Sync Reference */ 5170dca1793SAdrian Knoth #define HDSPM_SyncRef1 0x20000 5180dca1793SAdrian Knoth 5190dca1793SAdrian Knoth #define HDSPM_SelSyncRef0 (1<<8) /* AutoSync Source */ 520763f356cSTakashi Iwai #define HDSPM_SelSyncRef1 (1<<9) /* 000=word, 001=MADI, */ 521763f356cSTakashi Iwai #define HDSPM_SelSyncRef2 (1<<10) /* 111=no valid signal */ 522763f356cSTakashi Iwai 523763f356cSTakashi Iwai #define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync) 524763f356cSTakashi Iwai 525a8cd7148SAdrian Knoth #define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2|\ 526a8cd7148SAdrian Knoth HDSPM_wc_freq3) 527763f356cSTakashi Iwai #define HDSPM_wcFreq32 (HDSPM_wc_freq0) 528763f356cSTakashi Iwai #define HDSPM_wcFreq44_1 (HDSPM_wc_freq1) 529763f356cSTakashi Iwai #define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1) 530763f356cSTakashi Iwai #define HDSPM_wcFreq64 (HDSPM_wc_freq2) 531763f356cSTakashi Iwai #define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2) 532763f356cSTakashi Iwai #define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) 533a8cd7148SAdrian Knoth #define HDSPM_wcFreq128 (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) 534a8cd7148SAdrian Knoth #define HDSPM_wcFreq176_4 (HDSPM_wc_freq3) 535a8cd7148SAdrian Knoth #define HDSPM_wcFreq192 (HDSPM_wc_freq0|HDSPM_wc_freq3) 536763f356cSTakashi Iwai 5370dca1793SAdrian Knoth #define HDSPM_status1_F_0 0x0400000 5380dca1793SAdrian Knoth #define HDSPM_status1_F_1 0x0800000 5390dca1793SAdrian Knoth #define HDSPM_status1_F_2 0x1000000 5400dca1793SAdrian Knoth #define HDSPM_status1_F_3 0x2000000 5410dca1793SAdrian Knoth #define HDSPM_status1_freqMask (HDSPM_status1_F_0|HDSPM_status1_F_1|HDSPM_status1_F_2|HDSPM_status1_F_3) 5420dca1793SAdrian Knoth 543763f356cSTakashi Iwai 544ef5fa1a4STakashi Iwai #define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ 545ef5fa1a4STakashi Iwai HDSPM_SelSyncRef2) 546763f356cSTakashi Iwai #define HDSPM_SelSyncRef_WORD 0 547763f356cSTakashi Iwai #define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) 5480dca1793SAdrian Knoth #define HDSPM_SelSyncRef_TCO (HDSPM_SelSyncRef1) 5490dca1793SAdrian Knoth #define HDSPM_SelSyncRef_SyncIn (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1) 550ef5fa1a4STakashi Iwai #define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ 551ef5fa1a4STakashi Iwai HDSPM_SelSyncRef2) 552763f356cSTakashi Iwai 5533cee5a60SRemy Bruno /* 5543cee5a60SRemy Bruno For AES32, bits for status, status2 and timecode are different 5553cee5a60SRemy Bruno */ 5563cee5a60SRemy Bruno /* status */ 5573cee5a60SRemy Bruno #define HDSPM_AES32_wcLock 0x0200000 55856bde0f3SAndre Schramm #define HDSPM_AES32_wcSync 0x0100000 5593cee5a60SRemy Bruno #define HDSPM_AES32_wcFreq_bit 22 5603cee5a60SRemy Bruno /* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function 5613cee5a60SRemy Bruno HDSPM_bit2freq */ 5623cee5a60SRemy Bruno #define HDSPM_AES32_syncref_bit 16 5633cee5a60SRemy Bruno /* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */ 5643cee5a60SRemy Bruno 5653cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_WORD 0 5663cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES1 1 5673cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES2 2 5683cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES3 3 5693cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES4 4 5703cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES5 5 5713cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 5723cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 5733cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 574b0bf5504SAdrian Knoth #define HDSPM_AES32_AUTOSYNC_FROM_TCO 9 575b0bf5504SAdrian Knoth #define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10 576b0bf5504SAdrian Knoth #define HDSPM_AES32_AUTOSYNC_FROM_NONE 11 5773cee5a60SRemy Bruno 5783cee5a60SRemy Bruno /* status2 */ 5793cee5a60SRemy Bruno /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ 5803cee5a60SRemy Bruno #define HDSPM_LockAES 0x80 5813cee5a60SRemy Bruno #define HDSPM_LockAES1 0x80 5823cee5a60SRemy Bruno #define HDSPM_LockAES2 0x40 5833cee5a60SRemy Bruno #define HDSPM_LockAES3 0x20 5843cee5a60SRemy Bruno #define HDSPM_LockAES4 0x10 5853cee5a60SRemy Bruno #define HDSPM_LockAES5 0x8 5863cee5a60SRemy Bruno #define HDSPM_LockAES6 0x4 5873cee5a60SRemy Bruno #define HDSPM_LockAES7 0x2 5883cee5a60SRemy Bruno #define HDSPM_LockAES8 0x1 5893cee5a60SRemy Bruno /* 5903cee5a60SRemy Bruno Timecode 5913cee5a60SRemy Bruno After windows driver sources, bits 4*i to 4*i+3 give the input frequency on 5923cee5a60SRemy Bruno AES i+1 5933cee5a60SRemy Bruno bits 3210 5943cee5a60SRemy Bruno 0001 32kHz 5953cee5a60SRemy Bruno 0010 44.1kHz 5963cee5a60SRemy Bruno 0011 48kHz 5973cee5a60SRemy Bruno 0100 64kHz 5983cee5a60SRemy Bruno 0101 88.2kHz 5993cee5a60SRemy Bruno 0110 96kHz 6003cee5a60SRemy Bruno 0111 128kHz 6013cee5a60SRemy Bruno 1000 176.4kHz 6023cee5a60SRemy Bruno 1001 192kHz 6033cee5a60SRemy Bruno NB: Timecode register doesn't seem to work on AES32 card revision 230 6043cee5a60SRemy Bruno */ 6053cee5a60SRemy Bruno 606763f356cSTakashi Iwai /* Mixer Values */ 607763f356cSTakashi Iwai #define UNITY_GAIN 32768 /* = 65536/2 */ 608763f356cSTakashi Iwai #define MINUS_INFINITY_GAIN 0 609763f356cSTakashi Iwai 610763f356cSTakashi Iwai /* Number of channels for different Speed Modes */ 611763f356cSTakashi Iwai #define MADI_SS_CHANNELS 64 612763f356cSTakashi Iwai #define MADI_DS_CHANNELS 32 613763f356cSTakashi Iwai #define MADI_QS_CHANNELS 16 614763f356cSTakashi Iwai 6150dca1793SAdrian Knoth #define RAYDAT_SS_CHANNELS 36 6160dca1793SAdrian Knoth #define RAYDAT_DS_CHANNELS 20 6170dca1793SAdrian Knoth #define RAYDAT_QS_CHANNELS 12 6180dca1793SAdrian Knoth 6190dca1793SAdrian Knoth #define AIO_IN_SS_CHANNELS 14 6200dca1793SAdrian Knoth #define AIO_IN_DS_CHANNELS 10 6210dca1793SAdrian Knoth #define AIO_IN_QS_CHANNELS 8 6220dca1793SAdrian Knoth #define AIO_OUT_SS_CHANNELS 16 6230dca1793SAdrian Knoth #define AIO_OUT_DS_CHANNELS 12 6240dca1793SAdrian Knoth #define AIO_OUT_QS_CHANNELS 10 6250dca1793SAdrian Knoth 626d2d10a21SAdrian Knoth #define AES32_CHANNELS 16 627d2d10a21SAdrian Knoth 628763f356cSTakashi Iwai /* the size of a substream (1 mono data stream) */ 629763f356cSTakashi Iwai #define HDSPM_CHANNEL_BUFFER_SAMPLES (16*1024) 630763f356cSTakashi Iwai #define HDSPM_CHANNEL_BUFFER_BYTES (4*HDSPM_CHANNEL_BUFFER_SAMPLES) 631763f356cSTakashi Iwai 632763f356cSTakashi Iwai /* the size of the area we need to allocate for DMA transfers. the 633763f356cSTakashi Iwai size is the same regardless of the number of channels, and 634763f356cSTakashi Iwai also the latency to use. 635763f356cSTakashi Iwai for one direction !!! 636763f356cSTakashi Iwai */ 637ffb2c3c0SRemy Bruno #define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) 638763f356cSTakashi Iwai #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) 639763f356cSTakashi Iwai 6400dca1793SAdrian Knoth #define HDSPM_RAYDAT_REV 211 6410dca1793SAdrian Knoth #define HDSPM_AIO_REV 212 6420dca1793SAdrian Knoth #define HDSPM_MADIFACE_REV 213 6433cee5a60SRemy Bruno 6446534599dSRemy Bruno /* speed factor modes */ 6456534599dSRemy Bruno #define HDSPM_SPEED_SINGLE 0 6466534599dSRemy Bruno #define HDSPM_SPEED_DOUBLE 1 6476534599dSRemy Bruno #define HDSPM_SPEED_QUAD 2 6480dca1793SAdrian Knoth 6496534599dSRemy Bruno /* names for speed modes */ 6506534599dSRemy Bruno static char *hdspm_speed_names[] = { "single", "double", "quad" }; 6516534599dSRemy Bruno 652eb0d4dbfSAdrian Knoth static const char *const texts_autosync_aes_tco[] = { "Word Clock", 6530dca1793SAdrian Knoth "AES1", "AES2", "AES3", "AES4", 6540dca1793SAdrian Knoth "AES5", "AES6", "AES7", "AES8", 655db2d1a91SAdrian Knoth "TCO", "Sync In" 656db2d1a91SAdrian Knoth }; 657eb0d4dbfSAdrian Knoth static const char *const texts_autosync_aes[] = { "Word Clock", 6580dca1793SAdrian Knoth "AES1", "AES2", "AES3", "AES4", 659db2d1a91SAdrian Knoth "AES5", "AES6", "AES7", "AES8", 660db2d1a91SAdrian Knoth "Sync In" 661db2d1a91SAdrian Knoth }; 662eb0d4dbfSAdrian Knoth static const char *const texts_autosync_madi_tco[] = { "Word Clock", 6630dca1793SAdrian Knoth "MADI", "TCO", "Sync In" }; 664eb0d4dbfSAdrian Knoth static const char *const texts_autosync_madi[] = { "Word Clock", 6650dca1793SAdrian Knoth "MADI", "Sync In" }; 6660dca1793SAdrian Knoth 667eb0d4dbfSAdrian Knoth static const char *const texts_autosync_raydat_tco[] = { 6680dca1793SAdrian Knoth "Word Clock", 6690dca1793SAdrian Knoth "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", 6700dca1793SAdrian Knoth "AES", "SPDIF", "TCO", "Sync In" 6710dca1793SAdrian Knoth }; 672eb0d4dbfSAdrian Knoth static const char *const texts_autosync_raydat[] = { 6730dca1793SAdrian Knoth "Word Clock", 6740dca1793SAdrian Knoth "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", 6750dca1793SAdrian Knoth "AES", "SPDIF", "Sync In" 6760dca1793SAdrian Knoth }; 677eb0d4dbfSAdrian Knoth static const char *const texts_autosync_aio_tco[] = { 6780dca1793SAdrian Knoth "Word Clock", 6790dca1793SAdrian Knoth "ADAT", "AES", "SPDIF", "TCO", "Sync In" 6800dca1793SAdrian Knoth }; 681eb0d4dbfSAdrian Knoth static const char *const texts_autosync_aio[] = { "Word Clock", 6820dca1793SAdrian Knoth "ADAT", "AES", "SPDIF", "Sync In" }; 6830dca1793SAdrian Knoth 68438816545SAdrian Knoth static const char *const texts_freq[] = { 6850dca1793SAdrian Knoth "No Lock", 6860dca1793SAdrian Knoth "32 kHz", 6870dca1793SAdrian Knoth "44.1 kHz", 6880dca1793SAdrian Knoth "48 kHz", 6890dca1793SAdrian Knoth "64 kHz", 6900dca1793SAdrian Knoth "88.2 kHz", 6910dca1793SAdrian Knoth "96 kHz", 6920dca1793SAdrian Knoth "128 kHz", 6930dca1793SAdrian Knoth "176.4 kHz", 6940dca1793SAdrian Knoth "192 kHz" 6950dca1793SAdrian Knoth }; 6960dca1793SAdrian Knoth 6970dca1793SAdrian Knoth static char *texts_ports_madi[] = { 6980dca1793SAdrian Knoth "MADI.1", "MADI.2", "MADI.3", "MADI.4", "MADI.5", "MADI.6", 6990dca1793SAdrian Knoth "MADI.7", "MADI.8", "MADI.9", "MADI.10", "MADI.11", "MADI.12", 7000dca1793SAdrian Knoth "MADI.13", "MADI.14", "MADI.15", "MADI.16", "MADI.17", "MADI.18", 7010dca1793SAdrian Knoth "MADI.19", "MADI.20", "MADI.21", "MADI.22", "MADI.23", "MADI.24", 7020dca1793SAdrian Knoth "MADI.25", "MADI.26", "MADI.27", "MADI.28", "MADI.29", "MADI.30", 7030dca1793SAdrian Knoth "MADI.31", "MADI.32", "MADI.33", "MADI.34", "MADI.35", "MADI.36", 7040dca1793SAdrian Knoth "MADI.37", "MADI.38", "MADI.39", "MADI.40", "MADI.41", "MADI.42", 7050dca1793SAdrian Knoth "MADI.43", "MADI.44", "MADI.45", "MADI.46", "MADI.47", "MADI.48", 7060dca1793SAdrian Knoth "MADI.49", "MADI.50", "MADI.51", "MADI.52", "MADI.53", "MADI.54", 7070dca1793SAdrian Knoth "MADI.55", "MADI.56", "MADI.57", "MADI.58", "MADI.59", "MADI.60", 7080dca1793SAdrian Knoth "MADI.61", "MADI.62", "MADI.63", "MADI.64", 7090dca1793SAdrian Knoth }; 7100dca1793SAdrian Knoth 7110dca1793SAdrian Knoth 7120dca1793SAdrian Knoth static char *texts_ports_raydat_ss[] = { 7130dca1793SAdrian Knoth "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4", "ADAT1.5", "ADAT1.6", 7140dca1793SAdrian Knoth "ADAT1.7", "ADAT1.8", "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4", 7150dca1793SAdrian Knoth "ADAT2.5", "ADAT2.6", "ADAT2.7", "ADAT2.8", "ADAT3.1", "ADAT3.2", 7160dca1793SAdrian Knoth "ADAT3.3", "ADAT3.4", "ADAT3.5", "ADAT3.6", "ADAT3.7", "ADAT3.8", 7170dca1793SAdrian Knoth "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4", "ADAT4.5", "ADAT4.6", 7180dca1793SAdrian Knoth "ADAT4.7", "ADAT4.8", 7190dca1793SAdrian Knoth "AES.L", "AES.R", 7200dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R" 7210dca1793SAdrian Knoth }; 7220dca1793SAdrian Knoth 7230dca1793SAdrian Knoth static char *texts_ports_raydat_ds[] = { 7240dca1793SAdrian Knoth "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4", 7250dca1793SAdrian Knoth "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4", 7260dca1793SAdrian Knoth "ADAT3.1", "ADAT3.2", "ADAT3.3", "ADAT3.4", 7270dca1793SAdrian Knoth "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4", 7280dca1793SAdrian Knoth "AES.L", "AES.R", 7290dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R" 7300dca1793SAdrian Knoth }; 7310dca1793SAdrian Knoth 7320dca1793SAdrian Knoth static char *texts_ports_raydat_qs[] = { 7330dca1793SAdrian Knoth "ADAT1.1", "ADAT1.2", 7340dca1793SAdrian Knoth "ADAT2.1", "ADAT2.2", 7350dca1793SAdrian Knoth "ADAT3.1", "ADAT3.2", 7360dca1793SAdrian Knoth "ADAT4.1", "ADAT4.2", 7370dca1793SAdrian Knoth "AES.L", "AES.R", 7380dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R" 7390dca1793SAdrian Knoth }; 7400dca1793SAdrian Knoth 7410dca1793SAdrian Knoth 7420dca1793SAdrian Knoth static char *texts_ports_aio_in_ss[] = { 7430dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 7440dca1793SAdrian Knoth "AES.L", "AES.R", 7450dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 7460dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", 7473de9db26SAdrian Knoth "ADAT.7", "ADAT.8", 7483de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7490dca1793SAdrian Knoth }; 7500dca1793SAdrian Knoth 7510dca1793SAdrian Knoth static char *texts_ports_aio_out_ss[] = { 7520dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 7530dca1793SAdrian Knoth "AES.L", "AES.R", 7540dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 7550dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", 7560dca1793SAdrian Knoth "ADAT.7", "ADAT.8", 7573de9db26SAdrian Knoth "Phone.L", "Phone.R", 7583de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7590dca1793SAdrian Knoth }; 7600dca1793SAdrian Knoth 7610dca1793SAdrian Knoth static char *texts_ports_aio_in_ds[] = { 7620dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 7630dca1793SAdrian Knoth "AES.L", "AES.R", 7640dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 7653de9db26SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 7663de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7670dca1793SAdrian Knoth }; 7680dca1793SAdrian Knoth 7690dca1793SAdrian Knoth static char *texts_ports_aio_out_ds[] = { 7700dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 7710dca1793SAdrian Knoth "AES.L", "AES.R", 7720dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 7730dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 7743de9db26SAdrian Knoth "Phone.L", "Phone.R", 7753de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7760dca1793SAdrian Knoth }; 7770dca1793SAdrian Knoth 7780dca1793SAdrian Knoth static char *texts_ports_aio_in_qs[] = { 7790dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 7800dca1793SAdrian Knoth "AES.L", "AES.R", 7810dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 7823de9db26SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 7833de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7840dca1793SAdrian Knoth }; 7850dca1793SAdrian Knoth 7860dca1793SAdrian Knoth static char *texts_ports_aio_out_qs[] = { 7870dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 7880dca1793SAdrian Knoth "AES.L", "AES.R", 7890dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 7900dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 7913de9db26SAdrian Knoth "Phone.L", "Phone.R", 7923de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4" 7930dca1793SAdrian Knoth }; 7940dca1793SAdrian Knoth 795432d2500SAdrian Knoth static char *texts_ports_aes32[] = { 796432d2500SAdrian Knoth "AES.1", "AES.2", "AES.3", "AES.4", "AES.5", "AES.6", "AES.7", 797432d2500SAdrian Knoth "AES.8", "AES.9.", "AES.10", "AES.11", "AES.12", "AES.13", "AES.14", 798432d2500SAdrian Knoth "AES.15", "AES.16" 799432d2500SAdrian Knoth }; 800432d2500SAdrian Knoth 80155a57606SAdrian Knoth /* These tables map the ALSA channels 1..N to the channels that we 80255a57606SAdrian Knoth need to use in order to find the relevant channel buffer. RME 80355a57606SAdrian Knoth refers to this kind of mapping as between "the ADAT channel and 80455a57606SAdrian Knoth the DMA channel." We index it using the logical audio channel, 80555a57606SAdrian Knoth and the value is the DMA channel (i.e. channel buffer number) 80655a57606SAdrian Knoth where the data for that channel can be read/written from/to. 80755a57606SAdrian Knoth */ 80855a57606SAdrian Knoth 80955a57606SAdrian Knoth static char channel_map_unity_ss[HDSPM_MAX_CHANNELS] = { 81055a57606SAdrian Knoth 0, 1, 2, 3, 4, 5, 6, 7, 81155a57606SAdrian Knoth 8, 9, 10, 11, 12, 13, 14, 15, 81255a57606SAdrian Knoth 16, 17, 18, 19, 20, 21, 22, 23, 81355a57606SAdrian Knoth 24, 25, 26, 27, 28, 29, 30, 31, 81455a57606SAdrian Knoth 32, 33, 34, 35, 36, 37, 38, 39, 81555a57606SAdrian Knoth 40, 41, 42, 43, 44, 45, 46, 47, 81655a57606SAdrian Knoth 48, 49, 50, 51, 52, 53, 54, 55, 81755a57606SAdrian Knoth 56, 57, 58, 59, 60, 61, 62, 63 81855a57606SAdrian Knoth }; 81955a57606SAdrian Knoth 82055a57606SAdrian Knoth static char channel_map_raydat_ss[HDSPM_MAX_CHANNELS] = { 82155a57606SAdrian Knoth 4, 5, 6, 7, 8, 9, 10, 11, /* ADAT 1 */ 82255a57606SAdrian Knoth 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT 2 */ 82355a57606SAdrian Knoth 20, 21, 22, 23, 24, 25, 26, 27, /* ADAT 3 */ 82455a57606SAdrian Knoth 28, 29, 30, 31, 32, 33, 34, 35, /* ADAT 4 */ 82555a57606SAdrian Knoth 0, 1, /* AES */ 82655a57606SAdrian Knoth 2, 3, /* SPDIF */ 82755a57606SAdrian Knoth -1, -1, -1, -1, 82855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 82955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 83055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 83155a57606SAdrian Knoth }; 83255a57606SAdrian Knoth 83355a57606SAdrian Knoth static char channel_map_raydat_ds[HDSPM_MAX_CHANNELS] = { 83455a57606SAdrian Knoth 4, 5, 6, 7, /* ADAT 1 */ 83555a57606SAdrian Knoth 8, 9, 10, 11, /* ADAT 2 */ 83655a57606SAdrian Knoth 12, 13, 14, 15, /* ADAT 3 */ 83755a57606SAdrian Knoth 16, 17, 18, 19, /* ADAT 4 */ 83855a57606SAdrian Knoth 0, 1, /* AES */ 83955a57606SAdrian Knoth 2, 3, /* SPDIF */ 84055a57606SAdrian Knoth -1, -1, -1, -1, 84155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 84255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 84355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 84455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 84555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 84655a57606SAdrian Knoth }; 84755a57606SAdrian Knoth 84855a57606SAdrian Knoth static char channel_map_raydat_qs[HDSPM_MAX_CHANNELS] = { 84955a57606SAdrian Knoth 4, 5, /* ADAT 1 */ 85055a57606SAdrian Knoth 6, 7, /* ADAT 2 */ 85155a57606SAdrian Knoth 8, 9, /* ADAT 3 */ 85255a57606SAdrian Knoth 10, 11, /* ADAT 4 */ 85355a57606SAdrian Knoth 0, 1, /* AES */ 85455a57606SAdrian Knoth 2, 3, /* SPDIF */ 85555a57606SAdrian Knoth -1, -1, -1, -1, 85655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 85755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 85855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 85955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 86055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 86155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 86255a57606SAdrian Knoth }; 86355a57606SAdrian Knoth 86455a57606SAdrian Knoth static char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = { 86555a57606SAdrian Knoth 0, 1, /* line in */ 86655a57606SAdrian Knoth 8, 9, /* aes in, */ 86755a57606SAdrian Knoth 10, 11, /* spdif in */ 86855a57606SAdrian Knoth 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */ 8693de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */ 8703de9db26SAdrian Knoth -1, -1, -1, -1, -1, -1, 87155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 87255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 87355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 87455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 87555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 87655a57606SAdrian Knoth }; 87755a57606SAdrian Knoth 87855a57606SAdrian Knoth static char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = { 87955a57606SAdrian Knoth 0, 1, /* line out */ 88055a57606SAdrian Knoth 8, 9, /* aes out */ 88155a57606SAdrian Knoth 10, 11, /* spdif out */ 88255a57606SAdrian Knoth 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */ 88355a57606SAdrian Knoth 6, 7, /* phone out */ 8843de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */ 8853de9db26SAdrian Knoth -1, -1, -1, -1, 88655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 88755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 88855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 88955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 89055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 89155a57606SAdrian Knoth }; 89255a57606SAdrian Knoth 89355a57606SAdrian Knoth static char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = { 89455a57606SAdrian Knoth 0, 1, /* line in */ 89555a57606SAdrian Knoth 8, 9, /* aes in */ 89655a57606SAdrian Knoth 10, 11, /* spdif in */ 89755a57606SAdrian Knoth 12, 14, 16, 18, /* adat in */ 8983de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */ 8993de9db26SAdrian Knoth -1, -1, 90055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 90155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 90255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 90355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 90455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 90555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1 90655a57606SAdrian Knoth }; 90755a57606SAdrian Knoth 90855a57606SAdrian Knoth static char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = { 90955a57606SAdrian Knoth 0, 1, /* line out */ 91055a57606SAdrian Knoth 8, 9, /* aes out */ 91155a57606SAdrian Knoth 10, 11, /* spdif out */ 91255a57606SAdrian Knoth 12, 14, 16, 18, /* adat out */ 91355a57606SAdrian Knoth 6, 7, /* phone out */ 9143de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */ 91555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 91655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 91755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 91855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 91955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 92055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1 92155a57606SAdrian Knoth }; 92255a57606SAdrian Knoth 92355a57606SAdrian Knoth static char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = { 92455a57606SAdrian Knoth 0, 1, /* line in */ 92555a57606SAdrian Knoth 8, 9, /* aes in */ 92655a57606SAdrian Knoth 10, 11, /* spdif in */ 92755a57606SAdrian Knoth 12, 16, /* adat in */ 9283de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */ 9293de9db26SAdrian Knoth -1, -1, -1, -1, 93055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 93155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 93255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 93355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 93455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 93555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1 93655a57606SAdrian Knoth }; 93755a57606SAdrian Knoth 93855a57606SAdrian Knoth static char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = { 93955a57606SAdrian Knoth 0, 1, /* line out */ 94055a57606SAdrian Knoth 8, 9, /* aes out */ 94155a57606SAdrian Knoth 10, 11, /* spdif out */ 94255a57606SAdrian Knoth 12, 16, /* adat out */ 94355a57606SAdrian Knoth 6, 7, /* phone out */ 9443de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */ 9453de9db26SAdrian Knoth -1, -1, 94655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 94755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 94855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 94955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 95055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 95155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1 95255a57606SAdrian Knoth }; 95355a57606SAdrian Knoth 954432d2500SAdrian Knoth static char channel_map_aes32[HDSPM_MAX_CHANNELS] = { 955432d2500SAdrian Knoth 0, 1, 2, 3, 4, 5, 6, 7, 956432d2500SAdrian Knoth 8, 9, 10, 11, 12, 13, 14, 15, 957432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 958432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 959432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 960432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 961432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 962432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1 963432d2500SAdrian Knoth }; 964432d2500SAdrian Knoth 96598274f07STakashi Iwai struct hdspm_midi { 96698274f07STakashi Iwai struct hdspm *hdspm; 967763f356cSTakashi Iwai int id; 96898274f07STakashi Iwai struct snd_rawmidi *rmidi; 96998274f07STakashi Iwai struct snd_rawmidi_substream *input; 97098274f07STakashi Iwai struct snd_rawmidi_substream *output; 971763f356cSTakashi Iwai char istimer; /* timer in use */ 972763f356cSTakashi Iwai struct timer_list timer; 973763f356cSTakashi Iwai spinlock_t lock; 974763f356cSTakashi Iwai int pending; 9750dca1793SAdrian Knoth int dataIn; 9760dca1793SAdrian Knoth int statusIn; 9770dca1793SAdrian Knoth int dataOut; 9780dca1793SAdrian Knoth int statusOut; 9790dca1793SAdrian Knoth int ie; 9800dca1793SAdrian Knoth int irq; 9810dca1793SAdrian Knoth }; 9820dca1793SAdrian Knoth 9830dca1793SAdrian Knoth struct hdspm_tco { 984*69358fcaSMartin Dausel int input; /* 0: LTC, 1:Video, 2: WC*/ 985*69358fcaSMartin Dausel int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */ 986*69358fcaSMartin Dausel int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */ 987*69358fcaSMartin Dausel int samplerate; /* 0=44.1, 1=48, 2= freq from app */ 988*69358fcaSMartin Dausel int pull; /* 0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/ 9890dca1793SAdrian Knoth int term; /* 0 = off, 1 = on */ 990763f356cSTakashi Iwai }; 991763f356cSTakashi Iwai 99298274f07STakashi Iwai struct hdspm { 993763f356cSTakashi Iwai spinlock_t lock; 994ef5fa1a4STakashi Iwai /* only one playback and/or capture stream */ 995ef5fa1a4STakashi Iwai struct snd_pcm_substream *capture_substream; 996ef5fa1a4STakashi Iwai struct snd_pcm_substream *playback_substream; 997763f356cSTakashi Iwai 998763f356cSTakashi Iwai char *card_name; /* for procinfo */ 9993cee5a60SRemy Bruno unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/ 10003cee5a60SRemy Bruno 10010dca1793SAdrian Knoth uint8_t io_type; 1002763f356cSTakashi Iwai 1003763f356cSTakashi Iwai int monitor_outs; /* set up monitoring outs init flag */ 1004763f356cSTakashi Iwai 1005763f356cSTakashi Iwai u32 control_register; /* cached value */ 1006763f356cSTakashi Iwai u32 control2_register; /* cached value */ 1007*69358fcaSMartin Dausel u32 settings_register; /* cached value for AIO / RayDat (sync reference, master/slave) */ 1008763f356cSTakashi Iwai 10090dca1793SAdrian Knoth struct hdspm_midi midi[4]; 1010763f356cSTakashi Iwai struct tasklet_struct midi_tasklet; 1011763f356cSTakashi Iwai 1012763f356cSTakashi Iwai size_t period_bytes; 10130dca1793SAdrian Knoth unsigned char ss_in_channels; 10140dca1793SAdrian Knoth unsigned char ds_in_channels; 10150dca1793SAdrian Knoth unsigned char qs_in_channels; 10160dca1793SAdrian Knoth unsigned char ss_out_channels; 10170dca1793SAdrian Knoth unsigned char ds_out_channels; 10180dca1793SAdrian Knoth unsigned char qs_out_channels; 10190dca1793SAdrian Knoth 10200dca1793SAdrian Knoth unsigned char max_channels_in; 10210dca1793SAdrian Knoth unsigned char max_channels_out; 10220dca1793SAdrian Knoth 1023286bed0fSTakashi Iwai signed char *channel_map_in; 1024286bed0fSTakashi Iwai signed char *channel_map_out; 10250dca1793SAdrian Knoth 1026286bed0fSTakashi Iwai signed char *channel_map_in_ss, *channel_map_in_ds, *channel_map_in_qs; 1027286bed0fSTakashi Iwai signed char *channel_map_out_ss, *channel_map_out_ds, *channel_map_out_qs; 10280dca1793SAdrian Knoth 10290dca1793SAdrian Knoth char **port_names_in; 10300dca1793SAdrian Knoth char **port_names_out; 10310dca1793SAdrian Knoth 10320dca1793SAdrian Knoth char **port_names_in_ss, **port_names_in_ds, **port_names_in_qs; 10330dca1793SAdrian Knoth char **port_names_out_ss, **port_names_out_ds, **port_names_out_qs; 1034763f356cSTakashi Iwai 1035763f356cSTakashi Iwai unsigned char *playback_buffer; /* suitably aligned address */ 1036763f356cSTakashi Iwai unsigned char *capture_buffer; /* suitably aligned address */ 1037763f356cSTakashi Iwai 1038763f356cSTakashi Iwai pid_t capture_pid; /* process id which uses capture */ 1039763f356cSTakashi Iwai pid_t playback_pid; /* process id which uses capture */ 1040763f356cSTakashi Iwai int running; /* running status */ 1041763f356cSTakashi Iwai 1042763f356cSTakashi Iwai int last_external_sample_rate; /* samplerate mystic ... */ 1043763f356cSTakashi Iwai int last_internal_sample_rate; 1044763f356cSTakashi Iwai int system_sample_rate; 1045763f356cSTakashi Iwai 1046763f356cSTakashi Iwai int dev; /* Hardware vars... */ 1047763f356cSTakashi Iwai int irq; 1048763f356cSTakashi Iwai unsigned long port; 1049763f356cSTakashi Iwai void __iomem *iobase; 1050763f356cSTakashi Iwai 1051763f356cSTakashi Iwai int irq_count; /* for debug */ 10520dca1793SAdrian Knoth int midiPorts; 1053763f356cSTakashi Iwai 105498274f07STakashi Iwai struct snd_card *card; /* one card */ 105598274f07STakashi Iwai struct snd_pcm *pcm; /* has one pcm */ 105698274f07STakashi Iwai struct snd_hwdep *hwdep; /* and a hwdep for additional ioctl */ 1057763f356cSTakashi Iwai struct pci_dev *pci; /* and an pci info */ 1058763f356cSTakashi Iwai 1059763f356cSTakashi Iwai /* Mixer vars */ 1060ef5fa1a4STakashi Iwai /* fast alsa mixer */ 1061ef5fa1a4STakashi Iwai struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; 1062ef5fa1a4STakashi Iwai /* but input to much, so not used */ 1063ef5fa1a4STakashi Iwai struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS]; 106425985edcSLucas De Marchi /* full mixer accessible over mixer ioctl or hwdep-device */ 1065ef5fa1a4STakashi Iwai struct hdspm_mixer *mixer; 1066763f356cSTakashi Iwai 10670dca1793SAdrian Knoth struct hdspm_tco *tco; /* NULL if no TCO detected */ 1068763f356cSTakashi Iwai 1069eb0d4dbfSAdrian Knoth const char *const *texts_autosync; 10700dca1793SAdrian Knoth int texts_autosync_items; 1071763f356cSTakashi Iwai 10720dca1793SAdrian Knoth cycles_t last_interrupt; 1073730a5865SJaroslav Kysela 10747d53a631SAdrian Knoth unsigned int serial; 10757d53a631SAdrian Knoth 1076730a5865SJaroslav Kysela struct hdspm_peak_rms peak_rms; 1077763f356cSTakashi Iwai }; 1078763f356cSTakashi Iwai 1079763f356cSTakashi Iwai 1080cebe41d4SAlexey Dobriyan static DEFINE_PCI_DEVICE_TABLE(snd_hdspm_ids) = { 1081763f356cSTakashi Iwai { 1082763f356cSTakashi Iwai .vendor = PCI_VENDOR_ID_XILINX, 1083763f356cSTakashi Iwai .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, 1084763f356cSTakashi Iwai .subvendor = PCI_ANY_ID, 1085763f356cSTakashi Iwai .subdevice = PCI_ANY_ID, 1086763f356cSTakashi Iwai .class = 0, 1087763f356cSTakashi Iwai .class_mask = 0, 1088763f356cSTakashi Iwai .driver_data = 0}, 1089763f356cSTakashi Iwai {0,} 1090763f356cSTakashi Iwai }; 1091763f356cSTakashi Iwai 1092763f356cSTakashi Iwai MODULE_DEVICE_TABLE(pci, snd_hdspm_ids); 1093763f356cSTakashi Iwai 1094763f356cSTakashi Iwai /* prototypes */ 1095e23e7a14SBill Pemberton static int snd_hdspm_create_alsa_devices(struct snd_card *card, 109698274f07STakashi Iwai struct hdspm *hdspm); 1097e23e7a14SBill Pemberton static int snd_hdspm_create_pcm(struct snd_card *card, 109898274f07STakashi Iwai struct hdspm *hdspm); 1099763f356cSTakashi Iwai 110098274f07STakashi Iwai static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm); 11013f7bf918SAdrian Knoth static inline int hdspm_get_pll_freq(struct hdspm *hdspm); 110298274f07STakashi Iwai static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); 110398274f07STakashi Iwai static int hdspm_autosync_ref(struct hdspm *hdspm); 110434be7ebbSAdrian Knoth static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out); 110598274f07STakashi Iwai static int snd_hdspm_set_defaults(struct hdspm *hdspm); 110621a164dfSAdrian Knoth static int hdspm_system_clock_mode(struct hdspm *hdspm); 110777a23f26STakashi Iwai static void hdspm_set_sgbuf(struct hdspm *hdspm, 110877a23f26STakashi Iwai struct snd_pcm_substream *substream, 1109763f356cSTakashi Iwai unsigned int reg, int channels); 1110763f356cSTakashi Iwai 11115b266354SAdrian Knoth static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx); 11125b266354SAdrian Knoth static int hdspm_wc_sync_check(struct hdspm *hdspm); 11135b266354SAdrian Knoth static int hdspm_tco_sync_check(struct hdspm *hdspm); 11145b266354SAdrian Knoth static int hdspm_sync_in_sync_check(struct hdspm *hdspm); 11155b266354SAdrian Knoth 11165b266354SAdrian Knoth static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index); 11175b266354SAdrian Knoth static int hdspm_get_tco_sample_rate(struct hdspm *hdspm); 11185b266354SAdrian Knoth static int hdspm_get_wc_sample_rate(struct hdspm *hdspm); 11195b266354SAdrian Knoth 11205b266354SAdrian Knoth 11215b266354SAdrian Knoth 11223cee5a60SRemy Bruno static inline int HDSPM_bit2freq(int n) 11233cee5a60SRemy Bruno { 112462cef821SDenys Vlasenko static const int bit2freq_tab[] = { 112562cef821SDenys Vlasenko 0, 32000, 44100, 48000, 64000, 88200, 11263cee5a60SRemy Bruno 96000, 128000, 176400, 192000 }; 11273cee5a60SRemy Bruno if (n < 1 || n > 9) 11283cee5a60SRemy Bruno return 0; 11293cee5a60SRemy Bruno return bit2freq_tab[n]; 11303cee5a60SRemy Bruno } 11313cee5a60SRemy Bruno 1132b2ed6326SAdrian Knoth static bool hdspm_is_raydat_or_aio(struct hdspm *hdspm) 1133b2ed6326SAdrian Knoth { 1134b2ed6326SAdrian Knoth return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type)); 1135b2ed6326SAdrian Knoth } 1136b2ed6326SAdrian Knoth 1137b2ed6326SAdrian Knoth 11380dca1793SAdrian Knoth /* Write/read to/from HDSPM with Adresses in Bytes 1139763f356cSTakashi Iwai not words but only 32Bit writes are allowed */ 1140763f356cSTakashi Iwai 114198274f07STakashi Iwai static inline void hdspm_write(struct hdspm * hdspm, unsigned int reg, 1142763f356cSTakashi Iwai unsigned int val) 1143763f356cSTakashi Iwai { 1144763f356cSTakashi Iwai writel(val, hdspm->iobase + reg); 1145763f356cSTakashi Iwai } 1146763f356cSTakashi Iwai 114798274f07STakashi Iwai static inline unsigned int hdspm_read(struct hdspm * hdspm, unsigned int reg) 1148763f356cSTakashi Iwai { 1149763f356cSTakashi Iwai return readl(hdspm->iobase + reg); 1150763f356cSTakashi Iwai } 1151763f356cSTakashi Iwai 1152763f356cSTakashi Iwai /* for each output channel (chan) I have an Input (in) and Playback (pb) Fader 1153763f356cSTakashi Iwai mixer is write only on hardware so we have to cache him for read 1154763f356cSTakashi Iwai each fader is a u32, but uses only the first 16 bit */ 1155763f356cSTakashi Iwai 115698274f07STakashi Iwai static inline int hdspm_read_in_gain(struct hdspm * hdspm, unsigned int chan, 1157763f356cSTakashi Iwai unsigned int in) 1158763f356cSTakashi Iwai { 11595bab2482SAdrian Bunk if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) 1160763f356cSTakashi Iwai return 0; 1161763f356cSTakashi Iwai 1162763f356cSTakashi Iwai return hdspm->mixer->ch[chan].in[in]; 1163763f356cSTakashi Iwai } 1164763f356cSTakashi Iwai 116598274f07STakashi Iwai static inline int hdspm_read_pb_gain(struct hdspm * hdspm, unsigned int chan, 1166763f356cSTakashi Iwai unsigned int pb) 1167763f356cSTakashi Iwai { 11685bab2482SAdrian Bunk if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) 1169763f356cSTakashi Iwai return 0; 1170763f356cSTakashi Iwai return hdspm->mixer->ch[chan].pb[pb]; 1171763f356cSTakashi Iwai } 1172763f356cSTakashi Iwai 117362cef821SDenys Vlasenko static int hdspm_write_in_gain(struct hdspm *hdspm, unsigned int chan, 1174763f356cSTakashi Iwai unsigned int in, unsigned short data) 1175763f356cSTakashi Iwai { 1176763f356cSTakashi Iwai if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) 1177763f356cSTakashi Iwai return -1; 1178763f356cSTakashi Iwai 1179763f356cSTakashi Iwai hdspm_write(hdspm, 1180763f356cSTakashi Iwai HDSPM_MADI_mixerBase + 1181763f356cSTakashi Iwai ((in + 128 * chan) * sizeof(u32)), 1182763f356cSTakashi Iwai (hdspm->mixer->ch[chan].in[in] = data & 0xFFFF)); 1183763f356cSTakashi Iwai return 0; 1184763f356cSTakashi Iwai } 1185763f356cSTakashi Iwai 118662cef821SDenys Vlasenko static int hdspm_write_pb_gain(struct hdspm *hdspm, unsigned int chan, 1187763f356cSTakashi Iwai unsigned int pb, unsigned short data) 1188763f356cSTakashi Iwai { 1189763f356cSTakashi Iwai if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) 1190763f356cSTakashi Iwai return -1; 1191763f356cSTakashi Iwai 1192763f356cSTakashi Iwai hdspm_write(hdspm, 1193763f356cSTakashi Iwai HDSPM_MADI_mixerBase + 1194763f356cSTakashi Iwai ((64 + pb + 128 * chan) * sizeof(u32)), 1195763f356cSTakashi Iwai (hdspm->mixer->ch[chan].pb[pb] = data & 0xFFFF)); 1196763f356cSTakashi Iwai return 0; 1197763f356cSTakashi Iwai } 1198763f356cSTakashi Iwai 1199763f356cSTakashi Iwai 1200763f356cSTakashi Iwai /* enable DMA for specific channels, now available for DSP-MADI */ 120198274f07STakashi Iwai static inline void snd_hdspm_enable_in(struct hdspm * hdspm, int i, int v) 1202763f356cSTakashi Iwai { 1203763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_inputEnableBase + (4 * i), v); 1204763f356cSTakashi Iwai } 1205763f356cSTakashi Iwai 120698274f07STakashi Iwai static inline void snd_hdspm_enable_out(struct hdspm * hdspm, int i, int v) 1207763f356cSTakashi Iwai { 1208763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_outputEnableBase + (4 * i), v); 1209763f356cSTakashi Iwai } 1210763f356cSTakashi Iwai 1211763f356cSTakashi Iwai /* check if same process is writing and reading */ 121262cef821SDenys Vlasenko static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm) 1213763f356cSTakashi Iwai { 1214763f356cSTakashi Iwai unsigned long flags; 1215763f356cSTakashi Iwai int ret = 1; 1216763f356cSTakashi Iwai 1217763f356cSTakashi Iwai spin_lock_irqsave(&hdspm->lock, flags); 1218763f356cSTakashi Iwai if ((hdspm->playback_pid != hdspm->capture_pid) && 1219763f356cSTakashi Iwai (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) { 1220763f356cSTakashi Iwai ret = 0; 1221763f356cSTakashi Iwai } 1222763f356cSTakashi Iwai spin_unlock_irqrestore(&hdspm->lock, flags); 1223763f356cSTakashi Iwai return ret; 1224763f356cSTakashi Iwai } 1225763f356cSTakashi Iwai 1226fcdc4ba1SAdrian Knoth /* round arbitary sample rates to commonly known rates */ 1227fcdc4ba1SAdrian Knoth static int hdspm_round_frequency(int rate) 1228fcdc4ba1SAdrian Knoth { 1229fcdc4ba1SAdrian Knoth if (rate < 38050) 1230fcdc4ba1SAdrian Knoth return 32000; 1231fcdc4ba1SAdrian Knoth if (rate < 46008) 1232fcdc4ba1SAdrian Knoth return 44100; 1233fcdc4ba1SAdrian Knoth else 1234fcdc4ba1SAdrian Knoth return 48000; 1235fcdc4ba1SAdrian Knoth } 1236fcdc4ba1SAdrian Knoth 1237a8a729faSAdrian Knoth /* QS and DS rates normally can not be detected 1238a8a729faSAdrian Knoth * automatically by the card. Only exception is MADI 1239a8a729faSAdrian Knoth * in 96k frame mode. 1240a8a729faSAdrian Knoth * 1241a8a729faSAdrian Knoth * So if we read SS values (32 .. 48k), check for 1242a8a729faSAdrian Knoth * user-provided DS/QS bits in the control register 1243a8a729faSAdrian Knoth * and multiply the base frequency accordingly. 1244a8a729faSAdrian Knoth */ 1245a8a729faSAdrian Knoth static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate) 1246a8a729faSAdrian Knoth { 1247a8a729faSAdrian Knoth if (rate <= 48000) { 1248a8a729faSAdrian Knoth if (hdspm->control_register & HDSPM_QuadSpeed) 1249a8a729faSAdrian Knoth return rate * 4; 1250a8a729faSAdrian Knoth else if (hdspm->control_register & 1251a8a729faSAdrian Knoth HDSPM_DoubleSpeed) 1252a8a729faSAdrian Knoth return rate * 2; 1253a8a729faSAdrian Knoth }; 1254a8a729faSAdrian Knoth return rate; 1255a8a729faSAdrian Knoth } 1256a8a729faSAdrian Knoth 12575b266354SAdrian Knoth /* check for external sample rate, returns the sample rate in Hz*/ 125862cef821SDenys Vlasenko static int hdspm_external_sample_rate(struct hdspm *hdspm) 1259763f356cSTakashi Iwai { 12600dca1793SAdrian Knoth unsigned int status, status2, timecode; 12610dca1793SAdrian Knoth int syncref, rate = 0, rate_bits; 12623cee5a60SRemy Bruno 12630dca1793SAdrian Knoth switch (hdspm->io_type) { 12640dca1793SAdrian Knoth case AES32: 12650dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 12660dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 12670dca1793SAdrian Knoth timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); 12680dca1793SAdrian Knoth 12690dca1793SAdrian Knoth syncref = hdspm_autosync_ref(hdspm); 1270dbae4a0cSAdrian Knoth switch (syncref) { 1271dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_WORD: 1272dbae4a0cSAdrian Knoth /* Check WC sync and get sample rate */ 1273dbae4a0cSAdrian Knoth if (hdspm_wc_sync_check(hdspm)) 1274dbae4a0cSAdrian Knoth return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm)); 1275dbae4a0cSAdrian Knoth break; 12763cee5a60SRemy Bruno 1277dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES1: 1278dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES2: 1279dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES3: 1280dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES4: 1281dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES5: 1282dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES6: 1283dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES7: 1284dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES8: 1285dbae4a0cSAdrian Knoth /* Check AES sync and get sample rate */ 1286dbae4a0cSAdrian Knoth if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)) 1287dbae4a0cSAdrian Knoth return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm, 1288dbae4a0cSAdrian Knoth syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)); 1289dbae4a0cSAdrian Knoth break; 12900dca1793SAdrian Knoth 1291dbae4a0cSAdrian Knoth 1292dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_TCO: 1293dbae4a0cSAdrian Knoth /* Check TCO sync and get sample rate */ 1294dbae4a0cSAdrian Knoth if (hdspm_tco_sync_check(hdspm)) 1295dbae4a0cSAdrian Knoth return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm)); 1296dbae4a0cSAdrian Knoth break; 1297dbae4a0cSAdrian Knoth default: 12983cee5a60SRemy Bruno return 0; 1299dbae4a0cSAdrian Knoth } /* end switch(syncref) */ 13000dca1793SAdrian Knoth break; 13010dca1793SAdrian Knoth 13020dca1793SAdrian Knoth case MADIface: 13030dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 13040dca1793SAdrian Knoth 13050dca1793SAdrian Knoth if (!(status & HDSPM_madiLock)) { 13060dca1793SAdrian Knoth rate = 0; /* no lock */ 13073cee5a60SRemy Bruno } else { 13080dca1793SAdrian Knoth switch (status & (HDSPM_status1_freqMask)) { 13090dca1793SAdrian Knoth case HDSPM_status1_F_0*1: 13100dca1793SAdrian Knoth rate = 32000; break; 13110dca1793SAdrian Knoth case HDSPM_status1_F_0*2: 13120dca1793SAdrian Knoth rate = 44100; break; 13130dca1793SAdrian Knoth case HDSPM_status1_F_0*3: 13140dca1793SAdrian Knoth rate = 48000; break; 13150dca1793SAdrian Knoth case HDSPM_status1_F_0*4: 13160dca1793SAdrian Knoth rate = 64000; break; 13170dca1793SAdrian Knoth case HDSPM_status1_F_0*5: 13180dca1793SAdrian Knoth rate = 88200; break; 13190dca1793SAdrian Knoth case HDSPM_status1_F_0*6: 13200dca1793SAdrian Knoth rate = 96000; break; 13210dca1793SAdrian Knoth case HDSPM_status1_F_0*7: 13220dca1793SAdrian Knoth rate = 128000; break; 13230dca1793SAdrian Knoth case HDSPM_status1_F_0*8: 13240dca1793SAdrian Knoth rate = 176400; break; 13250dca1793SAdrian Knoth case HDSPM_status1_F_0*9: 13260dca1793SAdrian Knoth rate = 192000; break; 13270dca1793SAdrian Knoth default: 13280dca1793SAdrian Knoth rate = 0; break; 13290dca1793SAdrian Knoth } 13300dca1793SAdrian Knoth } 13310dca1793SAdrian Knoth 13320dca1793SAdrian Knoth break; 13330dca1793SAdrian Knoth 13340dca1793SAdrian Knoth case MADI: 13350dca1793SAdrian Knoth case AIO: 13360dca1793SAdrian Knoth case RayDAT: 13370dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 13380dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 13390dca1793SAdrian Knoth rate = 0; 1340763f356cSTakashi Iwai 1341763f356cSTakashi Iwai /* if wordclock has synced freq and wordclock is valid */ 1342763f356cSTakashi Iwai if ((status2 & HDSPM_wcLock) != 0 && 1343fedf1535SAdrian Knoth (status2 & HDSPM_SelSyncRef0) == 0) { 1344763f356cSTakashi Iwai 1345763f356cSTakashi Iwai rate_bits = status2 & HDSPM_wcFreqMask; 1346763f356cSTakashi Iwai 13470dca1793SAdrian Knoth 1348763f356cSTakashi Iwai switch (rate_bits) { 1349763f356cSTakashi Iwai case HDSPM_wcFreq32: 1350763f356cSTakashi Iwai rate = 32000; 1351763f356cSTakashi Iwai break; 1352763f356cSTakashi Iwai case HDSPM_wcFreq44_1: 1353763f356cSTakashi Iwai rate = 44100; 1354763f356cSTakashi Iwai break; 1355763f356cSTakashi Iwai case HDSPM_wcFreq48: 1356763f356cSTakashi Iwai rate = 48000; 1357763f356cSTakashi Iwai break; 1358763f356cSTakashi Iwai case HDSPM_wcFreq64: 1359763f356cSTakashi Iwai rate = 64000; 1360763f356cSTakashi Iwai break; 1361763f356cSTakashi Iwai case HDSPM_wcFreq88_2: 1362763f356cSTakashi Iwai rate = 88200; 1363763f356cSTakashi Iwai break; 1364763f356cSTakashi Iwai case HDSPM_wcFreq96: 1365763f356cSTakashi Iwai rate = 96000; 1366763f356cSTakashi Iwai break; 1367a8cd7148SAdrian Knoth case HDSPM_wcFreq128: 1368a8cd7148SAdrian Knoth rate = 128000; 1369a8cd7148SAdrian Knoth break; 1370a8cd7148SAdrian Knoth case HDSPM_wcFreq176_4: 1371a8cd7148SAdrian Knoth rate = 176400; 1372a8cd7148SAdrian Knoth break; 1373a8cd7148SAdrian Knoth case HDSPM_wcFreq192: 1374a8cd7148SAdrian Knoth rate = 192000; 1375a8cd7148SAdrian Knoth break; 1376763f356cSTakashi Iwai default: 1377763f356cSTakashi Iwai rate = 0; 1378763f356cSTakashi Iwai break; 1379763f356cSTakashi Iwai } 1380763f356cSTakashi Iwai } 1381763f356cSTakashi Iwai 1382ef5fa1a4STakashi Iwai /* if rate detected and Syncref is Word than have it, 1383ef5fa1a4STakashi Iwai * word has priority to MADI 1384ef5fa1a4STakashi Iwai */ 13853cee5a60SRemy Bruno if (rate != 0 && 13863cee5a60SRemy Bruno (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) 13877b559397SAdrian Knoth return hdspm_rate_multiplier(hdspm, rate); 1388763f356cSTakashi Iwai 13890dca1793SAdrian Knoth /* maybe a madi input (which is taken if sel sync is madi) */ 1390763f356cSTakashi Iwai if (status & HDSPM_madiLock) { 1391763f356cSTakashi Iwai rate_bits = status & HDSPM_madiFreqMask; 1392763f356cSTakashi Iwai 1393763f356cSTakashi Iwai switch (rate_bits) { 1394763f356cSTakashi Iwai case HDSPM_madiFreq32: 1395763f356cSTakashi Iwai rate = 32000; 1396763f356cSTakashi Iwai break; 1397763f356cSTakashi Iwai case HDSPM_madiFreq44_1: 1398763f356cSTakashi Iwai rate = 44100; 1399763f356cSTakashi Iwai break; 1400763f356cSTakashi Iwai case HDSPM_madiFreq48: 1401763f356cSTakashi Iwai rate = 48000; 1402763f356cSTakashi Iwai break; 1403763f356cSTakashi Iwai case HDSPM_madiFreq64: 1404763f356cSTakashi Iwai rate = 64000; 1405763f356cSTakashi Iwai break; 1406763f356cSTakashi Iwai case HDSPM_madiFreq88_2: 1407763f356cSTakashi Iwai rate = 88200; 1408763f356cSTakashi Iwai break; 1409763f356cSTakashi Iwai case HDSPM_madiFreq96: 1410763f356cSTakashi Iwai rate = 96000; 1411763f356cSTakashi Iwai break; 1412763f356cSTakashi Iwai case HDSPM_madiFreq128: 1413763f356cSTakashi Iwai rate = 128000; 1414763f356cSTakashi Iwai break; 1415763f356cSTakashi Iwai case HDSPM_madiFreq176_4: 1416763f356cSTakashi Iwai rate = 176400; 1417763f356cSTakashi Iwai break; 1418763f356cSTakashi Iwai case HDSPM_madiFreq192: 1419763f356cSTakashi Iwai rate = 192000; 1420763f356cSTakashi Iwai break; 1421763f356cSTakashi Iwai default: 1422763f356cSTakashi Iwai rate = 0; 1423763f356cSTakashi Iwai break; 1424763f356cSTakashi Iwai } 1425d12c51d8SAdrian Knoth 1426fcdc4ba1SAdrian Knoth } /* endif HDSPM_madiLock */ 1427fcdc4ba1SAdrian Knoth 1428fcdc4ba1SAdrian Knoth /* check sample rate from TCO or SYNC_IN */ 1429fcdc4ba1SAdrian Knoth { 1430fcdc4ba1SAdrian Knoth bool is_valid_input = 0; 1431fcdc4ba1SAdrian Knoth bool has_sync = 0; 1432fcdc4ba1SAdrian Knoth 1433fcdc4ba1SAdrian Knoth syncref = hdspm_autosync_ref(hdspm); 1434fcdc4ba1SAdrian Knoth if (HDSPM_AUTOSYNC_FROM_TCO == syncref) { 1435fcdc4ba1SAdrian Knoth is_valid_input = 1; 1436fcdc4ba1SAdrian Knoth has_sync = (HDSPM_SYNC_CHECK_SYNC == 1437fcdc4ba1SAdrian Knoth hdspm_tco_sync_check(hdspm)); 1438fcdc4ba1SAdrian Knoth } else if (HDSPM_AUTOSYNC_FROM_SYNC_IN == syncref) { 1439fcdc4ba1SAdrian Knoth is_valid_input = 1; 1440fcdc4ba1SAdrian Knoth has_sync = (HDSPM_SYNC_CHECK_SYNC == 1441fcdc4ba1SAdrian Knoth hdspm_sync_in_sync_check(hdspm)); 1442fcdc4ba1SAdrian Knoth } 1443fcdc4ba1SAdrian Knoth 1444fcdc4ba1SAdrian Knoth if (is_valid_input && has_sync) { 1445fcdc4ba1SAdrian Knoth rate = hdspm_round_frequency( 1446fcdc4ba1SAdrian Knoth hdspm_get_pll_freq(hdspm)); 1447fcdc4ba1SAdrian Knoth } 1448fcdc4ba1SAdrian Knoth } 1449fcdc4ba1SAdrian Knoth 1450a8a729faSAdrian Knoth rate = hdspm_rate_multiplier(hdspm, rate); 1451a8a729faSAdrian Knoth 14520dca1793SAdrian Knoth break; 1453763f356cSTakashi Iwai } 14540dca1793SAdrian Knoth 14550dca1793SAdrian Knoth return rate; 14563cee5a60SRemy Bruno } 1457763f356cSTakashi Iwai 14587cb155ffSAdrian Knoth /* return latency in samples per period */ 14597cb155ffSAdrian Knoth static int hdspm_get_latency(struct hdspm *hdspm) 14607cb155ffSAdrian Knoth { 14617cb155ffSAdrian Knoth int n; 14627cb155ffSAdrian Knoth 14637cb155ffSAdrian Knoth n = hdspm_decode_latency(hdspm->control_register); 14647cb155ffSAdrian Knoth 14657cb155ffSAdrian Knoth /* Special case for new RME cards with 32 samples period size. 14667cb155ffSAdrian Knoth * The three latency bits in the control register 14677cb155ffSAdrian Knoth * (HDSP_LatencyMask) encode latency values of 64 samples as 14687cb155ffSAdrian Knoth * 0, 128 samples as 1 ... 4096 samples as 6. For old cards, 7 14697cb155ffSAdrian Knoth * denotes 8192 samples, but on new cards like RayDAT or AIO, 14707cb155ffSAdrian Knoth * it corresponds to 32 samples. 14717cb155ffSAdrian Knoth */ 14727cb155ffSAdrian Knoth if ((7 == n) && (RayDAT == hdspm->io_type || AIO == hdspm->io_type)) 14737cb155ffSAdrian Knoth n = -1; 14747cb155ffSAdrian Knoth 14757cb155ffSAdrian Knoth return 1 << (n + 6); 14767cb155ffSAdrian Knoth } 14777cb155ffSAdrian Knoth 1478763f356cSTakashi Iwai /* Latency function */ 147998274f07STakashi Iwai static inline void hdspm_compute_period_size(struct hdspm *hdspm) 1480763f356cSTakashi Iwai { 14817cb155ffSAdrian Knoth hdspm->period_bytes = 4 * hdspm_get_latency(hdspm); 1482763f356cSTakashi Iwai } 1483763f356cSTakashi Iwai 14840dca1793SAdrian Knoth 148598274f07STakashi Iwai static snd_pcm_uframes_t hdspm_hw_pointer(struct hdspm *hdspm) 1486763f356cSTakashi Iwai { 1487763f356cSTakashi Iwai int position; 1488763f356cSTakashi Iwai 1489763f356cSTakashi Iwai position = hdspm_read(hdspm, HDSPM_statusRegister); 1490483cee77SAdrian Knoth 1491483cee77SAdrian Knoth switch (hdspm->io_type) { 1492483cee77SAdrian Knoth case RayDAT: 1493483cee77SAdrian Knoth case AIO: 1494763f356cSTakashi Iwai position &= HDSPM_BufferPositionMask; 14950dca1793SAdrian Knoth position /= 4; /* Bytes per sample */ 1496483cee77SAdrian Knoth break; 1497483cee77SAdrian Knoth default: 1498483cee77SAdrian Knoth position = (position & HDSPM_BufferID) ? 1499483cee77SAdrian Knoth (hdspm->period_bytes / 4) : 0; 1500483cee77SAdrian Knoth } 1501763f356cSTakashi Iwai 1502763f356cSTakashi Iwai return position; 1503763f356cSTakashi Iwai } 1504763f356cSTakashi Iwai 1505763f356cSTakashi Iwai 150698274f07STakashi Iwai static inline void hdspm_start_audio(struct hdspm * s) 1507763f356cSTakashi Iwai { 1508763f356cSTakashi Iwai s->control_register |= (HDSPM_AudioInterruptEnable | HDSPM_Start); 1509763f356cSTakashi Iwai hdspm_write(s, HDSPM_controlRegister, s->control_register); 1510763f356cSTakashi Iwai } 1511763f356cSTakashi Iwai 151298274f07STakashi Iwai static inline void hdspm_stop_audio(struct hdspm * s) 1513763f356cSTakashi Iwai { 1514763f356cSTakashi Iwai s->control_register &= ~(HDSPM_Start | HDSPM_AudioInterruptEnable); 1515763f356cSTakashi Iwai hdspm_write(s, HDSPM_controlRegister, s->control_register); 1516763f356cSTakashi Iwai } 1517763f356cSTakashi Iwai 1518763f356cSTakashi Iwai /* should I silence all or only opened ones ? doit all for first even is 4MB*/ 151962cef821SDenys Vlasenko static void hdspm_silence_playback(struct hdspm *hdspm) 1520763f356cSTakashi Iwai { 1521763f356cSTakashi Iwai int i; 1522763f356cSTakashi Iwai int n = hdspm->period_bytes; 1523763f356cSTakashi Iwai void *buf = hdspm->playback_buffer; 1524763f356cSTakashi Iwai 15253cee5a60SRemy Bruno if (buf == NULL) 15263cee5a60SRemy Bruno return; 1527763f356cSTakashi Iwai 1528763f356cSTakashi Iwai for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { 1529763f356cSTakashi Iwai memset(buf, 0, n); 1530763f356cSTakashi Iwai buf += HDSPM_CHANNEL_BUFFER_BYTES; 1531763f356cSTakashi Iwai } 1532763f356cSTakashi Iwai } 1533763f356cSTakashi Iwai 153498274f07STakashi Iwai static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames) 1535763f356cSTakashi Iwai { 1536763f356cSTakashi Iwai int n; 1537763f356cSTakashi Iwai 1538763f356cSTakashi Iwai spin_lock_irq(&s->lock); 1539763f356cSTakashi Iwai 15402e610270SAdrian Knoth if (32 == frames) { 15412e610270SAdrian Knoth /* Special case for new RME cards like RayDAT/AIO which 15422e610270SAdrian Knoth * support period sizes of 32 samples. Since latency is 15432e610270SAdrian Knoth * encoded in the three bits of HDSP_LatencyMask, we can only 15442e610270SAdrian Knoth * have values from 0 .. 7. While 0 still means 64 samples and 15452e610270SAdrian Knoth * 6 represents 4096 samples on all cards, 7 represents 8192 15462e610270SAdrian Knoth * on older cards and 32 samples on new cards. 15472e610270SAdrian Knoth * 15482e610270SAdrian Knoth * In other words, period size in samples is calculated by 15492e610270SAdrian Knoth * 2^(n+6) with n ranging from 0 .. 7. 15502e610270SAdrian Knoth */ 15512e610270SAdrian Knoth n = 7; 15522e610270SAdrian Knoth } else { 1553763f356cSTakashi Iwai frames >>= 7; 1554763f356cSTakashi Iwai n = 0; 1555763f356cSTakashi Iwai while (frames) { 1556763f356cSTakashi Iwai n++; 1557763f356cSTakashi Iwai frames >>= 1; 1558763f356cSTakashi Iwai } 15592e610270SAdrian Knoth } 15602e610270SAdrian Knoth 1561763f356cSTakashi Iwai s->control_register &= ~HDSPM_LatencyMask; 1562763f356cSTakashi Iwai s->control_register |= hdspm_encode_latency(n); 1563763f356cSTakashi Iwai 1564763f356cSTakashi Iwai hdspm_write(s, HDSPM_controlRegister, s->control_register); 1565763f356cSTakashi Iwai 1566763f356cSTakashi Iwai hdspm_compute_period_size(s); 1567763f356cSTakashi Iwai 1568763f356cSTakashi Iwai spin_unlock_irq(&s->lock); 1569763f356cSTakashi Iwai 1570763f356cSTakashi Iwai return 0; 1571763f356cSTakashi Iwai } 1572763f356cSTakashi Iwai 15730dca1793SAdrian Knoth static u64 hdspm_calc_dds_value(struct hdspm *hdspm, u64 period) 15740dca1793SAdrian Knoth { 15750dca1793SAdrian Knoth u64 freq_const; 15760dca1793SAdrian Knoth 15770dca1793SAdrian Knoth if (period == 0) 15780dca1793SAdrian Knoth return 0; 15790dca1793SAdrian Knoth 15800dca1793SAdrian Knoth switch (hdspm->io_type) { 15810dca1793SAdrian Knoth case MADI: 15820dca1793SAdrian Knoth case AES32: 15830dca1793SAdrian Knoth freq_const = 110069313433624ULL; 15840dca1793SAdrian Knoth break; 15850dca1793SAdrian Knoth case RayDAT: 15860dca1793SAdrian Knoth case AIO: 15870dca1793SAdrian Knoth freq_const = 104857600000000ULL; 15880dca1793SAdrian Knoth break; 15890dca1793SAdrian Knoth case MADIface: 15900dca1793SAdrian Knoth freq_const = 131072000000000ULL; 15913d56c8e6STakashi Iwai break; 15923d56c8e6STakashi Iwai default: 15933d56c8e6STakashi Iwai snd_BUG(); 15943d56c8e6STakashi Iwai return 0; 15950dca1793SAdrian Knoth } 15960dca1793SAdrian Knoth 15970dca1793SAdrian Knoth return div_u64(freq_const, period); 15980dca1793SAdrian Knoth } 15990dca1793SAdrian Knoth 16000dca1793SAdrian Knoth 1601ffb2c3c0SRemy Bruno static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) 1602ffb2c3c0SRemy Bruno { 1603ffb2c3c0SRemy Bruno u64 n; 1604ffb2c3c0SRemy Bruno 1605ffb2c3c0SRemy Bruno if (rate >= 112000) 1606ffb2c3c0SRemy Bruno rate /= 4; 1607ffb2c3c0SRemy Bruno else if (rate >= 56000) 1608ffb2c3c0SRemy Bruno rate /= 2; 1609ffb2c3c0SRemy Bruno 16100dca1793SAdrian Knoth switch (hdspm->io_type) { 16110dca1793SAdrian Knoth case MADIface: 16120dca1793SAdrian Knoth n = 131072000000000ULL; /* 125 MHz */ 16130dca1793SAdrian Knoth break; 16140dca1793SAdrian Knoth case MADI: 16150dca1793SAdrian Knoth case AES32: 16160dca1793SAdrian Knoth n = 110069313433624ULL; /* 105 MHz */ 16170dca1793SAdrian Knoth break; 16180dca1793SAdrian Knoth case RayDAT: 16190dca1793SAdrian Knoth case AIO: 16200dca1793SAdrian Knoth n = 104857600000000ULL; /* 100 MHz */ 16210dca1793SAdrian Knoth break; 16223d56c8e6STakashi Iwai default: 16233d56c8e6STakashi Iwai snd_BUG(); 16243d56c8e6STakashi Iwai return; 16250dca1793SAdrian Knoth } 16260dca1793SAdrian Knoth 16273f7440a6STakashi Iwai n = div_u64(n, rate); 1628ffb2c3c0SRemy Bruno /* n should be less than 2^32 for being written to FREQ register */ 1629da3cec35STakashi Iwai snd_BUG_ON(n >> 32); 1630ffb2c3c0SRemy Bruno hdspm_write(hdspm, HDSPM_freqReg, (u32)n); 1631ffb2c3c0SRemy Bruno } 1632763f356cSTakashi Iwai 1633763f356cSTakashi Iwai /* dummy set rate lets see what happens */ 163498274f07STakashi Iwai static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) 1635763f356cSTakashi Iwai { 1636763f356cSTakashi Iwai int current_rate; 1637763f356cSTakashi Iwai int rate_bits; 1638763f356cSTakashi Iwai int not_set = 0; 16396534599dSRemy Bruno int current_speed, target_speed; 1640763f356cSTakashi Iwai 1641763f356cSTakashi Iwai /* ASSUMPTION: hdspm->lock is either set, or there is no need for 1642763f356cSTakashi Iwai it (e.g. during module initialization). 1643763f356cSTakashi Iwai */ 1644763f356cSTakashi Iwai 1645763f356cSTakashi Iwai if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { 1646763f356cSTakashi Iwai 1647763f356cSTakashi Iwai /* SLAVE --- */ 1648763f356cSTakashi Iwai if (called_internally) { 1649763f356cSTakashi Iwai 1650763f356cSTakashi Iwai /* request from ctl or card initialization 1651763f356cSTakashi Iwai just make a warning an remember setting 1652763f356cSTakashi Iwai for future master mode switching */ 1653763f356cSTakashi Iwai 1654ef5fa1a4STakashi Iwai snd_printk(KERN_WARNING "HDSPM: " 1655ef5fa1a4STakashi Iwai "Warning: device is not running " 1656ef5fa1a4STakashi Iwai "as a clock master.\n"); 1657763f356cSTakashi Iwai not_set = 1; 1658763f356cSTakashi Iwai } else { 1659763f356cSTakashi Iwai 1660763f356cSTakashi Iwai /* hw_param request while in AutoSync mode */ 1661763f356cSTakashi Iwai int external_freq = 1662763f356cSTakashi Iwai hdspm_external_sample_rate(hdspm); 1663763f356cSTakashi Iwai 1664ef5fa1a4STakashi Iwai if (hdspm_autosync_ref(hdspm) == 1665ef5fa1a4STakashi Iwai HDSPM_AUTOSYNC_FROM_NONE) { 1666763f356cSTakashi Iwai 1667ef5fa1a4STakashi Iwai snd_printk(KERN_WARNING "HDSPM: " 1668ef5fa1a4STakashi Iwai "Detected no Externel Sync \n"); 1669763f356cSTakashi Iwai not_set = 1; 1670763f356cSTakashi Iwai 1671763f356cSTakashi Iwai } else if (rate != external_freq) { 1672763f356cSTakashi Iwai 1673ef5fa1a4STakashi Iwai snd_printk(KERN_WARNING "HDSPM: " 1674ef5fa1a4STakashi Iwai "Warning: No AutoSync source for " 1675ef5fa1a4STakashi Iwai "requested rate\n"); 1676763f356cSTakashi Iwai not_set = 1; 1677763f356cSTakashi Iwai } 1678763f356cSTakashi Iwai } 1679763f356cSTakashi Iwai } 1680763f356cSTakashi Iwai 1681763f356cSTakashi Iwai current_rate = hdspm->system_sample_rate; 1682763f356cSTakashi Iwai 1683763f356cSTakashi Iwai /* Changing between Singe, Double and Quad speed is not 1684763f356cSTakashi Iwai allowed if any substreams are open. This is because such a change 1685763f356cSTakashi Iwai causes a shift in the location of the DMA buffers and a reduction 1686763f356cSTakashi Iwai in the number of available buffers. 1687763f356cSTakashi Iwai 1688763f356cSTakashi Iwai Note that a similar but essentially insoluble problem exists for 1689763f356cSTakashi Iwai externally-driven rate changes. All we can do is to flag rate 1690763f356cSTakashi Iwai changes in the read/write routines. 1691763f356cSTakashi Iwai */ 1692763f356cSTakashi Iwai 16936534599dSRemy Bruno if (current_rate <= 48000) 16946534599dSRemy Bruno current_speed = HDSPM_SPEED_SINGLE; 16956534599dSRemy Bruno else if (current_rate <= 96000) 16966534599dSRemy Bruno current_speed = HDSPM_SPEED_DOUBLE; 16976534599dSRemy Bruno else 16986534599dSRemy Bruno current_speed = HDSPM_SPEED_QUAD; 16996534599dSRemy Bruno 17006534599dSRemy Bruno if (rate <= 48000) 17016534599dSRemy Bruno target_speed = HDSPM_SPEED_SINGLE; 17026534599dSRemy Bruno else if (rate <= 96000) 17036534599dSRemy Bruno target_speed = HDSPM_SPEED_DOUBLE; 17046534599dSRemy Bruno else 17056534599dSRemy Bruno target_speed = HDSPM_SPEED_QUAD; 17063cee5a60SRemy Bruno 1707763f356cSTakashi Iwai switch (rate) { 1708763f356cSTakashi Iwai case 32000: 1709763f356cSTakashi Iwai rate_bits = HDSPM_Frequency32KHz; 1710763f356cSTakashi Iwai break; 1711763f356cSTakashi Iwai case 44100: 1712763f356cSTakashi Iwai rate_bits = HDSPM_Frequency44_1KHz; 1713763f356cSTakashi Iwai break; 1714763f356cSTakashi Iwai case 48000: 1715763f356cSTakashi Iwai rate_bits = HDSPM_Frequency48KHz; 1716763f356cSTakashi Iwai break; 1717763f356cSTakashi Iwai case 64000: 1718763f356cSTakashi Iwai rate_bits = HDSPM_Frequency64KHz; 1719763f356cSTakashi Iwai break; 1720763f356cSTakashi Iwai case 88200: 1721763f356cSTakashi Iwai rate_bits = HDSPM_Frequency88_2KHz; 1722763f356cSTakashi Iwai break; 1723763f356cSTakashi Iwai case 96000: 1724763f356cSTakashi Iwai rate_bits = HDSPM_Frequency96KHz; 1725763f356cSTakashi Iwai break; 17263cee5a60SRemy Bruno case 128000: 17273cee5a60SRemy Bruno rate_bits = HDSPM_Frequency128KHz; 17283cee5a60SRemy Bruno break; 17293cee5a60SRemy Bruno case 176400: 17303cee5a60SRemy Bruno rate_bits = HDSPM_Frequency176_4KHz; 17313cee5a60SRemy Bruno break; 17323cee5a60SRemy Bruno case 192000: 17333cee5a60SRemy Bruno rate_bits = HDSPM_Frequency192KHz; 17343cee5a60SRemy Bruno break; 1735763f356cSTakashi Iwai default: 1736763f356cSTakashi Iwai return -EINVAL; 1737763f356cSTakashi Iwai } 1738763f356cSTakashi Iwai 17396534599dSRemy Bruno if (current_speed != target_speed 1740763f356cSTakashi Iwai && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { 1741763f356cSTakashi Iwai snd_printk 1742ef5fa1a4STakashi Iwai (KERN_ERR "HDSPM: " 17436534599dSRemy Bruno "cannot change from %s speed to %s speed mode " 1744ef5fa1a4STakashi Iwai "(capture PID = %d, playback PID = %d)\n", 17456534599dSRemy Bruno hdspm_speed_names[current_speed], 17466534599dSRemy Bruno hdspm_speed_names[target_speed], 1747763f356cSTakashi Iwai hdspm->capture_pid, hdspm->playback_pid); 1748763f356cSTakashi Iwai return -EBUSY; 1749763f356cSTakashi Iwai } 1750763f356cSTakashi Iwai 1751763f356cSTakashi Iwai hdspm->control_register &= ~HDSPM_FrequencyMask; 1752763f356cSTakashi Iwai hdspm->control_register |= rate_bits; 1753763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 1754763f356cSTakashi Iwai 1755ffb2c3c0SRemy Bruno /* For AES32, need to set DDS value in FREQ register 1756ffb2c3c0SRemy Bruno For MADI, also apparently */ 1757ffb2c3c0SRemy Bruno hdspm_set_dds_value(hdspm, rate); 1758ffb2c3c0SRemy Bruno 17590dca1793SAdrian Knoth if (AES32 == hdspm->io_type && rate != current_rate) 1760ffb2c3c0SRemy Bruno hdspm_write(hdspm, HDSPM_eeprom_wr, 0); 1761ffb2c3c0SRemy Bruno 1762763f356cSTakashi Iwai hdspm->system_sample_rate = rate; 1763763f356cSTakashi Iwai 17640dca1793SAdrian Knoth if (rate <= 48000) { 17650dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_in_ss; 17660dca1793SAdrian Knoth hdspm->channel_map_out = hdspm->channel_map_out_ss; 17670dca1793SAdrian Knoth hdspm->max_channels_in = hdspm->ss_in_channels; 17680dca1793SAdrian Knoth hdspm->max_channels_out = hdspm->ss_out_channels; 17690dca1793SAdrian Knoth hdspm->port_names_in = hdspm->port_names_in_ss; 17700dca1793SAdrian Knoth hdspm->port_names_out = hdspm->port_names_out_ss; 17710dca1793SAdrian Knoth } else if (rate <= 96000) { 17720dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_in_ds; 17730dca1793SAdrian Knoth hdspm->channel_map_out = hdspm->channel_map_out_ds; 17740dca1793SAdrian Knoth hdspm->max_channels_in = hdspm->ds_in_channels; 17750dca1793SAdrian Knoth hdspm->max_channels_out = hdspm->ds_out_channels; 17760dca1793SAdrian Knoth hdspm->port_names_in = hdspm->port_names_in_ds; 17770dca1793SAdrian Knoth hdspm->port_names_out = hdspm->port_names_out_ds; 17780dca1793SAdrian Knoth } else { 17790dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_in_qs; 17800dca1793SAdrian Knoth hdspm->channel_map_out = hdspm->channel_map_out_qs; 17810dca1793SAdrian Knoth hdspm->max_channels_in = hdspm->qs_in_channels; 17820dca1793SAdrian Knoth hdspm->max_channels_out = hdspm->qs_out_channels; 17830dca1793SAdrian Knoth hdspm->port_names_in = hdspm->port_names_in_qs; 17840dca1793SAdrian Knoth hdspm->port_names_out = hdspm->port_names_out_qs; 17850dca1793SAdrian Knoth } 17860dca1793SAdrian Knoth 1787763f356cSTakashi Iwai if (not_set != 0) 1788763f356cSTakashi Iwai return -1; 1789763f356cSTakashi Iwai 1790763f356cSTakashi Iwai return 0; 1791763f356cSTakashi Iwai } 1792763f356cSTakashi Iwai 1793763f356cSTakashi Iwai /* mainly for init to 0 on load */ 179498274f07STakashi Iwai static void all_in_all_mixer(struct hdspm * hdspm, int sgain) 1795763f356cSTakashi Iwai { 1796763f356cSTakashi Iwai int i, j; 1797ef5fa1a4STakashi Iwai unsigned int gain; 1798ef5fa1a4STakashi Iwai 1799ef5fa1a4STakashi Iwai if (sgain > UNITY_GAIN) 1800ef5fa1a4STakashi Iwai gain = UNITY_GAIN; 1801ef5fa1a4STakashi Iwai else if (sgain < 0) 1802ef5fa1a4STakashi Iwai gain = 0; 1803ef5fa1a4STakashi Iwai else 1804ef5fa1a4STakashi Iwai gain = sgain; 1805763f356cSTakashi Iwai 1806763f356cSTakashi Iwai for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) 1807763f356cSTakashi Iwai for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) { 1808763f356cSTakashi Iwai hdspm_write_in_gain(hdspm, i, j, gain); 1809763f356cSTakashi Iwai hdspm_write_pb_gain(hdspm, i, j, gain); 1810763f356cSTakashi Iwai } 1811763f356cSTakashi Iwai } 1812763f356cSTakashi Iwai 1813763f356cSTakashi Iwai /*---------------------------------------------------------------------------- 1814763f356cSTakashi Iwai MIDI 1815763f356cSTakashi Iwai ----------------------------------------------------------------------------*/ 1816763f356cSTakashi Iwai 1817ef5fa1a4STakashi Iwai static inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm, 1818ef5fa1a4STakashi Iwai int id) 1819763f356cSTakashi Iwai { 1820763f356cSTakashi Iwai /* the hardware already does the relevant bit-mask with 0xff */ 18210dca1793SAdrian Knoth return hdspm_read(hdspm, hdspm->midi[id].dataIn); 1822763f356cSTakashi Iwai } 1823763f356cSTakashi Iwai 1824ef5fa1a4STakashi Iwai static inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id, 1825ef5fa1a4STakashi Iwai int val) 1826763f356cSTakashi Iwai { 1827763f356cSTakashi Iwai /* the hardware already does the relevant bit-mask with 0xff */ 18280dca1793SAdrian Knoth return hdspm_write(hdspm, hdspm->midi[id].dataOut, val); 1829763f356cSTakashi Iwai } 1830763f356cSTakashi Iwai 183198274f07STakashi Iwai static inline int snd_hdspm_midi_input_available (struct hdspm *hdspm, int id) 1832763f356cSTakashi Iwai { 18330dca1793SAdrian Knoth return hdspm_read(hdspm, hdspm->midi[id].statusIn) & 0xFF; 1834763f356cSTakashi Iwai } 1835763f356cSTakashi Iwai 183698274f07STakashi Iwai static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id) 1837763f356cSTakashi Iwai { 1838763f356cSTakashi Iwai int fifo_bytes_used; 1839763f356cSTakashi Iwai 18400dca1793SAdrian Knoth fifo_bytes_used = hdspm_read(hdspm, hdspm->midi[id].statusOut) & 0xFF; 1841763f356cSTakashi Iwai 1842763f356cSTakashi Iwai if (fifo_bytes_used < 128) 1843763f356cSTakashi Iwai return 128 - fifo_bytes_used; 1844763f356cSTakashi Iwai else 1845763f356cSTakashi Iwai return 0; 1846763f356cSTakashi Iwai } 1847763f356cSTakashi Iwai 184862cef821SDenys Vlasenko static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id) 1849763f356cSTakashi Iwai { 1850763f356cSTakashi Iwai while (snd_hdspm_midi_input_available (hdspm, id)) 1851763f356cSTakashi Iwai snd_hdspm_midi_read_byte (hdspm, id); 1852763f356cSTakashi Iwai } 1853763f356cSTakashi Iwai 185498274f07STakashi Iwai static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) 1855763f356cSTakashi Iwai { 1856763f356cSTakashi Iwai unsigned long flags; 1857763f356cSTakashi Iwai int n_pending; 1858763f356cSTakashi Iwai int to_write; 1859763f356cSTakashi Iwai int i; 1860763f356cSTakashi Iwai unsigned char buf[128]; 1861763f356cSTakashi Iwai 1862763f356cSTakashi Iwai /* Output is not interrupt driven */ 1863763f356cSTakashi Iwai 1864763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags); 1865ef5fa1a4STakashi Iwai if (hmidi->output && 1866ef5fa1a4STakashi Iwai !snd_rawmidi_transmit_empty (hmidi->output)) { 1867ef5fa1a4STakashi Iwai n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, 1868ef5fa1a4STakashi Iwai hmidi->id); 1869ef5fa1a4STakashi Iwai if (n_pending > 0) { 1870763f356cSTakashi Iwai if (n_pending > (int)sizeof (buf)) 1871763f356cSTakashi Iwai n_pending = sizeof (buf); 1872763f356cSTakashi Iwai 1873ef5fa1a4STakashi Iwai to_write = snd_rawmidi_transmit (hmidi->output, buf, 1874ef5fa1a4STakashi Iwai n_pending); 1875ef5fa1a4STakashi Iwai if (to_write > 0) { 1876763f356cSTakashi Iwai for (i = 0; i < to_write; ++i) 1877ef5fa1a4STakashi Iwai snd_hdspm_midi_write_byte (hmidi->hdspm, 1878ef5fa1a4STakashi Iwai hmidi->id, 1879ef5fa1a4STakashi Iwai buf[i]); 1880763f356cSTakashi Iwai } 1881763f356cSTakashi Iwai } 1882763f356cSTakashi Iwai } 1883763f356cSTakashi Iwai spin_unlock_irqrestore (&hmidi->lock, flags); 1884763f356cSTakashi Iwai return 0; 1885763f356cSTakashi Iwai } 1886763f356cSTakashi Iwai 188798274f07STakashi Iwai static int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi) 1888763f356cSTakashi Iwai { 1889ef5fa1a4STakashi Iwai unsigned char buf[128]; /* this buffer is designed to match the MIDI 1890ef5fa1a4STakashi Iwai * input FIFO size 1891ef5fa1a4STakashi Iwai */ 1892763f356cSTakashi Iwai unsigned long flags; 1893763f356cSTakashi Iwai int n_pending; 1894763f356cSTakashi Iwai int i; 1895763f356cSTakashi Iwai 1896763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags); 1897ef5fa1a4STakashi Iwai n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id); 1898ef5fa1a4STakashi Iwai if (n_pending > 0) { 1899763f356cSTakashi Iwai if (hmidi->input) { 1900ef5fa1a4STakashi Iwai if (n_pending > (int)sizeof (buf)) 1901763f356cSTakashi Iwai n_pending = sizeof (buf); 1902ef5fa1a4STakashi Iwai for (i = 0; i < n_pending; ++i) 1903ef5fa1a4STakashi Iwai buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, 1904ef5fa1a4STakashi Iwai hmidi->id); 1905ef5fa1a4STakashi Iwai if (n_pending) 1906ef5fa1a4STakashi Iwai snd_rawmidi_receive (hmidi->input, buf, 1907ef5fa1a4STakashi Iwai n_pending); 1908763f356cSTakashi Iwai } else { 1909763f356cSTakashi Iwai /* flush the MIDI input FIFO */ 1910ef5fa1a4STakashi Iwai while (n_pending--) 1911ef5fa1a4STakashi Iwai snd_hdspm_midi_read_byte (hmidi->hdspm, 1912ef5fa1a4STakashi Iwai hmidi->id); 1913763f356cSTakashi Iwai } 1914763f356cSTakashi Iwai } 1915763f356cSTakashi Iwai hmidi->pending = 0; 1916c0da0014SAdrian Knoth spin_unlock_irqrestore(&hmidi->lock, flags); 19170dca1793SAdrian Knoth 1918c0da0014SAdrian Knoth spin_lock_irqsave(&hmidi->hdspm->lock, flags); 19190dca1793SAdrian Knoth hmidi->hdspm->control_register |= hmidi->ie; 1920ef5fa1a4STakashi Iwai hdspm_write(hmidi->hdspm, HDSPM_controlRegister, 1921ef5fa1a4STakashi Iwai hmidi->hdspm->control_register); 1922c0da0014SAdrian Knoth spin_unlock_irqrestore(&hmidi->hdspm->lock, flags); 19230dca1793SAdrian Knoth 1924763f356cSTakashi Iwai return snd_hdspm_midi_output_write (hmidi); 1925763f356cSTakashi Iwai } 1926763f356cSTakashi Iwai 1927ef5fa1a4STakashi Iwai static void 1928ef5fa1a4STakashi Iwai snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) 1929763f356cSTakashi Iwai { 193098274f07STakashi Iwai struct hdspm *hdspm; 193198274f07STakashi Iwai struct hdspm_midi *hmidi; 1932763f356cSTakashi Iwai unsigned long flags; 1933763f356cSTakashi Iwai 1934ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 1935763f356cSTakashi Iwai hdspm = hmidi->hdspm; 19360dca1793SAdrian Knoth 1937763f356cSTakashi Iwai spin_lock_irqsave (&hdspm->lock, flags); 1938763f356cSTakashi Iwai if (up) { 19390dca1793SAdrian Knoth if (!(hdspm->control_register & hmidi->ie)) { 1940763f356cSTakashi Iwai snd_hdspm_flush_midi_input (hdspm, hmidi->id); 19410dca1793SAdrian Knoth hdspm->control_register |= hmidi->ie; 1942763f356cSTakashi Iwai } 1943763f356cSTakashi Iwai } else { 19440dca1793SAdrian Knoth hdspm->control_register &= ~hmidi->ie; 1945763f356cSTakashi Iwai } 1946763f356cSTakashi Iwai 1947763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 1948763f356cSTakashi Iwai spin_unlock_irqrestore (&hdspm->lock, flags); 1949763f356cSTakashi Iwai } 1950763f356cSTakashi Iwai 1951763f356cSTakashi Iwai static void snd_hdspm_midi_output_timer(unsigned long data) 1952763f356cSTakashi Iwai { 195398274f07STakashi Iwai struct hdspm_midi *hmidi = (struct hdspm_midi *) data; 1954763f356cSTakashi Iwai unsigned long flags; 1955763f356cSTakashi Iwai 1956763f356cSTakashi Iwai snd_hdspm_midi_output_write(hmidi); 1957763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags); 1958763f356cSTakashi Iwai 1959763f356cSTakashi Iwai /* this does not bump hmidi->istimer, because the 1960763f356cSTakashi Iwai kernel automatically removed the timer when it 1961763f356cSTakashi Iwai expired, and we are now adding it back, thus 1962763f356cSTakashi Iwai leaving istimer wherever it was set before. 1963763f356cSTakashi Iwai */ 1964763f356cSTakashi Iwai 1965763f356cSTakashi Iwai if (hmidi->istimer) { 1966763f356cSTakashi Iwai hmidi->timer.expires = 1 + jiffies; 1967763f356cSTakashi Iwai add_timer(&hmidi->timer); 1968763f356cSTakashi Iwai } 1969763f356cSTakashi Iwai 1970763f356cSTakashi Iwai spin_unlock_irqrestore (&hmidi->lock, flags); 1971763f356cSTakashi Iwai } 1972763f356cSTakashi Iwai 1973ef5fa1a4STakashi Iwai static void 1974ef5fa1a4STakashi Iwai snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) 1975763f356cSTakashi Iwai { 197698274f07STakashi Iwai struct hdspm_midi *hmidi; 1977763f356cSTakashi Iwai unsigned long flags; 1978763f356cSTakashi Iwai 1979ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 1980763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags); 1981763f356cSTakashi Iwai if (up) { 1982763f356cSTakashi Iwai if (!hmidi->istimer) { 1983763f356cSTakashi Iwai init_timer(&hmidi->timer); 1984763f356cSTakashi Iwai hmidi->timer.function = snd_hdspm_midi_output_timer; 1985763f356cSTakashi Iwai hmidi->timer.data = (unsigned long) hmidi; 1986763f356cSTakashi Iwai hmidi->timer.expires = 1 + jiffies; 1987763f356cSTakashi Iwai add_timer(&hmidi->timer); 1988763f356cSTakashi Iwai hmidi->istimer++; 1989763f356cSTakashi Iwai } 1990763f356cSTakashi Iwai } else { 1991ef5fa1a4STakashi Iwai if (hmidi->istimer && --hmidi->istimer <= 0) 1992763f356cSTakashi Iwai del_timer (&hmidi->timer); 1993763f356cSTakashi Iwai } 1994763f356cSTakashi Iwai spin_unlock_irqrestore (&hmidi->lock, flags); 1995763f356cSTakashi Iwai if (up) 1996763f356cSTakashi Iwai snd_hdspm_midi_output_write(hmidi); 1997763f356cSTakashi Iwai } 1998763f356cSTakashi Iwai 199998274f07STakashi Iwai static int snd_hdspm_midi_input_open(struct snd_rawmidi_substream *substream) 2000763f356cSTakashi Iwai { 200198274f07STakashi Iwai struct hdspm_midi *hmidi; 2002763f356cSTakashi Iwai 2003ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 2004763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock); 2005763f356cSTakashi Iwai snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id); 2006763f356cSTakashi Iwai hmidi->input = substream; 2007763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock); 2008763f356cSTakashi Iwai 2009763f356cSTakashi Iwai return 0; 2010763f356cSTakashi Iwai } 2011763f356cSTakashi Iwai 201298274f07STakashi Iwai static int snd_hdspm_midi_output_open(struct snd_rawmidi_substream *substream) 2013763f356cSTakashi Iwai { 201498274f07STakashi Iwai struct hdspm_midi *hmidi; 2015763f356cSTakashi Iwai 2016ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 2017763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock); 2018763f356cSTakashi Iwai hmidi->output = substream; 2019763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock); 2020763f356cSTakashi Iwai 2021763f356cSTakashi Iwai return 0; 2022763f356cSTakashi Iwai } 2023763f356cSTakashi Iwai 202498274f07STakashi Iwai static int snd_hdspm_midi_input_close(struct snd_rawmidi_substream *substream) 2025763f356cSTakashi Iwai { 202698274f07STakashi Iwai struct hdspm_midi *hmidi; 2027763f356cSTakashi Iwai 2028763f356cSTakashi Iwai snd_hdspm_midi_input_trigger (substream, 0); 2029763f356cSTakashi Iwai 2030ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 2031763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock); 2032763f356cSTakashi Iwai hmidi->input = NULL; 2033763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock); 2034763f356cSTakashi Iwai 2035763f356cSTakashi Iwai return 0; 2036763f356cSTakashi Iwai } 2037763f356cSTakashi Iwai 203898274f07STakashi Iwai static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream) 2039763f356cSTakashi Iwai { 204098274f07STakashi Iwai struct hdspm_midi *hmidi; 2041763f356cSTakashi Iwai 2042763f356cSTakashi Iwai snd_hdspm_midi_output_trigger (substream, 0); 2043763f356cSTakashi Iwai 2044ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 2045763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock); 2046763f356cSTakashi Iwai hmidi->output = NULL; 2047763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock); 2048763f356cSTakashi Iwai 2049763f356cSTakashi Iwai return 0; 2050763f356cSTakashi Iwai } 2051763f356cSTakashi Iwai 205298274f07STakashi Iwai static struct snd_rawmidi_ops snd_hdspm_midi_output = 2053763f356cSTakashi Iwai { 2054763f356cSTakashi Iwai .open = snd_hdspm_midi_output_open, 2055763f356cSTakashi Iwai .close = snd_hdspm_midi_output_close, 2056763f356cSTakashi Iwai .trigger = snd_hdspm_midi_output_trigger, 2057763f356cSTakashi Iwai }; 2058763f356cSTakashi Iwai 205998274f07STakashi Iwai static struct snd_rawmidi_ops snd_hdspm_midi_input = 2060763f356cSTakashi Iwai { 2061763f356cSTakashi Iwai .open = snd_hdspm_midi_input_open, 2062763f356cSTakashi Iwai .close = snd_hdspm_midi_input_close, 2063763f356cSTakashi Iwai .trigger = snd_hdspm_midi_input_trigger, 2064763f356cSTakashi Iwai }; 2065763f356cSTakashi Iwai 2066e23e7a14SBill Pemberton static int snd_hdspm_create_midi(struct snd_card *card, 2067ef5fa1a4STakashi Iwai struct hdspm *hdspm, int id) 2068763f356cSTakashi Iwai { 2069763f356cSTakashi Iwai int err; 2070763f356cSTakashi Iwai char buf[32]; 2071763f356cSTakashi Iwai 2072763f356cSTakashi Iwai hdspm->midi[id].id = id; 2073763f356cSTakashi Iwai hdspm->midi[id].hdspm = hdspm; 2074763f356cSTakashi Iwai spin_lock_init (&hdspm->midi[id].lock); 2075763f356cSTakashi Iwai 20760dca1793SAdrian Knoth if (0 == id) { 20770dca1793SAdrian Knoth if (MADIface == hdspm->io_type) { 20780dca1793SAdrian Knoth /* MIDI-over-MADI on HDSPe MADIface */ 20790dca1793SAdrian Knoth hdspm->midi[0].dataIn = HDSPM_midiDataIn2; 20800dca1793SAdrian Knoth hdspm->midi[0].statusIn = HDSPM_midiStatusIn2; 20810dca1793SAdrian Knoth hdspm->midi[0].dataOut = HDSPM_midiDataOut2; 20820dca1793SAdrian Knoth hdspm->midi[0].statusOut = HDSPM_midiStatusOut2; 20830dca1793SAdrian Knoth hdspm->midi[0].ie = HDSPM_Midi2InterruptEnable; 20840dca1793SAdrian Knoth hdspm->midi[0].irq = HDSPM_midi2IRQPending; 20850dca1793SAdrian Knoth } else { 20860dca1793SAdrian Knoth hdspm->midi[0].dataIn = HDSPM_midiDataIn0; 20870dca1793SAdrian Knoth hdspm->midi[0].statusIn = HDSPM_midiStatusIn0; 20880dca1793SAdrian Knoth hdspm->midi[0].dataOut = HDSPM_midiDataOut0; 20890dca1793SAdrian Knoth hdspm->midi[0].statusOut = HDSPM_midiStatusOut0; 20900dca1793SAdrian Knoth hdspm->midi[0].ie = HDSPM_Midi0InterruptEnable; 20910dca1793SAdrian Knoth hdspm->midi[0].irq = HDSPM_midi0IRQPending; 20920dca1793SAdrian Knoth } 20930dca1793SAdrian Knoth } else if (1 == id) { 20940dca1793SAdrian Knoth hdspm->midi[1].dataIn = HDSPM_midiDataIn1; 20950dca1793SAdrian Knoth hdspm->midi[1].statusIn = HDSPM_midiStatusIn1; 20960dca1793SAdrian Knoth hdspm->midi[1].dataOut = HDSPM_midiDataOut1; 20970dca1793SAdrian Knoth hdspm->midi[1].statusOut = HDSPM_midiStatusOut1; 20980dca1793SAdrian Knoth hdspm->midi[1].ie = HDSPM_Midi1InterruptEnable; 20990dca1793SAdrian Knoth hdspm->midi[1].irq = HDSPM_midi1IRQPending; 21000dca1793SAdrian Knoth } else if ((2 == id) && (MADI == hdspm->io_type)) { 21010dca1793SAdrian Knoth /* MIDI-over-MADI on HDSPe MADI */ 21020dca1793SAdrian Knoth hdspm->midi[2].dataIn = HDSPM_midiDataIn2; 21030dca1793SAdrian Knoth hdspm->midi[2].statusIn = HDSPM_midiStatusIn2; 21040dca1793SAdrian Knoth hdspm->midi[2].dataOut = HDSPM_midiDataOut2; 21050dca1793SAdrian Knoth hdspm->midi[2].statusOut = HDSPM_midiStatusOut2; 21060dca1793SAdrian Knoth hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable; 21070dca1793SAdrian Knoth hdspm->midi[2].irq = HDSPM_midi2IRQPending; 21080dca1793SAdrian Knoth } else if (2 == id) { 21090dca1793SAdrian Knoth /* TCO MTC, read only */ 21100dca1793SAdrian Knoth hdspm->midi[2].dataIn = HDSPM_midiDataIn2; 21110dca1793SAdrian Knoth hdspm->midi[2].statusIn = HDSPM_midiStatusIn2; 21120dca1793SAdrian Knoth hdspm->midi[2].dataOut = -1; 21130dca1793SAdrian Knoth hdspm->midi[2].statusOut = -1; 21140dca1793SAdrian Knoth hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable; 21150dca1793SAdrian Knoth hdspm->midi[2].irq = HDSPM_midi2IRQPendingAES; 21160dca1793SAdrian Knoth } else if (3 == id) { 21170dca1793SAdrian Knoth /* TCO MTC on HDSPe MADI */ 21180dca1793SAdrian Knoth hdspm->midi[3].dataIn = HDSPM_midiDataIn3; 21190dca1793SAdrian Knoth hdspm->midi[3].statusIn = HDSPM_midiStatusIn3; 21200dca1793SAdrian Knoth hdspm->midi[3].dataOut = -1; 21210dca1793SAdrian Knoth hdspm->midi[3].statusOut = -1; 21220dca1793SAdrian Knoth hdspm->midi[3].ie = HDSPM_Midi3InterruptEnable; 21230dca1793SAdrian Knoth hdspm->midi[3].irq = HDSPM_midi3IRQPending; 21240dca1793SAdrian Knoth } 21250dca1793SAdrian Knoth 21260dca1793SAdrian Knoth if ((id < 2) || ((2 == id) && ((MADI == hdspm->io_type) || 21270dca1793SAdrian Knoth (MADIface == hdspm->io_type)))) { 21280dca1793SAdrian Knoth if ((id == 0) && (MADIface == hdspm->io_type)) { 21290dca1793SAdrian Knoth sprintf(buf, "%s MIDIoverMADI", card->shortname); 21300dca1793SAdrian Knoth } else if ((id == 2) && (MADI == hdspm->io_type)) { 21310dca1793SAdrian Knoth sprintf(buf, "%s MIDIoverMADI", card->shortname); 21320dca1793SAdrian Knoth } else { 2133763f356cSTakashi Iwai sprintf(buf, "%s MIDI %d", card->shortname, id+1); 21340dca1793SAdrian Knoth } 21350dca1793SAdrian Knoth err = snd_rawmidi_new(card, buf, id, 1, 1, 21360dca1793SAdrian Knoth &hdspm->midi[id].rmidi); 2137ef5fa1a4STakashi Iwai if (err < 0) 2138763f356cSTakashi Iwai return err; 2139763f356cSTakashi Iwai 21400dca1793SAdrian Knoth sprintf(hdspm->midi[id].rmidi->name, "%s MIDI %d", 21410dca1793SAdrian Knoth card->id, id+1); 2142763f356cSTakashi Iwai hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; 2143763f356cSTakashi Iwai 21440dca1793SAdrian Knoth snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 21450dca1793SAdrian Knoth SNDRV_RAWMIDI_STREAM_OUTPUT, 2146ef5fa1a4STakashi Iwai &snd_hdspm_midi_output); 21470dca1793SAdrian Knoth snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 21480dca1793SAdrian Knoth SNDRV_RAWMIDI_STREAM_INPUT, 2149ef5fa1a4STakashi Iwai &snd_hdspm_midi_input); 2150763f356cSTakashi Iwai 21510dca1793SAdrian Knoth hdspm->midi[id].rmidi->info_flags |= 21520dca1793SAdrian Knoth SNDRV_RAWMIDI_INFO_OUTPUT | 2153763f356cSTakashi Iwai SNDRV_RAWMIDI_INFO_INPUT | 2154763f356cSTakashi Iwai SNDRV_RAWMIDI_INFO_DUPLEX; 21550dca1793SAdrian Knoth } else { 21560dca1793SAdrian Knoth /* TCO MTC, read only */ 21570dca1793SAdrian Knoth sprintf(buf, "%s MTC %d", card->shortname, id+1); 21580dca1793SAdrian Knoth err = snd_rawmidi_new(card, buf, id, 1, 1, 21590dca1793SAdrian Knoth &hdspm->midi[id].rmidi); 21600dca1793SAdrian Knoth if (err < 0) 21610dca1793SAdrian Knoth return err; 21620dca1793SAdrian Knoth 21630dca1793SAdrian Knoth sprintf(hdspm->midi[id].rmidi->name, 21640dca1793SAdrian Knoth "%s MTC %d", card->id, id+1); 21650dca1793SAdrian Knoth hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; 21660dca1793SAdrian Knoth 21670dca1793SAdrian Knoth snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 21680dca1793SAdrian Knoth SNDRV_RAWMIDI_STREAM_INPUT, 21690dca1793SAdrian Knoth &snd_hdspm_midi_input); 21700dca1793SAdrian Knoth 21710dca1793SAdrian Knoth hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; 21720dca1793SAdrian Knoth } 2173763f356cSTakashi Iwai 2174763f356cSTakashi Iwai return 0; 2175763f356cSTakashi Iwai } 2176763f356cSTakashi Iwai 2177763f356cSTakashi Iwai 2178763f356cSTakashi Iwai static void hdspm_midi_tasklet(unsigned long arg) 2179763f356cSTakashi Iwai { 218098274f07STakashi Iwai struct hdspm *hdspm = (struct hdspm *)arg; 21810dca1793SAdrian Knoth int i = 0; 2182763f356cSTakashi Iwai 21830dca1793SAdrian Knoth while (i < hdspm->midiPorts) { 21840dca1793SAdrian Knoth if (hdspm->midi[i].pending) 21850dca1793SAdrian Knoth snd_hdspm_midi_input_read(&hdspm->midi[i]); 21860dca1793SAdrian Knoth 21870dca1793SAdrian Knoth i++; 21880dca1793SAdrian Knoth } 2189763f356cSTakashi Iwai } 2190763f356cSTakashi Iwai 2191763f356cSTakashi Iwai 2192763f356cSTakashi Iwai /*----------------------------------------------------------------------------- 2193763f356cSTakashi Iwai Status Interface 2194763f356cSTakashi Iwai ----------------------------------------------------------------------------*/ 2195763f356cSTakashi Iwai 2196763f356cSTakashi Iwai /* get the system sample rate which is set */ 2197763f356cSTakashi Iwai 21980dca1793SAdrian Knoth 21993f7bf918SAdrian Knoth static inline int hdspm_get_pll_freq(struct hdspm *hdspm) 22003f7bf918SAdrian Knoth { 22013f7bf918SAdrian Knoth unsigned int period, rate; 22023f7bf918SAdrian Knoth 22033f7bf918SAdrian Knoth period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 22043f7bf918SAdrian Knoth rate = hdspm_calc_dds_value(hdspm, period); 22053f7bf918SAdrian Knoth 22063f7bf918SAdrian Knoth return rate; 22073f7bf918SAdrian Knoth } 22083f7bf918SAdrian Knoth 22090dca1793SAdrian Knoth /** 22100dca1793SAdrian Knoth * Calculate the real sample rate from the 22110dca1793SAdrian Knoth * current DDS value. 22120dca1793SAdrian Knoth **/ 22130dca1793SAdrian Knoth static int hdspm_get_system_sample_rate(struct hdspm *hdspm) 22140dca1793SAdrian Knoth { 22153f7bf918SAdrian Knoth unsigned int rate; 22160dca1793SAdrian Knoth 22173f7bf918SAdrian Knoth rate = hdspm_get_pll_freq(hdspm); 22180dca1793SAdrian Knoth 2219a97bda7dSAdrian Knoth if (rate > 207000) { 222021a164dfSAdrian Knoth /* Unreasonable high sample rate as seen on PCI MADI cards. */ 222121a164dfSAdrian Knoth if (0 == hdspm_system_clock_mode(hdspm)) { 222221a164dfSAdrian Knoth /* master mode, return internal sample rate */ 2223a97bda7dSAdrian Knoth rate = hdspm->system_sample_rate; 222421a164dfSAdrian Knoth } else { 222521a164dfSAdrian Knoth /* slave mode, return external sample rate */ 222621a164dfSAdrian Knoth rate = hdspm_external_sample_rate(hdspm); 222721a164dfSAdrian Knoth } 2228a97bda7dSAdrian Knoth } 2229a97bda7dSAdrian Knoth 22300dca1793SAdrian Knoth return rate; 22310dca1793SAdrian Knoth } 22320dca1793SAdrian Knoth 22330dca1793SAdrian Knoth 2234763f356cSTakashi Iwai #define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \ 223567ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2236763f356cSTakashi Iwai .name = xname, \ 2237763f356cSTakashi Iwai .index = xindex, \ 223841285a98SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 223941285a98SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 2240763f356cSTakashi Iwai .info = snd_hdspm_info_system_sample_rate, \ 224141285a98SAdrian Knoth .put = snd_hdspm_put_system_sample_rate, \ 2242763f356cSTakashi Iwai .get = snd_hdspm_get_system_sample_rate \ 2243763f356cSTakashi Iwai } 2244763f356cSTakashi Iwai 224598274f07STakashi Iwai static int snd_hdspm_info_system_sample_rate(struct snd_kcontrol *kcontrol, 224698274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 2247763f356cSTakashi Iwai { 2248763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2249763f356cSTakashi Iwai uinfo->count = 1; 22500dca1793SAdrian Knoth uinfo->value.integer.min = 27000; 22510dca1793SAdrian Knoth uinfo->value.integer.max = 207000; 22520dca1793SAdrian Knoth uinfo->value.integer.step = 1; 2253763f356cSTakashi Iwai return 0; 2254763f356cSTakashi Iwai } 2255763f356cSTakashi Iwai 22560dca1793SAdrian Knoth 225798274f07STakashi Iwai static int snd_hdspm_get_system_sample_rate(struct snd_kcontrol *kcontrol, 225898274f07STakashi Iwai struct snd_ctl_elem_value * 2259763f356cSTakashi Iwai ucontrol) 2260763f356cSTakashi Iwai { 226198274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2262763f356cSTakashi Iwai 22630dca1793SAdrian Knoth ucontrol->value.integer.value[0] = hdspm_get_system_sample_rate(hdspm); 2264763f356cSTakashi Iwai return 0; 2265763f356cSTakashi Iwai } 2266763f356cSTakashi Iwai 226741285a98SAdrian Knoth static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol, 226841285a98SAdrian Knoth struct snd_ctl_elem_value * 226941285a98SAdrian Knoth ucontrol) 227041285a98SAdrian Knoth { 227141285a98SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 227241285a98SAdrian Knoth 227341285a98SAdrian Knoth hdspm_set_dds_value(hdspm, ucontrol->value.enumerated.item[0]); 227441285a98SAdrian Knoth return 0; 227541285a98SAdrian Knoth } 227641285a98SAdrian Knoth 22770dca1793SAdrian Knoth 22780dca1793SAdrian Knoth /** 22790dca1793SAdrian Knoth * Returns the WordClock sample rate class for the given card. 22800dca1793SAdrian Knoth **/ 22810dca1793SAdrian Knoth static int hdspm_get_wc_sample_rate(struct hdspm *hdspm) 22820dca1793SAdrian Knoth { 22830dca1793SAdrian Knoth int status; 22840dca1793SAdrian Knoth 22850dca1793SAdrian Knoth switch (hdspm->io_type) { 22860dca1793SAdrian Knoth case RayDAT: 22870dca1793SAdrian Knoth case AIO: 22880dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 22890dca1793SAdrian Knoth return (status >> 16) & 0xF; 22900dca1793SAdrian Knoth break; 2291a57fea8eSAdrian Knoth case AES32: 2292a57fea8eSAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 2293a57fea8eSAdrian Knoth return (status >> HDSPM_AES32_wcFreq_bit) & 0xF; 22940dca1793SAdrian Knoth default: 22950dca1793SAdrian Knoth break; 22960dca1793SAdrian Knoth } 22970dca1793SAdrian Knoth 22980dca1793SAdrian Knoth 22990dca1793SAdrian Knoth return 0; 23000dca1793SAdrian Knoth } 23010dca1793SAdrian Knoth 23020dca1793SAdrian Knoth 23030dca1793SAdrian Knoth /** 23040dca1793SAdrian Knoth * Returns the TCO sample rate class for the given card. 23050dca1793SAdrian Knoth **/ 23060dca1793SAdrian Knoth static int hdspm_get_tco_sample_rate(struct hdspm *hdspm) 23070dca1793SAdrian Knoth { 23080dca1793SAdrian Knoth int status; 23090dca1793SAdrian Knoth 23100dca1793SAdrian Knoth if (hdspm->tco) { 23110dca1793SAdrian Knoth switch (hdspm->io_type) { 23120dca1793SAdrian Knoth case RayDAT: 23130dca1793SAdrian Knoth case AIO: 23140dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 23150dca1793SAdrian Knoth return (status >> 20) & 0xF; 23160dca1793SAdrian Knoth break; 2317051c44feSAdrian Knoth case AES32: 2318051c44feSAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 2319051c44feSAdrian Knoth return (status >> 1) & 0xF; 23200dca1793SAdrian Knoth default: 23210dca1793SAdrian Knoth break; 23220dca1793SAdrian Knoth } 23230dca1793SAdrian Knoth } 23240dca1793SAdrian Knoth 23250dca1793SAdrian Knoth return 0; 23260dca1793SAdrian Knoth } 23270dca1793SAdrian Knoth 23280dca1793SAdrian Knoth 23290dca1793SAdrian Knoth /** 23300dca1793SAdrian Knoth * Returns the SYNC_IN sample rate class for the given card. 23310dca1793SAdrian Knoth **/ 23320dca1793SAdrian Knoth static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) 23330dca1793SAdrian Knoth { 23340dca1793SAdrian Knoth int status; 23350dca1793SAdrian Knoth 23360dca1793SAdrian Knoth if (hdspm->tco) { 23370dca1793SAdrian Knoth switch (hdspm->io_type) { 23380dca1793SAdrian Knoth case RayDAT: 23390dca1793SAdrian Knoth case AIO: 23400dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_2); 23410dca1793SAdrian Knoth return (status >> 12) & 0xF; 23420dca1793SAdrian Knoth break; 23430dca1793SAdrian Knoth default: 23440dca1793SAdrian Knoth break; 23450dca1793SAdrian Knoth } 23460dca1793SAdrian Knoth } 23470dca1793SAdrian Knoth 23480dca1793SAdrian Knoth return 0; 23490dca1793SAdrian Knoth } 23500dca1793SAdrian Knoth 2351d3c36ed8SAdrian Knoth /** 2352d3c36ed8SAdrian Knoth * Returns the AES sample rate class for the given card. 2353d3c36ed8SAdrian Knoth **/ 2354d3c36ed8SAdrian Knoth static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index) 2355d3c36ed8SAdrian Knoth { 2356d3c36ed8SAdrian Knoth int timecode; 2357d3c36ed8SAdrian Knoth 2358d3c36ed8SAdrian Knoth switch (hdspm->io_type) { 2359d3c36ed8SAdrian Knoth case AES32: 2360d3c36ed8SAdrian Knoth timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); 2361d3c36ed8SAdrian Knoth return (timecode >> (4*index)) & 0xF; 2362d3c36ed8SAdrian Knoth break; 2363d3c36ed8SAdrian Knoth default: 2364d3c36ed8SAdrian Knoth break; 2365d3c36ed8SAdrian Knoth } 2366d3c36ed8SAdrian Knoth return 0; 2367d3c36ed8SAdrian Knoth } 23680dca1793SAdrian Knoth 23690dca1793SAdrian Knoth /** 23700dca1793SAdrian Knoth * Returns the sample rate class for input source <idx> for 23710dca1793SAdrian Knoth * 'new style' cards like the AIO and RayDAT. 23720dca1793SAdrian Knoth **/ 23730dca1793SAdrian Knoth static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) 23740dca1793SAdrian Knoth { 23750dca1793SAdrian Knoth int status = hdspm_read(hdspm, HDSPM_RD_STATUS_2); 23760dca1793SAdrian Knoth 23770dca1793SAdrian Knoth return (status >> (idx*4)) & 0xF; 23780dca1793SAdrian Knoth } 23790dca1793SAdrian Knoth 23808cea5710SAdrian Knoth #define ENUMERATED_CTL_INFO(info, texts) \ 238138816545SAdrian Knoth snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts) 23828cea5710SAdrian Knoth 23830dca1793SAdrian Knoth 23842336142fSAdrian Knoth /* Helper function to query the external sample rate and return the 23852336142fSAdrian Knoth * corresponding enum to be returned to userspace. 23862336142fSAdrian Knoth */ 23872336142fSAdrian Knoth static int hdspm_external_rate_to_enum(struct hdspm *hdspm) 23882336142fSAdrian Knoth { 23892336142fSAdrian Knoth int rate = hdspm_external_sample_rate(hdspm); 23902336142fSAdrian Knoth int i, selected_rate = 0; 23912336142fSAdrian Knoth for (i = 1; i < 10; i++) 23922336142fSAdrian Knoth if (HDSPM_bit2freq(i) == rate) { 23932336142fSAdrian Knoth selected_rate = i; 23942336142fSAdrian Knoth break; 23952336142fSAdrian Knoth } 23962336142fSAdrian Knoth return selected_rate; 23972336142fSAdrian Knoth } 23982336142fSAdrian Knoth 23990dca1793SAdrian Knoth 2400763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ 240167ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2402763f356cSTakashi Iwai .name = xname, \ 24030dca1793SAdrian Knoth .private_value = xindex, \ 2404763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ, \ 2405763f356cSTakashi Iwai .info = snd_hdspm_info_autosync_sample_rate, \ 2406763f356cSTakashi Iwai .get = snd_hdspm_get_autosync_sample_rate \ 2407763f356cSTakashi Iwai } 2408763f356cSTakashi Iwai 24090dca1793SAdrian Knoth 241098274f07STakashi Iwai static int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, 241198274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 2412763f356cSTakashi Iwai { 2413e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts_freq); 2414763f356cSTakashi Iwai return 0; 2415763f356cSTakashi Iwai } 2416763f356cSTakashi Iwai 24170dca1793SAdrian Knoth 241898274f07STakashi Iwai static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, 241998274f07STakashi Iwai struct snd_ctl_elem_value * 2420763f356cSTakashi Iwai ucontrol) 2421763f356cSTakashi Iwai { 242298274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2423763f356cSTakashi Iwai 24240dca1793SAdrian Knoth switch (hdspm->io_type) { 24250dca1793SAdrian Knoth case RayDAT: 24260dca1793SAdrian Knoth switch (kcontrol->private_value) { 24270dca1793SAdrian Knoth case 0: 24280dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 24290dca1793SAdrian Knoth hdspm_get_wc_sample_rate(hdspm); 2430763f356cSTakashi Iwai break; 24310dca1793SAdrian Knoth case 7: 24320dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 24330dca1793SAdrian Knoth hdspm_get_tco_sample_rate(hdspm); 2434763f356cSTakashi Iwai break; 24350dca1793SAdrian Knoth case 8: 24360dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 24370dca1793SAdrian Knoth hdspm_get_sync_in_sample_rate(hdspm); 2438763f356cSTakashi Iwai break; 2439763f356cSTakashi Iwai default: 24400dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 24410dca1793SAdrian Knoth hdspm_get_s1_sample_rate(hdspm, 24420dca1793SAdrian Knoth kcontrol->private_value-1); 2443763f356cSTakashi Iwai } 2444d681deaaSAdrian Knoth break; 24450dca1793SAdrian Knoth 24460dca1793SAdrian Knoth case AIO: 24470dca1793SAdrian Knoth switch (kcontrol->private_value) { 24480dca1793SAdrian Knoth case 0: /* WC */ 24490dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 24500dca1793SAdrian Knoth hdspm_get_wc_sample_rate(hdspm); 24510dca1793SAdrian Knoth break; 24520dca1793SAdrian Knoth case 4: /* TCO */ 24530dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 24540dca1793SAdrian Knoth hdspm_get_tco_sample_rate(hdspm); 24550dca1793SAdrian Knoth break; 24560dca1793SAdrian Knoth case 5: /* SYNC_IN */ 24570dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 24580dca1793SAdrian Knoth hdspm_get_sync_in_sample_rate(hdspm); 24590dca1793SAdrian Knoth break; 24600dca1793SAdrian Knoth default: 24610dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 24620dca1793SAdrian Knoth hdspm_get_s1_sample_rate(hdspm, 24631cb7dbf4SAdrian Knoth kcontrol->private_value-1); 24640dca1793SAdrian Knoth } 2465d681deaaSAdrian Knoth break; 24667c4a95b5SAdrian Knoth 24677c4a95b5SAdrian Knoth case AES32: 24687c4a95b5SAdrian Knoth 24697c4a95b5SAdrian Knoth switch (kcontrol->private_value) { 24707c4a95b5SAdrian Knoth case 0: /* WC */ 24717c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] = 24727c4a95b5SAdrian Knoth hdspm_get_wc_sample_rate(hdspm); 24737c4a95b5SAdrian Knoth break; 24747c4a95b5SAdrian Knoth case 9: /* TCO */ 24757c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] = 24767c4a95b5SAdrian Knoth hdspm_get_tco_sample_rate(hdspm); 24777c4a95b5SAdrian Knoth break; 24787c4a95b5SAdrian Knoth case 10: /* SYNC_IN */ 24797c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] = 24807c4a95b5SAdrian Knoth hdspm_get_sync_in_sample_rate(hdspm); 24817c4a95b5SAdrian Knoth break; 24822d63ec38SAdrian Knoth case 11: /* External Rate */ 24832d63ec38SAdrian Knoth ucontrol->value.enumerated.item[0] = 24842d63ec38SAdrian Knoth hdspm_external_rate_to_enum(hdspm); 24852d63ec38SAdrian Knoth break; 24867c4a95b5SAdrian Knoth default: /* AES1 to AES8 */ 24877c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] = 24882d63ec38SAdrian Knoth hdspm_get_aes_sample_rate(hdspm, 24892d63ec38SAdrian Knoth kcontrol->private_value - 24902d63ec38SAdrian Knoth HDSPM_AES32_AUTOSYNC_FROM_AES1); 24917c4a95b5SAdrian Knoth break; 24927c4a95b5SAdrian Knoth } 2493d681deaaSAdrian Knoth break; 2494b8812c55SAdrian Knoth 2495b8812c55SAdrian Knoth case MADI: 2496b8812c55SAdrian Knoth case MADIface: 24972336142fSAdrian Knoth ucontrol->value.enumerated.item[0] = 24982336142fSAdrian Knoth hdspm_external_rate_to_enum(hdspm); 2499b8812c55SAdrian Knoth break; 25000dca1793SAdrian Knoth default: 25010dca1793SAdrian Knoth break; 25020dca1793SAdrian Knoth } 25030dca1793SAdrian Knoth 2504763f356cSTakashi Iwai return 0; 2505763f356cSTakashi Iwai } 2506763f356cSTakashi Iwai 25070dca1793SAdrian Knoth 2508763f356cSTakashi Iwai #define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \ 250967ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2510763f356cSTakashi Iwai .name = xname, \ 2511763f356cSTakashi Iwai .index = xindex, \ 25120dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 25130dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 2514763f356cSTakashi Iwai .info = snd_hdspm_info_system_clock_mode, \ 2515763f356cSTakashi Iwai .get = snd_hdspm_get_system_clock_mode, \ 25160dca1793SAdrian Knoth .put = snd_hdspm_put_system_clock_mode, \ 2517763f356cSTakashi Iwai } 2518763f356cSTakashi Iwai 2519763f356cSTakashi Iwai 25200dca1793SAdrian Knoth /** 25210dca1793SAdrian Knoth * Returns the system clock mode for the given card. 25220dca1793SAdrian Knoth * @returns 0 - master, 1 - slave 25230dca1793SAdrian Knoth **/ 252498274f07STakashi Iwai static int hdspm_system_clock_mode(struct hdspm *hdspm) 2525763f356cSTakashi Iwai { 25260dca1793SAdrian Knoth switch (hdspm->io_type) { 25270dca1793SAdrian Knoth case AIO: 25280dca1793SAdrian Knoth case RayDAT: 25290dca1793SAdrian Knoth if (hdspm->settings_register & HDSPM_c0Master) 25300dca1793SAdrian Knoth return 0; 25310dca1793SAdrian Knoth break; 2532763f356cSTakashi Iwai 25330dca1793SAdrian Knoth default: 2534763f356cSTakashi Iwai if (hdspm->control_register & HDSPM_ClockModeMaster) 2535763f356cSTakashi Iwai return 0; 25360dca1793SAdrian Knoth } 25370dca1793SAdrian Knoth 2538763f356cSTakashi Iwai return 1; 2539763f356cSTakashi Iwai } 2540763f356cSTakashi Iwai 25410dca1793SAdrian Knoth 25420dca1793SAdrian Knoth /** 25430dca1793SAdrian Knoth * Sets the system clock mode. 25440dca1793SAdrian Knoth * @param mode 0 - master, 1 - slave 25450dca1793SAdrian Knoth **/ 25460dca1793SAdrian Knoth static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) 25470dca1793SAdrian Knoth { 254834be7ebbSAdrian Knoth hdspm_set_toggle_setting(hdspm, 254934be7ebbSAdrian Knoth (hdspm_is_raydat_or_aio(hdspm)) ? 255034be7ebbSAdrian Knoth HDSPM_c0Master : HDSPM_ClockModeMaster, 255134be7ebbSAdrian Knoth (0 == mode)); 25520dca1793SAdrian Knoth } 25530dca1793SAdrian Knoth 25540dca1793SAdrian Knoth 255598274f07STakashi Iwai static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, 255698274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 2557763f356cSTakashi Iwai { 255838816545SAdrian Knoth static const char *const texts[] = { "Master", "AutoSync" }; 2559e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 2560763f356cSTakashi Iwai return 0; 2561763f356cSTakashi Iwai } 2562763f356cSTakashi Iwai 256398274f07STakashi Iwai static int snd_hdspm_get_system_clock_mode(struct snd_kcontrol *kcontrol, 256498274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2565763f356cSTakashi Iwai { 256698274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2567763f356cSTakashi Iwai 25680dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm_system_clock_mode(hdspm); 2569763f356cSTakashi Iwai return 0; 2570763f356cSTakashi Iwai } 2571763f356cSTakashi Iwai 25720dca1793SAdrian Knoth static int snd_hdspm_put_system_clock_mode(struct snd_kcontrol *kcontrol, 25730dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 25740dca1793SAdrian Knoth { 25750dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 25760dca1793SAdrian Knoth int val; 25770dca1793SAdrian Knoth 25780dca1793SAdrian Knoth if (!snd_hdspm_use_is_exclusive(hdspm)) 25790dca1793SAdrian Knoth return -EBUSY; 25800dca1793SAdrian Knoth 25810dca1793SAdrian Knoth val = ucontrol->value.enumerated.item[0]; 25820dca1793SAdrian Knoth if (val < 0) 25830dca1793SAdrian Knoth val = 0; 25840dca1793SAdrian Knoth else if (val > 1) 25850dca1793SAdrian Knoth val = 1; 25860dca1793SAdrian Knoth 25870dca1793SAdrian Knoth hdspm_set_system_clock_mode(hdspm, val); 25880dca1793SAdrian Knoth 25890dca1793SAdrian Knoth return 0; 25900dca1793SAdrian Knoth } 25910dca1793SAdrian Knoth 25920dca1793SAdrian Knoth 25930dca1793SAdrian Knoth #define HDSPM_INTERNAL_CLOCK(xname, xindex) \ 259467ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2595763f356cSTakashi Iwai .name = xname, \ 2596763f356cSTakashi Iwai .index = xindex, \ 2597763f356cSTakashi Iwai .info = snd_hdspm_info_clock_source, \ 2598763f356cSTakashi Iwai .get = snd_hdspm_get_clock_source, \ 2599763f356cSTakashi Iwai .put = snd_hdspm_put_clock_source \ 2600763f356cSTakashi Iwai } 2601763f356cSTakashi Iwai 26020dca1793SAdrian Knoth 260398274f07STakashi Iwai static int hdspm_clock_source(struct hdspm * hdspm) 2604763f356cSTakashi Iwai { 2605763f356cSTakashi Iwai switch (hdspm->system_sample_rate) { 26060dca1793SAdrian Knoth case 32000: return 0; 26070dca1793SAdrian Knoth case 44100: return 1; 26080dca1793SAdrian Knoth case 48000: return 2; 26090dca1793SAdrian Knoth case 64000: return 3; 26100dca1793SAdrian Knoth case 88200: return 4; 26110dca1793SAdrian Knoth case 96000: return 5; 26120dca1793SAdrian Knoth case 128000: return 6; 26130dca1793SAdrian Knoth case 176400: return 7; 26140dca1793SAdrian Knoth case 192000: return 8; 2615763f356cSTakashi Iwai } 26160dca1793SAdrian Knoth 26170dca1793SAdrian Knoth return -1; 2618763f356cSTakashi Iwai } 2619763f356cSTakashi Iwai 262098274f07STakashi Iwai static int hdspm_set_clock_source(struct hdspm * hdspm, int mode) 2621763f356cSTakashi Iwai { 2622763f356cSTakashi Iwai int rate; 2623763f356cSTakashi Iwai switch (mode) { 26240dca1793SAdrian Knoth case 0: 26250dca1793SAdrian Knoth rate = 32000; break; 26260dca1793SAdrian Knoth case 1: 26270dca1793SAdrian Knoth rate = 44100; break; 26280dca1793SAdrian Knoth case 2: 26290dca1793SAdrian Knoth rate = 48000; break; 26300dca1793SAdrian Knoth case 3: 26310dca1793SAdrian Knoth rate = 64000; break; 26320dca1793SAdrian Knoth case 4: 26330dca1793SAdrian Knoth rate = 88200; break; 26340dca1793SAdrian Knoth case 5: 26350dca1793SAdrian Knoth rate = 96000; break; 26360dca1793SAdrian Knoth case 6: 26370dca1793SAdrian Knoth rate = 128000; break; 26380dca1793SAdrian Knoth case 7: 26390dca1793SAdrian Knoth rate = 176400; break; 26400dca1793SAdrian Knoth case 8: 26410dca1793SAdrian Knoth rate = 192000; break; 2642763f356cSTakashi Iwai default: 26430dca1793SAdrian Knoth rate = 48000; 2644763f356cSTakashi Iwai } 2645763f356cSTakashi Iwai hdspm_set_rate(hdspm, rate, 1); 2646763f356cSTakashi Iwai return 0; 2647763f356cSTakashi Iwai } 2648763f356cSTakashi Iwai 264998274f07STakashi Iwai static int snd_hdspm_info_clock_source(struct snd_kcontrol *kcontrol, 265098274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 2651763f356cSTakashi Iwai { 2652763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2653763f356cSTakashi Iwai uinfo->count = 1; 26540dca1793SAdrian Knoth uinfo->value.enumerated.items = 9; 2655763f356cSTakashi Iwai 2656763f356cSTakashi Iwai if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 2657763f356cSTakashi Iwai uinfo->value.enumerated.item = 2658763f356cSTakashi Iwai uinfo->value.enumerated.items - 1; 2659763f356cSTakashi Iwai 2660763f356cSTakashi Iwai strcpy(uinfo->value.enumerated.name, 26610dca1793SAdrian Knoth texts_freq[uinfo->value.enumerated.item+1]); 2662763f356cSTakashi Iwai 2663763f356cSTakashi Iwai return 0; 2664763f356cSTakashi Iwai } 2665763f356cSTakashi Iwai 266698274f07STakashi Iwai static int snd_hdspm_get_clock_source(struct snd_kcontrol *kcontrol, 266798274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2668763f356cSTakashi Iwai { 266998274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2670763f356cSTakashi Iwai 2671763f356cSTakashi Iwai ucontrol->value.enumerated.item[0] = hdspm_clock_source(hdspm); 2672763f356cSTakashi Iwai return 0; 2673763f356cSTakashi Iwai } 2674763f356cSTakashi Iwai 267598274f07STakashi Iwai static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol, 267698274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2677763f356cSTakashi Iwai { 267898274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2679763f356cSTakashi Iwai int change; 2680763f356cSTakashi Iwai int val; 2681763f356cSTakashi Iwai 2682763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 2683763f356cSTakashi Iwai return -EBUSY; 2684763f356cSTakashi Iwai val = ucontrol->value.enumerated.item[0]; 2685763f356cSTakashi Iwai if (val < 0) 2686763f356cSTakashi Iwai val = 0; 26876534599dSRemy Bruno if (val > 9) 26886534599dSRemy Bruno val = 9; 2689763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 2690763f356cSTakashi Iwai if (val != hdspm_clock_source(hdspm)) 2691763f356cSTakashi Iwai change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0; 2692763f356cSTakashi Iwai else 2693763f356cSTakashi Iwai change = 0; 2694763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 2695763f356cSTakashi Iwai return change; 2696763f356cSTakashi Iwai } 2697763f356cSTakashi Iwai 26980dca1793SAdrian Knoth 2699763f356cSTakashi Iwai #define HDSPM_PREF_SYNC_REF(xname, xindex) \ 270067ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2701763f356cSTakashi Iwai .name = xname, \ 2702763f356cSTakashi Iwai .index = xindex, \ 27030dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 27040dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 2705763f356cSTakashi Iwai .info = snd_hdspm_info_pref_sync_ref, \ 2706763f356cSTakashi Iwai .get = snd_hdspm_get_pref_sync_ref, \ 2707763f356cSTakashi Iwai .put = snd_hdspm_put_pref_sync_ref \ 2708763f356cSTakashi Iwai } 2709763f356cSTakashi Iwai 27100dca1793SAdrian Knoth 27110dca1793SAdrian Knoth /** 27120dca1793SAdrian Knoth * Returns the current preferred sync reference setting. 27130dca1793SAdrian Knoth * The semantics of the return value are depending on the 27140dca1793SAdrian Knoth * card, please see the comments for clarification. 27150dca1793SAdrian Knoth **/ 271698274f07STakashi Iwai static int hdspm_pref_sync_ref(struct hdspm * hdspm) 2717763f356cSTakashi Iwai { 27180dca1793SAdrian Knoth switch (hdspm->io_type) { 27190dca1793SAdrian Knoth case AES32: 27203cee5a60SRemy Bruno switch (hdspm->control_register & HDSPM_SyncRefMask) { 27210dca1793SAdrian Knoth case 0: return 0; /* WC */ 27220dca1793SAdrian Knoth case HDSPM_SyncRef0: return 1; /* AES 1 */ 27230dca1793SAdrian Knoth case HDSPM_SyncRef1: return 2; /* AES 2 */ 27240dca1793SAdrian Knoth case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3; /* AES 3 */ 27250dca1793SAdrian Knoth case HDSPM_SyncRef2: return 4; /* AES 4 */ 27260dca1793SAdrian Knoth case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5; /* AES 5 */ 27270dca1793SAdrian Knoth case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6; /* AES 6 */ 27280dca1793SAdrian Knoth case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0: 27290dca1793SAdrian Knoth return 7; /* AES 7 */ 27300dca1793SAdrian Knoth case HDSPM_SyncRef3: return 8; /* AES 8 */ 27310dca1793SAdrian Knoth case HDSPM_SyncRef3+HDSPM_SyncRef0: return 9; /* TCO */ 27320dca1793SAdrian Knoth } 27330dca1793SAdrian Knoth break; 27340dca1793SAdrian Knoth 27350dca1793SAdrian Knoth case MADI: 27360dca1793SAdrian Knoth case MADIface: 27370dca1793SAdrian Knoth if (hdspm->tco) { 27380dca1793SAdrian Knoth switch (hdspm->control_register & HDSPM_SyncRefMask) { 27390dca1793SAdrian Knoth case 0: return 0; /* WC */ 27400dca1793SAdrian Knoth case HDSPM_SyncRef0: return 1; /* MADI */ 27410dca1793SAdrian Knoth case HDSPM_SyncRef1: return 2; /* TCO */ 27420dca1793SAdrian Knoth case HDSPM_SyncRef1+HDSPM_SyncRef0: 27430dca1793SAdrian Knoth return 3; /* SYNC_IN */ 27443cee5a60SRemy Bruno } 27453cee5a60SRemy Bruno } else { 2746763f356cSTakashi Iwai switch (hdspm->control_register & HDSPM_SyncRefMask) { 27470dca1793SAdrian Knoth case 0: return 0; /* WC */ 27480dca1793SAdrian Knoth case HDSPM_SyncRef0: return 1; /* MADI */ 27490dca1793SAdrian Knoth case HDSPM_SyncRef1+HDSPM_SyncRef0: 27500dca1793SAdrian Knoth return 2; /* SYNC_IN */ 27510dca1793SAdrian Knoth } 27520dca1793SAdrian Knoth } 27530dca1793SAdrian Knoth break; 27540dca1793SAdrian Knoth 27550dca1793SAdrian Knoth case RayDAT: 27560dca1793SAdrian Knoth if (hdspm->tco) { 27570dca1793SAdrian Knoth switch ((hdspm->settings_register & 27580dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 27590dca1793SAdrian Knoth case 0: return 0; /* WC */ 27600dca1793SAdrian Knoth case 3: return 1; /* ADAT 1 */ 27610dca1793SAdrian Knoth case 4: return 2; /* ADAT 2 */ 27620dca1793SAdrian Knoth case 5: return 3; /* ADAT 3 */ 27630dca1793SAdrian Knoth case 6: return 4; /* ADAT 4 */ 27640dca1793SAdrian Knoth case 1: return 5; /* AES */ 27650dca1793SAdrian Knoth case 2: return 6; /* SPDIF */ 27660dca1793SAdrian Knoth case 9: return 7; /* TCO */ 27670dca1793SAdrian Knoth case 10: return 8; /* SYNC_IN */ 27680dca1793SAdrian Knoth } 27690dca1793SAdrian Knoth } else { 27700dca1793SAdrian Knoth switch ((hdspm->settings_register & 27710dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 27720dca1793SAdrian Knoth case 0: return 0; /* WC */ 27730dca1793SAdrian Knoth case 3: return 1; /* ADAT 1 */ 27740dca1793SAdrian Knoth case 4: return 2; /* ADAT 2 */ 27750dca1793SAdrian Knoth case 5: return 3; /* ADAT 3 */ 27760dca1793SAdrian Knoth case 6: return 4; /* ADAT 4 */ 27770dca1793SAdrian Knoth case 1: return 5; /* AES */ 27780dca1793SAdrian Knoth case 2: return 6; /* SPDIF */ 27790dca1793SAdrian Knoth case 10: return 7; /* SYNC_IN */ 2780763f356cSTakashi Iwai } 27813cee5a60SRemy Bruno } 2782763f356cSTakashi Iwai 27830dca1793SAdrian Knoth break; 27840dca1793SAdrian Knoth 27850dca1793SAdrian Knoth case AIO: 27860dca1793SAdrian Knoth if (hdspm->tco) { 27870dca1793SAdrian Knoth switch ((hdspm->settings_register & 27880dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 27890dca1793SAdrian Knoth case 0: return 0; /* WC */ 27900dca1793SAdrian Knoth case 3: return 1; /* ADAT */ 27910dca1793SAdrian Knoth case 1: return 2; /* AES */ 27920dca1793SAdrian Knoth case 2: return 3; /* SPDIF */ 27930dca1793SAdrian Knoth case 9: return 4; /* TCO */ 27940dca1793SAdrian Knoth case 10: return 5; /* SYNC_IN */ 27950dca1793SAdrian Knoth } 27960dca1793SAdrian Knoth } else { 27970dca1793SAdrian Knoth switch ((hdspm->settings_register & 27980dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 27990dca1793SAdrian Knoth case 0: return 0; /* WC */ 28000dca1793SAdrian Knoth case 3: return 1; /* ADAT */ 28010dca1793SAdrian Knoth case 1: return 2; /* AES */ 28020dca1793SAdrian Knoth case 2: return 3; /* SPDIF */ 28030dca1793SAdrian Knoth case 10: return 4; /* SYNC_IN */ 28040dca1793SAdrian Knoth } 2805763f356cSTakashi Iwai } 2806763f356cSTakashi Iwai 28070dca1793SAdrian Knoth break; 28080dca1793SAdrian Knoth } 28090dca1793SAdrian Knoth 28100dca1793SAdrian Knoth return -1; 28110dca1793SAdrian Knoth } 28120dca1793SAdrian Knoth 28130dca1793SAdrian Knoth 28140dca1793SAdrian Knoth /** 28150dca1793SAdrian Knoth * Set the preferred sync reference to <pref>. The semantics 28160dca1793SAdrian Knoth * of <pref> are depending on the card type, see the comments 28170dca1793SAdrian Knoth * for clarification. 28180dca1793SAdrian Knoth **/ 281998274f07STakashi Iwai static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref) 2820763f356cSTakashi Iwai { 28210dca1793SAdrian Knoth int p = 0; 2822763f356cSTakashi Iwai 28230dca1793SAdrian Knoth switch (hdspm->io_type) { 28240dca1793SAdrian Knoth case AES32: 28250dca1793SAdrian Knoth hdspm->control_register &= ~HDSPM_SyncRefMask; 28263cee5a60SRemy Bruno switch (pref) { 28270dca1793SAdrian Knoth case 0: /* WC */ 28283cee5a60SRemy Bruno break; 28290dca1793SAdrian Knoth case 1: /* AES 1 */ 28303cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef0; 28313cee5a60SRemy Bruno break; 28320dca1793SAdrian Knoth case 2: /* AES 2 */ 28333cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef1; 28343cee5a60SRemy Bruno break; 28350dca1793SAdrian Knoth case 3: /* AES 3 */ 28360dca1793SAdrian Knoth hdspm->control_register |= 28370dca1793SAdrian Knoth HDSPM_SyncRef1+HDSPM_SyncRef0; 28383cee5a60SRemy Bruno break; 28390dca1793SAdrian Knoth case 4: /* AES 4 */ 28403cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef2; 28413cee5a60SRemy Bruno break; 28420dca1793SAdrian Knoth case 5: /* AES 5 */ 28430dca1793SAdrian Knoth hdspm->control_register |= 28440dca1793SAdrian Knoth HDSPM_SyncRef2+HDSPM_SyncRef0; 28453cee5a60SRemy Bruno break; 28460dca1793SAdrian Knoth case 6: /* AES 6 */ 28470dca1793SAdrian Knoth hdspm->control_register |= 28480dca1793SAdrian Knoth HDSPM_SyncRef2+HDSPM_SyncRef1; 28493cee5a60SRemy Bruno break; 28500dca1793SAdrian Knoth case 7: /* AES 7 */ 2851ef5fa1a4STakashi Iwai hdspm->control_register |= 2852ef5fa1a4STakashi Iwai HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0; 28533cee5a60SRemy Bruno break; 28540dca1793SAdrian Knoth case 8: /* AES 8 */ 28553cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef3; 28563cee5a60SRemy Bruno break; 28570dca1793SAdrian Knoth case 9: /* TCO */ 28580dca1793SAdrian Knoth hdspm->control_register |= 28590dca1793SAdrian Knoth HDSPM_SyncRef3+HDSPM_SyncRef0; 28600dca1793SAdrian Knoth break; 28610dca1793SAdrian Knoth default: 28620dca1793SAdrian Knoth return -1; 28630dca1793SAdrian Knoth } 28640dca1793SAdrian Knoth 28650dca1793SAdrian Knoth break; 28660dca1793SAdrian Knoth 28670dca1793SAdrian Knoth case MADI: 28680dca1793SAdrian Knoth case MADIface: 28690dca1793SAdrian Knoth hdspm->control_register &= ~HDSPM_SyncRefMask; 28700dca1793SAdrian Knoth if (hdspm->tco) { 28710dca1793SAdrian Knoth switch (pref) { 28720dca1793SAdrian Knoth case 0: /* WC */ 28730dca1793SAdrian Knoth break; 28740dca1793SAdrian Knoth case 1: /* MADI */ 28750dca1793SAdrian Knoth hdspm->control_register |= HDSPM_SyncRef0; 28760dca1793SAdrian Knoth break; 28770dca1793SAdrian Knoth case 2: /* TCO */ 28780dca1793SAdrian Knoth hdspm->control_register |= HDSPM_SyncRef1; 28790dca1793SAdrian Knoth break; 28800dca1793SAdrian Knoth case 3: /* SYNC_IN */ 28810dca1793SAdrian Knoth hdspm->control_register |= 28820dca1793SAdrian Knoth HDSPM_SyncRef0+HDSPM_SyncRef1; 28830dca1793SAdrian Knoth break; 28843cee5a60SRemy Bruno default: 28853cee5a60SRemy Bruno return -1; 28863cee5a60SRemy Bruno } 28873cee5a60SRemy Bruno } else { 2888763f356cSTakashi Iwai switch (pref) { 28890dca1793SAdrian Knoth case 0: /* WC */ 2890763f356cSTakashi Iwai break; 28910dca1793SAdrian Knoth case 1: /* MADI */ 28920dca1793SAdrian Knoth hdspm->control_register |= HDSPM_SyncRef0; 28930dca1793SAdrian Knoth break; 28940dca1793SAdrian Knoth case 2: /* SYNC_IN */ 28950dca1793SAdrian Knoth hdspm->control_register |= 28960dca1793SAdrian Knoth HDSPM_SyncRef0+HDSPM_SyncRef1; 2897763f356cSTakashi Iwai break; 2898763f356cSTakashi Iwai default: 2899763f356cSTakashi Iwai return -1; 2900763f356cSTakashi Iwai } 29013cee5a60SRemy Bruno } 29020dca1793SAdrian Knoth 29030dca1793SAdrian Knoth break; 29040dca1793SAdrian Knoth 29050dca1793SAdrian Knoth case RayDAT: 29060dca1793SAdrian Knoth if (hdspm->tco) { 29070dca1793SAdrian Knoth switch (pref) { 29080dca1793SAdrian Knoth case 0: p = 0; break; /* WC */ 29090dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT 1 */ 29100dca1793SAdrian Knoth case 2: p = 4; break; /* ADAT 2 */ 29110dca1793SAdrian Knoth case 3: p = 5; break; /* ADAT 3 */ 29120dca1793SAdrian Knoth case 4: p = 6; break; /* ADAT 4 */ 29130dca1793SAdrian Knoth case 5: p = 1; break; /* AES */ 29140dca1793SAdrian Knoth case 6: p = 2; break; /* SPDIF */ 29150dca1793SAdrian Knoth case 7: p = 9; break; /* TCO */ 29160dca1793SAdrian Knoth case 8: p = 10; break; /* SYNC_IN */ 29170dca1793SAdrian Knoth default: return -1; 29180dca1793SAdrian Knoth } 29190dca1793SAdrian Knoth } else { 29200dca1793SAdrian Knoth switch (pref) { 29210dca1793SAdrian Knoth case 0: p = 0; break; /* WC */ 29220dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT 1 */ 29230dca1793SAdrian Knoth case 2: p = 4; break; /* ADAT 2 */ 29240dca1793SAdrian Knoth case 3: p = 5; break; /* ADAT 3 */ 29250dca1793SAdrian Knoth case 4: p = 6; break; /* ADAT 4 */ 29260dca1793SAdrian Knoth case 5: p = 1; break; /* AES */ 29270dca1793SAdrian Knoth case 6: p = 2; break; /* SPDIF */ 29280dca1793SAdrian Knoth case 7: p = 10; break; /* SYNC_IN */ 29290dca1793SAdrian Knoth default: return -1; 29300dca1793SAdrian Knoth } 29310dca1793SAdrian Knoth } 29320dca1793SAdrian Knoth break; 29330dca1793SAdrian Knoth 29340dca1793SAdrian Knoth case AIO: 29350dca1793SAdrian Knoth if (hdspm->tco) { 29360dca1793SAdrian Knoth switch (pref) { 29370dca1793SAdrian Knoth case 0: p = 0; break; /* WC */ 29380dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT */ 29390dca1793SAdrian Knoth case 2: p = 1; break; /* AES */ 29400dca1793SAdrian Knoth case 3: p = 2; break; /* SPDIF */ 29410dca1793SAdrian Knoth case 4: p = 9; break; /* TCO */ 29420dca1793SAdrian Knoth case 5: p = 10; break; /* SYNC_IN */ 29430dca1793SAdrian Knoth default: return -1; 29440dca1793SAdrian Knoth } 29450dca1793SAdrian Knoth } else { 29460dca1793SAdrian Knoth switch (pref) { 29470dca1793SAdrian Knoth case 0: p = 0; break; /* WC */ 29480dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT */ 29490dca1793SAdrian Knoth case 2: p = 1; break; /* AES */ 29500dca1793SAdrian Knoth case 3: p = 2; break; /* SPDIF */ 29510dca1793SAdrian Knoth case 4: p = 10; break; /* SYNC_IN */ 29520dca1793SAdrian Knoth default: return -1; 29530dca1793SAdrian Knoth } 29540dca1793SAdrian Knoth } 29550dca1793SAdrian Knoth break; 29560dca1793SAdrian Knoth } 29570dca1793SAdrian Knoth 29580dca1793SAdrian Knoth switch (hdspm->io_type) { 29590dca1793SAdrian Knoth case RayDAT: 29600dca1793SAdrian Knoth case AIO: 29610dca1793SAdrian Knoth hdspm->settings_register &= ~HDSPM_c0_SyncRefMask; 29620dca1793SAdrian Knoth hdspm->settings_register |= HDSPM_c0_SyncRef0 * p; 29630dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 29640dca1793SAdrian Knoth break; 29650dca1793SAdrian Knoth 29660dca1793SAdrian Knoth case MADI: 29670dca1793SAdrian Knoth case MADIface: 29680dca1793SAdrian Knoth case AES32: 29690dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_controlRegister, 29700dca1793SAdrian Knoth hdspm->control_register); 29710dca1793SAdrian Knoth } 29720dca1793SAdrian Knoth 2973763f356cSTakashi Iwai return 0; 2974763f356cSTakashi Iwai } 2975763f356cSTakashi Iwai 29760dca1793SAdrian Knoth 297798274f07STakashi Iwai static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, 297898274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 2979763f356cSTakashi Iwai { 29803cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 29813cee5a60SRemy Bruno 2982eb0d4dbfSAdrian Knoth snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync); 2983763f356cSTakashi Iwai 2984763f356cSTakashi Iwai return 0; 2985763f356cSTakashi Iwai } 2986763f356cSTakashi Iwai 298798274f07STakashi Iwai static int snd_hdspm_get_pref_sync_ref(struct snd_kcontrol *kcontrol, 298898274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2989763f356cSTakashi Iwai { 299098274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 29910dca1793SAdrian Knoth int psf = hdspm_pref_sync_ref(hdspm); 2992763f356cSTakashi Iwai 29930dca1793SAdrian Knoth if (psf >= 0) { 29940dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = psf; 2995763f356cSTakashi Iwai return 0; 2996763f356cSTakashi Iwai } 2997763f356cSTakashi Iwai 29980dca1793SAdrian Knoth return -1; 29990dca1793SAdrian Knoth } 30000dca1793SAdrian Knoth 300198274f07STakashi Iwai static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, 300298274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3003763f356cSTakashi Iwai { 300498274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 30050dca1793SAdrian Knoth int val, change = 0; 3006763f356cSTakashi Iwai 3007763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 3008763f356cSTakashi Iwai return -EBUSY; 3009763f356cSTakashi Iwai 30100dca1793SAdrian Knoth val = ucontrol->value.enumerated.item[0]; 30110dca1793SAdrian Knoth 30120dca1793SAdrian Knoth if (val < 0) 30130dca1793SAdrian Knoth val = 0; 30140dca1793SAdrian Knoth else if (val >= hdspm->texts_autosync_items) 30150dca1793SAdrian Knoth val = hdspm->texts_autosync_items-1; 3016763f356cSTakashi Iwai 3017763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 30180dca1793SAdrian Knoth if (val != hdspm_pref_sync_ref(hdspm)) 30190dca1793SAdrian Knoth change = (0 == hdspm_set_pref_sync_ref(hdspm, val)) ? 1 : 0; 30200dca1793SAdrian Knoth 3021763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3022763f356cSTakashi Iwai return change; 3023763f356cSTakashi Iwai } 3024763f356cSTakashi Iwai 30250dca1793SAdrian Knoth 3026763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_REF(xname, xindex) \ 302767ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3028763f356cSTakashi Iwai .name = xname, \ 3029763f356cSTakashi Iwai .index = xindex, \ 3030763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ, \ 3031763f356cSTakashi Iwai .info = snd_hdspm_info_autosync_ref, \ 3032763f356cSTakashi Iwai .get = snd_hdspm_get_autosync_ref, \ 3033763f356cSTakashi Iwai } 3034763f356cSTakashi Iwai 303598274f07STakashi Iwai static int hdspm_autosync_ref(struct hdspm *hdspm) 3036763f356cSTakashi Iwai { 3037763f356cSTakashi Iwai /* This looks at the autosync selected sync reference */ 30382d60fc7fSAdrian Knoth if (AES32 == hdspm->io_type) { 3039763f356cSTakashi Iwai 30402d60fc7fSAdrian Knoth unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); 30412d60fc7fSAdrian Knoth unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; 30422d60fc7fSAdrian Knoth if ((syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD) && 30432d60fc7fSAdrian Knoth (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN)) { 30442d60fc7fSAdrian Knoth return syncref; 30452d60fc7fSAdrian Knoth } 30462d60fc7fSAdrian Knoth return HDSPM_AES32_AUTOSYNC_FROM_NONE; 30472d60fc7fSAdrian Knoth 30482d60fc7fSAdrian Knoth } else if (MADI == hdspm->io_type) { 30492d60fc7fSAdrian Knoth 30502d60fc7fSAdrian Knoth unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 3051763f356cSTakashi Iwai switch (status2 & HDSPM_SelSyncRefMask) { 3052763f356cSTakashi Iwai case HDSPM_SelSyncRef_WORD: 3053763f356cSTakashi Iwai return HDSPM_AUTOSYNC_FROM_WORD; 3054763f356cSTakashi Iwai case HDSPM_SelSyncRef_MADI: 3055763f356cSTakashi Iwai return HDSPM_AUTOSYNC_FROM_MADI; 30560dca1793SAdrian Knoth case HDSPM_SelSyncRef_TCO: 30570dca1793SAdrian Knoth return HDSPM_AUTOSYNC_FROM_TCO; 30580dca1793SAdrian Knoth case HDSPM_SelSyncRef_SyncIn: 30590dca1793SAdrian Knoth return HDSPM_AUTOSYNC_FROM_SYNC_IN; 3060763f356cSTakashi Iwai case HDSPM_SelSyncRef_NVALID: 3061763f356cSTakashi Iwai return HDSPM_AUTOSYNC_FROM_NONE; 3062763f356cSTakashi Iwai default: 3063e71b95adSAdrian Knoth return HDSPM_AUTOSYNC_FROM_NONE; 3064763f356cSTakashi Iwai } 3065763f356cSTakashi Iwai 30660dca1793SAdrian Knoth } 3067763f356cSTakashi Iwai return 0; 3068763f356cSTakashi Iwai } 30690dca1793SAdrian Knoth 3070763f356cSTakashi Iwai 307198274f07STakashi Iwai static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, 307298274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 3073763f356cSTakashi Iwai { 30743cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 30753cee5a60SRemy Bruno 30760dca1793SAdrian Knoth if (AES32 == hdspm->io_type) { 307704659f9eSAdrian Knoth static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3", 3078db2d1a91SAdrian Knoth "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"}; 30793cee5a60SRemy Bruno 308004659f9eSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 30810dca1793SAdrian Knoth } else if (MADI == hdspm->io_type) { 308204659f9eSAdrian Knoth static const char *const texts[] = {"Word Clock", "MADI", "TCO", 30830dca1793SAdrian Knoth "Sync In", "None" }; 3084763f356cSTakashi Iwai 308504659f9eSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 30863cee5a60SRemy Bruno } 3087763f356cSTakashi Iwai return 0; 3088763f356cSTakashi Iwai } 3089763f356cSTakashi Iwai 309098274f07STakashi Iwai static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, 309198274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3092763f356cSTakashi Iwai { 309398274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3094763f356cSTakashi Iwai 30956534599dSRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_autosync_ref(hdspm); 3096763f356cSTakashi Iwai return 0; 3097763f356cSTakashi Iwai } 3098763f356cSTakashi Iwai 3099f99c7881SAdrian Knoth 3100f99c7881SAdrian Knoth 3101f99c7881SAdrian Knoth #define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname, xindex) \ 3102f99c7881SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3103f99c7881SAdrian Knoth .name = xname, \ 3104f99c7881SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READ |\ 3105f99c7881SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 3106f99c7881SAdrian Knoth .info = snd_hdspm_info_tco_video_input_format, \ 3107f99c7881SAdrian Knoth .get = snd_hdspm_get_tco_video_input_format, \ 3108f99c7881SAdrian Knoth } 3109f99c7881SAdrian Knoth 3110f99c7881SAdrian Knoth static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol, 3111f99c7881SAdrian Knoth struct snd_ctl_elem_info *uinfo) 3112f99c7881SAdrian Knoth { 311338816545SAdrian Knoth static const char *const texts[] = {"No video", "NTSC", "PAL"}; 3114f99c7881SAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 3115f99c7881SAdrian Knoth return 0; 3116f99c7881SAdrian Knoth } 3117f99c7881SAdrian Knoth 3118f99c7881SAdrian Knoth static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol, 3119f99c7881SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 3120f99c7881SAdrian Knoth { 3121f99c7881SAdrian Knoth u32 status; 3122f99c7881SAdrian Knoth int ret = 0; 3123f99c7881SAdrian Knoth 3124f99c7881SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3125f99c7881SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 3126f99c7881SAdrian Knoth switch (status & (HDSPM_TCO1_Video_Input_Format_NTSC | 3127f99c7881SAdrian Knoth HDSPM_TCO1_Video_Input_Format_PAL)) { 3128f99c7881SAdrian Knoth case HDSPM_TCO1_Video_Input_Format_NTSC: 3129f99c7881SAdrian Knoth /* ntsc */ 3130f99c7881SAdrian Knoth ret = 1; 3131f99c7881SAdrian Knoth break; 3132f99c7881SAdrian Knoth case HDSPM_TCO1_Video_Input_Format_PAL: 3133f99c7881SAdrian Knoth /* pal */ 3134f99c7881SAdrian Knoth ret = 2; 3135f99c7881SAdrian Knoth break; 3136f99c7881SAdrian Knoth default: 3137f99c7881SAdrian Knoth /* no video */ 3138f99c7881SAdrian Knoth ret = 0; 3139f99c7881SAdrian Knoth break; 3140f99c7881SAdrian Knoth } 3141f99c7881SAdrian Knoth ucontrol->value.enumerated.item[0] = ret; 3142f99c7881SAdrian Knoth return 0; 3143f99c7881SAdrian Knoth } 3144f99c7881SAdrian Knoth 3145f99c7881SAdrian Knoth 3146f99c7881SAdrian Knoth 3147f99c7881SAdrian Knoth #define HDSPM_TCO_LTC_FRAMES(xname, xindex) \ 3148f99c7881SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3149f99c7881SAdrian Knoth .name = xname, \ 3150f99c7881SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READ |\ 3151f99c7881SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 3152f99c7881SAdrian Knoth .info = snd_hdspm_info_tco_ltc_frames, \ 3153f99c7881SAdrian Knoth .get = snd_hdspm_get_tco_ltc_frames, \ 3154f99c7881SAdrian Knoth } 3155f99c7881SAdrian Knoth 3156f99c7881SAdrian Knoth static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol, 3157f99c7881SAdrian Knoth struct snd_ctl_elem_info *uinfo) 3158f99c7881SAdrian Knoth { 315938816545SAdrian Knoth static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", 3160f99c7881SAdrian Knoth "30 fps"}; 3161f99c7881SAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 3162f99c7881SAdrian Knoth return 0; 3163f99c7881SAdrian Knoth } 3164f99c7881SAdrian Knoth 3165f99c7881SAdrian Knoth static int hdspm_tco_ltc_frames(struct hdspm *hdspm) 3166f99c7881SAdrian Knoth { 3167f99c7881SAdrian Knoth u32 status; 3168f99c7881SAdrian Knoth int ret = 0; 3169f99c7881SAdrian Knoth 3170f99c7881SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 3171f99c7881SAdrian Knoth if (status & HDSPM_TCO1_LTC_Input_valid) { 3172f99c7881SAdrian Knoth switch (status & (HDSPM_TCO1_LTC_Format_LSB | 3173f99c7881SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB)) { 3174f99c7881SAdrian Knoth case 0: 3175f99c7881SAdrian Knoth /* 24 fps */ 3176f99c7881SAdrian Knoth ret = 1; 3177f99c7881SAdrian Knoth break; 3178f99c7881SAdrian Knoth case HDSPM_TCO1_LTC_Format_LSB: 3179f99c7881SAdrian Knoth /* 25 fps */ 3180f99c7881SAdrian Knoth ret = 2; 3181f99c7881SAdrian Knoth break; 3182f99c7881SAdrian Knoth case HDSPM_TCO1_LTC_Format_MSB: 3183f99c7881SAdrian Knoth /* 25 fps */ 3184f99c7881SAdrian Knoth ret = 3; 3185f99c7881SAdrian Knoth break; 3186f99c7881SAdrian Knoth default: 3187f99c7881SAdrian Knoth /* 30 fps */ 3188f99c7881SAdrian Knoth ret = 4; 3189f99c7881SAdrian Knoth break; 3190f99c7881SAdrian Knoth } 3191f99c7881SAdrian Knoth } 3192f99c7881SAdrian Knoth 3193f99c7881SAdrian Knoth return ret; 3194f99c7881SAdrian Knoth } 3195f99c7881SAdrian Knoth 3196f99c7881SAdrian Knoth static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol, 3197f99c7881SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 3198f99c7881SAdrian Knoth { 3199f99c7881SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3200f99c7881SAdrian Knoth 3201f99c7881SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm_tco_ltc_frames(hdspm); 3202f99c7881SAdrian Knoth return 0; 3203f99c7881SAdrian Knoth } 3204f99c7881SAdrian Knoth 3205bf0ff87bSAdrian Knoth #define HDSPM_TOGGLE_SETTING(xname, xindex) \ 3206bf0ff87bSAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3207bf0ff87bSAdrian Knoth .name = xname, \ 3208bf0ff87bSAdrian Knoth .private_value = xindex, \ 3209bf0ff87bSAdrian Knoth .info = snd_hdspm_info_toggle_setting, \ 3210bf0ff87bSAdrian Knoth .get = snd_hdspm_get_toggle_setting, \ 3211bf0ff87bSAdrian Knoth .put = snd_hdspm_put_toggle_setting \ 3212bf0ff87bSAdrian Knoth } 3213bf0ff87bSAdrian Knoth 3214bf0ff87bSAdrian Knoth static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask) 3215bf0ff87bSAdrian Knoth { 3216ce13f3f3SAdrian Knoth u32 reg; 3217ce13f3f3SAdrian Knoth 3218ce13f3f3SAdrian Knoth if (hdspm_is_raydat_or_aio(hdspm)) 3219ce13f3f3SAdrian Knoth reg = hdspm->settings_register; 3220ce13f3f3SAdrian Knoth else 3221ce13f3f3SAdrian Knoth reg = hdspm->control_register; 3222ce13f3f3SAdrian Knoth 3223ce13f3f3SAdrian Knoth return (reg & regmask) ? 1 : 0; 3224bf0ff87bSAdrian Knoth } 3225bf0ff87bSAdrian Knoth 3226bf0ff87bSAdrian Knoth static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out) 3227bf0ff87bSAdrian Knoth { 3228ce13f3f3SAdrian Knoth u32 *reg; 3229ce13f3f3SAdrian Knoth u32 target_reg; 3230ce13f3f3SAdrian Knoth 3231ce13f3f3SAdrian Knoth if (hdspm_is_raydat_or_aio(hdspm)) { 3232ce13f3f3SAdrian Knoth reg = &(hdspm->settings_register); 3233ce13f3f3SAdrian Knoth target_reg = HDSPM_WR_SETTINGS; 3234ce13f3f3SAdrian Knoth } else { 3235ce13f3f3SAdrian Knoth reg = &(hdspm->control_register); 3236ce13f3f3SAdrian Knoth target_reg = HDSPM_controlRegister; 3237ce13f3f3SAdrian Knoth } 3238ce13f3f3SAdrian Knoth 3239bf0ff87bSAdrian Knoth if (out) 3240ce13f3f3SAdrian Knoth *reg |= regmask; 3241bf0ff87bSAdrian Knoth else 3242ce13f3f3SAdrian Knoth *reg &= ~regmask; 3243ce13f3f3SAdrian Knoth 3244ce13f3f3SAdrian Knoth hdspm_write(hdspm, target_reg, *reg); 3245bf0ff87bSAdrian Knoth 3246bf0ff87bSAdrian Knoth return 0; 3247bf0ff87bSAdrian Knoth } 3248bf0ff87bSAdrian Knoth 3249bf0ff87bSAdrian Knoth #define snd_hdspm_info_toggle_setting snd_ctl_boolean_mono_info 3250bf0ff87bSAdrian Knoth 3251bf0ff87bSAdrian Knoth static int snd_hdspm_get_toggle_setting(struct snd_kcontrol *kcontrol, 3252bf0ff87bSAdrian Knoth struct snd_ctl_elem_value *ucontrol) 3253bf0ff87bSAdrian Knoth { 3254bf0ff87bSAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3255bf0ff87bSAdrian Knoth u32 regmask = kcontrol->private_value; 3256bf0ff87bSAdrian Knoth 3257bf0ff87bSAdrian Knoth spin_lock_irq(&hdspm->lock); 3258bf0ff87bSAdrian Knoth ucontrol->value.integer.value[0] = hdspm_toggle_setting(hdspm, regmask); 3259bf0ff87bSAdrian Knoth spin_unlock_irq(&hdspm->lock); 3260bf0ff87bSAdrian Knoth return 0; 3261bf0ff87bSAdrian Knoth } 3262bf0ff87bSAdrian Knoth 3263bf0ff87bSAdrian Knoth static int snd_hdspm_put_toggle_setting(struct snd_kcontrol *kcontrol, 3264bf0ff87bSAdrian Knoth struct snd_ctl_elem_value *ucontrol) 3265bf0ff87bSAdrian Knoth { 3266bf0ff87bSAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3267bf0ff87bSAdrian Knoth u32 regmask = kcontrol->private_value; 3268bf0ff87bSAdrian Knoth int change; 3269bf0ff87bSAdrian Knoth unsigned int val; 3270bf0ff87bSAdrian Knoth 3271bf0ff87bSAdrian Knoth if (!snd_hdspm_use_is_exclusive(hdspm)) 3272bf0ff87bSAdrian Knoth return -EBUSY; 3273bf0ff87bSAdrian Knoth val = ucontrol->value.integer.value[0] & 1; 3274bf0ff87bSAdrian Knoth spin_lock_irq(&hdspm->lock); 3275bf0ff87bSAdrian Knoth change = (int) val != hdspm_toggle_setting(hdspm, regmask); 3276bf0ff87bSAdrian Knoth hdspm_set_toggle_setting(hdspm, regmask, val); 3277bf0ff87bSAdrian Knoth spin_unlock_irq(&hdspm->lock); 3278bf0ff87bSAdrian Knoth return change; 3279bf0ff87bSAdrian Knoth } 3280bf0ff87bSAdrian Knoth 3281763f356cSTakashi Iwai #define HDSPM_INPUT_SELECT(xname, xindex) \ 328267ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3283763f356cSTakashi Iwai .name = xname, \ 3284763f356cSTakashi Iwai .index = xindex, \ 3285763f356cSTakashi Iwai .info = snd_hdspm_info_input_select, \ 3286763f356cSTakashi Iwai .get = snd_hdspm_get_input_select, \ 3287763f356cSTakashi Iwai .put = snd_hdspm_put_input_select \ 3288763f356cSTakashi Iwai } 3289763f356cSTakashi Iwai 329098274f07STakashi Iwai static int hdspm_input_select(struct hdspm * hdspm) 3291763f356cSTakashi Iwai { 3292763f356cSTakashi Iwai return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0; 3293763f356cSTakashi Iwai } 3294763f356cSTakashi Iwai 329598274f07STakashi Iwai static int hdspm_set_input_select(struct hdspm * hdspm, int out) 3296763f356cSTakashi Iwai { 3297763f356cSTakashi Iwai if (out) 3298763f356cSTakashi Iwai hdspm->control_register |= HDSPM_InputSelect0; 3299763f356cSTakashi Iwai else 3300763f356cSTakashi Iwai hdspm->control_register &= ~HDSPM_InputSelect0; 3301763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 3302763f356cSTakashi Iwai 3303763f356cSTakashi Iwai return 0; 3304763f356cSTakashi Iwai } 3305763f356cSTakashi Iwai 330698274f07STakashi Iwai static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, 330798274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 3308763f356cSTakashi Iwai { 330938816545SAdrian Knoth static const char *const texts[] = { "optical", "coaxial" }; 3310e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 3311763f356cSTakashi Iwai return 0; 3312763f356cSTakashi Iwai } 3313763f356cSTakashi Iwai 331498274f07STakashi Iwai static int snd_hdspm_get_input_select(struct snd_kcontrol *kcontrol, 331598274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3316763f356cSTakashi Iwai { 331798274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3318763f356cSTakashi Iwai 3319763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3320763f356cSTakashi Iwai ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm); 3321763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3322763f356cSTakashi Iwai return 0; 3323763f356cSTakashi Iwai } 3324763f356cSTakashi Iwai 332598274f07STakashi Iwai static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol, 332698274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3327763f356cSTakashi Iwai { 332898274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3329763f356cSTakashi Iwai int change; 3330763f356cSTakashi Iwai unsigned int val; 3331763f356cSTakashi Iwai 3332763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 3333763f356cSTakashi Iwai return -EBUSY; 3334763f356cSTakashi Iwai val = ucontrol->value.integer.value[0] & 1; 3335763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3336763f356cSTakashi Iwai change = (int) val != hdspm_input_select(hdspm); 3337763f356cSTakashi Iwai hdspm_set_input_select(hdspm, val); 3338763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3339763f356cSTakashi Iwai return change; 3340763f356cSTakashi Iwai } 3341763f356cSTakashi Iwai 33420dca1793SAdrian Knoth 33433cee5a60SRemy Bruno #define HDSPM_DS_WIRE(xname, xindex) \ 33443cee5a60SRemy Bruno { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 33453cee5a60SRemy Bruno .name = xname, \ 33463cee5a60SRemy Bruno .index = xindex, \ 33473cee5a60SRemy Bruno .info = snd_hdspm_info_ds_wire, \ 33483cee5a60SRemy Bruno .get = snd_hdspm_get_ds_wire, \ 33493cee5a60SRemy Bruno .put = snd_hdspm_put_ds_wire \ 33503cee5a60SRemy Bruno } 33513cee5a60SRemy Bruno 33523cee5a60SRemy Bruno static int hdspm_ds_wire(struct hdspm * hdspm) 33533cee5a60SRemy Bruno { 33543cee5a60SRemy Bruno return (hdspm->control_register & HDSPM_DS_DoubleWire) ? 1 : 0; 33553cee5a60SRemy Bruno } 33563cee5a60SRemy Bruno 33573cee5a60SRemy Bruno static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds) 33583cee5a60SRemy Bruno { 33593cee5a60SRemy Bruno if (ds) 33603cee5a60SRemy Bruno hdspm->control_register |= HDSPM_DS_DoubleWire; 33613cee5a60SRemy Bruno else 33623cee5a60SRemy Bruno hdspm->control_register &= ~HDSPM_DS_DoubleWire; 33633cee5a60SRemy Bruno hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 33643cee5a60SRemy Bruno 33653cee5a60SRemy Bruno return 0; 33663cee5a60SRemy Bruno } 33673cee5a60SRemy Bruno 33683cee5a60SRemy Bruno static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, 33693cee5a60SRemy Bruno struct snd_ctl_elem_info *uinfo) 33703cee5a60SRemy Bruno { 337138816545SAdrian Knoth static const char *const texts[] = { "Single", "Double" }; 3372e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 33733cee5a60SRemy Bruno return 0; 33743cee5a60SRemy Bruno } 33753cee5a60SRemy Bruno 33763cee5a60SRemy Bruno static int snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol, 33773cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 33783cee5a60SRemy Bruno { 33793cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 33803cee5a60SRemy Bruno 33813cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 33823cee5a60SRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm); 33833cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 33843cee5a60SRemy Bruno return 0; 33853cee5a60SRemy Bruno } 33863cee5a60SRemy Bruno 33873cee5a60SRemy Bruno static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol, 33883cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 33893cee5a60SRemy Bruno { 33903cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 33913cee5a60SRemy Bruno int change; 33923cee5a60SRemy Bruno unsigned int val; 33933cee5a60SRemy Bruno 33943cee5a60SRemy Bruno if (!snd_hdspm_use_is_exclusive(hdspm)) 33953cee5a60SRemy Bruno return -EBUSY; 33963cee5a60SRemy Bruno val = ucontrol->value.integer.value[0] & 1; 33973cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 33983cee5a60SRemy Bruno change = (int) val != hdspm_ds_wire(hdspm); 33993cee5a60SRemy Bruno hdspm_set_ds_wire(hdspm, val); 34003cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 34013cee5a60SRemy Bruno return change; 34023cee5a60SRemy Bruno } 34033cee5a60SRemy Bruno 34040dca1793SAdrian Knoth 34053cee5a60SRemy Bruno #define HDSPM_QS_WIRE(xname, xindex) \ 34063cee5a60SRemy Bruno { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 34073cee5a60SRemy Bruno .name = xname, \ 34083cee5a60SRemy Bruno .index = xindex, \ 34093cee5a60SRemy Bruno .info = snd_hdspm_info_qs_wire, \ 34103cee5a60SRemy Bruno .get = snd_hdspm_get_qs_wire, \ 34113cee5a60SRemy Bruno .put = snd_hdspm_put_qs_wire \ 34123cee5a60SRemy Bruno } 34133cee5a60SRemy Bruno 34143cee5a60SRemy Bruno static int hdspm_qs_wire(struct hdspm * hdspm) 34153cee5a60SRemy Bruno { 34163cee5a60SRemy Bruno if (hdspm->control_register & HDSPM_QS_DoubleWire) 34173cee5a60SRemy Bruno return 1; 34183cee5a60SRemy Bruno if (hdspm->control_register & HDSPM_QS_QuadWire) 34193cee5a60SRemy Bruno return 2; 34203cee5a60SRemy Bruno return 0; 34213cee5a60SRemy Bruno } 34223cee5a60SRemy Bruno 34233cee5a60SRemy Bruno static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode) 34243cee5a60SRemy Bruno { 34253cee5a60SRemy Bruno hdspm->control_register &= ~(HDSPM_QS_DoubleWire | HDSPM_QS_QuadWire); 34263cee5a60SRemy Bruno switch (mode) { 34273cee5a60SRemy Bruno case 0: 34283cee5a60SRemy Bruno break; 34293cee5a60SRemy Bruno case 1: 34303cee5a60SRemy Bruno hdspm->control_register |= HDSPM_QS_DoubleWire; 34313cee5a60SRemy Bruno break; 34323cee5a60SRemy Bruno case 2: 34333cee5a60SRemy Bruno hdspm->control_register |= HDSPM_QS_QuadWire; 34343cee5a60SRemy Bruno break; 34353cee5a60SRemy Bruno } 34363cee5a60SRemy Bruno hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 34373cee5a60SRemy Bruno 34383cee5a60SRemy Bruno return 0; 34393cee5a60SRemy Bruno } 34403cee5a60SRemy Bruno 34413cee5a60SRemy Bruno static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, 34423cee5a60SRemy Bruno struct snd_ctl_elem_info *uinfo) 34433cee5a60SRemy Bruno { 344438816545SAdrian Knoth static const char *const texts[] = { "Single", "Double", "Quad" }; 3445e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 34463cee5a60SRemy Bruno return 0; 34473cee5a60SRemy Bruno } 34483cee5a60SRemy Bruno 34493cee5a60SRemy Bruno static int snd_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol, 34503cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 34513cee5a60SRemy Bruno { 34523cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 34533cee5a60SRemy Bruno 34543cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 34553cee5a60SRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm); 34563cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 34573cee5a60SRemy Bruno return 0; 34583cee5a60SRemy Bruno } 34593cee5a60SRemy Bruno 34603cee5a60SRemy Bruno static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, 34613cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 34623cee5a60SRemy Bruno { 34633cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 34643cee5a60SRemy Bruno int change; 34653cee5a60SRemy Bruno int val; 34663cee5a60SRemy Bruno 34673cee5a60SRemy Bruno if (!snd_hdspm_use_is_exclusive(hdspm)) 34683cee5a60SRemy Bruno return -EBUSY; 34693cee5a60SRemy Bruno val = ucontrol->value.integer.value[0]; 34703cee5a60SRemy Bruno if (val < 0) 34713cee5a60SRemy Bruno val = 0; 34723cee5a60SRemy Bruno if (val > 2) 34733cee5a60SRemy Bruno val = 2; 34743cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 3475ef5fa1a4STakashi Iwai change = val != hdspm_qs_wire(hdspm); 34763cee5a60SRemy Bruno hdspm_set_qs_wire(hdspm, val); 34773cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 34783cee5a60SRemy Bruno return change; 34793cee5a60SRemy Bruno } 34803cee5a60SRemy Bruno 3481acf14767SAdrian Knoth #define HDSPM_CONTROL_TRISTATE(xname, xindex) \ 3482acf14767SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3483acf14767SAdrian Knoth .name = xname, \ 3484acf14767SAdrian Knoth .private_value = xindex, \ 3485acf14767SAdrian Knoth .info = snd_hdspm_info_tristate, \ 3486acf14767SAdrian Knoth .get = snd_hdspm_get_tristate, \ 3487acf14767SAdrian Knoth .put = snd_hdspm_put_tristate \ 3488acf14767SAdrian Knoth } 3489acf14767SAdrian Knoth 3490acf14767SAdrian Knoth static int hdspm_tristate(struct hdspm *hdspm, u32 regmask) 3491acf14767SAdrian Knoth { 3492acf14767SAdrian Knoth u32 reg = hdspm->settings_register & (regmask * 3); 3493acf14767SAdrian Knoth return reg / regmask; 3494acf14767SAdrian Knoth } 3495acf14767SAdrian Knoth 3496acf14767SAdrian Knoth static int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask) 3497acf14767SAdrian Knoth { 3498acf14767SAdrian Knoth hdspm->settings_register &= ~(regmask * 3); 3499acf14767SAdrian Knoth hdspm->settings_register |= (regmask * mode); 3500acf14767SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 3501acf14767SAdrian Knoth 3502acf14767SAdrian Knoth return 0; 3503acf14767SAdrian Knoth } 3504acf14767SAdrian Knoth 3505acf14767SAdrian Knoth static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol, 3506acf14767SAdrian Knoth struct snd_ctl_elem_info *uinfo) 3507acf14767SAdrian Knoth { 3508acf14767SAdrian Knoth u32 regmask = kcontrol->private_value; 3509acf14767SAdrian Knoth 351038816545SAdrian Knoth static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" }; 351138816545SAdrian Knoth static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" }; 3512acf14767SAdrian Knoth 3513acf14767SAdrian Knoth switch (regmask) { 3514acf14767SAdrian Knoth case HDSPM_c0_Input0: 3515acf14767SAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts_spdif); 3516acf14767SAdrian Knoth break; 3517acf14767SAdrian Knoth default: 3518acf14767SAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts_levels); 3519acf14767SAdrian Knoth break; 3520acf14767SAdrian Knoth } 3521acf14767SAdrian Knoth return 0; 3522acf14767SAdrian Knoth } 3523acf14767SAdrian Knoth 3524acf14767SAdrian Knoth static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol, 3525acf14767SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 3526acf14767SAdrian Knoth { 3527acf14767SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3528acf14767SAdrian Knoth u32 regmask = kcontrol->private_value; 3529acf14767SAdrian Knoth 3530acf14767SAdrian Knoth spin_lock_irq(&hdspm->lock); 3531acf14767SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask); 3532acf14767SAdrian Knoth spin_unlock_irq(&hdspm->lock); 3533acf14767SAdrian Knoth return 0; 3534acf14767SAdrian Knoth } 3535acf14767SAdrian Knoth 3536acf14767SAdrian Knoth static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol, 3537acf14767SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 3538acf14767SAdrian Knoth { 3539acf14767SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3540acf14767SAdrian Knoth u32 regmask = kcontrol->private_value; 3541acf14767SAdrian Knoth int change; 3542acf14767SAdrian Knoth int val; 3543acf14767SAdrian Knoth 3544acf14767SAdrian Knoth if (!snd_hdspm_use_is_exclusive(hdspm)) 3545acf14767SAdrian Knoth return -EBUSY; 3546acf14767SAdrian Knoth val = ucontrol->value.integer.value[0]; 3547acf14767SAdrian Knoth if (val < 0) 3548acf14767SAdrian Knoth val = 0; 3549acf14767SAdrian Knoth if (val > 2) 3550acf14767SAdrian Knoth val = 2; 3551acf14767SAdrian Knoth 3552acf14767SAdrian Knoth spin_lock_irq(&hdspm->lock); 3553acf14767SAdrian Knoth change = val != hdspm_tristate(hdspm, regmask); 3554acf14767SAdrian Knoth hdspm_set_tristate(hdspm, val, regmask); 3555acf14767SAdrian Knoth spin_unlock_irq(&hdspm->lock); 3556acf14767SAdrian Knoth return change; 3557acf14767SAdrian Knoth } 3558acf14767SAdrian Knoth 3559700d1ef3SAdrian Knoth #define HDSPM_MADI_SPEEDMODE(xname, xindex) \ 3560700d1ef3SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3561700d1ef3SAdrian Knoth .name = xname, \ 3562700d1ef3SAdrian Knoth .index = xindex, \ 3563700d1ef3SAdrian Knoth .info = snd_hdspm_info_madi_speedmode, \ 3564700d1ef3SAdrian Knoth .get = snd_hdspm_get_madi_speedmode, \ 3565700d1ef3SAdrian Knoth .put = snd_hdspm_put_madi_speedmode \ 3566700d1ef3SAdrian Knoth } 3567700d1ef3SAdrian Knoth 3568700d1ef3SAdrian Knoth static int hdspm_madi_speedmode(struct hdspm *hdspm) 3569700d1ef3SAdrian Knoth { 3570700d1ef3SAdrian Knoth if (hdspm->control_register & HDSPM_QuadSpeed) 3571700d1ef3SAdrian Knoth return 2; 3572700d1ef3SAdrian Knoth if (hdspm->control_register & HDSPM_DoubleSpeed) 3573700d1ef3SAdrian Knoth return 1; 3574700d1ef3SAdrian Knoth return 0; 3575700d1ef3SAdrian Knoth } 3576700d1ef3SAdrian Knoth 3577700d1ef3SAdrian Knoth static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode) 3578700d1ef3SAdrian Knoth { 3579700d1ef3SAdrian Knoth hdspm->control_register &= ~(HDSPM_DoubleSpeed | HDSPM_QuadSpeed); 3580700d1ef3SAdrian Knoth switch (mode) { 3581700d1ef3SAdrian Knoth case 0: 3582700d1ef3SAdrian Knoth break; 3583700d1ef3SAdrian Knoth case 1: 3584700d1ef3SAdrian Knoth hdspm->control_register |= HDSPM_DoubleSpeed; 3585700d1ef3SAdrian Knoth break; 3586700d1ef3SAdrian Knoth case 2: 3587700d1ef3SAdrian Knoth hdspm->control_register |= HDSPM_QuadSpeed; 3588700d1ef3SAdrian Knoth break; 3589700d1ef3SAdrian Knoth } 3590700d1ef3SAdrian Knoth hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 3591700d1ef3SAdrian Knoth 3592700d1ef3SAdrian Knoth return 0; 3593700d1ef3SAdrian Knoth } 3594700d1ef3SAdrian Knoth 3595700d1ef3SAdrian Knoth static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, 3596700d1ef3SAdrian Knoth struct snd_ctl_elem_info *uinfo) 3597700d1ef3SAdrian Knoth { 359838816545SAdrian Knoth static const char *const texts[] = { "Single", "Double", "Quad" }; 3599e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 3600700d1ef3SAdrian Knoth return 0; 3601700d1ef3SAdrian Knoth } 3602700d1ef3SAdrian Knoth 3603700d1ef3SAdrian Knoth static int snd_hdspm_get_madi_speedmode(struct snd_kcontrol *kcontrol, 3604700d1ef3SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 3605700d1ef3SAdrian Knoth { 3606700d1ef3SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3607700d1ef3SAdrian Knoth 3608700d1ef3SAdrian Knoth spin_lock_irq(&hdspm->lock); 3609700d1ef3SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm_madi_speedmode(hdspm); 3610700d1ef3SAdrian Knoth spin_unlock_irq(&hdspm->lock); 3611700d1ef3SAdrian Knoth return 0; 3612700d1ef3SAdrian Knoth } 3613700d1ef3SAdrian Knoth 3614700d1ef3SAdrian Knoth static int snd_hdspm_put_madi_speedmode(struct snd_kcontrol *kcontrol, 3615700d1ef3SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 3616700d1ef3SAdrian Knoth { 3617700d1ef3SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3618700d1ef3SAdrian Knoth int change; 3619700d1ef3SAdrian Knoth int val; 3620700d1ef3SAdrian Knoth 3621700d1ef3SAdrian Knoth if (!snd_hdspm_use_is_exclusive(hdspm)) 3622700d1ef3SAdrian Knoth return -EBUSY; 3623700d1ef3SAdrian Knoth val = ucontrol->value.integer.value[0]; 3624700d1ef3SAdrian Knoth if (val < 0) 3625700d1ef3SAdrian Knoth val = 0; 3626700d1ef3SAdrian Knoth if (val > 2) 3627700d1ef3SAdrian Knoth val = 2; 3628700d1ef3SAdrian Knoth spin_lock_irq(&hdspm->lock); 3629700d1ef3SAdrian Knoth change = val != hdspm_madi_speedmode(hdspm); 3630700d1ef3SAdrian Knoth hdspm_set_madi_speedmode(hdspm, val); 3631700d1ef3SAdrian Knoth spin_unlock_irq(&hdspm->lock); 3632700d1ef3SAdrian Knoth return change; 3633700d1ef3SAdrian Knoth } 3634763f356cSTakashi Iwai 3635763f356cSTakashi Iwai #define HDSPM_MIXER(xname, xindex) \ 3636763f356cSTakashi Iwai { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ 3637763f356cSTakashi Iwai .name = xname, \ 3638763f356cSTakashi Iwai .index = xindex, \ 363967ed4161SClemens Ladisch .device = 0, \ 3640763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 3641763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 3642763f356cSTakashi Iwai .info = snd_hdspm_info_mixer, \ 3643763f356cSTakashi Iwai .get = snd_hdspm_get_mixer, \ 3644763f356cSTakashi Iwai .put = snd_hdspm_put_mixer \ 3645763f356cSTakashi Iwai } 3646763f356cSTakashi Iwai 364798274f07STakashi Iwai static int snd_hdspm_info_mixer(struct snd_kcontrol *kcontrol, 364898274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 3649763f356cSTakashi Iwai { 3650763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 3651763f356cSTakashi Iwai uinfo->count = 3; 3652763f356cSTakashi Iwai uinfo->value.integer.min = 0; 3653763f356cSTakashi Iwai uinfo->value.integer.max = 65535; 3654763f356cSTakashi Iwai uinfo->value.integer.step = 1; 3655763f356cSTakashi Iwai return 0; 3656763f356cSTakashi Iwai } 3657763f356cSTakashi Iwai 365898274f07STakashi Iwai static int snd_hdspm_get_mixer(struct snd_kcontrol *kcontrol, 365998274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3660763f356cSTakashi Iwai { 366198274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3662763f356cSTakashi Iwai int source; 3663763f356cSTakashi Iwai int destination; 3664763f356cSTakashi Iwai 3665763f356cSTakashi Iwai source = ucontrol->value.integer.value[0]; 3666763f356cSTakashi Iwai if (source < 0) 3667763f356cSTakashi Iwai source = 0; 3668763f356cSTakashi Iwai else if (source >= 2 * HDSPM_MAX_CHANNELS) 3669763f356cSTakashi Iwai source = 2 * HDSPM_MAX_CHANNELS - 1; 3670763f356cSTakashi Iwai 3671763f356cSTakashi Iwai destination = ucontrol->value.integer.value[1]; 3672763f356cSTakashi Iwai if (destination < 0) 3673763f356cSTakashi Iwai destination = 0; 3674763f356cSTakashi Iwai else if (destination >= HDSPM_MAX_CHANNELS) 3675763f356cSTakashi Iwai destination = HDSPM_MAX_CHANNELS - 1; 3676763f356cSTakashi Iwai 3677763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3678763f356cSTakashi Iwai if (source >= HDSPM_MAX_CHANNELS) 3679763f356cSTakashi Iwai ucontrol->value.integer.value[2] = 3680763f356cSTakashi Iwai hdspm_read_pb_gain(hdspm, destination, 3681763f356cSTakashi Iwai source - HDSPM_MAX_CHANNELS); 3682763f356cSTakashi Iwai else 3683763f356cSTakashi Iwai ucontrol->value.integer.value[2] = 3684763f356cSTakashi Iwai hdspm_read_in_gain(hdspm, destination, source); 3685763f356cSTakashi Iwai 3686763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3687763f356cSTakashi Iwai 3688763f356cSTakashi Iwai return 0; 3689763f356cSTakashi Iwai } 3690763f356cSTakashi Iwai 369198274f07STakashi Iwai static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol, 369298274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3693763f356cSTakashi Iwai { 369498274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3695763f356cSTakashi Iwai int change; 3696763f356cSTakashi Iwai int source; 3697763f356cSTakashi Iwai int destination; 3698763f356cSTakashi Iwai int gain; 3699763f356cSTakashi Iwai 3700763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 3701763f356cSTakashi Iwai return -EBUSY; 3702763f356cSTakashi Iwai 3703763f356cSTakashi Iwai source = ucontrol->value.integer.value[0]; 3704763f356cSTakashi Iwai destination = ucontrol->value.integer.value[1]; 3705763f356cSTakashi Iwai 3706763f356cSTakashi Iwai if (source < 0 || source >= 2 * HDSPM_MAX_CHANNELS) 3707763f356cSTakashi Iwai return -1; 3708763f356cSTakashi Iwai if (destination < 0 || destination >= HDSPM_MAX_CHANNELS) 3709763f356cSTakashi Iwai return -1; 3710763f356cSTakashi Iwai 3711763f356cSTakashi Iwai gain = ucontrol->value.integer.value[2]; 3712763f356cSTakashi Iwai 3713763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3714763f356cSTakashi Iwai 3715763f356cSTakashi Iwai if (source >= HDSPM_MAX_CHANNELS) 3716763f356cSTakashi Iwai change = gain != hdspm_read_pb_gain(hdspm, destination, 3717763f356cSTakashi Iwai source - 3718763f356cSTakashi Iwai HDSPM_MAX_CHANNELS); 3719763f356cSTakashi Iwai else 3720ef5fa1a4STakashi Iwai change = gain != hdspm_read_in_gain(hdspm, destination, 3721ef5fa1a4STakashi Iwai source); 3722763f356cSTakashi Iwai 3723763f356cSTakashi Iwai if (change) { 3724763f356cSTakashi Iwai if (source >= HDSPM_MAX_CHANNELS) 3725763f356cSTakashi Iwai hdspm_write_pb_gain(hdspm, destination, 3726763f356cSTakashi Iwai source - HDSPM_MAX_CHANNELS, 3727763f356cSTakashi Iwai gain); 3728763f356cSTakashi Iwai else 3729763f356cSTakashi Iwai hdspm_write_in_gain(hdspm, destination, source, 3730763f356cSTakashi Iwai gain); 3731763f356cSTakashi Iwai } 3732763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3733763f356cSTakashi Iwai 3734763f356cSTakashi Iwai return change; 3735763f356cSTakashi Iwai } 3736763f356cSTakashi Iwai 3737763f356cSTakashi Iwai /* The simple mixer control(s) provide gain control for the 3738763f356cSTakashi Iwai basic 1:1 mappings of playback streams to output 3739763f356cSTakashi Iwai streams. 3740763f356cSTakashi Iwai */ 3741763f356cSTakashi Iwai 3742763f356cSTakashi Iwai #define HDSPM_PLAYBACK_MIXER \ 3743763f356cSTakashi Iwai { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3744763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ 3745763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 3746763f356cSTakashi Iwai .info = snd_hdspm_info_playback_mixer, \ 3747763f356cSTakashi Iwai .get = snd_hdspm_get_playback_mixer, \ 3748763f356cSTakashi Iwai .put = snd_hdspm_put_playback_mixer \ 3749763f356cSTakashi Iwai } 3750763f356cSTakashi Iwai 375198274f07STakashi Iwai static int snd_hdspm_info_playback_mixer(struct snd_kcontrol *kcontrol, 375298274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 3753763f356cSTakashi Iwai { 3754763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 3755763f356cSTakashi Iwai uinfo->count = 1; 3756763f356cSTakashi Iwai uinfo->value.integer.min = 0; 37570dca1793SAdrian Knoth uinfo->value.integer.max = 64; 3758763f356cSTakashi Iwai uinfo->value.integer.step = 1; 3759763f356cSTakashi Iwai return 0; 3760763f356cSTakashi Iwai } 3761763f356cSTakashi Iwai 376298274f07STakashi Iwai static int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol, 376398274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3764763f356cSTakashi Iwai { 376598274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3766763f356cSTakashi Iwai int channel; 3767763f356cSTakashi Iwai 3768763f356cSTakashi Iwai channel = ucontrol->id.index - 1; 3769763f356cSTakashi Iwai 3770da3cec35STakashi Iwai if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS)) 3771da3cec35STakashi Iwai return -EINVAL; 3772763f356cSTakashi Iwai 3773763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3774763f356cSTakashi Iwai ucontrol->value.integer.value[0] = 37750dca1793SAdrian Knoth (hdspm_read_pb_gain(hdspm, channel, channel)*64)/UNITY_GAIN; 3776763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3777763f356cSTakashi Iwai 3778763f356cSTakashi Iwai return 0; 3779763f356cSTakashi Iwai } 3780763f356cSTakashi Iwai 378198274f07STakashi Iwai static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, 378298274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3783763f356cSTakashi Iwai { 378498274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3785763f356cSTakashi Iwai int change; 3786763f356cSTakashi Iwai int channel; 3787763f356cSTakashi Iwai int gain; 3788763f356cSTakashi Iwai 3789763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 3790763f356cSTakashi Iwai return -EBUSY; 3791763f356cSTakashi Iwai 3792763f356cSTakashi Iwai channel = ucontrol->id.index - 1; 3793763f356cSTakashi Iwai 3794da3cec35STakashi Iwai if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS)) 3795da3cec35STakashi Iwai return -EINVAL; 3796763f356cSTakashi Iwai 37970dca1793SAdrian Knoth gain = ucontrol->value.integer.value[0]*UNITY_GAIN/64; 3798763f356cSTakashi Iwai 3799763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3800763f356cSTakashi Iwai change = 38010dca1793SAdrian Knoth gain != hdspm_read_pb_gain(hdspm, channel, 38020dca1793SAdrian Knoth channel); 3803763f356cSTakashi Iwai if (change) 38040dca1793SAdrian Knoth hdspm_write_pb_gain(hdspm, channel, channel, 3805763f356cSTakashi Iwai gain); 3806763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3807763f356cSTakashi Iwai return change; 3808763f356cSTakashi Iwai } 3809763f356cSTakashi Iwai 38100dca1793SAdrian Knoth #define HDSPM_SYNC_CHECK(xname, xindex) \ 381167ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3812763f356cSTakashi Iwai .name = xname, \ 38130dca1793SAdrian Knoth .private_value = xindex, \ 3814763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 3815763f356cSTakashi Iwai .info = snd_hdspm_info_sync_check, \ 38160dca1793SAdrian Knoth .get = snd_hdspm_get_sync_check \ 3817763f356cSTakashi Iwai } 3818763f356cSTakashi Iwai 381934542213SAdrian Knoth #define HDSPM_TCO_LOCK_CHECK(xname, xindex) \ 382034542213SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 382134542213SAdrian Knoth .name = xname, \ 382234542213SAdrian Knoth .private_value = xindex, \ 382334542213SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 382434542213SAdrian Knoth .info = snd_hdspm_tco_info_lock_check, \ 382534542213SAdrian Knoth .get = snd_hdspm_get_sync_check \ 382634542213SAdrian Knoth } 382734542213SAdrian Knoth 382834542213SAdrian Knoth 38290dca1793SAdrian Knoth 383098274f07STakashi Iwai static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, 383198274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 3832763f356cSTakashi Iwai { 383338816545SAdrian Knoth static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" }; 3834e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 3835763f356cSTakashi Iwai return 0; 3836763f356cSTakashi Iwai } 3837763f356cSTakashi Iwai 383834542213SAdrian Knoth static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol, 383934542213SAdrian Knoth struct snd_ctl_elem_info *uinfo) 384034542213SAdrian Knoth { 384138816545SAdrian Knoth static const char *const texts[] = { "No Lock", "Lock" }; 384234542213SAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 384334542213SAdrian Knoth return 0; 384434542213SAdrian Knoth } 384534542213SAdrian Knoth 384698274f07STakashi Iwai static int hdspm_wc_sync_check(struct hdspm *hdspm) 3847763f356cSTakashi Iwai { 38480dca1793SAdrian Knoth int status, status2; 38490dca1793SAdrian Knoth 38500dca1793SAdrian Knoth switch (hdspm->io_type) { 38510dca1793SAdrian Knoth case AES32: 38520dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 385356bde0f3SAndre Schramm if (status & HDSPM_AES32_wcLock) { 385456bde0f3SAndre Schramm if (status & HDSPM_AES32_wcSync) 38553cee5a60SRemy Bruno return 2; 385656bde0f3SAndre Schramm else 38570dca1793SAdrian Knoth return 1; 385856bde0f3SAndre Schramm } 38593cee5a60SRemy Bruno return 0; 38600dca1793SAdrian Knoth break; 38610dca1793SAdrian Knoth 38620dca1793SAdrian Knoth case MADI: 38630dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 3864763f356cSTakashi Iwai if (status2 & HDSPM_wcLock) { 3865763f356cSTakashi Iwai if (status2 & HDSPM_wcSync) 3866763f356cSTakashi Iwai return 2; 3867763f356cSTakashi Iwai else 3868763f356cSTakashi Iwai return 1; 3869763f356cSTakashi Iwai } 3870763f356cSTakashi Iwai return 0; 38710dca1793SAdrian Knoth break; 3872763f356cSTakashi Iwai 38730dca1793SAdrian Knoth case RayDAT: 38740dca1793SAdrian Knoth case AIO: 38750dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 3876763f356cSTakashi Iwai 38770dca1793SAdrian Knoth if (status & 0x2000000) 38780dca1793SAdrian Knoth return 2; 38790dca1793SAdrian Knoth else if (status & 0x1000000) 38800dca1793SAdrian Knoth return 1; 3881763f356cSTakashi Iwai return 0; 38820dca1793SAdrian Knoth 38830dca1793SAdrian Knoth break; 38840dca1793SAdrian Knoth 38850dca1793SAdrian Knoth case MADIface: 38860dca1793SAdrian Knoth break; 3887763f356cSTakashi Iwai } 3888763f356cSTakashi Iwai 3889763f356cSTakashi Iwai 38900dca1793SAdrian Knoth return 3; 3891763f356cSTakashi Iwai } 3892763f356cSTakashi Iwai 38930dca1793SAdrian Knoth 38940dca1793SAdrian Knoth static int hdspm_madi_sync_check(struct hdspm *hdspm) 3895763f356cSTakashi Iwai { 3896763f356cSTakashi Iwai int status = hdspm_read(hdspm, HDSPM_statusRegister); 3897763f356cSTakashi Iwai if (status & HDSPM_madiLock) { 3898763f356cSTakashi Iwai if (status & HDSPM_madiSync) 3899763f356cSTakashi Iwai return 2; 3900763f356cSTakashi Iwai else 3901763f356cSTakashi Iwai return 1; 3902763f356cSTakashi Iwai } 3903763f356cSTakashi Iwai return 0; 3904763f356cSTakashi Iwai } 3905763f356cSTakashi Iwai 3906763f356cSTakashi Iwai 39070dca1793SAdrian Knoth static int hdspm_s1_sync_check(struct hdspm *hdspm, int idx) 39080dca1793SAdrian Knoth { 39090dca1793SAdrian Knoth int status, lock, sync; 39100dca1793SAdrian Knoth 39110dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 39120dca1793SAdrian Knoth 39130dca1793SAdrian Knoth lock = (status & (0x1<<idx)) ? 1 : 0; 39140dca1793SAdrian Knoth sync = (status & (0x100<<idx)) ? 1 : 0; 39150dca1793SAdrian Knoth 39160dca1793SAdrian Knoth if (lock && sync) 39170dca1793SAdrian Knoth return 2; 39180dca1793SAdrian Knoth else if (lock) 39190dca1793SAdrian Knoth return 1; 3920763f356cSTakashi Iwai return 0; 3921763f356cSTakashi Iwai } 3922763f356cSTakashi Iwai 3923763f356cSTakashi Iwai 39240dca1793SAdrian Knoth static int hdspm_sync_in_sync_check(struct hdspm *hdspm) 39250dca1793SAdrian Knoth { 39260dca1793SAdrian Knoth int status, lock = 0, sync = 0; 39270dca1793SAdrian Knoth 39280dca1793SAdrian Knoth switch (hdspm->io_type) { 39290dca1793SAdrian Knoth case RayDAT: 39300dca1793SAdrian Knoth case AIO: 39310dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_3); 39320dca1793SAdrian Knoth lock = (status & 0x400) ? 1 : 0; 39330dca1793SAdrian Knoth sync = (status & 0x800) ? 1 : 0; 39340dca1793SAdrian Knoth break; 39350dca1793SAdrian Knoth 39360dca1793SAdrian Knoth case MADI: 39372e0452f5SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 39382e0452f5SAdrian Knoth lock = (status & HDSPM_syncInLock) ? 1 : 0; 39392e0452f5SAdrian Knoth sync = (status & HDSPM_syncInSync) ? 1 : 0; 39402e0452f5SAdrian Knoth break; 39412e0452f5SAdrian Knoth 39420dca1793SAdrian Knoth case AES32: 39430dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister2); 39449a215f47SAdrian Knoth lock = (status & 0x100000) ? 1 : 0; 39459a215f47SAdrian Knoth sync = (status & 0x200000) ? 1 : 0; 39460dca1793SAdrian Knoth break; 39470dca1793SAdrian Knoth 39480dca1793SAdrian Knoth case MADIface: 39490dca1793SAdrian Knoth break; 39500dca1793SAdrian Knoth } 39510dca1793SAdrian Knoth 39520dca1793SAdrian Knoth if (lock && sync) 39530dca1793SAdrian Knoth return 2; 39540dca1793SAdrian Knoth else if (lock) 39550dca1793SAdrian Knoth return 1; 39560dca1793SAdrian Knoth 39570dca1793SAdrian Knoth return 0; 39583cee5a60SRemy Bruno } 39593cee5a60SRemy Bruno 39603cee5a60SRemy Bruno static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx) 39613cee5a60SRemy Bruno { 39620dca1793SAdrian Knoth int status2, lock, sync; 39630dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 39640dca1793SAdrian Knoth 39650dca1793SAdrian Knoth lock = (status2 & (0x0080 >> idx)) ? 1 : 0; 39660dca1793SAdrian Knoth sync = (status2 & (0x8000 >> idx)) ? 1 : 0; 39670dca1793SAdrian Knoth 39680dca1793SAdrian Knoth if (sync) 39693cee5a60SRemy Bruno return 2; 39700dca1793SAdrian Knoth else if (lock) 39710dca1793SAdrian Knoth return 1; 39723cee5a60SRemy Bruno return 0; 39733cee5a60SRemy Bruno } 39743cee5a60SRemy Bruno 397534542213SAdrian Knoth static int hdspm_tco_input_check(struct hdspm *hdspm, u32 mask) 397634542213SAdrian Knoth { 397734542213SAdrian Knoth u32 status; 397834542213SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 397934542213SAdrian Knoth 398034542213SAdrian Knoth return (status & mask) ? 1 : 0; 398134542213SAdrian Knoth } 398234542213SAdrian Knoth 39830dca1793SAdrian Knoth 39840dca1793SAdrian Knoth static int hdspm_tco_sync_check(struct hdspm *hdspm) 39850dca1793SAdrian Knoth { 39860dca1793SAdrian Knoth int status; 39870dca1793SAdrian Knoth 39880dca1793SAdrian Knoth if (hdspm->tco) { 39890dca1793SAdrian Knoth switch (hdspm->io_type) { 39900dca1793SAdrian Knoth case MADI: 3991b0bf5504SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 3992b0bf5504SAdrian Knoth if (status & HDSPM_tcoLockMadi) { 3993b0bf5504SAdrian Knoth if (status & HDSPM_tcoSync) 3994b0bf5504SAdrian Knoth return 2; 3995b0bf5504SAdrian Knoth else 3996b0bf5504SAdrian Knoth return 1; 3997b0bf5504SAdrian Knoth } 3998b0bf5504SAdrian Knoth return 0; 3999b0bf5504SAdrian Knoth break; 40000dca1793SAdrian Knoth case AES32: 40010dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 4002b0bf5504SAdrian Knoth if (status & HDSPM_tcoLockAes) { 40030dca1793SAdrian Knoth if (status & HDSPM_tcoSync) 40040dca1793SAdrian Knoth return 2; 40050dca1793SAdrian Knoth else 40060dca1793SAdrian Knoth return 1; 40070dca1793SAdrian Knoth } 40080dca1793SAdrian Knoth return 0; 40090dca1793SAdrian Knoth 40100dca1793SAdrian Knoth break; 40110dca1793SAdrian Knoth 40120dca1793SAdrian Knoth case RayDAT: 40130dca1793SAdrian Knoth case AIO: 40140dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 40150dca1793SAdrian Knoth 40160dca1793SAdrian Knoth if (status & 0x8000000) 40170dca1793SAdrian Knoth return 2; /* Sync */ 40180dca1793SAdrian Knoth if (status & 0x4000000) 40190dca1793SAdrian Knoth return 1; /* Lock */ 40200dca1793SAdrian Knoth return 0; /* No signal */ 40210dca1793SAdrian Knoth break; 40220dca1793SAdrian Knoth 40230dca1793SAdrian Knoth default: 40240dca1793SAdrian Knoth break; 40250dca1793SAdrian Knoth } 40260dca1793SAdrian Knoth } 40270dca1793SAdrian Knoth 40280dca1793SAdrian Knoth return 3; /* N/A */ 40290dca1793SAdrian Knoth } 40300dca1793SAdrian Knoth 40310dca1793SAdrian Knoth 40320dca1793SAdrian Knoth static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, 40333cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 40343cee5a60SRemy Bruno { 40353cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 40360dca1793SAdrian Knoth int val = -1; 40373cee5a60SRemy Bruno 40380dca1793SAdrian Knoth switch (hdspm->io_type) { 40390dca1793SAdrian Knoth case RayDAT: 40400dca1793SAdrian Knoth switch (kcontrol->private_value) { 40410dca1793SAdrian Knoth case 0: /* WC */ 40420dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break; 40430dca1793SAdrian Knoth case 7: /* TCO */ 40440dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break; 40450dca1793SAdrian Knoth case 8: /* SYNC IN */ 40460dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break; 40470dca1793SAdrian Knoth default: 4048d1a3c98dSAdrian Knoth val = hdspm_s1_sync_check(hdspm, 4049d1a3c98dSAdrian Knoth kcontrol->private_value-1); 40500dca1793SAdrian Knoth } 4051fba30fd3SAdrian Knoth break; 40523cee5a60SRemy Bruno 40530dca1793SAdrian Knoth case AIO: 40540dca1793SAdrian Knoth switch (kcontrol->private_value) { 40550dca1793SAdrian Knoth case 0: /* WC */ 40560dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break; 40570dca1793SAdrian Knoth case 4: /* TCO */ 40580dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break; 40590dca1793SAdrian Knoth case 5: /* SYNC IN */ 40600dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break; 40610dca1793SAdrian Knoth default: 40621cb7dbf4SAdrian Knoth val = hdspm_s1_sync_check(hdspm, 40631cb7dbf4SAdrian Knoth kcontrol->private_value-1); 40640dca1793SAdrian Knoth } 4065fba30fd3SAdrian Knoth break; 40660dca1793SAdrian Knoth 40670dca1793SAdrian Knoth case MADI: 40680dca1793SAdrian Knoth switch (kcontrol->private_value) { 40690dca1793SAdrian Knoth case 0: /* WC */ 40700dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break; 40710dca1793SAdrian Knoth case 1: /* MADI */ 40720dca1793SAdrian Knoth val = hdspm_madi_sync_check(hdspm); break; 40730dca1793SAdrian Knoth case 2: /* TCO */ 40740dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break; 40750dca1793SAdrian Knoth case 3: /* SYNC_IN */ 40760dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break; 40770dca1793SAdrian Knoth } 4078fba30fd3SAdrian Knoth break; 40790dca1793SAdrian Knoth 40800dca1793SAdrian Knoth case MADIface: 40810dca1793SAdrian Knoth val = hdspm_madi_sync_check(hdspm); /* MADI */ 40820dca1793SAdrian Knoth break; 40830dca1793SAdrian Knoth 40840dca1793SAdrian Knoth case AES32: 40850dca1793SAdrian Knoth switch (kcontrol->private_value) { 40860dca1793SAdrian Knoth case 0: /* WC */ 40870dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break; 40880dca1793SAdrian Knoth case 9: /* TCO */ 40890dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break; 40900dca1793SAdrian Knoth case 10 /* SYNC IN */: 40910dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break; 40927c4a95b5SAdrian Knoth default: /* AES1 to AES8 */ 40930dca1793SAdrian Knoth val = hdspm_aes_sync_check(hdspm, 40947c4a95b5SAdrian Knoth kcontrol->private_value-1); 40950dca1793SAdrian Knoth } 4096fba30fd3SAdrian Knoth break; 40970dca1793SAdrian Knoth 40980dca1793SAdrian Knoth } 40990dca1793SAdrian Knoth 410034542213SAdrian Knoth if (hdspm->tco) { 410134542213SAdrian Knoth switch (kcontrol->private_value) { 410234542213SAdrian Knoth case 11: 410334542213SAdrian Knoth /* Check TCO for lock state of its current input */ 410434542213SAdrian Knoth val = hdspm_tco_input_check(hdspm, HDSPM_TCO1_TCO_lock); 410534542213SAdrian Knoth break; 410634542213SAdrian Knoth case 12: 410734542213SAdrian Knoth /* Check TCO for valid time code on LTC input. */ 410834542213SAdrian Knoth val = hdspm_tco_input_check(hdspm, 410934542213SAdrian Knoth HDSPM_TCO1_LTC_Input_valid); 411034542213SAdrian Knoth break; 411134542213SAdrian Knoth default: 411234542213SAdrian Knoth break; 411334542213SAdrian Knoth } 411434542213SAdrian Knoth } 411534542213SAdrian Knoth 41160dca1793SAdrian Knoth if (-1 == val) 41170dca1793SAdrian Knoth val = 3; 41180dca1793SAdrian Knoth 41190dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = val; 41203cee5a60SRemy Bruno return 0; 41213cee5a60SRemy Bruno } 4122763f356cSTakashi Iwai 4123763f356cSTakashi Iwai 41240dca1793SAdrian Knoth 41250dca1793SAdrian Knoth /** 41260dca1793SAdrian Knoth * TCO controls 41270dca1793SAdrian Knoth **/ 41280dca1793SAdrian Knoth static void hdspm_tco_write(struct hdspm *hdspm) 41290dca1793SAdrian Knoth { 41300dca1793SAdrian Knoth unsigned int tc[4] = { 0, 0, 0, 0}; 41310dca1793SAdrian Knoth 41320dca1793SAdrian Knoth switch (hdspm->tco->input) { 41330dca1793SAdrian Knoth case 0: 41340dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_input_MSB; 41350dca1793SAdrian Knoth break; 41360dca1793SAdrian Knoth case 1: 41370dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_input_LSB; 41380dca1793SAdrian Knoth break; 41390dca1793SAdrian Knoth default: 41400dca1793SAdrian Knoth break; 41410dca1793SAdrian Knoth } 41420dca1793SAdrian Knoth 41430dca1793SAdrian Knoth switch (hdspm->tco->framerate) { 41440dca1793SAdrian Knoth case 1: 41450dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_LSB; 41460dca1793SAdrian Knoth break; 41470dca1793SAdrian Knoth case 2: 41480dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_MSB; 41490dca1793SAdrian Knoth break; 41500dca1793SAdrian Knoth case 3: 41510dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_MSB + 41520dca1793SAdrian Knoth HDSPM_TCO1_set_drop_frame_flag; 41530dca1793SAdrian Knoth break; 41540dca1793SAdrian Knoth case 4: 41550dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_LSB + 41560dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB; 41570dca1793SAdrian Knoth break; 41580dca1793SAdrian Knoth case 5: 41590dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_LSB + 41600dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB + 41610dca1793SAdrian Knoth HDSPM_TCO1_set_drop_frame_flag; 41620dca1793SAdrian Knoth break; 41630dca1793SAdrian Knoth default: 41640dca1793SAdrian Knoth break; 41650dca1793SAdrian Knoth } 41660dca1793SAdrian Knoth 41670dca1793SAdrian Knoth switch (hdspm->tco->wordclock) { 41680dca1793SAdrian Knoth case 1: 41690dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_WCK_IO_ratio_LSB; 41700dca1793SAdrian Knoth break; 41710dca1793SAdrian Knoth case 2: 41720dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_WCK_IO_ratio_MSB; 41730dca1793SAdrian Knoth break; 41740dca1793SAdrian Knoth default: 41750dca1793SAdrian Knoth break; 41760dca1793SAdrian Knoth } 41770dca1793SAdrian Knoth 41780dca1793SAdrian Knoth switch (hdspm->tco->samplerate) { 41790dca1793SAdrian Knoth case 1: 41800dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_freq; 41810dca1793SAdrian Knoth break; 41820dca1793SAdrian Knoth case 2: 41830dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_freq_from_app; 41840dca1793SAdrian Knoth break; 41850dca1793SAdrian Knoth default: 41860dca1793SAdrian Knoth break; 41870dca1793SAdrian Knoth } 41880dca1793SAdrian Knoth 41890dca1793SAdrian Knoth switch (hdspm->tco->pull) { 41900dca1793SAdrian Knoth case 1: 41910dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_up; 41920dca1793SAdrian Knoth break; 41930dca1793SAdrian Knoth case 2: 41940dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_down; 41950dca1793SAdrian Knoth break; 41960dca1793SAdrian Knoth case 3: 41970dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_up + HDSPM_TCO2_set_01_4; 41980dca1793SAdrian Knoth break; 41990dca1793SAdrian Knoth case 4: 42000dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_down + HDSPM_TCO2_set_01_4; 42010dca1793SAdrian Knoth break; 42020dca1793SAdrian Knoth default: 42030dca1793SAdrian Knoth break; 42040dca1793SAdrian Knoth } 42050dca1793SAdrian Knoth 42060dca1793SAdrian Knoth if (1 == hdspm->tco->term) { 42070dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_term_75R; 42080dca1793SAdrian Knoth } 42090dca1793SAdrian Knoth 42100dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO, tc[0]); 42110dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO+4, tc[1]); 42120dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO+8, tc[2]); 42130dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO+12, tc[3]); 42140dca1793SAdrian Knoth } 42150dca1793SAdrian Knoth 42160dca1793SAdrian Knoth 42170dca1793SAdrian Knoth #define HDSPM_TCO_SAMPLE_RATE(xname, xindex) \ 42180dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 42190dca1793SAdrian Knoth .name = xname, \ 42200dca1793SAdrian Knoth .index = xindex, \ 42210dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 42220dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 42230dca1793SAdrian Knoth .info = snd_hdspm_info_tco_sample_rate, \ 42240dca1793SAdrian Knoth .get = snd_hdspm_get_tco_sample_rate, \ 42250dca1793SAdrian Knoth .put = snd_hdspm_put_tco_sample_rate \ 42260dca1793SAdrian Knoth } 42270dca1793SAdrian Knoth 42280dca1793SAdrian Knoth static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, 42290dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 42300dca1793SAdrian Knoth { 4231*69358fcaSMartin Dausel /* TODO freq from app could be supported here, see tco->samplerate */ 423238816545SAdrian Knoth static const char *const texts[] = { "44.1 kHz", "48 kHz" }; 4233e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 42340dca1793SAdrian Knoth return 0; 42350dca1793SAdrian Knoth } 42360dca1793SAdrian Knoth 42370dca1793SAdrian Knoth static int snd_hdspm_get_tco_sample_rate(struct snd_kcontrol *kcontrol, 42380dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 42390dca1793SAdrian Knoth { 42400dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 42410dca1793SAdrian Knoth 42420dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->samplerate; 42430dca1793SAdrian Knoth 42440dca1793SAdrian Knoth return 0; 42450dca1793SAdrian Knoth } 42460dca1793SAdrian Knoth 42470dca1793SAdrian Knoth static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol, 42480dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 42490dca1793SAdrian Knoth { 42500dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 42510dca1793SAdrian Knoth 42520dca1793SAdrian Knoth if (hdspm->tco->samplerate != ucontrol->value.enumerated.item[0]) { 42530dca1793SAdrian Knoth hdspm->tco->samplerate = ucontrol->value.enumerated.item[0]; 42540dca1793SAdrian Knoth 42550dca1793SAdrian Knoth hdspm_tco_write(hdspm); 42560dca1793SAdrian Knoth 42570dca1793SAdrian Knoth return 1; 42580dca1793SAdrian Knoth } 42590dca1793SAdrian Knoth 42600dca1793SAdrian Knoth return 0; 42610dca1793SAdrian Knoth } 42620dca1793SAdrian Knoth 42630dca1793SAdrian Knoth 42640dca1793SAdrian Knoth #define HDSPM_TCO_PULL(xname, xindex) \ 42650dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 42660dca1793SAdrian Knoth .name = xname, \ 42670dca1793SAdrian Knoth .index = xindex, \ 42680dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 42690dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 42700dca1793SAdrian Knoth .info = snd_hdspm_info_tco_pull, \ 42710dca1793SAdrian Knoth .get = snd_hdspm_get_tco_pull, \ 42720dca1793SAdrian Knoth .put = snd_hdspm_put_tco_pull \ 42730dca1793SAdrian Knoth } 42740dca1793SAdrian Knoth 42750dca1793SAdrian Knoth static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, 42760dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 42770dca1793SAdrian Knoth { 427838816545SAdrian Knoth static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %", 427938816545SAdrian Knoth "+ 4 %", "- 4 %" }; 4280e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 42810dca1793SAdrian Knoth return 0; 42820dca1793SAdrian Knoth } 42830dca1793SAdrian Knoth 42840dca1793SAdrian Knoth static int snd_hdspm_get_tco_pull(struct snd_kcontrol *kcontrol, 42850dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 42860dca1793SAdrian Knoth { 42870dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 42880dca1793SAdrian Knoth 42890dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->pull; 42900dca1793SAdrian Knoth 42910dca1793SAdrian Knoth return 0; 42920dca1793SAdrian Knoth } 42930dca1793SAdrian Knoth 42940dca1793SAdrian Knoth static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol, 42950dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 42960dca1793SAdrian Knoth { 42970dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 42980dca1793SAdrian Knoth 42990dca1793SAdrian Knoth if (hdspm->tco->pull != ucontrol->value.enumerated.item[0]) { 43000dca1793SAdrian Knoth hdspm->tco->pull = ucontrol->value.enumerated.item[0]; 43010dca1793SAdrian Knoth 43020dca1793SAdrian Knoth hdspm_tco_write(hdspm); 43030dca1793SAdrian Knoth 43040dca1793SAdrian Knoth return 1; 43050dca1793SAdrian Knoth } 43060dca1793SAdrian Knoth 43070dca1793SAdrian Knoth return 0; 43080dca1793SAdrian Knoth } 43090dca1793SAdrian Knoth 43100dca1793SAdrian Knoth #define HDSPM_TCO_WCK_CONVERSION(xname, xindex) \ 43110dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 43120dca1793SAdrian Knoth .name = xname, \ 43130dca1793SAdrian Knoth .index = xindex, \ 43140dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 43150dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 43160dca1793SAdrian Knoth .info = snd_hdspm_info_tco_wck_conversion, \ 43170dca1793SAdrian Knoth .get = snd_hdspm_get_tco_wck_conversion, \ 43180dca1793SAdrian Knoth .put = snd_hdspm_put_tco_wck_conversion \ 43190dca1793SAdrian Knoth } 43200dca1793SAdrian Knoth 43210dca1793SAdrian Knoth static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, 43220dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 43230dca1793SAdrian Knoth { 432438816545SAdrian Knoth static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; 4325e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 43260dca1793SAdrian Knoth return 0; 43270dca1793SAdrian Knoth } 43280dca1793SAdrian Knoth 43290dca1793SAdrian Knoth static int snd_hdspm_get_tco_wck_conversion(struct snd_kcontrol *kcontrol, 43300dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 43310dca1793SAdrian Knoth { 43320dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 43330dca1793SAdrian Knoth 43340dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->wordclock; 43350dca1793SAdrian Knoth 43360dca1793SAdrian Knoth return 0; 43370dca1793SAdrian Knoth } 43380dca1793SAdrian Knoth 43390dca1793SAdrian Knoth static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol, 43400dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 43410dca1793SAdrian Knoth { 43420dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 43430dca1793SAdrian Knoth 43440dca1793SAdrian Knoth if (hdspm->tco->wordclock != ucontrol->value.enumerated.item[0]) { 43450dca1793SAdrian Knoth hdspm->tco->wordclock = ucontrol->value.enumerated.item[0]; 43460dca1793SAdrian Knoth 43470dca1793SAdrian Knoth hdspm_tco_write(hdspm); 43480dca1793SAdrian Knoth 43490dca1793SAdrian Knoth return 1; 43500dca1793SAdrian Knoth } 43510dca1793SAdrian Knoth 43520dca1793SAdrian Knoth return 0; 43530dca1793SAdrian Knoth } 43540dca1793SAdrian Knoth 43550dca1793SAdrian Knoth 43560dca1793SAdrian Knoth #define HDSPM_TCO_FRAME_RATE(xname, xindex) \ 43570dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 43580dca1793SAdrian Knoth .name = xname, \ 43590dca1793SAdrian Knoth .index = xindex, \ 43600dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 43610dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 43620dca1793SAdrian Knoth .info = snd_hdspm_info_tco_frame_rate, \ 43630dca1793SAdrian Knoth .get = snd_hdspm_get_tco_frame_rate, \ 43640dca1793SAdrian Knoth .put = snd_hdspm_put_tco_frame_rate \ 43650dca1793SAdrian Knoth } 43660dca1793SAdrian Knoth 43670dca1793SAdrian Knoth static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, 43680dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 43690dca1793SAdrian Knoth { 437038816545SAdrian Knoth static const char *const texts[] = { "24 fps", "25 fps", "29.97fps", 43710dca1793SAdrian Knoth "29.97 dfps", "30 fps", "30 dfps" }; 4372e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 43730dca1793SAdrian Knoth return 0; 43740dca1793SAdrian Knoth } 43750dca1793SAdrian Knoth 43760dca1793SAdrian Knoth static int snd_hdspm_get_tco_frame_rate(struct snd_kcontrol *kcontrol, 43770dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 43780dca1793SAdrian Knoth { 43790dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 43800dca1793SAdrian Knoth 43810dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->framerate; 43820dca1793SAdrian Knoth 43830dca1793SAdrian Knoth return 0; 43840dca1793SAdrian Knoth } 43850dca1793SAdrian Knoth 43860dca1793SAdrian Knoth static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol, 43870dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 43880dca1793SAdrian Knoth { 43890dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 43900dca1793SAdrian Knoth 43910dca1793SAdrian Knoth if (hdspm->tco->framerate != ucontrol->value.enumerated.item[0]) { 43920dca1793SAdrian Knoth hdspm->tco->framerate = ucontrol->value.enumerated.item[0]; 43930dca1793SAdrian Knoth 43940dca1793SAdrian Knoth hdspm_tco_write(hdspm); 43950dca1793SAdrian Knoth 43960dca1793SAdrian Knoth return 1; 43970dca1793SAdrian Knoth } 43980dca1793SAdrian Knoth 43990dca1793SAdrian Knoth return 0; 44000dca1793SAdrian Knoth } 44010dca1793SAdrian Knoth 44020dca1793SAdrian Knoth 44030dca1793SAdrian Knoth #define HDSPM_TCO_SYNC_SOURCE(xname, xindex) \ 44040dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 44050dca1793SAdrian Knoth .name = xname, \ 44060dca1793SAdrian Knoth .index = xindex, \ 44070dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 44080dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 44090dca1793SAdrian Knoth .info = snd_hdspm_info_tco_sync_source, \ 44100dca1793SAdrian Knoth .get = snd_hdspm_get_tco_sync_source, \ 44110dca1793SAdrian Knoth .put = snd_hdspm_put_tco_sync_source \ 44120dca1793SAdrian Knoth } 44130dca1793SAdrian Knoth 44140dca1793SAdrian Knoth static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, 44150dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 44160dca1793SAdrian Knoth { 441738816545SAdrian Knoth static const char *const texts[] = { "LTC", "Video", "WCK" }; 4418e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts); 44190dca1793SAdrian Knoth return 0; 44200dca1793SAdrian Knoth } 44210dca1793SAdrian Knoth 44220dca1793SAdrian Knoth static int snd_hdspm_get_tco_sync_source(struct snd_kcontrol *kcontrol, 44230dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 44240dca1793SAdrian Knoth { 44250dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 44260dca1793SAdrian Knoth 44270dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->input; 44280dca1793SAdrian Knoth 44290dca1793SAdrian Knoth return 0; 44300dca1793SAdrian Knoth } 44310dca1793SAdrian Knoth 44320dca1793SAdrian Knoth static int snd_hdspm_put_tco_sync_source(struct snd_kcontrol *kcontrol, 44330dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 44340dca1793SAdrian Knoth { 44350dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 44360dca1793SAdrian Knoth 44370dca1793SAdrian Knoth if (hdspm->tco->input != ucontrol->value.enumerated.item[0]) { 44380dca1793SAdrian Knoth hdspm->tco->input = ucontrol->value.enumerated.item[0]; 44390dca1793SAdrian Knoth 44400dca1793SAdrian Knoth hdspm_tco_write(hdspm); 44410dca1793SAdrian Knoth 44420dca1793SAdrian Knoth return 1; 44430dca1793SAdrian Knoth } 44440dca1793SAdrian Knoth 44450dca1793SAdrian Knoth return 0; 44460dca1793SAdrian Knoth } 44470dca1793SAdrian Knoth 44480dca1793SAdrian Knoth 44490dca1793SAdrian Knoth #define HDSPM_TCO_WORD_TERM(xname, xindex) \ 44500dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 44510dca1793SAdrian Knoth .name = xname, \ 44520dca1793SAdrian Knoth .index = xindex, \ 44530dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 44540dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 44550dca1793SAdrian Knoth .info = snd_hdspm_info_tco_word_term, \ 44560dca1793SAdrian Knoth .get = snd_hdspm_get_tco_word_term, \ 44570dca1793SAdrian Knoth .put = snd_hdspm_put_tco_word_term \ 44580dca1793SAdrian Knoth } 44590dca1793SAdrian Knoth 44600dca1793SAdrian Knoth static int snd_hdspm_info_tco_word_term(struct snd_kcontrol *kcontrol, 44610dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 44620dca1793SAdrian Knoth { 44630dca1793SAdrian Knoth uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 44640dca1793SAdrian Knoth uinfo->count = 1; 44650dca1793SAdrian Knoth uinfo->value.integer.min = 0; 44660dca1793SAdrian Knoth uinfo->value.integer.max = 1; 44670dca1793SAdrian Knoth 44680dca1793SAdrian Knoth return 0; 44690dca1793SAdrian Knoth } 44700dca1793SAdrian Knoth 44710dca1793SAdrian Knoth 44720dca1793SAdrian Knoth static int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol, 44730dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 44740dca1793SAdrian Knoth { 44750dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 44760dca1793SAdrian Knoth 44770dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->term; 44780dca1793SAdrian Knoth 44790dca1793SAdrian Knoth return 0; 44800dca1793SAdrian Knoth } 44810dca1793SAdrian Knoth 44820dca1793SAdrian Knoth 44830dca1793SAdrian Knoth static int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol, 44840dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 44850dca1793SAdrian Knoth { 44860dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 44870dca1793SAdrian Knoth 44880dca1793SAdrian Knoth if (hdspm->tco->term != ucontrol->value.enumerated.item[0]) { 44890dca1793SAdrian Knoth hdspm->tco->term = ucontrol->value.enumerated.item[0]; 44900dca1793SAdrian Knoth 44910dca1793SAdrian Knoth hdspm_tco_write(hdspm); 44920dca1793SAdrian Knoth 44930dca1793SAdrian Knoth return 1; 44940dca1793SAdrian Knoth } 44950dca1793SAdrian Knoth 44960dca1793SAdrian Knoth return 0; 44970dca1793SAdrian Knoth } 44980dca1793SAdrian Knoth 44990dca1793SAdrian Knoth 45000dca1793SAdrian Knoth 45010dca1793SAdrian Knoth 45023cee5a60SRemy Bruno static struct snd_kcontrol_new snd_hdspm_controls_madi[] = { 4503763f356cSTakashi Iwai HDSPM_MIXER("Mixer", 0), 45040dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 4505763f356cSTakashi Iwai HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 4506763f356cSTakashi Iwai HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 4507763f356cSTakashi Iwai HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), 4508763f356cSTakashi Iwai HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 4509b8812c55SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 45100dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC SyncCheck", 0), 45110dca1793SAdrian Knoth HDSPM_SYNC_CHECK("MADI SyncCheck", 1), 4512930f4ff0SAdrian Knoth HDSPM_SYNC_CHECK("TCO SyncCheck", 2), 45130dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3), 4514c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut), 4515c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch), 4516696be0fbSAdrian Knoth HDSPM_TOGGLE_SETTING("Disable 96K frames", HDSPM_SMUX), 4517c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), 4518c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp), 4519700d1ef3SAdrian Knoth HDSPM_INPUT_SELECT("Input Select", 0), 4520700d1ef3SAdrian Knoth HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) 45210dca1793SAdrian Knoth }; 45220dca1793SAdrian Knoth 45230dca1793SAdrian Knoth 45240dca1793SAdrian Knoth static struct snd_kcontrol_new snd_hdspm_controls_madiface[] = { 45250dca1793SAdrian Knoth HDSPM_MIXER("Mixer", 0), 45260dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 45270dca1793SAdrian Knoth HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 45280dca1793SAdrian Knoth HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 45290dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 45300dca1793SAdrian Knoth HDSPM_SYNC_CHECK("MADI SyncCheck", 0), 4531c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch), 4532c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), 4533c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp), 4534700d1ef3SAdrian Knoth HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) 4535763f356cSTakashi Iwai }; 4536763f356cSTakashi Iwai 45370dca1793SAdrian Knoth static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { 45383cee5a60SRemy Bruno HDSPM_MIXER("Mixer", 0), 45390dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 45403cee5a60SRemy Bruno HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 45413cee5a60SRemy Bruno HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 45423cee5a60SRemy Bruno HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 45433cee5a60SRemy Bruno HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 45440dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC SyncCheck", 0), 45450dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES SyncCheck", 1), 45460dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2), 45470dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT SyncCheck", 3), 45480dca1793SAdrian Knoth HDSPM_SYNC_CHECK("TCO SyncCheck", 4), 45490dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 5), 45500dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 45510dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1), 45520dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), 45530dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), 45540dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), 4555fb0f121eSAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5), 455642f4c12dSAdrian Knoth HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0), 4557fb0f121eSAdrian Knoth HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt), 4558fb0f121eSAdrian Knoth HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), 4559fb0f121eSAdrian Knoth HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1), 4560fb0f121eSAdrian Knoth HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db), 456142f4c12dSAdrian Knoth HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48), 456242f4c12dSAdrian Knoth HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0), 456342f4c12dSAdrian Knoth HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0), 456442f4c12dSAdrian Knoth HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0) 45650dca1793SAdrian Knoth 45660dca1793SAdrian Knoth /* 45670dca1793SAdrian Knoth HDSPM_INPUT_SELECT("Input Select", 0), 45680dca1793SAdrian Knoth HDSPM_SPDIF_OPTICAL("SPDIF Out Optical", 0), 45690dca1793SAdrian Knoth HDSPM_PROFESSIONAL("SPDIF Out Professional", 0); 45700dca1793SAdrian Knoth HDSPM_SPDIF_IN("SPDIF In", 0); 45710dca1793SAdrian Knoth HDSPM_BREAKOUT_CABLE("Breakout Cable", 0); 45720dca1793SAdrian Knoth HDSPM_INPUT_LEVEL("Input Level", 0); 45730dca1793SAdrian Knoth HDSPM_OUTPUT_LEVEL("Output Level", 0); 45740dca1793SAdrian Knoth HDSPM_PHONES("Phones", 0); 45750dca1793SAdrian Knoth */ 45760dca1793SAdrian Knoth }; 45770dca1793SAdrian Knoth 45780dca1793SAdrian Knoth static struct snd_kcontrol_new snd_hdspm_controls_raydat[] = { 45790dca1793SAdrian Knoth HDSPM_MIXER("Mixer", 0), 45800dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 45810dca1793SAdrian Knoth HDSPM_SYSTEM_CLOCK_MODE("Clock Mode", 0), 45820dca1793SAdrian Knoth HDSPM_PREF_SYNC_REF("Pref Sync Ref", 0), 45830dca1793SAdrian Knoth HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 45840dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC SyncCheck", 0), 45850dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES SyncCheck", 1), 45860dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2), 45870dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT1 SyncCheck", 3), 45880dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT2 SyncCheck", 4), 45890dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT3 SyncCheck", 5), 45900dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT4 SyncCheck", 6), 45910dca1793SAdrian Knoth HDSPM_SYNC_CHECK("TCO SyncCheck", 7), 45920dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 8), 45930dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 45940dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1), 45950dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), 45960dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT1 Frequency", 3), 45970dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT2 Frequency", 4), 45980dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5), 45990dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6), 46000dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7), 460111a5cd3cSAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8), 460211a5cd3cSAdrian Knoth HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), 460311a5cd3cSAdrian Knoth HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48) 46040dca1793SAdrian Knoth }; 46050dca1793SAdrian Knoth 46060dca1793SAdrian Knoth static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { 46070dca1793SAdrian Knoth HDSPM_MIXER("Mixer", 0), 46080dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 46090dca1793SAdrian Knoth HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 46100dca1793SAdrian Knoth HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 46110dca1793SAdrian Knoth HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), 46120dca1793SAdrian Knoth HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 46132d63ec38SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11), 46140dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC Sync Check", 0), 46150dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES1 Sync Check", 1), 46160dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES2 Sync Check", 2), 46170dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES3 Sync Check", 3), 46180dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES4 Sync Check", 4), 46190dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES5 Sync Check", 5), 46200dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES6 Sync Check", 6), 46210dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES7 Sync Check", 7), 46220dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES8 Sync Check", 8), 46230dca1793SAdrian Knoth HDSPM_SYNC_CHECK("TCO Sync Check", 9), 46240dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN Sync Check", 10), 46250dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 46260dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES1 Frequency", 1), 46270dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES2 Frequency", 2), 46280dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES3 Frequency", 3), 46290dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES4 Frequency", 4), 46300dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES5 Frequency", 5), 46310dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES6 Frequency", 6), 46320dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES7 Frequency", 7), 46330dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES8 Frequency", 8), 46340dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 9), 46350dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 10), 4636c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut), 4637c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Emphasis", HDSPM_Emphasis), 4638c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Non Audio", HDSPM_Dolby), 4639c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Professional", HDSPM_Professional), 4640c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), 46413cee5a60SRemy Bruno HDSPM_DS_WIRE("Double Speed Wire Mode", 0), 46423cee5a60SRemy Bruno HDSPM_QS_WIRE("Quad Speed Wire Mode", 0), 46433cee5a60SRemy Bruno }; 46443cee5a60SRemy Bruno 46450dca1793SAdrian Knoth 46460dca1793SAdrian Knoth 46470dca1793SAdrian Knoth /* Control elements for the optional TCO module */ 46480dca1793SAdrian Knoth static struct snd_kcontrol_new snd_hdspm_controls_tco[] = { 46490dca1793SAdrian Knoth HDSPM_TCO_SAMPLE_RATE("TCO Sample Rate", 0), 46500dca1793SAdrian Knoth HDSPM_TCO_PULL("TCO Pull", 0), 46510dca1793SAdrian Knoth HDSPM_TCO_WCK_CONVERSION("TCO WCK Conversion", 0), 46520dca1793SAdrian Knoth HDSPM_TCO_FRAME_RATE("TCO Frame Rate", 0), 46530dca1793SAdrian Knoth HDSPM_TCO_SYNC_SOURCE("TCO Sync Source", 0), 4654a817650eSAdrian Knoth HDSPM_TCO_WORD_TERM("TCO Word Term", 0), 4655a817650eSAdrian Knoth HDSPM_TCO_LOCK_CHECK("TCO Input Check", 11), 4656a817650eSAdrian Knoth HDSPM_TCO_LOCK_CHECK("TCO LTC Valid", 12), 4657a817650eSAdrian Knoth HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate", 0), 4658a817650eSAdrian Knoth HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format", 0) 46590dca1793SAdrian Knoth }; 46600dca1793SAdrian Knoth 46610dca1793SAdrian Knoth 466298274f07STakashi Iwai static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER; 4663763f356cSTakashi Iwai 4664763f356cSTakashi Iwai 466598274f07STakashi Iwai static int hdspm_update_simple_mixer_controls(struct hdspm * hdspm) 4666763f356cSTakashi Iwai { 4667763f356cSTakashi Iwai int i; 4668763f356cSTakashi Iwai 46690dca1793SAdrian Knoth for (i = hdspm->ds_out_channels; i < hdspm->ss_out_channels; ++i) { 4670763f356cSTakashi Iwai if (hdspm->system_sample_rate > 48000) { 4671763f356cSTakashi Iwai hdspm->playback_mixer_ctls[i]->vd[0].access = 4672763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_INACTIVE | 4673763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_READ | 4674763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE; 4675763f356cSTakashi Iwai } else { 4676763f356cSTakashi Iwai hdspm->playback_mixer_ctls[i]->vd[0].access = 4677763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_READWRITE | 4678763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE; 4679763f356cSTakashi Iwai } 4680763f356cSTakashi Iwai snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE | 4681763f356cSTakashi Iwai SNDRV_CTL_EVENT_MASK_INFO, 4682763f356cSTakashi Iwai &hdspm->playback_mixer_ctls[i]->id); 4683763f356cSTakashi Iwai } 4684763f356cSTakashi Iwai 4685763f356cSTakashi Iwai return 0; 4686763f356cSTakashi Iwai } 4687763f356cSTakashi Iwai 4688763f356cSTakashi Iwai 46890dca1793SAdrian Knoth static int snd_hdspm_create_controls(struct snd_card *card, 46900dca1793SAdrian Knoth struct hdspm *hdspm) 4691763f356cSTakashi Iwai { 4692763f356cSTakashi Iwai unsigned int idx, limit; 4693763f356cSTakashi Iwai int err; 469498274f07STakashi Iwai struct snd_kcontrol *kctl; 46950dca1793SAdrian Knoth struct snd_kcontrol_new *list = NULL; 4696763f356cSTakashi Iwai 46970dca1793SAdrian Knoth switch (hdspm->io_type) { 46980dca1793SAdrian Knoth case MADI: 46990dca1793SAdrian Knoth list = snd_hdspm_controls_madi; 47000dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_madi); 47010dca1793SAdrian Knoth break; 47020dca1793SAdrian Knoth case MADIface: 47030dca1793SAdrian Knoth list = snd_hdspm_controls_madiface; 47040dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_madiface); 47050dca1793SAdrian Knoth break; 47060dca1793SAdrian Knoth case AIO: 47070dca1793SAdrian Knoth list = snd_hdspm_controls_aio; 47080dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_aio); 47090dca1793SAdrian Knoth break; 47100dca1793SAdrian Knoth case RayDAT: 47110dca1793SAdrian Knoth list = snd_hdspm_controls_raydat; 47120dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_raydat); 47130dca1793SAdrian Knoth break; 47140dca1793SAdrian Knoth case AES32: 47150dca1793SAdrian Knoth list = snd_hdspm_controls_aes32; 47160dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_aes32); 47170dca1793SAdrian Knoth break; 47180dca1793SAdrian Knoth } 4719763f356cSTakashi Iwai 47200dca1793SAdrian Knoth if (NULL != list) { 47210dca1793SAdrian Knoth for (idx = 0; idx < limit; idx++) { 47223cee5a60SRemy Bruno err = snd_ctl_add(card, 47230dca1793SAdrian Knoth snd_ctl_new1(&list[idx], hdspm)); 47243cee5a60SRemy Bruno if (err < 0) 4725763f356cSTakashi Iwai return err; 4726763f356cSTakashi Iwai } 4727763f356cSTakashi Iwai } 4728763f356cSTakashi Iwai 4729763f356cSTakashi Iwai 47300dca1793SAdrian Knoth /* create simple 1:1 playback mixer controls */ 4731763f356cSTakashi Iwai snd_hdspm_playback_mixer.name = "Chn"; 47320dca1793SAdrian Knoth if (hdspm->system_sample_rate >= 128000) { 47330dca1793SAdrian Knoth limit = hdspm->qs_out_channels; 47340dca1793SAdrian Knoth } else if (hdspm->system_sample_rate >= 64000) { 47350dca1793SAdrian Knoth limit = hdspm->ds_out_channels; 47360dca1793SAdrian Knoth } else { 47370dca1793SAdrian Knoth limit = hdspm->ss_out_channels; 47380dca1793SAdrian Knoth } 4739763f356cSTakashi Iwai for (idx = 0; idx < limit; ++idx) { 4740763f356cSTakashi Iwai snd_hdspm_playback_mixer.index = idx + 1; 4741ef5fa1a4STakashi Iwai kctl = snd_ctl_new1(&snd_hdspm_playback_mixer, hdspm); 4742ef5fa1a4STakashi Iwai err = snd_ctl_add(card, kctl); 4743ef5fa1a4STakashi Iwai if (err < 0) 4744763f356cSTakashi Iwai return err; 4745763f356cSTakashi Iwai hdspm->playback_mixer_ctls[idx] = kctl; 4746763f356cSTakashi Iwai } 4747763f356cSTakashi Iwai 47480dca1793SAdrian Knoth 47490dca1793SAdrian Knoth if (hdspm->tco) { 47500dca1793SAdrian Knoth /* add tco control elements */ 47510dca1793SAdrian Knoth list = snd_hdspm_controls_tco; 47520dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_tco); 47530dca1793SAdrian Knoth for (idx = 0; idx < limit; idx++) { 47540dca1793SAdrian Knoth err = snd_ctl_add(card, 47550dca1793SAdrian Knoth snd_ctl_new1(&list[idx], hdspm)); 47560dca1793SAdrian Knoth if (err < 0) 47570dca1793SAdrian Knoth return err; 47580dca1793SAdrian Knoth } 47590dca1793SAdrian Knoth } 47600dca1793SAdrian Knoth 4761763f356cSTakashi Iwai return 0; 4762763f356cSTakashi Iwai } 4763763f356cSTakashi Iwai 4764763f356cSTakashi Iwai /*------------------------------------------------------------ 4765763f356cSTakashi Iwai /proc interface 4766763f356cSTakashi Iwai ------------------------------------------------------------*/ 4767763f356cSTakashi Iwai 4768763f356cSTakashi Iwai static void 47695760107cSAdrian Knoth snd_hdspm_proc_read_tco(struct snd_info_entry *entry, 47703cee5a60SRemy Bruno struct snd_info_buffer *buffer) 4771763f356cSTakashi Iwai { 4772ef5fa1a4STakashi Iwai struct hdspm *hdspm = entry->private_data; 47735760107cSAdrian Knoth unsigned int status, control; 47740dca1793SAdrian Knoth int a, ltc, frames, seconds, minutes, hours; 47750dca1793SAdrian Knoth unsigned int period; 47760dca1793SAdrian Knoth u64 freq_const = 0; 47770dca1793SAdrian Knoth u32 rate; 47780dca1793SAdrian Knoth 47795760107cSAdrian Knoth snd_iprintf(buffer, "--- TCO ---\n"); 47805760107cSAdrian Knoth 4781763f356cSTakashi Iwai status = hdspm_read(hdspm, HDSPM_statusRegister); 47820dca1793SAdrian Knoth control = hdspm->control_register; 4783763f356cSTakashi Iwai 4784763f356cSTakashi Iwai 47850dca1793SAdrian Knoth if (status & HDSPM_tco_detect) { 47860dca1793SAdrian Knoth snd_iprintf(buffer, "TCO module detected.\n"); 47870dca1793SAdrian Knoth a = hdspm_read(hdspm, HDSPM_RD_TCO+4); 47880dca1793SAdrian Knoth if (a & HDSPM_TCO1_LTC_Input_valid) { 47890dca1793SAdrian Knoth snd_iprintf(buffer, " LTC valid, "); 47900dca1793SAdrian Knoth switch (a & (HDSPM_TCO1_LTC_Format_LSB | 47910dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB)) { 47920dca1793SAdrian Knoth case 0: 47930dca1793SAdrian Knoth snd_iprintf(buffer, "24 fps, "); 47940dca1793SAdrian Knoth break; 47950dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_LSB: 47960dca1793SAdrian Knoth snd_iprintf(buffer, "25 fps, "); 47970dca1793SAdrian Knoth break; 47980dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_MSB: 47990dca1793SAdrian Knoth snd_iprintf(buffer, "29.97 fps, "); 48000dca1793SAdrian Knoth break; 48010dca1793SAdrian Knoth default: 48020dca1793SAdrian Knoth snd_iprintf(buffer, "30 fps, "); 48030dca1793SAdrian Knoth break; 48040dca1793SAdrian Knoth } 48050dca1793SAdrian Knoth if (a & HDSPM_TCO1_set_drop_frame_flag) { 48060dca1793SAdrian Knoth snd_iprintf(buffer, "drop frame\n"); 48070dca1793SAdrian Knoth } else { 48080dca1793SAdrian Knoth snd_iprintf(buffer, "full frame\n"); 48090dca1793SAdrian Knoth } 48100dca1793SAdrian Knoth } else { 48110dca1793SAdrian Knoth snd_iprintf(buffer, " no LTC\n"); 48120dca1793SAdrian Knoth } 48130dca1793SAdrian Knoth if (a & HDSPM_TCO1_Video_Input_Format_NTSC) { 48140dca1793SAdrian Knoth snd_iprintf(buffer, " Video: NTSC\n"); 48150dca1793SAdrian Knoth } else if (a & HDSPM_TCO1_Video_Input_Format_PAL) { 48160dca1793SAdrian Knoth snd_iprintf(buffer, " Video: PAL\n"); 48170dca1793SAdrian Knoth } else { 48180dca1793SAdrian Knoth snd_iprintf(buffer, " No video\n"); 48190dca1793SAdrian Knoth } 48200dca1793SAdrian Knoth if (a & HDSPM_TCO1_TCO_lock) { 48210dca1793SAdrian Knoth snd_iprintf(buffer, " Sync: lock\n"); 48220dca1793SAdrian Knoth } else { 48230dca1793SAdrian Knoth snd_iprintf(buffer, " Sync: no lock\n"); 48240dca1793SAdrian Knoth } 48250dca1793SAdrian Knoth 48260dca1793SAdrian Knoth switch (hdspm->io_type) { 48270dca1793SAdrian Knoth case MADI: 48280dca1793SAdrian Knoth case AES32: 48290dca1793SAdrian Knoth freq_const = 110069313433624ULL; 48300dca1793SAdrian Knoth break; 48310dca1793SAdrian Knoth case RayDAT: 48320dca1793SAdrian Knoth case AIO: 48330dca1793SAdrian Knoth freq_const = 104857600000000ULL; 48340dca1793SAdrian Knoth break; 48350dca1793SAdrian Knoth case MADIface: 48360dca1793SAdrian Knoth break; /* no TCO possible */ 48370dca1793SAdrian Knoth } 48380dca1793SAdrian Knoth 48390dca1793SAdrian Knoth period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 48400dca1793SAdrian Knoth snd_iprintf(buffer, " period: %u\n", period); 48410dca1793SAdrian Knoth 48420dca1793SAdrian Knoth 48430dca1793SAdrian Knoth /* rate = freq_const/period; */ 48440dca1793SAdrian Knoth rate = div_u64(freq_const, period); 48450dca1793SAdrian Knoth 48460dca1793SAdrian Knoth if (control & HDSPM_QuadSpeed) { 48470dca1793SAdrian Knoth rate *= 4; 48480dca1793SAdrian Knoth } else if (control & HDSPM_DoubleSpeed) { 48490dca1793SAdrian Knoth rate *= 2; 48500dca1793SAdrian Knoth } 48510dca1793SAdrian Knoth 48520dca1793SAdrian Knoth snd_iprintf(buffer, " Frequency: %u Hz\n", 48530dca1793SAdrian Knoth (unsigned int) rate); 48540dca1793SAdrian Knoth 48550dca1793SAdrian Knoth ltc = hdspm_read(hdspm, HDSPM_RD_TCO); 48560dca1793SAdrian Knoth frames = ltc & 0xF; 48570dca1793SAdrian Knoth ltc >>= 4; 48580dca1793SAdrian Knoth frames += (ltc & 0x3) * 10; 48590dca1793SAdrian Knoth ltc >>= 4; 48600dca1793SAdrian Knoth seconds = ltc & 0xF; 48610dca1793SAdrian Knoth ltc >>= 4; 48620dca1793SAdrian Knoth seconds += (ltc & 0x7) * 10; 48630dca1793SAdrian Knoth ltc >>= 4; 48640dca1793SAdrian Knoth minutes = ltc & 0xF; 48650dca1793SAdrian Knoth ltc >>= 4; 48660dca1793SAdrian Knoth minutes += (ltc & 0x7) * 10; 48670dca1793SAdrian Knoth ltc >>= 4; 48680dca1793SAdrian Knoth hours = ltc & 0xF; 48690dca1793SAdrian Knoth ltc >>= 4; 48700dca1793SAdrian Knoth hours += (ltc & 0x3) * 10; 48710dca1793SAdrian Knoth snd_iprintf(buffer, 48720dca1793SAdrian Knoth " LTC In: %02d:%02d:%02d:%02d\n", 48730dca1793SAdrian Knoth hours, minutes, seconds, frames); 48740dca1793SAdrian Knoth 48750dca1793SAdrian Knoth } else { 48760dca1793SAdrian Knoth snd_iprintf(buffer, "No TCO module detected.\n"); 48770dca1793SAdrian Knoth } 48785760107cSAdrian Knoth } 48795760107cSAdrian Knoth 48805760107cSAdrian Knoth static void 48815760107cSAdrian Knoth snd_hdspm_proc_read_madi(struct snd_info_entry *entry, 48825760107cSAdrian Knoth struct snd_info_buffer *buffer) 48835760107cSAdrian Knoth { 48845760107cSAdrian Knoth struct hdspm *hdspm = entry->private_data; 48855760107cSAdrian Knoth unsigned int status, status2, control, freq; 48865760107cSAdrian Knoth 48875760107cSAdrian Knoth char *pref_sync_ref; 48885760107cSAdrian Knoth char *autosync_ref; 48895760107cSAdrian Knoth char *system_clock_mode; 48905760107cSAdrian Knoth char *insel; 48915760107cSAdrian Knoth int x, x2; 48925760107cSAdrian Knoth 48935760107cSAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 48945760107cSAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 48955760107cSAdrian Knoth control = hdspm->control_register; 48965760107cSAdrian Knoth freq = hdspm_read(hdspm, HDSPM_timecodeRegister); 48975760107cSAdrian Knoth 48985760107cSAdrian Knoth snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", 48995760107cSAdrian Knoth hdspm->card_name, hdspm->card->number + 1, 49005760107cSAdrian Knoth hdspm->firmware_rev, 49015760107cSAdrian Knoth (status2 & HDSPM_version0) | 49025760107cSAdrian Knoth (status2 & HDSPM_version1) | (status2 & 49035760107cSAdrian Knoth HDSPM_version2)); 49045760107cSAdrian Knoth 49055760107cSAdrian Knoth snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", 49065760107cSAdrian Knoth (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, 49075760107cSAdrian Knoth hdspm->serial); 49085760107cSAdrian Knoth 49095760107cSAdrian Knoth snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", 49105760107cSAdrian Knoth hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); 49115760107cSAdrian Knoth 49125760107cSAdrian Knoth snd_iprintf(buffer, "--- System ---\n"); 49135760107cSAdrian Knoth 49145760107cSAdrian Knoth snd_iprintf(buffer, 49155760107cSAdrian Knoth "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", 49165760107cSAdrian Knoth status & HDSPM_audioIRQPending, 49175760107cSAdrian Knoth (status & HDSPM_midi0IRQPending) ? 1 : 0, 49185760107cSAdrian Knoth (status & HDSPM_midi1IRQPending) ? 1 : 0, 49195760107cSAdrian Knoth hdspm->irq_count); 49205760107cSAdrian Knoth snd_iprintf(buffer, 49215760107cSAdrian Knoth "HW pointer: id = %d, rawptr = %d (%d->%d) " 49225760107cSAdrian Knoth "estimated= %ld (bytes)\n", 49235760107cSAdrian Knoth ((status & HDSPM_BufferID) ? 1 : 0), 49245760107cSAdrian Knoth (status & HDSPM_BufferPositionMask), 49255760107cSAdrian Knoth (status & HDSPM_BufferPositionMask) % 49265760107cSAdrian Knoth (2 * (int)hdspm->period_bytes), 49275760107cSAdrian Knoth ((status & HDSPM_BufferPositionMask) - 64) % 49285760107cSAdrian Knoth (2 * (int)hdspm->period_bytes), 49295760107cSAdrian Knoth (long) hdspm_hw_pointer(hdspm) * 4); 49305760107cSAdrian Knoth 49315760107cSAdrian Knoth snd_iprintf(buffer, 49325760107cSAdrian Knoth "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", 49335760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, 49345760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, 49355760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, 49365760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); 49375760107cSAdrian Knoth snd_iprintf(buffer, 49385760107cSAdrian Knoth "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", 49395760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, 49405760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); 49415760107cSAdrian Knoth snd_iprintf(buffer, 49425760107cSAdrian Knoth "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " 49435760107cSAdrian Knoth "status2=0x%x\n", 49445760107cSAdrian Knoth hdspm->control_register, hdspm->control2_register, 49455760107cSAdrian Knoth status, status2); 49465760107cSAdrian Knoth 4947763f356cSTakashi Iwai 4948763f356cSTakashi Iwai snd_iprintf(buffer, "--- Settings ---\n"); 4949763f356cSTakashi Iwai 49507cb155ffSAdrian Knoth x = hdspm_get_latency(hdspm); 4951763f356cSTakashi Iwai 4952763f356cSTakashi Iwai snd_iprintf(buffer, 4953763f356cSTakashi Iwai "Size (Latency): %d samples (2 periods of %lu bytes)\n", 4954763f356cSTakashi Iwai x, (unsigned long) hdspm->period_bytes); 4955763f356cSTakashi Iwai 49560dca1793SAdrian Knoth snd_iprintf(buffer, "Line out: %s\n", 49570dca1793SAdrian Knoth (hdspm->control_register & HDSPM_LineOut) ? "on " : "off"); 4958763f356cSTakashi Iwai 4959763f356cSTakashi Iwai switch (hdspm->control_register & HDSPM_InputMask) { 4960763f356cSTakashi Iwai case HDSPM_InputOptical: 4961763f356cSTakashi Iwai insel = "Optical"; 4962763f356cSTakashi Iwai break; 4963763f356cSTakashi Iwai case HDSPM_InputCoaxial: 4964763f356cSTakashi Iwai insel = "Coaxial"; 4965763f356cSTakashi Iwai break; 4966763f356cSTakashi Iwai default: 4967ec8f53fbSMasanari Iida insel = "Unknown"; 4968763f356cSTakashi Iwai } 4969763f356cSTakashi Iwai 4970763f356cSTakashi Iwai snd_iprintf(buffer, 4971ef5fa1a4STakashi Iwai "ClearTrackMarker = %s, Transmit in %s Channel Mode, " 4972ef5fa1a4STakashi Iwai "Auto Input %s\n", 49730dca1793SAdrian Knoth (hdspm->control_register & HDSPM_clr_tms) ? "on" : "off", 49740dca1793SAdrian Knoth (hdspm->control_register & HDSPM_TX_64ch) ? "64" : "56", 49750dca1793SAdrian Knoth (hdspm->control_register & HDSPM_AutoInp) ? "on" : "off"); 4976763f356cSTakashi Iwai 49770dca1793SAdrian Knoth 49783cee5a60SRemy Bruno if (!(hdspm->control_register & HDSPM_ClockModeMaster)) 49790dca1793SAdrian Knoth system_clock_mode = "AutoSync"; 49803cee5a60SRemy Bruno else 4981763f356cSTakashi Iwai system_clock_mode = "Master"; 49820dca1793SAdrian Knoth snd_iprintf(buffer, "AutoSync Reference: %s\n", system_clock_mode); 4983763f356cSTakashi Iwai 4984763f356cSTakashi Iwai switch (hdspm_pref_sync_ref(hdspm)) { 4985763f356cSTakashi Iwai case HDSPM_SYNC_FROM_WORD: 4986763f356cSTakashi Iwai pref_sync_ref = "Word Clock"; 4987763f356cSTakashi Iwai break; 4988763f356cSTakashi Iwai case HDSPM_SYNC_FROM_MADI: 4989763f356cSTakashi Iwai pref_sync_ref = "MADI Sync"; 4990763f356cSTakashi Iwai break; 49910dca1793SAdrian Knoth case HDSPM_SYNC_FROM_TCO: 49920dca1793SAdrian Knoth pref_sync_ref = "TCO"; 49930dca1793SAdrian Knoth break; 49940dca1793SAdrian Knoth case HDSPM_SYNC_FROM_SYNC_IN: 49950dca1793SAdrian Knoth pref_sync_ref = "Sync In"; 49960dca1793SAdrian Knoth break; 4997763f356cSTakashi Iwai default: 4998763f356cSTakashi Iwai pref_sync_ref = "XXXX Clock"; 4999763f356cSTakashi Iwai break; 5000763f356cSTakashi Iwai } 5001763f356cSTakashi Iwai snd_iprintf(buffer, "Preferred Sync Reference: %s\n", 5002763f356cSTakashi Iwai pref_sync_ref); 5003763f356cSTakashi Iwai 5004763f356cSTakashi Iwai snd_iprintf(buffer, "System Clock Frequency: %d\n", 5005763f356cSTakashi Iwai hdspm->system_sample_rate); 5006763f356cSTakashi Iwai 5007763f356cSTakashi Iwai 5008763f356cSTakashi Iwai snd_iprintf(buffer, "--- Status:\n"); 5009763f356cSTakashi Iwai 5010763f356cSTakashi Iwai x = status & HDSPM_madiSync; 5011763f356cSTakashi Iwai x2 = status2 & HDSPM_wcSync; 5012763f356cSTakashi Iwai 5013763f356cSTakashi Iwai snd_iprintf(buffer, "Inputs MADI=%s, WordClock=%s\n", 5014763f356cSTakashi Iwai (status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") : 5015763f356cSTakashi Iwai "NoLock", 5016763f356cSTakashi Iwai (status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") : 5017763f356cSTakashi Iwai "NoLock"); 5018763f356cSTakashi Iwai 5019763f356cSTakashi Iwai switch (hdspm_autosync_ref(hdspm)) { 50200dca1793SAdrian Knoth case HDSPM_AUTOSYNC_FROM_SYNC_IN: 50210dca1793SAdrian Knoth autosync_ref = "Sync In"; 50220dca1793SAdrian Knoth break; 50230dca1793SAdrian Knoth case HDSPM_AUTOSYNC_FROM_TCO: 50240dca1793SAdrian Knoth autosync_ref = "TCO"; 50250dca1793SAdrian Knoth break; 5026763f356cSTakashi Iwai case HDSPM_AUTOSYNC_FROM_WORD: 5027763f356cSTakashi Iwai autosync_ref = "Word Clock"; 5028763f356cSTakashi Iwai break; 5029763f356cSTakashi Iwai case HDSPM_AUTOSYNC_FROM_MADI: 5030763f356cSTakashi Iwai autosync_ref = "MADI Sync"; 5031763f356cSTakashi Iwai break; 5032763f356cSTakashi Iwai case HDSPM_AUTOSYNC_FROM_NONE: 5033763f356cSTakashi Iwai autosync_ref = "Input not valid"; 5034763f356cSTakashi Iwai break; 5035763f356cSTakashi Iwai default: 5036763f356cSTakashi Iwai autosync_ref = "---"; 5037763f356cSTakashi Iwai break; 5038763f356cSTakashi Iwai } 5039763f356cSTakashi Iwai snd_iprintf(buffer, 5040763f356cSTakashi Iwai "AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n", 5041763f356cSTakashi Iwai autosync_ref, hdspm_external_sample_rate(hdspm), 5042763f356cSTakashi Iwai (status & HDSPM_madiFreqMask) >> 22, 5043763f356cSTakashi Iwai (status2 & HDSPM_wcFreqMask) >> 5); 5044763f356cSTakashi Iwai 5045763f356cSTakashi Iwai snd_iprintf(buffer, "Input: %s, Mode=%s\n", 5046763f356cSTakashi Iwai (status & HDSPM_AB_int) ? "Coax" : "Optical", 5047763f356cSTakashi Iwai (status & HDSPM_RX_64ch) ? "64 channels" : 5048763f356cSTakashi Iwai "56 channels"); 5049763f356cSTakashi Iwai 50505760107cSAdrian Knoth /* call readout function for TCO specific status */ 50515760107cSAdrian Knoth snd_hdspm_proc_read_tco(entry, buffer); 50525760107cSAdrian Knoth 5053763f356cSTakashi Iwai snd_iprintf(buffer, "\n"); 5054763f356cSTakashi Iwai } 5055763f356cSTakashi Iwai 50563cee5a60SRemy Bruno static void 50573cee5a60SRemy Bruno snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, 50583cee5a60SRemy Bruno struct snd_info_buffer *buffer) 50593cee5a60SRemy Bruno { 5060ef5fa1a4STakashi Iwai struct hdspm *hdspm = entry->private_data; 50613cee5a60SRemy Bruno unsigned int status; 50623cee5a60SRemy Bruno unsigned int status2; 50633cee5a60SRemy Bruno unsigned int timecode; 506456bde0f3SAndre Schramm unsigned int wcLock, wcSync; 50653cee5a60SRemy Bruno int pref_syncref; 50663cee5a60SRemy Bruno char *autosync_ref; 50673cee5a60SRemy Bruno int x; 50683cee5a60SRemy Bruno 50693cee5a60SRemy Bruno status = hdspm_read(hdspm, HDSPM_statusRegister); 50703cee5a60SRemy Bruno status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 50713cee5a60SRemy Bruno timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); 50723cee5a60SRemy Bruno 50733cee5a60SRemy Bruno snd_iprintf(buffer, "%s (Card #%d) Rev.%x\n", 50743cee5a60SRemy Bruno hdspm->card_name, hdspm->card->number + 1, 50753cee5a60SRemy Bruno hdspm->firmware_rev); 50763cee5a60SRemy Bruno 50773cee5a60SRemy Bruno snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", 50783cee5a60SRemy Bruno hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); 50793cee5a60SRemy Bruno 50803cee5a60SRemy Bruno snd_iprintf(buffer, "--- System ---\n"); 50813cee5a60SRemy Bruno 50823cee5a60SRemy Bruno snd_iprintf(buffer, 50833cee5a60SRemy Bruno "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", 50843cee5a60SRemy Bruno status & HDSPM_audioIRQPending, 50853cee5a60SRemy Bruno (status & HDSPM_midi0IRQPending) ? 1 : 0, 50863cee5a60SRemy Bruno (status & HDSPM_midi1IRQPending) ? 1 : 0, 50873cee5a60SRemy Bruno hdspm->irq_count); 50883cee5a60SRemy Bruno snd_iprintf(buffer, 5089ef5fa1a4STakashi Iwai "HW pointer: id = %d, rawptr = %d (%d->%d) " 5090ef5fa1a4STakashi Iwai "estimated= %ld (bytes)\n", 50913cee5a60SRemy Bruno ((status & HDSPM_BufferID) ? 1 : 0), 50923cee5a60SRemy Bruno (status & HDSPM_BufferPositionMask), 5093ef5fa1a4STakashi Iwai (status & HDSPM_BufferPositionMask) % 5094ef5fa1a4STakashi Iwai (2 * (int)hdspm->period_bytes), 5095ef5fa1a4STakashi Iwai ((status & HDSPM_BufferPositionMask) - 64) % 5096ef5fa1a4STakashi Iwai (2 * (int)hdspm->period_bytes), 50973cee5a60SRemy Bruno (long) hdspm_hw_pointer(hdspm) * 4); 50983cee5a60SRemy Bruno 50993cee5a60SRemy Bruno snd_iprintf(buffer, 51003cee5a60SRemy Bruno "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", 51013cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, 51023cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, 51033cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, 51043cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); 51053cee5a60SRemy Bruno snd_iprintf(buffer, 51060dca1793SAdrian Knoth "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", 51070dca1793SAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, 51080dca1793SAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); 51090dca1793SAdrian Knoth snd_iprintf(buffer, 51100dca1793SAdrian Knoth "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " 51110dca1793SAdrian Knoth "status2=0x%x\n", 51120dca1793SAdrian Knoth hdspm->control_register, hdspm->control2_register, 51130dca1793SAdrian Knoth status, status2); 51143cee5a60SRemy Bruno 51153cee5a60SRemy Bruno snd_iprintf(buffer, "--- Settings ---\n"); 51163cee5a60SRemy Bruno 51177cb155ffSAdrian Knoth x = hdspm_get_latency(hdspm); 51183cee5a60SRemy Bruno 51193cee5a60SRemy Bruno snd_iprintf(buffer, 51203cee5a60SRemy Bruno "Size (Latency): %d samples (2 periods of %lu bytes)\n", 51213cee5a60SRemy Bruno x, (unsigned long) hdspm->period_bytes); 51223cee5a60SRemy Bruno 51230dca1793SAdrian Knoth snd_iprintf(buffer, "Line out: %s\n", 51243cee5a60SRemy Bruno (hdspm-> 51250dca1793SAdrian Knoth control_register & HDSPM_LineOut) ? "on " : "off"); 51263cee5a60SRemy Bruno 51273cee5a60SRemy Bruno snd_iprintf(buffer, 51283cee5a60SRemy Bruno "ClearTrackMarker %s, Emphasis %s, Dolby %s\n", 51293cee5a60SRemy Bruno (hdspm-> 51303cee5a60SRemy Bruno control_register & HDSPM_clr_tms) ? "on" : "off", 51313cee5a60SRemy Bruno (hdspm-> 51323cee5a60SRemy Bruno control_register & HDSPM_Emphasis) ? "on" : "off", 51333cee5a60SRemy Bruno (hdspm-> 51343cee5a60SRemy Bruno control_register & HDSPM_Dolby) ? "on" : "off"); 51353cee5a60SRemy Bruno 51363cee5a60SRemy Bruno 51373cee5a60SRemy Bruno pref_syncref = hdspm_pref_sync_ref(hdspm); 51383cee5a60SRemy Bruno if (pref_syncref == 0) 51393cee5a60SRemy Bruno snd_iprintf(buffer, "Preferred Sync Reference: Word Clock\n"); 51403cee5a60SRemy Bruno else 51413cee5a60SRemy Bruno snd_iprintf(buffer, "Preferred Sync Reference: AES%d\n", 51423cee5a60SRemy Bruno pref_syncref); 51433cee5a60SRemy Bruno 51443cee5a60SRemy Bruno snd_iprintf(buffer, "System Clock Frequency: %d\n", 51453cee5a60SRemy Bruno hdspm->system_sample_rate); 51463cee5a60SRemy Bruno 51473cee5a60SRemy Bruno snd_iprintf(buffer, "Double speed: %s\n", 51483cee5a60SRemy Bruno hdspm->control_register & HDSPM_DS_DoubleWire? 51493cee5a60SRemy Bruno "Double wire" : "Single wire"); 51503cee5a60SRemy Bruno snd_iprintf(buffer, "Quad speed: %s\n", 51513cee5a60SRemy Bruno hdspm->control_register & HDSPM_QS_DoubleWire? 51523cee5a60SRemy Bruno "Double wire" : 51533cee5a60SRemy Bruno hdspm->control_register & HDSPM_QS_QuadWire? 51543cee5a60SRemy Bruno "Quad wire" : "Single wire"); 51553cee5a60SRemy Bruno 51563cee5a60SRemy Bruno snd_iprintf(buffer, "--- Status:\n"); 51573cee5a60SRemy Bruno 515856bde0f3SAndre Schramm wcLock = status & HDSPM_AES32_wcLock; 515956bde0f3SAndre Schramm wcSync = wcLock && (status & HDSPM_AES32_wcSync); 516056bde0f3SAndre Schramm 51613cee5a60SRemy Bruno snd_iprintf(buffer, "Word: %s Frequency: %d\n", 516256bde0f3SAndre Schramm (wcLock) ? (wcSync ? "Sync " : "Lock ") : "No Lock", 51633cee5a60SRemy Bruno HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); 51643cee5a60SRemy Bruno 51653cee5a60SRemy Bruno for (x = 0; x < 8; x++) { 51663cee5a60SRemy Bruno snd_iprintf(buffer, "AES%d: %s Frequency: %d\n", 51673cee5a60SRemy Bruno x+1, 5168ef5fa1a4STakashi Iwai (status2 & (HDSPM_LockAES >> x)) ? 5169ef5fa1a4STakashi Iwai "Sync " : "No Lock", 51703cee5a60SRemy Bruno HDSPM_bit2freq((timecode >> (4*x)) & 0xF)); 51713cee5a60SRemy Bruno } 51723cee5a60SRemy Bruno 51733cee5a60SRemy Bruno switch (hdspm_autosync_ref(hdspm)) { 51740dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_NONE: 51750dca1793SAdrian Knoth autosync_ref = "None"; break; 51760dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_WORD: 51770dca1793SAdrian Knoth autosync_ref = "Word Clock"; break; 51780dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES1: 51790dca1793SAdrian Knoth autosync_ref = "AES1"; break; 51800dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES2: 51810dca1793SAdrian Knoth autosync_ref = "AES2"; break; 51820dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES3: 51830dca1793SAdrian Knoth autosync_ref = "AES3"; break; 51840dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES4: 51850dca1793SAdrian Knoth autosync_ref = "AES4"; break; 51860dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES5: 51870dca1793SAdrian Knoth autosync_ref = "AES5"; break; 51880dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES6: 51890dca1793SAdrian Knoth autosync_ref = "AES6"; break; 51900dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES7: 51910dca1793SAdrian Knoth autosync_ref = "AES7"; break; 51920dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES8: 51930dca1793SAdrian Knoth autosync_ref = "AES8"; break; 5194194062daSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_TCO: 5195194062daSAdrian Knoth autosync_ref = "TCO"; break; 5196194062daSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN: 5197194062daSAdrian Knoth autosync_ref = "Sync In"; break; 51980dca1793SAdrian Knoth default: 51990dca1793SAdrian Knoth autosync_ref = "---"; break; 52003cee5a60SRemy Bruno } 52013cee5a60SRemy Bruno snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); 52023cee5a60SRemy Bruno 5203194062daSAdrian Knoth /* call readout function for TCO specific status */ 5204194062daSAdrian Knoth snd_hdspm_proc_read_tco(entry, buffer); 5205194062daSAdrian Knoth 52063cee5a60SRemy Bruno snd_iprintf(buffer, "\n"); 52073cee5a60SRemy Bruno } 52083cee5a60SRemy Bruno 52090dca1793SAdrian Knoth static void 52100dca1793SAdrian Knoth snd_hdspm_proc_read_raydat(struct snd_info_entry *entry, 52110dca1793SAdrian Knoth struct snd_info_buffer *buffer) 52120dca1793SAdrian Knoth { 52130dca1793SAdrian Knoth struct hdspm *hdspm = entry->private_data; 52140dca1793SAdrian Knoth unsigned int status1, status2, status3, control, i; 52150dca1793SAdrian Knoth unsigned int lock, sync; 52160dca1793SAdrian Knoth 52170dca1793SAdrian Knoth status1 = hdspm_read(hdspm, HDSPM_RD_STATUS_1); /* s1 */ 52180dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_RD_STATUS_2); /* freq */ 52190dca1793SAdrian Knoth status3 = hdspm_read(hdspm, HDSPM_RD_STATUS_3); /* s2 */ 52200dca1793SAdrian Knoth 52210dca1793SAdrian Knoth control = hdspm->control_register; 52220dca1793SAdrian Knoth 52230dca1793SAdrian Knoth snd_iprintf(buffer, "STATUS1: 0x%08x\n", status1); 52240dca1793SAdrian Knoth snd_iprintf(buffer, "STATUS2: 0x%08x\n", status2); 52250dca1793SAdrian Knoth snd_iprintf(buffer, "STATUS3: 0x%08x\n", status3); 52260dca1793SAdrian Knoth 52270dca1793SAdrian Knoth 52280dca1793SAdrian Knoth snd_iprintf(buffer, "\n*** CLOCK MODE\n\n"); 52290dca1793SAdrian Knoth 52300dca1793SAdrian Knoth snd_iprintf(buffer, "Clock mode : %s\n", 52310dca1793SAdrian Knoth (hdspm_system_clock_mode(hdspm) == 0) ? "master" : "slave"); 52320dca1793SAdrian Knoth snd_iprintf(buffer, "System frequency: %d Hz\n", 52330dca1793SAdrian Knoth hdspm_get_system_sample_rate(hdspm)); 52340dca1793SAdrian Knoth 52350dca1793SAdrian Knoth snd_iprintf(buffer, "\n*** INPUT STATUS\n\n"); 52360dca1793SAdrian Knoth 52370dca1793SAdrian Knoth lock = 0x1; 52380dca1793SAdrian Knoth sync = 0x100; 52390dca1793SAdrian Knoth 52400dca1793SAdrian Knoth for (i = 0; i < 8; i++) { 52410dca1793SAdrian Knoth snd_iprintf(buffer, "s1_input %d: Lock %d, Sync %d, Freq %s\n", 52420dca1793SAdrian Knoth i, 52430dca1793SAdrian Knoth (status1 & lock) ? 1 : 0, 52440dca1793SAdrian Knoth (status1 & sync) ? 1 : 0, 52450dca1793SAdrian Knoth texts_freq[(status2 >> (i * 4)) & 0xF]); 52460dca1793SAdrian Knoth 52470dca1793SAdrian Knoth lock = lock<<1; 52480dca1793SAdrian Knoth sync = sync<<1; 52490dca1793SAdrian Knoth } 52500dca1793SAdrian Knoth 52510dca1793SAdrian Knoth snd_iprintf(buffer, "WC input: Lock %d, Sync %d, Freq %s\n", 52520dca1793SAdrian Knoth (status1 & 0x1000000) ? 1 : 0, 52530dca1793SAdrian Knoth (status1 & 0x2000000) ? 1 : 0, 52540dca1793SAdrian Knoth texts_freq[(status1 >> 16) & 0xF]); 52550dca1793SAdrian Knoth 52560dca1793SAdrian Knoth snd_iprintf(buffer, "TCO input: Lock %d, Sync %d, Freq %s\n", 52570dca1793SAdrian Knoth (status1 & 0x4000000) ? 1 : 0, 52580dca1793SAdrian Knoth (status1 & 0x8000000) ? 1 : 0, 52590dca1793SAdrian Knoth texts_freq[(status1 >> 20) & 0xF]); 52600dca1793SAdrian Knoth 52610dca1793SAdrian Knoth snd_iprintf(buffer, "SYNC IN: Lock %d, Sync %d, Freq %s\n", 52620dca1793SAdrian Knoth (status3 & 0x400) ? 1 : 0, 52630dca1793SAdrian Knoth (status3 & 0x800) ? 1 : 0, 52640dca1793SAdrian Knoth texts_freq[(status2 >> 12) & 0xF]); 52650dca1793SAdrian Knoth 52660dca1793SAdrian Knoth } 52670dca1793SAdrian Knoth 52683cee5a60SRemy Bruno #ifdef CONFIG_SND_DEBUG 52693cee5a60SRemy Bruno static void 52703cee5a60SRemy Bruno snd_hdspm_proc_read_debug(struct snd_info_entry *entry, 52713cee5a60SRemy Bruno struct snd_info_buffer *buffer) 52723cee5a60SRemy Bruno { 5273ef5fa1a4STakashi Iwai struct hdspm *hdspm = entry->private_data; 52743cee5a60SRemy Bruno 52753cee5a60SRemy Bruno int j,i; 52763cee5a60SRemy Bruno 5277ef5fa1a4STakashi Iwai for (i = 0; i < 256 /* 1024*64 */; i += j) { 52783cee5a60SRemy Bruno snd_iprintf(buffer, "0x%08X: ", i); 52793cee5a60SRemy Bruno for (j = 0; j < 16; j += 4) 52803cee5a60SRemy Bruno snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j)); 52813cee5a60SRemy Bruno snd_iprintf(buffer, "\n"); 52823cee5a60SRemy Bruno } 52833cee5a60SRemy Bruno } 52843cee5a60SRemy Bruno #endif 52853cee5a60SRemy Bruno 52863cee5a60SRemy Bruno 52870dca1793SAdrian Knoth static void snd_hdspm_proc_ports_in(struct snd_info_entry *entry, 52880dca1793SAdrian Knoth struct snd_info_buffer *buffer) 52890dca1793SAdrian Knoth { 52900dca1793SAdrian Knoth struct hdspm *hdspm = entry->private_data; 52910dca1793SAdrian Knoth int i; 52920dca1793SAdrian Knoth 52930dca1793SAdrian Knoth snd_iprintf(buffer, "# generated by hdspm\n"); 52940dca1793SAdrian Knoth 52950dca1793SAdrian Knoth for (i = 0; i < hdspm->max_channels_in; i++) { 52960dca1793SAdrian Knoth snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_in[i]); 52970dca1793SAdrian Knoth } 52980dca1793SAdrian Knoth } 52990dca1793SAdrian Knoth 53000dca1793SAdrian Knoth static void snd_hdspm_proc_ports_out(struct snd_info_entry *entry, 53010dca1793SAdrian Knoth struct snd_info_buffer *buffer) 53020dca1793SAdrian Knoth { 53030dca1793SAdrian Knoth struct hdspm *hdspm = entry->private_data; 53040dca1793SAdrian Knoth int i; 53050dca1793SAdrian Knoth 53060dca1793SAdrian Knoth snd_iprintf(buffer, "# generated by hdspm\n"); 53070dca1793SAdrian Knoth 53080dca1793SAdrian Knoth for (i = 0; i < hdspm->max_channels_out; i++) { 53090dca1793SAdrian Knoth snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_out[i]); 53100dca1793SAdrian Knoth } 53110dca1793SAdrian Knoth } 53120dca1793SAdrian Knoth 53133cee5a60SRemy Bruno 5314e23e7a14SBill Pemberton static void snd_hdspm_proc_init(struct hdspm *hdspm) 5315763f356cSTakashi Iwai { 531698274f07STakashi Iwai struct snd_info_entry *entry; 5317763f356cSTakashi Iwai 53180dca1793SAdrian Knoth if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) { 53190dca1793SAdrian Knoth switch (hdspm->io_type) { 53200dca1793SAdrian Knoth case AES32: 5321bf850204STakashi Iwai snd_info_set_text_ops(entry, hdspm, 53220dca1793SAdrian Knoth snd_hdspm_proc_read_aes32); 53230dca1793SAdrian Knoth break; 53240dca1793SAdrian Knoth case MADI: 53250dca1793SAdrian Knoth snd_info_set_text_ops(entry, hdspm, 53263cee5a60SRemy Bruno snd_hdspm_proc_read_madi); 53270dca1793SAdrian Knoth break; 53280dca1793SAdrian Knoth case MADIface: 53290dca1793SAdrian Knoth /* snd_info_set_text_ops(entry, hdspm, 53300dca1793SAdrian Knoth snd_hdspm_proc_read_madiface); */ 53310dca1793SAdrian Knoth break; 53320dca1793SAdrian Knoth case RayDAT: 53330dca1793SAdrian Knoth snd_info_set_text_ops(entry, hdspm, 53340dca1793SAdrian Knoth snd_hdspm_proc_read_raydat); 53350dca1793SAdrian Knoth break; 53360dca1793SAdrian Knoth case AIO: 53370dca1793SAdrian Knoth break; 53380dca1793SAdrian Knoth } 53390dca1793SAdrian Knoth } 53400dca1793SAdrian Knoth 53410dca1793SAdrian Knoth if (!snd_card_proc_new(hdspm->card, "ports.in", &entry)) { 53420dca1793SAdrian Knoth snd_info_set_text_ops(entry, hdspm, snd_hdspm_proc_ports_in); 53430dca1793SAdrian Knoth } 53440dca1793SAdrian Knoth 53450dca1793SAdrian Knoth if (!snd_card_proc_new(hdspm->card, "ports.out", &entry)) { 53460dca1793SAdrian Knoth snd_info_set_text_ops(entry, hdspm, snd_hdspm_proc_ports_out); 53470dca1793SAdrian Knoth } 53480dca1793SAdrian Knoth 53493cee5a60SRemy Bruno #ifdef CONFIG_SND_DEBUG 53503cee5a60SRemy Bruno /* debug file to read all hdspm registers */ 53513cee5a60SRemy Bruno if (!snd_card_proc_new(hdspm->card, "debug", &entry)) 53523cee5a60SRemy Bruno snd_info_set_text_ops(entry, hdspm, 53533cee5a60SRemy Bruno snd_hdspm_proc_read_debug); 53543cee5a60SRemy Bruno #endif 5355763f356cSTakashi Iwai } 5356763f356cSTakashi Iwai 5357763f356cSTakashi Iwai /*------------------------------------------------------------ 5358763f356cSTakashi Iwai hdspm intitialize 5359763f356cSTakashi Iwai ------------------------------------------------------------*/ 5360763f356cSTakashi Iwai 536198274f07STakashi Iwai static int snd_hdspm_set_defaults(struct hdspm * hdspm) 5362763f356cSTakashi Iwai { 5363763f356cSTakashi Iwai /* ASSUMPTION: hdspm->lock is either held, or there is no need to 5364561de31aSJoe Perches hold it (e.g. during module initialization). 5365763f356cSTakashi Iwai */ 5366763f356cSTakashi Iwai 5367763f356cSTakashi Iwai /* set defaults: */ 5368763f356cSTakashi Iwai 53690dca1793SAdrian Knoth hdspm->settings_register = 0; 53700dca1793SAdrian Knoth 53710dca1793SAdrian Knoth switch (hdspm->io_type) { 53720dca1793SAdrian Knoth case MADI: 53730dca1793SAdrian Knoth case MADIface: 53740dca1793SAdrian Knoth hdspm->control_register = 53750dca1793SAdrian Knoth 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000; 53760dca1793SAdrian Knoth break; 53770dca1793SAdrian Knoth 53780dca1793SAdrian Knoth case RayDAT: 53790dca1793SAdrian Knoth case AIO: 53800dca1793SAdrian Knoth hdspm->settings_register = 0x1 + 0x1000; 53810dca1793SAdrian Knoth /* Magic values are: LAT_0, LAT_2, Master, freq1, tx64ch, inp_0, 53820dca1793SAdrian Knoth * line_out */ 53830dca1793SAdrian Knoth hdspm->control_register = 53840dca1793SAdrian Knoth 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000; 53850dca1793SAdrian Knoth break; 53860dca1793SAdrian Knoth 53870dca1793SAdrian Knoth case AES32: 5388ef5fa1a4STakashi Iwai hdspm->control_register = 5389e71b95adSAdrian Knoth HDSPM_ClockModeMaster | /* Master Clock Mode on */ 53900dca1793SAdrian Knoth hdspm_encode_latency(7) | /* latency max=8192samples */ 53913cee5a60SRemy Bruno HDSPM_SyncRef0 | /* AES1 is syncclock */ 53923cee5a60SRemy Bruno HDSPM_LineOut | /* Analog output in */ 53933cee5a60SRemy Bruno HDSPM_Professional; /* Professional mode */ 53940dca1793SAdrian Knoth break; 53950dca1793SAdrian Knoth } 5396763f356cSTakashi Iwai 5397763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 5398763f356cSTakashi Iwai 53990dca1793SAdrian Knoth if (AES32 == hdspm->io_type) { 5400ffb2c3c0SRemy Bruno /* No control2 register for AES32 */ 5401763f356cSTakashi Iwai #ifdef SNDRV_BIG_ENDIAN 5402763f356cSTakashi Iwai hdspm->control2_register = HDSPM_BIGENDIAN_MODE; 5403763f356cSTakashi Iwai #else 5404763f356cSTakashi Iwai hdspm->control2_register = 0; 5405763f356cSTakashi Iwai #endif 5406763f356cSTakashi Iwai 5407763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register); 5408ffb2c3c0SRemy Bruno } 5409763f356cSTakashi Iwai hdspm_compute_period_size(hdspm); 5410763f356cSTakashi Iwai 5411763f356cSTakashi Iwai /* silence everything */ 5412763f356cSTakashi Iwai 5413763f356cSTakashi Iwai all_in_all_mixer(hdspm, 0 * UNITY_GAIN); 5414763f356cSTakashi Iwai 5415b2ed6326SAdrian Knoth if (hdspm_is_raydat_or_aio(hdspm)) 54160dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 5417763f356cSTakashi Iwai 5418763f356cSTakashi Iwai /* set a default rate so that the channel map is set up. */ 54190dca1793SAdrian Knoth hdspm_set_rate(hdspm, 48000, 1); 5420763f356cSTakashi Iwai 5421763f356cSTakashi Iwai return 0; 5422763f356cSTakashi Iwai } 5423763f356cSTakashi Iwai 5424763f356cSTakashi Iwai 5425763f356cSTakashi Iwai /*------------------------------------------------------------ 5426561de31aSJoe Perches interrupt 5427763f356cSTakashi Iwai ------------------------------------------------------------*/ 5428763f356cSTakashi Iwai 54297d12e780SDavid Howells static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) 5430763f356cSTakashi Iwai { 543198274f07STakashi Iwai struct hdspm *hdspm = (struct hdspm *) dev_id; 5432763f356cSTakashi Iwai unsigned int status; 54330dca1793SAdrian Knoth int i, audio, midi, schedule = 0; 54340dca1793SAdrian Knoth /* cycles_t now; */ 5435763f356cSTakashi Iwai 5436763f356cSTakashi Iwai status = hdspm_read(hdspm, HDSPM_statusRegister); 5437763f356cSTakashi Iwai 5438763f356cSTakashi Iwai audio = status & HDSPM_audioIRQPending; 54390dca1793SAdrian Knoth midi = status & (HDSPM_midi0IRQPending | HDSPM_midi1IRQPending | 54400dca1793SAdrian Knoth HDSPM_midi2IRQPending | HDSPM_midi3IRQPending); 5441763f356cSTakashi Iwai 54420dca1793SAdrian Knoth /* now = get_cycles(); */ 54430dca1793SAdrian Knoth /** 54440dca1793SAdrian Knoth * LAT_2..LAT_0 period counter (win) counter (mac) 54450dca1793SAdrian Knoth * 6 4096 ~256053425 ~514672358 54460dca1793SAdrian Knoth * 5 2048 ~128024983 ~257373821 54470dca1793SAdrian Knoth * 4 1024 ~64023706 ~128718089 54480dca1793SAdrian Knoth * 3 512 ~32005945 ~64385999 54490dca1793SAdrian Knoth * 2 256 ~16003039 ~32260176 54500dca1793SAdrian Knoth * 1 128 ~7998738 ~16194507 54510dca1793SAdrian Knoth * 0 64 ~3998231 ~8191558 54520dca1793SAdrian Knoth **/ 54530dca1793SAdrian Knoth /* 54540dca1793SAdrian Knoth snd_printk(KERN_INFO "snd_hdspm_interrupt %llu @ %llx\n", 54550dca1793SAdrian Knoth now-hdspm->last_interrupt, status & 0xFFC0); 54560dca1793SAdrian Knoth hdspm->last_interrupt = now; 54570dca1793SAdrian Knoth */ 54580dca1793SAdrian Knoth 54590dca1793SAdrian Knoth if (!audio && !midi) 5460763f356cSTakashi Iwai return IRQ_NONE; 5461763f356cSTakashi Iwai 5462763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_interruptConfirmation, 0); 5463763f356cSTakashi Iwai hdspm->irq_count++; 5464763f356cSTakashi Iwai 5465763f356cSTakashi Iwai 5466763f356cSTakashi Iwai if (audio) { 5467763f356cSTakashi Iwai if (hdspm->capture_substream) 5468ef5fa1a4STakashi Iwai snd_pcm_period_elapsed(hdspm->capture_substream); 5469763f356cSTakashi Iwai 5470763f356cSTakashi Iwai if (hdspm->playback_substream) 5471ef5fa1a4STakashi Iwai snd_pcm_period_elapsed(hdspm->playback_substream); 5472763f356cSTakashi Iwai } 5473763f356cSTakashi Iwai 54740dca1793SAdrian Knoth if (midi) { 54750dca1793SAdrian Knoth i = 0; 54760dca1793SAdrian Knoth while (i < hdspm->midiPorts) { 54770dca1793SAdrian Knoth if ((hdspm_read(hdspm, 54780dca1793SAdrian Knoth hdspm->midi[i].statusIn) & 0xff) && 54790dca1793SAdrian Knoth (status & hdspm->midi[i].irq)) { 54800dca1793SAdrian Knoth /* we disable interrupts for this input until 54810dca1793SAdrian Knoth * processing is done 5482ef5fa1a4STakashi Iwai */ 54830dca1793SAdrian Knoth hdspm->control_register &= ~hdspm->midi[i].ie; 5484763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, 5485763f356cSTakashi Iwai hdspm->control_register); 54860dca1793SAdrian Knoth hdspm->midi[i].pending = 1; 5487763f356cSTakashi Iwai schedule = 1; 5488763f356cSTakashi Iwai } 54890dca1793SAdrian Knoth 54900dca1793SAdrian Knoth i++; 5491763f356cSTakashi Iwai } 54920dca1793SAdrian Knoth 5493763f356cSTakashi Iwai if (schedule) 54940dca1793SAdrian Knoth tasklet_hi_schedule(&hdspm->midi_tasklet); 54950dca1793SAdrian Knoth } 54960dca1793SAdrian Knoth 5497763f356cSTakashi Iwai return IRQ_HANDLED; 5498763f356cSTakashi Iwai } 5499763f356cSTakashi Iwai 5500763f356cSTakashi Iwai /*------------------------------------------------------------ 5501763f356cSTakashi Iwai pcm interface 5502763f356cSTakashi Iwai ------------------------------------------------------------*/ 5503763f356cSTakashi Iwai 5504763f356cSTakashi Iwai 55050dca1793SAdrian Knoth static snd_pcm_uframes_t snd_hdspm_hw_pointer(struct snd_pcm_substream 55060dca1793SAdrian Knoth *substream) 5507763f356cSTakashi Iwai { 550898274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 5509763f356cSTakashi Iwai return hdspm_hw_pointer(hdspm); 5510763f356cSTakashi Iwai } 5511763f356cSTakashi Iwai 5512763f356cSTakashi Iwai 551398274f07STakashi Iwai static int snd_hdspm_reset(struct snd_pcm_substream *substream) 5514763f356cSTakashi Iwai { 551598274f07STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 551698274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 551798274f07STakashi Iwai struct snd_pcm_substream *other; 5518763f356cSTakashi Iwai 5519763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 5520763f356cSTakashi Iwai other = hdspm->capture_substream; 5521763f356cSTakashi Iwai else 5522763f356cSTakashi Iwai other = hdspm->playback_substream; 5523763f356cSTakashi Iwai 5524763f356cSTakashi Iwai if (hdspm->running) 5525763f356cSTakashi Iwai runtime->status->hw_ptr = hdspm_hw_pointer(hdspm); 5526763f356cSTakashi Iwai else 5527763f356cSTakashi Iwai runtime->status->hw_ptr = 0; 5528763f356cSTakashi Iwai if (other) { 552998274f07STakashi Iwai struct snd_pcm_substream *s; 553098274f07STakashi Iwai struct snd_pcm_runtime *oruntime = other->runtime; 5531ef991b95STakashi Iwai snd_pcm_group_for_each_entry(s, substream) { 5532763f356cSTakashi Iwai if (s == other) { 5533763f356cSTakashi Iwai oruntime->status->hw_ptr = 5534763f356cSTakashi Iwai runtime->status->hw_ptr; 5535763f356cSTakashi Iwai break; 5536763f356cSTakashi Iwai } 5537763f356cSTakashi Iwai } 5538763f356cSTakashi Iwai } 5539763f356cSTakashi Iwai return 0; 5540763f356cSTakashi Iwai } 5541763f356cSTakashi Iwai 554298274f07STakashi Iwai static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, 554398274f07STakashi Iwai struct snd_pcm_hw_params *params) 5544763f356cSTakashi Iwai { 554598274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 5546763f356cSTakashi Iwai int err; 5547763f356cSTakashi Iwai int i; 5548763f356cSTakashi Iwai pid_t this_pid; 5549763f356cSTakashi Iwai pid_t other_pid; 5550763f356cSTakashi Iwai 5551763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 5552763f356cSTakashi Iwai 5553763f356cSTakashi Iwai if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5554763f356cSTakashi Iwai this_pid = hdspm->playback_pid; 5555763f356cSTakashi Iwai other_pid = hdspm->capture_pid; 5556763f356cSTakashi Iwai } else { 5557763f356cSTakashi Iwai this_pid = hdspm->capture_pid; 5558763f356cSTakashi Iwai other_pid = hdspm->playback_pid; 5559763f356cSTakashi Iwai } 5560763f356cSTakashi Iwai 5561ef5fa1a4STakashi Iwai if (other_pid > 0 && this_pid != other_pid) { 5562763f356cSTakashi Iwai 5563763f356cSTakashi Iwai /* The other stream is open, and not by the same 5564763f356cSTakashi Iwai task as this one. Make sure that the parameters 5565763f356cSTakashi Iwai that matter are the same. 5566763f356cSTakashi Iwai */ 5567763f356cSTakashi Iwai 5568763f356cSTakashi Iwai if (params_rate(params) != hdspm->system_sample_rate) { 5569763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5570763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params, 5571763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_RATE); 5572763f356cSTakashi Iwai return -EBUSY; 5573763f356cSTakashi Iwai } 5574763f356cSTakashi Iwai 5575763f356cSTakashi Iwai if (params_period_size(params) != hdspm->period_bytes / 4) { 5576763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5577763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params, 5578763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 5579763f356cSTakashi Iwai return -EBUSY; 5580763f356cSTakashi Iwai } 5581763f356cSTakashi Iwai 5582763f356cSTakashi Iwai } 5583763f356cSTakashi Iwai /* We're fine. */ 5584763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5585763f356cSTakashi Iwai 5586763f356cSTakashi Iwai /* how to make sure that the rate matches an externally-set one ? */ 5587763f356cSTakashi Iwai 5588763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 5589ef5fa1a4STakashi Iwai err = hdspm_set_rate(hdspm, params_rate(params), 0); 5590ef5fa1a4STakashi Iwai if (err < 0) { 55910dca1793SAdrian Knoth snd_printk(KERN_INFO "err on hdspm_set_rate: %d\n", err); 5592763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5593763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params, 5594763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_RATE); 5595763f356cSTakashi Iwai return err; 5596763f356cSTakashi Iwai } 5597763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5598763f356cSTakashi Iwai 5599ef5fa1a4STakashi Iwai err = hdspm_set_interrupt_interval(hdspm, 5600ef5fa1a4STakashi Iwai params_period_size(params)); 5601ef5fa1a4STakashi Iwai if (err < 0) { 56020dca1793SAdrian Knoth snd_printk(KERN_INFO "err on hdspm_set_interrupt_interval: %d\n", err); 5603763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params, 5604763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 5605763f356cSTakashi Iwai return err; 5606763f356cSTakashi Iwai } 5607763f356cSTakashi Iwai 5608ef5fa1a4STakashi Iwai /* Memory allocation, takashi's method, dont know if we should 5609ef5fa1a4STakashi Iwai * spinlock 5610ef5fa1a4STakashi Iwai */ 5611763f356cSTakashi Iwai /* malloc all buffer even if not enabled to get sure */ 5612ffb2c3c0SRemy Bruno /* Update for MADI rev 204: we need to allocate for all channels, 5613ffb2c3c0SRemy Bruno * otherwise it doesn't work at 96kHz */ 56140dca1793SAdrian Knoth 5615763f356cSTakashi Iwai err = 5616ffb2c3c0SRemy Bruno snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES); 56170dca1793SAdrian Knoth if (err < 0) { 56180dca1793SAdrian Knoth snd_printk(KERN_INFO "err on snd_pcm_lib_malloc_pages: %d\n", err); 5619763f356cSTakashi Iwai return err; 56200dca1793SAdrian Knoth } 5621763f356cSTakashi Iwai 5622763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5623763f356cSTakashi Iwai 562477a23f26STakashi Iwai hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferOut, 5625763f356cSTakashi Iwai params_channels(params)); 5626763f356cSTakashi Iwai 5627763f356cSTakashi Iwai for (i = 0; i < params_channels(params); ++i) 5628763f356cSTakashi Iwai snd_hdspm_enable_out(hdspm, i, 1); 5629763f356cSTakashi Iwai 5630763f356cSTakashi Iwai hdspm->playback_buffer = 5631763f356cSTakashi Iwai (unsigned char *) substream->runtime->dma_area; 563254bf5dd9STakashi Iwai snd_printdd("Allocated sample buffer for playback at %p\n", 56333cee5a60SRemy Bruno hdspm->playback_buffer); 5634763f356cSTakashi Iwai } else { 563577a23f26STakashi Iwai hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferIn, 5636763f356cSTakashi Iwai params_channels(params)); 5637763f356cSTakashi Iwai 5638763f356cSTakashi Iwai for (i = 0; i < params_channels(params); ++i) 5639763f356cSTakashi Iwai snd_hdspm_enable_in(hdspm, i, 1); 5640763f356cSTakashi Iwai 5641763f356cSTakashi Iwai hdspm->capture_buffer = 5642763f356cSTakashi Iwai (unsigned char *) substream->runtime->dma_area; 564354bf5dd9STakashi Iwai snd_printdd("Allocated sample buffer for capture at %p\n", 56443cee5a60SRemy Bruno hdspm->capture_buffer); 5645763f356cSTakashi Iwai } 56460dca1793SAdrian Knoth 56473cee5a60SRemy Bruno /* 56483cee5a60SRemy Bruno snd_printdd("Allocated sample buffer for %s at 0x%08X\n", 56493cee5a60SRemy Bruno substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 56503cee5a60SRemy Bruno "playback" : "capture", 565177a23f26STakashi Iwai snd_pcm_sgbuf_get_addr(substream, 0)); 56523cee5a60SRemy Bruno */ 5653ffb2c3c0SRemy Bruno /* 5654ffb2c3c0SRemy Bruno snd_printdd("set_hwparams: %s %d Hz, %d channels, bs = %d\n", 5655ffb2c3c0SRemy Bruno substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 5656ffb2c3c0SRemy Bruno "playback" : "capture", 5657ffb2c3c0SRemy Bruno params_rate(params), params_channels(params), 5658ffb2c3c0SRemy Bruno params_buffer_size(params)); 5659ffb2c3c0SRemy Bruno */ 56600dca1793SAdrian Knoth 56610dca1793SAdrian Knoth 56623ac9b0acSAdrian Knoth /* For AES cards, the float format bit is the same as the 56633ac9b0acSAdrian Knoth * preferred sync reference. Since we don't want to break 56643ac9b0acSAdrian Knoth * sync settings, we have to skip the remaining part of this 56653ac9b0acSAdrian Knoth * function. 56663ac9b0acSAdrian Knoth */ 56673ac9b0acSAdrian Knoth if (hdspm->io_type == AES32) { 56683ac9b0acSAdrian Knoth return 0; 56693ac9b0acSAdrian Knoth } 56703ac9b0acSAdrian Knoth 56713ac9b0acSAdrian Knoth 56720dca1793SAdrian Knoth /* Switch to native float format if requested */ 56730dca1793SAdrian Knoth if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) { 56740dca1793SAdrian Knoth if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT)) 56750dca1793SAdrian Knoth snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE float format.\n"); 56760dca1793SAdrian Knoth 56770dca1793SAdrian Knoth hdspm->control_register |= HDSPe_FLOAT_FORMAT; 56780dca1793SAdrian Knoth } else if (SNDRV_PCM_FORMAT_S32_LE == params_format(params)) { 56790dca1793SAdrian Knoth if (hdspm->control_register & HDSPe_FLOAT_FORMAT) 56800dca1793SAdrian Knoth snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE integer format.\n"); 56810dca1793SAdrian Knoth 56820dca1793SAdrian Knoth hdspm->control_register &= ~HDSPe_FLOAT_FORMAT; 56830dca1793SAdrian Knoth } 56840dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 56850dca1793SAdrian Knoth 5686763f356cSTakashi Iwai return 0; 5687763f356cSTakashi Iwai } 5688763f356cSTakashi Iwai 568998274f07STakashi Iwai static int snd_hdspm_hw_free(struct snd_pcm_substream *substream) 5690763f356cSTakashi Iwai { 5691763f356cSTakashi Iwai int i; 569298274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 5693763f356cSTakashi Iwai 5694763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5695763f356cSTakashi Iwai 5696763f356cSTakashi Iwai /* params_channels(params) should be enough, 5697763f356cSTakashi Iwai but to get sure in case of error */ 56980dca1793SAdrian Knoth for (i = 0; i < hdspm->max_channels_out; ++i) 5699763f356cSTakashi Iwai snd_hdspm_enable_out(hdspm, i, 0); 5700763f356cSTakashi Iwai 5701763f356cSTakashi Iwai hdspm->playback_buffer = NULL; 5702763f356cSTakashi Iwai } else { 57030dca1793SAdrian Knoth for (i = 0; i < hdspm->max_channels_in; ++i) 5704763f356cSTakashi Iwai snd_hdspm_enable_in(hdspm, i, 0); 5705763f356cSTakashi Iwai 5706763f356cSTakashi Iwai hdspm->capture_buffer = NULL; 5707763f356cSTakashi Iwai 5708763f356cSTakashi Iwai } 5709763f356cSTakashi Iwai 5710763f356cSTakashi Iwai snd_pcm_lib_free_pages(substream); 5711763f356cSTakashi Iwai 5712763f356cSTakashi Iwai return 0; 5713763f356cSTakashi Iwai } 5714763f356cSTakashi Iwai 57150dca1793SAdrian Knoth 571698274f07STakashi Iwai static int snd_hdspm_channel_info(struct snd_pcm_substream *substream, 571798274f07STakashi Iwai struct snd_pcm_channel_info *info) 5718763f356cSTakashi Iwai { 571998274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 5720763f356cSTakashi Iwai 57210dca1793SAdrian Knoth if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 57220dca1793SAdrian Knoth if (snd_BUG_ON(info->channel >= hdspm->max_channels_out)) { 57230dca1793SAdrian Knoth snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel out of range (%d)\n", info->channel); 5724da3cec35STakashi Iwai return -EINVAL; 57250dca1793SAdrian Knoth } 5726763f356cSTakashi Iwai 57270dca1793SAdrian Knoth if (hdspm->channel_map_out[info->channel] < 0) { 57280dca1793SAdrian Knoth snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel %d mapped out\n", info->channel); 5729763f356cSTakashi Iwai return -EINVAL; 57300dca1793SAdrian Knoth } 5731763f356cSTakashi Iwai 57320dca1793SAdrian Knoth info->offset = hdspm->channel_map_out[info->channel] * 57330dca1793SAdrian Knoth HDSPM_CHANNEL_BUFFER_BYTES; 57340dca1793SAdrian Knoth } else { 57350dca1793SAdrian Knoth if (snd_BUG_ON(info->channel >= hdspm->max_channels_in)) { 57360dca1793SAdrian Knoth snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel out of range (%d)\n", info->channel); 57370dca1793SAdrian Knoth return -EINVAL; 57380dca1793SAdrian Knoth } 57390dca1793SAdrian Knoth 57400dca1793SAdrian Knoth if (hdspm->channel_map_in[info->channel] < 0) { 57410dca1793SAdrian Knoth snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel %d mapped out\n", info->channel); 57420dca1793SAdrian Knoth return -EINVAL; 57430dca1793SAdrian Knoth } 57440dca1793SAdrian Knoth 57450dca1793SAdrian Knoth info->offset = hdspm->channel_map_in[info->channel] * 57460dca1793SAdrian Knoth HDSPM_CHANNEL_BUFFER_BYTES; 57470dca1793SAdrian Knoth } 57480dca1793SAdrian Knoth 5749763f356cSTakashi Iwai info->first = 0; 5750763f356cSTakashi Iwai info->step = 32; 5751763f356cSTakashi Iwai return 0; 5752763f356cSTakashi Iwai } 5753763f356cSTakashi Iwai 57540dca1793SAdrian Knoth 575598274f07STakashi Iwai static int snd_hdspm_ioctl(struct snd_pcm_substream *substream, 5756763f356cSTakashi Iwai unsigned int cmd, void *arg) 5757763f356cSTakashi Iwai { 5758763f356cSTakashi Iwai switch (cmd) { 5759763f356cSTakashi Iwai case SNDRV_PCM_IOCTL1_RESET: 5760763f356cSTakashi Iwai return snd_hdspm_reset(substream); 5761763f356cSTakashi Iwai 5762763f356cSTakashi Iwai case SNDRV_PCM_IOCTL1_CHANNEL_INFO: 5763763f356cSTakashi Iwai { 576498274f07STakashi Iwai struct snd_pcm_channel_info *info = arg; 5765763f356cSTakashi Iwai return snd_hdspm_channel_info(substream, info); 5766763f356cSTakashi Iwai } 5767763f356cSTakashi Iwai default: 5768763f356cSTakashi Iwai break; 5769763f356cSTakashi Iwai } 5770763f356cSTakashi Iwai 5771763f356cSTakashi Iwai return snd_pcm_lib_ioctl(substream, cmd, arg); 5772763f356cSTakashi Iwai } 5773763f356cSTakashi Iwai 577498274f07STakashi Iwai static int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd) 5775763f356cSTakashi Iwai { 577698274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 577798274f07STakashi Iwai struct snd_pcm_substream *other; 5778763f356cSTakashi Iwai int running; 5779763f356cSTakashi Iwai 5780763f356cSTakashi Iwai spin_lock(&hdspm->lock); 5781763f356cSTakashi Iwai running = hdspm->running; 5782763f356cSTakashi Iwai switch (cmd) { 5783763f356cSTakashi Iwai case SNDRV_PCM_TRIGGER_START: 5784763f356cSTakashi Iwai running |= 1 << substream->stream; 5785763f356cSTakashi Iwai break; 5786763f356cSTakashi Iwai case SNDRV_PCM_TRIGGER_STOP: 5787763f356cSTakashi Iwai running &= ~(1 << substream->stream); 5788763f356cSTakashi Iwai break; 5789763f356cSTakashi Iwai default: 5790763f356cSTakashi Iwai snd_BUG(); 5791763f356cSTakashi Iwai spin_unlock(&hdspm->lock); 5792763f356cSTakashi Iwai return -EINVAL; 5793763f356cSTakashi Iwai } 5794763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 5795763f356cSTakashi Iwai other = hdspm->capture_substream; 5796763f356cSTakashi Iwai else 5797763f356cSTakashi Iwai other = hdspm->playback_substream; 5798763f356cSTakashi Iwai 5799763f356cSTakashi Iwai if (other) { 580098274f07STakashi Iwai struct snd_pcm_substream *s; 5801ef991b95STakashi Iwai snd_pcm_group_for_each_entry(s, substream) { 5802763f356cSTakashi Iwai if (s == other) { 5803763f356cSTakashi Iwai snd_pcm_trigger_done(s, substream); 5804763f356cSTakashi Iwai if (cmd == SNDRV_PCM_TRIGGER_START) 5805763f356cSTakashi Iwai running |= 1 << s->stream; 5806763f356cSTakashi Iwai else 5807763f356cSTakashi Iwai running &= ~(1 << s->stream); 5808763f356cSTakashi Iwai goto _ok; 5809763f356cSTakashi Iwai } 5810763f356cSTakashi Iwai } 5811763f356cSTakashi Iwai if (cmd == SNDRV_PCM_TRIGGER_START) { 5812763f356cSTakashi Iwai if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) 5813763f356cSTakashi Iwai && substream->stream == 5814763f356cSTakashi Iwai SNDRV_PCM_STREAM_CAPTURE) 5815763f356cSTakashi Iwai hdspm_silence_playback(hdspm); 5816763f356cSTakashi Iwai } else { 5817763f356cSTakashi Iwai if (running && 5818763f356cSTakashi Iwai substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 5819763f356cSTakashi Iwai hdspm_silence_playback(hdspm); 5820763f356cSTakashi Iwai } 5821763f356cSTakashi Iwai } else { 5822763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 5823763f356cSTakashi Iwai hdspm_silence_playback(hdspm); 5824763f356cSTakashi Iwai } 5825763f356cSTakashi Iwai _ok: 5826763f356cSTakashi Iwai snd_pcm_trigger_done(substream, substream); 5827763f356cSTakashi Iwai if (!hdspm->running && running) 5828763f356cSTakashi Iwai hdspm_start_audio(hdspm); 5829763f356cSTakashi Iwai else if (hdspm->running && !running) 5830763f356cSTakashi Iwai hdspm_stop_audio(hdspm); 5831763f356cSTakashi Iwai hdspm->running = running; 5832763f356cSTakashi Iwai spin_unlock(&hdspm->lock); 5833763f356cSTakashi Iwai 5834763f356cSTakashi Iwai return 0; 5835763f356cSTakashi Iwai } 5836763f356cSTakashi Iwai 583798274f07STakashi Iwai static int snd_hdspm_prepare(struct snd_pcm_substream *substream) 5838763f356cSTakashi Iwai { 5839763f356cSTakashi Iwai return 0; 5840763f356cSTakashi Iwai } 5841763f356cSTakashi Iwai 584298274f07STakashi Iwai static struct snd_pcm_hardware snd_hdspm_playback_subinfo = { 5843763f356cSTakashi Iwai .info = (SNDRV_PCM_INFO_MMAP | 5844763f356cSTakashi Iwai SNDRV_PCM_INFO_MMAP_VALID | 5845763f356cSTakashi Iwai SNDRV_PCM_INFO_NONINTERLEAVED | 5846763f356cSTakashi Iwai SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_DOUBLE), 5847763f356cSTakashi Iwai .formats = SNDRV_PCM_FMTBIT_S32_LE, 5848763f356cSTakashi Iwai .rates = (SNDRV_PCM_RATE_32000 | 5849763f356cSTakashi Iwai SNDRV_PCM_RATE_44100 | 5850763f356cSTakashi Iwai SNDRV_PCM_RATE_48000 | 5851763f356cSTakashi Iwai SNDRV_PCM_RATE_64000 | 58523cee5a60SRemy Bruno SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 58533cee5a60SRemy Bruno SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ), 5854763f356cSTakashi Iwai .rate_min = 32000, 58553cee5a60SRemy Bruno .rate_max = 192000, 5856763f356cSTakashi Iwai .channels_min = 1, 5857763f356cSTakashi Iwai .channels_max = HDSPM_MAX_CHANNELS, 5858763f356cSTakashi Iwai .buffer_bytes_max = 5859763f356cSTakashi Iwai HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, 58601b6fa108SAdrian Knoth .period_bytes_min = (32 * 4), 586152e6fb48STakashi Iwai .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, 5862763f356cSTakashi Iwai .periods_min = 2, 58630dca1793SAdrian Knoth .periods_max = 512, 5864763f356cSTakashi Iwai .fifo_size = 0 5865763f356cSTakashi Iwai }; 5866763f356cSTakashi Iwai 586798274f07STakashi Iwai static struct snd_pcm_hardware snd_hdspm_capture_subinfo = { 5868763f356cSTakashi Iwai .info = (SNDRV_PCM_INFO_MMAP | 5869763f356cSTakashi Iwai SNDRV_PCM_INFO_MMAP_VALID | 5870763f356cSTakashi Iwai SNDRV_PCM_INFO_NONINTERLEAVED | 5871763f356cSTakashi Iwai SNDRV_PCM_INFO_SYNC_START), 5872763f356cSTakashi Iwai .formats = SNDRV_PCM_FMTBIT_S32_LE, 5873763f356cSTakashi Iwai .rates = (SNDRV_PCM_RATE_32000 | 5874763f356cSTakashi Iwai SNDRV_PCM_RATE_44100 | 5875763f356cSTakashi Iwai SNDRV_PCM_RATE_48000 | 5876763f356cSTakashi Iwai SNDRV_PCM_RATE_64000 | 58773cee5a60SRemy Bruno SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 58783cee5a60SRemy Bruno SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000), 5879763f356cSTakashi Iwai .rate_min = 32000, 58803cee5a60SRemy Bruno .rate_max = 192000, 5881763f356cSTakashi Iwai .channels_min = 1, 5882763f356cSTakashi Iwai .channels_max = HDSPM_MAX_CHANNELS, 5883763f356cSTakashi Iwai .buffer_bytes_max = 5884763f356cSTakashi Iwai HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, 58851b6fa108SAdrian Knoth .period_bytes_min = (32 * 4), 588652e6fb48STakashi Iwai .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, 5887763f356cSTakashi Iwai .periods_min = 2, 58880dca1793SAdrian Knoth .periods_max = 512, 5889763f356cSTakashi Iwai .fifo_size = 0 5890763f356cSTakashi Iwai }; 5891763f356cSTakashi Iwai 58920dca1793SAdrian Knoth static int snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params, 589398274f07STakashi Iwai struct snd_pcm_hw_rule *rule) 5894763f356cSTakashi Iwai { 589598274f07STakashi Iwai struct hdspm *hdspm = rule->private; 589698274f07STakashi Iwai struct snd_interval *c = 5897763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 589898274f07STakashi Iwai struct snd_interval *r = 5899763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 5900763f356cSTakashi Iwai 59010dca1793SAdrian Knoth if (r->min > 96000 && r->max <= 192000) { 590298274f07STakashi Iwai struct snd_interval t = { 59030dca1793SAdrian Knoth .min = hdspm->qs_in_channels, 59040dca1793SAdrian Knoth .max = hdspm->qs_in_channels, 59050dca1793SAdrian Knoth .integer = 1, 59060dca1793SAdrian Knoth }; 59070dca1793SAdrian Knoth return snd_interval_refine(c, &t); 59080dca1793SAdrian Knoth } else if (r->min > 48000 && r->max <= 96000) { 59090dca1793SAdrian Knoth struct snd_interval t = { 59100dca1793SAdrian Knoth .min = hdspm->ds_in_channels, 59110dca1793SAdrian Knoth .max = hdspm->ds_in_channels, 5912763f356cSTakashi Iwai .integer = 1, 5913763f356cSTakashi Iwai }; 5914763f356cSTakashi Iwai return snd_interval_refine(c, &t); 5915763f356cSTakashi Iwai } else if (r->max < 64000) { 591698274f07STakashi Iwai struct snd_interval t = { 59170dca1793SAdrian Knoth .min = hdspm->ss_in_channels, 59180dca1793SAdrian Knoth .max = hdspm->ss_in_channels, 5919763f356cSTakashi Iwai .integer = 1, 5920763f356cSTakashi Iwai }; 5921763f356cSTakashi Iwai return snd_interval_refine(c, &t); 5922763f356cSTakashi Iwai } 59230dca1793SAdrian Knoth 5924763f356cSTakashi Iwai return 0; 5925763f356cSTakashi Iwai } 5926763f356cSTakashi Iwai 59270dca1793SAdrian Knoth static int snd_hdspm_hw_rule_out_channels_rate(struct snd_pcm_hw_params *params, 592898274f07STakashi Iwai struct snd_pcm_hw_rule * rule) 5929763f356cSTakashi Iwai { 593098274f07STakashi Iwai struct hdspm *hdspm = rule->private; 593198274f07STakashi Iwai struct snd_interval *c = 5932763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 593398274f07STakashi Iwai struct snd_interval *r = 5934763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 5935763f356cSTakashi Iwai 59360dca1793SAdrian Knoth if (r->min > 96000 && r->max <= 192000) { 59370dca1793SAdrian Knoth struct snd_interval t = { 59380dca1793SAdrian Knoth .min = hdspm->qs_out_channels, 59390dca1793SAdrian Knoth .max = hdspm->qs_out_channels, 59400dca1793SAdrian Knoth .integer = 1, 59410dca1793SAdrian Knoth }; 59420dca1793SAdrian Knoth return snd_interval_refine(c, &t); 59430dca1793SAdrian Knoth } else if (r->min > 48000 && r->max <= 96000) { 59440dca1793SAdrian Knoth struct snd_interval t = { 59450dca1793SAdrian Knoth .min = hdspm->ds_out_channels, 59460dca1793SAdrian Knoth .max = hdspm->ds_out_channels, 59470dca1793SAdrian Knoth .integer = 1, 59480dca1793SAdrian Knoth }; 59490dca1793SAdrian Knoth return snd_interval_refine(c, &t); 59500dca1793SAdrian Knoth } else if (r->max < 64000) { 59510dca1793SAdrian Knoth struct snd_interval t = { 59520dca1793SAdrian Knoth .min = hdspm->ss_out_channels, 59530dca1793SAdrian Knoth .max = hdspm->ss_out_channels, 59540dca1793SAdrian Knoth .integer = 1, 59550dca1793SAdrian Knoth }; 59560dca1793SAdrian Knoth return snd_interval_refine(c, &t); 59570dca1793SAdrian Knoth } else { 59580dca1793SAdrian Knoth } 59590dca1793SAdrian Knoth return 0; 59600dca1793SAdrian Knoth } 59610dca1793SAdrian Knoth 59620dca1793SAdrian Knoth static int snd_hdspm_hw_rule_rate_in_channels(struct snd_pcm_hw_params *params, 59630dca1793SAdrian Knoth struct snd_pcm_hw_rule * rule) 59640dca1793SAdrian Knoth { 59650dca1793SAdrian Knoth struct hdspm *hdspm = rule->private; 59660dca1793SAdrian Knoth struct snd_interval *c = 59670dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 59680dca1793SAdrian Knoth struct snd_interval *r = 59690dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 59700dca1793SAdrian Knoth 59710dca1793SAdrian Knoth if (c->min >= hdspm->ss_in_channels) { 597298274f07STakashi Iwai struct snd_interval t = { 5973763f356cSTakashi Iwai .min = 32000, 5974763f356cSTakashi Iwai .max = 48000, 5975763f356cSTakashi Iwai .integer = 1, 5976763f356cSTakashi Iwai }; 5977763f356cSTakashi Iwai return snd_interval_refine(r, &t); 59780dca1793SAdrian Knoth } else if (c->max <= hdspm->qs_in_channels) { 59790dca1793SAdrian Knoth struct snd_interval t = { 59800dca1793SAdrian Knoth .min = 128000, 59810dca1793SAdrian Knoth .max = 192000, 59820dca1793SAdrian Knoth .integer = 1, 59830dca1793SAdrian Knoth }; 59840dca1793SAdrian Knoth return snd_interval_refine(r, &t); 59850dca1793SAdrian Knoth } else if (c->max <= hdspm->ds_in_channels) { 598698274f07STakashi Iwai struct snd_interval t = { 5987763f356cSTakashi Iwai .min = 64000, 5988763f356cSTakashi Iwai .max = 96000, 5989763f356cSTakashi Iwai .integer = 1, 5990763f356cSTakashi Iwai }; 5991763f356cSTakashi Iwai return snd_interval_refine(r, &t); 5992763f356cSTakashi Iwai } 59930dca1793SAdrian Knoth 59940dca1793SAdrian Knoth return 0; 59950dca1793SAdrian Knoth } 59960dca1793SAdrian Knoth static int snd_hdspm_hw_rule_rate_out_channels(struct snd_pcm_hw_params *params, 59970dca1793SAdrian Knoth struct snd_pcm_hw_rule *rule) 59980dca1793SAdrian Knoth { 59990dca1793SAdrian Knoth struct hdspm *hdspm = rule->private; 60000dca1793SAdrian Knoth struct snd_interval *c = 60010dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 60020dca1793SAdrian Knoth struct snd_interval *r = 60030dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 60040dca1793SAdrian Knoth 60050dca1793SAdrian Knoth if (c->min >= hdspm->ss_out_channels) { 60060dca1793SAdrian Knoth struct snd_interval t = { 60070dca1793SAdrian Knoth .min = 32000, 60080dca1793SAdrian Knoth .max = 48000, 60090dca1793SAdrian Knoth .integer = 1, 60100dca1793SAdrian Knoth }; 60110dca1793SAdrian Knoth return snd_interval_refine(r, &t); 60120dca1793SAdrian Knoth } else if (c->max <= hdspm->qs_out_channels) { 60130dca1793SAdrian Knoth struct snd_interval t = { 60140dca1793SAdrian Knoth .min = 128000, 60150dca1793SAdrian Knoth .max = 192000, 60160dca1793SAdrian Knoth .integer = 1, 60170dca1793SAdrian Knoth }; 60180dca1793SAdrian Knoth return snd_interval_refine(r, &t); 60190dca1793SAdrian Knoth } else if (c->max <= hdspm->ds_out_channels) { 60200dca1793SAdrian Knoth struct snd_interval t = { 60210dca1793SAdrian Knoth .min = 64000, 60220dca1793SAdrian Knoth .max = 96000, 60230dca1793SAdrian Knoth .integer = 1, 60240dca1793SAdrian Knoth }; 60250dca1793SAdrian Knoth return snd_interval_refine(r, &t); 60260dca1793SAdrian Knoth } 60270dca1793SAdrian Knoth 6028763f356cSTakashi Iwai return 0; 6029763f356cSTakashi Iwai } 6030763f356cSTakashi Iwai 60310dca1793SAdrian Knoth static int snd_hdspm_hw_rule_in_channels(struct snd_pcm_hw_params *params, 6032ffb2c3c0SRemy Bruno struct snd_pcm_hw_rule *rule) 6033ffb2c3c0SRemy Bruno { 6034ffb2c3c0SRemy Bruno unsigned int list[3]; 6035ffb2c3c0SRemy Bruno struct hdspm *hdspm = rule->private; 6036ffb2c3c0SRemy Bruno struct snd_interval *c = hw_param_interval(params, 6037ffb2c3c0SRemy Bruno SNDRV_PCM_HW_PARAM_CHANNELS); 60380dca1793SAdrian Knoth 60390dca1793SAdrian Knoth list[0] = hdspm->qs_in_channels; 60400dca1793SAdrian Knoth list[1] = hdspm->ds_in_channels; 60410dca1793SAdrian Knoth list[2] = hdspm->ss_in_channels; 6042ffb2c3c0SRemy Bruno return snd_interval_list(c, 3, list, 0); 6043ffb2c3c0SRemy Bruno } 60440dca1793SAdrian Knoth 60450dca1793SAdrian Knoth static int snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params *params, 60460dca1793SAdrian Knoth struct snd_pcm_hw_rule *rule) 60470dca1793SAdrian Knoth { 60480dca1793SAdrian Knoth unsigned int list[3]; 60490dca1793SAdrian Knoth struct hdspm *hdspm = rule->private; 60500dca1793SAdrian Knoth struct snd_interval *c = hw_param_interval(params, 60510dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_CHANNELS); 60520dca1793SAdrian Knoth 60530dca1793SAdrian Knoth list[0] = hdspm->qs_out_channels; 60540dca1793SAdrian Knoth list[1] = hdspm->ds_out_channels; 60550dca1793SAdrian Knoth list[2] = hdspm->ss_out_channels; 60560dca1793SAdrian Knoth return snd_interval_list(c, 3, list, 0); 6057ffb2c3c0SRemy Bruno } 6058ffb2c3c0SRemy Bruno 6059ffb2c3c0SRemy Bruno 6060ef5fa1a4STakashi Iwai static unsigned int hdspm_aes32_sample_rates[] = { 6061ef5fa1a4STakashi Iwai 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 6062ef5fa1a4STakashi Iwai }; 6063ffb2c3c0SRemy Bruno 6064ef5fa1a4STakashi Iwai static struct snd_pcm_hw_constraint_list 6065ef5fa1a4STakashi Iwai hdspm_hw_constraints_aes32_sample_rates = { 6066ffb2c3c0SRemy Bruno .count = ARRAY_SIZE(hdspm_aes32_sample_rates), 6067ffb2c3c0SRemy Bruno .list = hdspm_aes32_sample_rates, 6068ffb2c3c0SRemy Bruno .mask = 0 6069ffb2c3c0SRemy Bruno }; 6070ffb2c3c0SRemy Bruno 607198274f07STakashi Iwai static int snd_hdspm_playback_open(struct snd_pcm_substream *substream) 6072763f356cSTakashi Iwai { 607398274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 607498274f07STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 6075763f356cSTakashi Iwai 6076763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 6077763f356cSTakashi Iwai 6078763f356cSTakashi Iwai snd_pcm_set_sync(substream); 6079763f356cSTakashi Iwai 60800dca1793SAdrian Knoth 6081763f356cSTakashi Iwai runtime->hw = snd_hdspm_playback_subinfo; 6082763f356cSTakashi Iwai 6083763f356cSTakashi Iwai if (hdspm->capture_substream == NULL) 6084763f356cSTakashi Iwai hdspm_stop_audio(hdspm); 6085763f356cSTakashi Iwai 6086763f356cSTakashi Iwai hdspm->playback_pid = current->pid; 6087763f356cSTakashi Iwai hdspm->playback_substream = substream; 6088763f356cSTakashi Iwai 6089763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 6090763f356cSTakashi Iwai 6091763f356cSTakashi Iwai snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 6092d877681dSTakashi Iwai snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 6093763f356cSTakashi Iwai 60940dca1793SAdrian Knoth switch (hdspm->io_type) { 60950dca1793SAdrian Knoth case AIO: 60960dca1793SAdrian Knoth case RayDAT: 6097d877681dSTakashi Iwai snd_pcm_hw_constraint_minmax(runtime, 6098763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 6099d877681dSTakashi Iwai 32, 4096); 6100d877681dSTakashi Iwai /* RayDAT & AIO have a fixed buffer of 16384 samples per channel */ 6101d877681dSTakashi Iwai snd_pcm_hw_constraint_minmax(runtime, 61020dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 6103d877681dSTakashi Iwai 16384, 16384); 61040dca1793SAdrian Knoth break; 61050dca1793SAdrian Knoth 61060dca1793SAdrian Knoth default: 6107d877681dSTakashi Iwai snd_pcm_hw_constraint_minmax(runtime, 61080dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 6109d877681dSTakashi Iwai 64, 8192); 6110d877681dSTakashi Iwai break; 61110dca1793SAdrian Knoth } 61120dca1793SAdrian Knoth 61130dca1793SAdrian Knoth if (AES32 == hdspm->io_type) { 61143fa9e3d2STakashi Iwai runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; 6115ffb2c3c0SRemy Bruno snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 6116ffb2c3c0SRemy Bruno &hdspm_hw_constraints_aes32_sample_rates); 6117ffb2c3c0SRemy Bruno } else { 6118763f356cSTakashi Iwai snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 61190dca1793SAdrian Knoth snd_hdspm_hw_rule_rate_out_channels, hdspm, 6120763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_CHANNELS, -1); 6121ffb2c3c0SRemy Bruno } 612288fabbfcSAdrian Knoth 612388fabbfcSAdrian Knoth snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 612488fabbfcSAdrian Knoth snd_hdspm_hw_rule_out_channels, hdspm, 612588fabbfcSAdrian Knoth SNDRV_PCM_HW_PARAM_CHANNELS, -1); 612688fabbfcSAdrian Knoth 612788fabbfcSAdrian Knoth snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 612888fabbfcSAdrian Knoth snd_hdspm_hw_rule_out_channels_rate, hdspm, 612988fabbfcSAdrian Knoth SNDRV_PCM_HW_PARAM_RATE, -1); 613088fabbfcSAdrian Knoth 6131763f356cSTakashi Iwai return 0; 6132763f356cSTakashi Iwai } 6133763f356cSTakashi Iwai 613498274f07STakashi Iwai static int snd_hdspm_playback_release(struct snd_pcm_substream *substream) 6135763f356cSTakashi Iwai { 613698274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 6137763f356cSTakashi Iwai 6138763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 6139763f356cSTakashi Iwai 6140763f356cSTakashi Iwai hdspm->playback_pid = -1; 6141763f356cSTakashi Iwai hdspm->playback_substream = NULL; 6142763f356cSTakashi Iwai 6143763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 6144763f356cSTakashi Iwai 6145763f356cSTakashi Iwai return 0; 6146763f356cSTakashi Iwai } 6147763f356cSTakashi Iwai 6148763f356cSTakashi Iwai 614998274f07STakashi Iwai static int snd_hdspm_capture_open(struct snd_pcm_substream *substream) 6150763f356cSTakashi Iwai { 615198274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 615298274f07STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 6153763f356cSTakashi Iwai 6154763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 6155763f356cSTakashi Iwai snd_pcm_set_sync(substream); 6156763f356cSTakashi Iwai runtime->hw = snd_hdspm_capture_subinfo; 6157763f356cSTakashi Iwai 6158763f356cSTakashi Iwai if (hdspm->playback_substream == NULL) 6159763f356cSTakashi Iwai hdspm_stop_audio(hdspm); 6160763f356cSTakashi Iwai 6161763f356cSTakashi Iwai hdspm->capture_pid = current->pid; 6162763f356cSTakashi Iwai hdspm->capture_substream = substream; 6163763f356cSTakashi Iwai 6164763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 6165763f356cSTakashi Iwai 6166763f356cSTakashi Iwai snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 6167d877681dSTakashi Iwai snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 6168d877681dSTakashi Iwai 61690dca1793SAdrian Knoth switch (hdspm->io_type) { 61700dca1793SAdrian Knoth case AIO: 61710dca1793SAdrian Knoth case RayDAT: 6172d877681dSTakashi Iwai snd_pcm_hw_constraint_minmax(runtime, 6173763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 6174d877681dSTakashi Iwai 32, 4096); 6175d877681dSTakashi Iwai snd_pcm_hw_constraint_minmax(runtime, 61760dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 6177d877681dSTakashi Iwai 16384, 16384); 61780dca1793SAdrian Knoth break; 61790dca1793SAdrian Knoth 61800dca1793SAdrian Knoth default: 6181d877681dSTakashi Iwai snd_pcm_hw_constraint_minmax(runtime, 61820dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 6183d877681dSTakashi Iwai 64, 8192); 6184d877681dSTakashi Iwai break; 61850dca1793SAdrian Knoth } 61860dca1793SAdrian Knoth 61870dca1793SAdrian Knoth if (AES32 == hdspm->io_type) { 61883fa9e3d2STakashi Iwai runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; 6189ffb2c3c0SRemy Bruno snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 6190ffb2c3c0SRemy Bruno &hdspm_hw_constraints_aes32_sample_rates); 6191ffb2c3c0SRemy Bruno } else { 6192763f356cSTakashi Iwai snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 61930dca1793SAdrian Knoth snd_hdspm_hw_rule_rate_in_channels, hdspm, 6194763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_CHANNELS, -1); 6195ffb2c3c0SRemy Bruno } 619688fabbfcSAdrian Knoth 619788fabbfcSAdrian Knoth snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 619888fabbfcSAdrian Knoth snd_hdspm_hw_rule_in_channels, hdspm, 619988fabbfcSAdrian Knoth SNDRV_PCM_HW_PARAM_CHANNELS, -1); 620088fabbfcSAdrian Knoth 620188fabbfcSAdrian Knoth snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 620288fabbfcSAdrian Knoth snd_hdspm_hw_rule_in_channels_rate, hdspm, 620388fabbfcSAdrian Knoth SNDRV_PCM_HW_PARAM_RATE, -1); 620488fabbfcSAdrian Knoth 6205763f356cSTakashi Iwai return 0; 6206763f356cSTakashi Iwai } 6207763f356cSTakashi Iwai 620898274f07STakashi Iwai static int snd_hdspm_capture_release(struct snd_pcm_substream *substream) 6209763f356cSTakashi Iwai { 621098274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 6211763f356cSTakashi Iwai 6212763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 6213763f356cSTakashi Iwai 6214763f356cSTakashi Iwai hdspm->capture_pid = -1; 6215763f356cSTakashi Iwai hdspm->capture_substream = NULL; 6216763f356cSTakashi Iwai 6217763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 6218763f356cSTakashi Iwai return 0; 6219763f356cSTakashi Iwai } 6220763f356cSTakashi Iwai 62210dca1793SAdrian Knoth static int snd_hdspm_hwdep_dummy_op(struct snd_hwdep *hw, struct file *file) 6222763f356cSTakashi Iwai { 62230dca1793SAdrian Knoth /* we have nothing to initialize but the call is required */ 62240dca1793SAdrian Knoth return 0; 62250dca1793SAdrian Knoth } 62260dca1793SAdrian Knoth 62270dca1793SAdrian Knoth static inline int copy_u32_le(void __user *dest, void __iomem *src) 62280dca1793SAdrian Knoth { 62290dca1793SAdrian Knoth u32 val = readl(src); 62300dca1793SAdrian Knoth return copy_to_user(dest, &val, 4); 62310dca1793SAdrian Knoth } 62320dca1793SAdrian Knoth 62330dca1793SAdrian Knoth static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, 62342ca595abSDan Carpenter unsigned int cmd, unsigned long arg) 62350dca1793SAdrian Knoth { 62360dca1793SAdrian Knoth void __user *argp = (void __user *)arg; 6237ef5fa1a4STakashi Iwai struct hdspm *hdspm = hw->private_data; 623898274f07STakashi Iwai struct hdspm_mixer_ioctl mixer; 62390dca1793SAdrian Knoth struct hdspm_config info; 62400dca1793SAdrian Knoth struct hdspm_status status; 624198274f07STakashi Iwai struct hdspm_version hdspm_version; 6242730a5865SJaroslav Kysela struct hdspm_peak_rms *levels; 62430dca1793SAdrian Knoth struct hdspm_ltc ltc; 62440dca1793SAdrian Knoth unsigned int statusregister; 62450dca1793SAdrian Knoth long unsigned int s; 62460dca1793SAdrian Knoth int i = 0; 6247763f356cSTakashi Iwai 6248763f356cSTakashi Iwai switch (cmd) { 6249763f356cSTakashi Iwai 6250763f356cSTakashi Iwai case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS: 6251730a5865SJaroslav Kysela levels = &hdspm->peak_rms; 62520dca1793SAdrian Knoth for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { 6253730a5865SJaroslav Kysela levels->input_peaks[i] = 62540dca1793SAdrian Knoth readl(hdspm->iobase + 62550dca1793SAdrian Knoth HDSPM_MADI_INPUT_PEAK + i*4); 6256730a5865SJaroslav Kysela levels->playback_peaks[i] = 62570dca1793SAdrian Knoth readl(hdspm->iobase + 62580dca1793SAdrian Knoth HDSPM_MADI_PLAYBACK_PEAK + i*4); 6259730a5865SJaroslav Kysela levels->output_peaks[i] = 62600dca1793SAdrian Knoth readl(hdspm->iobase + 62610dca1793SAdrian Knoth HDSPM_MADI_OUTPUT_PEAK + i*4); 62620dca1793SAdrian Knoth 6263730a5865SJaroslav Kysela levels->input_rms[i] = 62640dca1793SAdrian Knoth ((uint64_t) readl(hdspm->iobase + 62650dca1793SAdrian Knoth HDSPM_MADI_INPUT_RMS_H + i*4) << 32) | 62660dca1793SAdrian Knoth (uint64_t) readl(hdspm->iobase + 62670dca1793SAdrian Knoth HDSPM_MADI_INPUT_RMS_L + i*4); 6268730a5865SJaroslav Kysela levels->playback_rms[i] = 62690dca1793SAdrian Knoth ((uint64_t)readl(hdspm->iobase + 62700dca1793SAdrian Knoth HDSPM_MADI_PLAYBACK_RMS_H+i*4) << 32) | 62710dca1793SAdrian Knoth (uint64_t)readl(hdspm->iobase + 62720dca1793SAdrian Knoth HDSPM_MADI_PLAYBACK_RMS_L + i*4); 6273730a5865SJaroslav Kysela levels->output_rms[i] = 62740dca1793SAdrian Knoth ((uint64_t)readl(hdspm->iobase + 62750dca1793SAdrian Knoth HDSPM_MADI_OUTPUT_RMS_H + i*4) << 32) | 62760dca1793SAdrian Knoth (uint64_t)readl(hdspm->iobase + 62770dca1793SAdrian Knoth HDSPM_MADI_OUTPUT_RMS_L + i*4); 62780dca1793SAdrian Knoth } 62790dca1793SAdrian Knoth 62800dca1793SAdrian Knoth if (hdspm->system_sample_rate > 96000) { 6281730a5865SJaroslav Kysela levels->speed = qs; 62820dca1793SAdrian Knoth } else if (hdspm->system_sample_rate > 48000) { 6283730a5865SJaroslav Kysela levels->speed = ds; 62840dca1793SAdrian Knoth } else { 6285730a5865SJaroslav Kysela levels->speed = ss; 62860dca1793SAdrian Knoth } 6287730a5865SJaroslav Kysela levels->status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 62880dca1793SAdrian Knoth 6289730a5865SJaroslav Kysela s = copy_to_user(argp, levels, sizeof(struct hdspm_peak_rms)); 62900dca1793SAdrian Knoth if (0 != s) { 62910dca1793SAdrian Knoth /* snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu 62920dca1793SAdrian Knoth [Levels]\n", sizeof(struct hdspm_peak_rms), s); 6293ef5fa1a4STakashi Iwai */ 6294763f356cSTakashi Iwai return -EFAULT; 62950dca1793SAdrian Knoth } 62960dca1793SAdrian Knoth break; 62970dca1793SAdrian Knoth 62980dca1793SAdrian Knoth case SNDRV_HDSPM_IOCTL_GET_LTC: 62990dca1793SAdrian Knoth ltc.ltc = hdspm_read(hdspm, HDSPM_RD_TCO); 63000dca1793SAdrian Knoth i = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 63010dca1793SAdrian Knoth if (i & HDSPM_TCO1_LTC_Input_valid) { 63020dca1793SAdrian Knoth switch (i & (HDSPM_TCO1_LTC_Format_LSB | 63030dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB)) { 63040dca1793SAdrian Knoth case 0: 63050dca1793SAdrian Knoth ltc.format = fps_24; 63060dca1793SAdrian Knoth break; 63070dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_LSB: 63080dca1793SAdrian Knoth ltc.format = fps_25; 63090dca1793SAdrian Knoth break; 63100dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_MSB: 63110dca1793SAdrian Knoth ltc.format = fps_2997; 63120dca1793SAdrian Knoth break; 63130dca1793SAdrian Knoth default: 63140dca1793SAdrian Knoth ltc.format = 30; 63150dca1793SAdrian Knoth break; 63160dca1793SAdrian Knoth } 63170dca1793SAdrian Knoth if (i & HDSPM_TCO1_set_drop_frame_flag) { 63180dca1793SAdrian Knoth ltc.frame = drop_frame; 63190dca1793SAdrian Knoth } else { 63200dca1793SAdrian Knoth ltc.frame = full_frame; 63210dca1793SAdrian Knoth } 63220dca1793SAdrian Knoth } else { 63230dca1793SAdrian Knoth ltc.format = format_invalid; 63240dca1793SAdrian Knoth ltc.frame = frame_invalid; 63250dca1793SAdrian Knoth } 63260dca1793SAdrian Knoth if (i & HDSPM_TCO1_Video_Input_Format_NTSC) { 63270dca1793SAdrian Knoth ltc.input_format = ntsc; 63280dca1793SAdrian Knoth } else if (i & HDSPM_TCO1_Video_Input_Format_PAL) { 63290dca1793SAdrian Knoth ltc.input_format = pal; 63300dca1793SAdrian Knoth } else { 63310dca1793SAdrian Knoth ltc.input_format = no_video; 63320dca1793SAdrian Knoth } 63330dca1793SAdrian Knoth 63340dca1793SAdrian Knoth s = copy_to_user(argp, <c, sizeof(struct hdspm_ltc)); 63350dca1793SAdrian Knoth if (0 != s) { 63360dca1793SAdrian Knoth /* 63370dca1793SAdrian Knoth snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */ 63380dca1793SAdrian Knoth return -EFAULT; 63390dca1793SAdrian Knoth } 6340763f356cSTakashi Iwai 6341763f356cSTakashi Iwai break; 6342763f356cSTakashi Iwai 63430dca1793SAdrian Knoth case SNDRV_HDSPM_IOCTL_GET_CONFIG: 6344763f356cSTakashi Iwai 63454ab69a2bSAdrian Knoth memset(&info, 0, sizeof(info)); 6346763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 6347ef5fa1a4STakashi Iwai info.pref_sync_ref = hdspm_pref_sync_ref(hdspm); 6348ef5fa1a4STakashi Iwai info.wordclock_sync_check = hdspm_wc_sync_check(hdspm); 6349763f356cSTakashi Iwai 6350763f356cSTakashi Iwai info.system_sample_rate = hdspm->system_sample_rate; 6351763f356cSTakashi Iwai info.autosync_sample_rate = 6352763f356cSTakashi Iwai hdspm_external_sample_rate(hdspm); 6353ef5fa1a4STakashi Iwai info.system_clock_mode = hdspm_system_clock_mode(hdspm); 6354ef5fa1a4STakashi Iwai info.clock_source = hdspm_clock_source(hdspm); 6355ef5fa1a4STakashi Iwai info.autosync_ref = hdspm_autosync_ref(hdspm); 6356c9e1668cSAdrian Knoth info.line_out = hdspm_toggle_setting(hdspm, HDSPM_LineOut); 6357763f356cSTakashi Iwai info.passthru = 0; 6358763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 63592ca595abSDan Carpenter if (copy_to_user(argp, &info, sizeof(info))) 6360763f356cSTakashi Iwai return -EFAULT; 6361763f356cSTakashi Iwai break; 6362763f356cSTakashi Iwai 63630dca1793SAdrian Knoth case SNDRV_HDSPM_IOCTL_GET_STATUS: 6364643d6bbbSDan Carpenter memset(&status, 0, sizeof(status)); 6365643d6bbbSDan Carpenter 63660dca1793SAdrian Knoth status.card_type = hdspm->io_type; 63670dca1793SAdrian Knoth 63680dca1793SAdrian Knoth status.autosync_source = hdspm_autosync_ref(hdspm); 63690dca1793SAdrian Knoth 63700dca1793SAdrian Knoth status.card_clock = 110069313433624ULL; 63710dca1793SAdrian Knoth status.master_period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 63720dca1793SAdrian Knoth 63730dca1793SAdrian Knoth switch (hdspm->io_type) { 63740dca1793SAdrian Knoth case MADI: 63750dca1793SAdrian Knoth case MADIface: 63760dca1793SAdrian Knoth status.card_specific.madi.sync_wc = 63770dca1793SAdrian Knoth hdspm_wc_sync_check(hdspm); 63780dca1793SAdrian Knoth status.card_specific.madi.sync_madi = 63790dca1793SAdrian Knoth hdspm_madi_sync_check(hdspm); 63800dca1793SAdrian Knoth status.card_specific.madi.sync_tco = 63810dca1793SAdrian Knoth hdspm_tco_sync_check(hdspm); 63820dca1793SAdrian Knoth status.card_specific.madi.sync_in = 63830dca1793SAdrian Knoth hdspm_sync_in_sync_check(hdspm); 63840dca1793SAdrian Knoth 63850dca1793SAdrian Knoth statusregister = 63860dca1793SAdrian Knoth hdspm_read(hdspm, HDSPM_statusRegister); 63870dca1793SAdrian Knoth status.card_specific.madi.madi_input = 63880dca1793SAdrian Knoth (statusregister & HDSPM_AB_int) ? 1 : 0; 63890dca1793SAdrian Knoth status.card_specific.madi.channel_format = 63909e6ff520SAdrian Knoth (statusregister & HDSPM_RX_64ch) ? 1 : 0; 63910dca1793SAdrian Knoth /* TODO: Mac driver sets it when f_s>48kHz */ 63920dca1793SAdrian Knoth status.card_specific.madi.frame_format = 0; 63930dca1793SAdrian Knoth 63940dca1793SAdrian Knoth default: 63950dca1793SAdrian Knoth break; 63960dca1793SAdrian Knoth } 63970dca1793SAdrian Knoth 63982ca595abSDan Carpenter if (copy_to_user(argp, &status, sizeof(status))) 63990dca1793SAdrian Knoth return -EFAULT; 64000dca1793SAdrian Knoth 64010dca1793SAdrian Knoth 64020dca1793SAdrian Knoth break; 64030dca1793SAdrian Knoth 6404763f356cSTakashi Iwai case SNDRV_HDSPM_IOCTL_GET_VERSION: 6405643d6bbbSDan Carpenter memset(&hdspm_version, 0, sizeof(hdspm_version)); 6406643d6bbbSDan Carpenter 64070dca1793SAdrian Knoth hdspm_version.card_type = hdspm->io_type; 64080dca1793SAdrian Knoth strncpy(hdspm_version.cardname, hdspm->card_name, 64090dca1793SAdrian Knoth sizeof(hdspm_version.cardname)); 64107d53a631SAdrian Knoth hdspm_version.serial = hdspm->serial; 6411763f356cSTakashi Iwai hdspm_version.firmware_rev = hdspm->firmware_rev; 64120dca1793SAdrian Knoth hdspm_version.addons = 0; 64130dca1793SAdrian Knoth if (hdspm->tco) 64140dca1793SAdrian Knoth hdspm_version.addons |= HDSPM_ADDON_TCO; 64150dca1793SAdrian Knoth 64162ca595abSDan Carpenter if (copy_to_user(argp, &hdspm_version, 6417763f356cSTakashi Iwai sizeof(hdspm_version))) 6418763f356cSTakashi Iwai return -EFAULT; 6419763f356cSTakashi Iwai break; 6420763f356cSTakashi Iwai 6421763f356cSTakashi Iwai case SNDRV_HDSPM_IOCTL_GET_MIXER: 64222ca595abSDan Carpenter if (copy_from_user(&mixer, argp, sizeof(mixer))) 6423763f356cSTakashi Iwai return -EFAULT; 6424ef5fa1a4STakashi Iwai if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer, 6425ef5fa1a4STakashi Iwai sizeof(struct hdspm_mixer))) 6426763f356cSTakashi Iwai return -EFAULT; 6427763f356cSTakashi Iwai break; 6428763f356cSTakashi Iwai 6429763f356cSTakashi Iwai default: 6430763f356cSTakashi Iwai return -EINVAL; 6431763f356cSTakashi Iwai } 6432763f356cSTakashi Iwai return 0; 6433763f356cSTakashi Iwai } 6434763f356cSTakashi Iwai 643598274f07STakashi Iwai static struct snd_pcm_ops snd_hdspm_playback_ops = { 6436763f356cSTakashi Iwai .open = snd_hdspm_playback_open, 6437763f356cSTakashi Iwai .close = snd_hdspm_playback_release, 6438763f356cSTakashi Iwai .ioctl = snd_hdspm_ioctl, 6439763f356cSTakashi Iwai .hw_params = snd_hdspm_hw_params, 6440763f356cSTakashi Iwai .hw_free = snd_hdspm_hw_free, 6441763f356cSTakashi Iwai .prepare = snd_hdspm_prepare, 6442763f356cSTakashi Iwai .trigger = snd_hdspm_trigger, 6443763f356cSTakashi Iwai .pointer = snd_hdspm_hw_pointer, 6444763f356cSTakashi Iwai .page = snd_pcm_sgbuf_ops_page, 6445763f356cSTakashi Iwai }; 6446763f356cSTakashi Iwai 644798274f07STakashi Iwai static struct snd_pcm_ops snd_hdspm_capture_ops = { 6448763f356cSTakashi Iwai .open = snd_hdspm_capture_open, 6449763f356cSTakashi Iwai .close = snd_hdspm_capture_release, 6450763f356cSTakashi Iwai .ioctl = snd_hdspm_ioctl, 6451763f356cSTakashi Iwai .hw_params = snd_hdspm_hw_params, 6452763f356cSTakashi Iwai .hw_free = snd_hdspm_hw_free, 6453763f356cSTakashi Iwai .prepare = snd_hdspm_prepare, 6454763f356cSTakashi Iwai .trigger = snd_hdspm_trigger, 6455763f356cSTakashi Iwai .pointer = snd_hdspm_hw_pointer, 6456763f356cSTakashi Iwai .page = snd_pcm_sgbuf_ops_page, 6457763f356cSTakashi Iwai }; 6458763f356cSTakashi Iwai 6459e23e7a14SBill Pemberton static int snd_hdspm_create_hwdep(struct snd_card *card, 646098274f07STakashi Iwai struct hdspm *hdspm) 6461763f356cSTakashi Iwai { 646298274f07STakashi Iwai struct snd_hwdep *hw; 6463763f356cSTakashi Iwai int err; 6464763f356cSTakashi Iwai 6465ef5fa1a4STakashi Iwai err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw); 6466ef5fa1a4STakashi Iwai if (err < 0) 6467763f356cSTakashi Iwai return err; 6468763f356cSTakashi Iwai 6469763f356cSTakashi Iwai hdspm->hwdep = hw; 6470763f356cSTakashi Iwai hw->private_data = hdspm; 6471763f356cSTakashi Iwai strcpy(hw->name, "HDSPM hwdep interface"); 6472763f356cSTakashi Iwai 64730dca1793SAdrian Knoth hw->ops.open = snd_hdspm_hwdep_dummy_op; 6474763f356cSTakashi Iwai hw->ops.ioctl = snd_hdspm_hwdep_ioctl; 64758de5d6f1SAdrian Knoth hw->ops.ioctl_compat = snd_hdspm_hwdep_ioctl; 64760dca1793SAdrian Knoth hw->ops.release = snd_hdspm_hwdep_dummy_op; 6477763f356cSTakashi Iwai 6478763f356cSTakashi Iwai return 0; 6479763f356cSTakashi Iwai } 6480763f356cSTakashi Iwai 6481763f356cSTakashi Iwai 6482763f356cSTakashi Iwai /*------------------------------------------------------------ 6483763f356cSTakashi Iwai memory interface 6484763f356cSTakashi Iwai ------------------------------------------------------------*/ 6485e23e7a14SBill Pemberton static int snd_hdspm_preallocate_memory(struct hdspm *hdspm) 6486763f356cSTakashi Iwai { 6487763f356cSTakashi Iwai int err; 648898274f07STakashi Iwai struct snd_pcm *pcm; 6489763f356cSTakashi Iwai size_t wanted; 6490763f356cSTakashi Iwai 6491763f356cSTakashi Iwai pcm = hdspm->pcm; 6492763f356cSTakashi Iwai 64933cee5a60SRemy Bruno wanted = HDSPM_DMA_AREA_BYTES; 6494763f356cSTakashi Iwai 6495ef5fa1a4STakashi Iwai err = 6496763f356cSTakashi Iwai snd_pcm_lib_preallocate_pages_for_all(pcm, 6497763f356cSTakashi Iwai SNDRV_DMA_TYPE_DEV_SG, 6498763f356cSTakashi Iwai snd_dma_pci_data(hdspm->pci), 6499763f356cSTakashi Iwai wanted, 6500ef5fa1a4STakashi Iwai wanted); 6501ef5fa1a4STakashi Iwai if (err < 0) { 6502e2eba3e7SAndrew Morton snd_printdd("Could not preallocate %zd Bytes\n", wanted); 6503763f356cSTakashi Iwai 6504763f356cSTakashi Iwai return err; 6505763f356cSTakashi Iwai } else 6506e2eba3e7SAndrew Morton snd_printdd(" Preallocated %zd Bytes\n", wanted); 6507763f356cSTakashi Iwai 6508763f356cSTakashi Iwai return 0; 6509763f356cSTakashi Iwai } 6510763f356cSTakashi Iwai 65110dca1793SAdrian Knoth 651277a23f26STakashi Iwai static void hdspm_set_sgbuf(struct hdspm *hdspm, 651377a23f26STakashi Iwai struct snd_pcm_substream *substream, 6514763f356cSTakashi Iwai unsigned int reg, int channels) 6515763f356cSTakashi Iwai { 6516763f356cSTakashi Iwai int i; 65170dca1793SAdrian Knoth 65180dca1793SAdrian Knoth /* continuous memory segment */ 6519763f356cSTakashi Iwai for (i = 0; i < (channels * 16); i++) 6520763f356cSTakashi Iwai hdspm_write(hdspm, reg + 4 * i, 652177a23f26STakashi Iwai snd_pcm_sgbuf_get_addr(substream, 4096 * i)); 6522763f356cSTakashi Iwai } 6523763f356cSTakashi Iwai 65240dca1793SAdrian Knoth 6525763f356cSTakashi Iwai /* ------------- ALSA Devices ---------------------------- */ 6526e23e7a14SBill Pemberton static int snd_hdspm_create_pcm(struct snd_card *card, 652798274f07STakashi Iwai struct hdspm *hdspm) 6528763f356cSTakashi Iwai { 652998274f07STakashi Iwai struct snd_pcm *pcm; 6530763f356cSTakashi Iwai int err; 6531763f356cSTakashi Iwai 6532ef5fa1a4STakashi Iwai err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm); 6533ef5fa1a4STakashi Iwai if (err < 0) 6534763f356cSTakashi Iwai return err; 6535763f356cSTakashi Iwai 6536763f356cSTakashi Iwai hdspm->pcm = pcm; 6537763f356cSTakashi Iwai pcm->private_data = hdspm; 6538763f356cSTakashi Iwai strcpy(pcm->name, hdspm->card_name); 6539763f356cSTakashi Iwai 6540763f356cSTakashi Iwai snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 6541763f356cSTakashi Iwai &snd_hdspm_playback_ops); 6542763f356cSTakashi Iwai snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 6543763f356cSTakashi Iwai &snd_hdspm_capture_ops); 6544763f356cSTakashi Iwai 6545763f356cSTakashi Iwai pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; 6546763f356cSTakashi Iwai 6547ef5fa1a4STakashi Iwai err = snd_hdspm_preallocate_memory(hdspm); 6548ef5fa1a4STakashi Iwai if (err < 0) 6549763f356cSTakashi Iwai return err; 6550763f356cSTakashi Iwai 6551763f356cSTakashi Iwai return 0; 6552763f356cSTakashi Iwai } 6553763f356cSTakashi Iwai 655498274f07STakashi Iwai static inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm) 6555763f356cSTakashi Iwai { 65567c7102b7SAdrian Knoth int i; 65577c7102b7SAdrian Knoth 65587c7102b7SAdrian Knoth for (i = 0; i < hdspm->midiPorts; i++) 65597c7102b7SAdrian Knoth snd_hdspm_flush_midi_input(hdspm, i); 6560763f356cSTakashi Iwai } 6561763f356cSTakashi Iwai 6562e23e7a14SBill Pemberton static int snd_hdspm_create_alsa_devices(struct snd_card *card, 656398274f07STakashi Iwai struct hdspm *hdspm) 6564763f356cSTakashi Iwai { 65650dca1793SAdrian Knoth int err, i; 6566763f356cSTakashi Iwai 6567763f356cSTakashi Iwai snd_printdd("Create card...\n"); 6568ef5fa1a4STakashi Iwai err = snd_hdspm_create_pcm(card, hdspm); 6569ef5fa1a4STakashi Iwai if (err < 0) 6570763f356cSTakashi Iwai return err; 6571763f356cSTakashi Iwai 65720dca1793SAdrian Knoth i = 0; 65730dca1793SAdrian Knoth while (i < hdspm->midiPorts) { 65740dca1793SAdrian Knoth err = snd_hdspm_create_midi(card, hdspm, i); 65750dca1793SAdrian Knoth if (err < 0) { 6576763f356cSTakashi Iwai return err; 65770dca1793SAdrian Knoth } 65780dca1793SAdrian Knoth i++; 65790dca1793SAdrian Knoth } 6580763f356cSTakashi Iwai 6581ef5fa1a4STakashi Iwai err = snd_hdspm_create_controls(card, hdspm); 6582ef5fa1a4STakashi Iwai if (err < 0) 6583763f356cSTakashi Iwai return err; 6584763f356cSTakashi Iwai 6585ef5fa1a4STakashi Iwai err = snd_hdspm_create_hwdep(card, hdspm); 6586ef5fa1a4STakashi Iwai if (err < 0) 6587763f356cSTakashi Iwai return err; 6588763f356cSTakashi Iwai 6589763f356cSTakashi Iwai snd_printdd("proc init...\n"); 6590763f356cSTakashi Iwai snd_hdspm_proc_init(hdspm); 6591763f356cSTakashi Iwai 6592763f356cSTakashi Iwai hdspm->system_sample_rate = -1; 6593763f356cSTakashi Iwai hdspm->last_external_sample_rate = -1; 6594763f356cSTakashi Iwai hdspm->last_internal_sample_rate = -1; 6595763f356cSTakashi Iwai hdspm->playback_pid = -1; 6596763f356cSTakashi Iwai hdspm->capture_pid = -1; 6597763f356cSTakashi Iwai hdspm->capture_substream = NULL; 6598763f356cSTakashi Iwai hdspm->playback_substream = NULL; 6599763f356cSTakashi Iwai 6600763f356cSTakashi Iwai snd_printdd("Set defaults...\n"); 6601ef5fa1a4STakashi Iwai err = snd_hdspm_set_defaults(hdspm); 6602ef5fa1a4STakashi Iwai if (err < 0) 6603763f356cSTakashi Iwai return err; 6604763f356cSTakashi Iwai 6605763f356cSTakashi Iwai snd_printdd("Update mixer controls...\n"); 6606763f356cSTakashi Iwai hdspm_update_simple_mixer_controls(hdspm); 6607763f356cSTakashi Iwai 6608763f356cSTakashi Iwai snd_printdd("Initializeing complete ???\n"); 6609763f356cSTakashi Iwai 6610ef5fa1a4STakashi Iwai err = snd_card_register(card); 6611ef5fa1a4STakashi Iwai if (err < 0) { 6612763f356cSTakashi Iwai snd_printk(KERN_ERR "HDSPM: error registering card\n"); 6613763f356cSTakashi Iwai return err; 6614763f356cSTakashi Iwai } 6615763f356cSTakashi Iwai 6616763f356cSTakashi Iwai snd_printdd("... yes now\n"); 6617763f356cSTakashi Iwai 6618763f356cSTakashi Iwai return 0; 6619763f356cSTakashi Iwai } 6620763f356cSTakashi Iwai 6621e23e7a14SBill Pemberton static int snd_hdspm_create(struct snd_card *card, 6622e23e7a14SBill Pemberton struct hdspm *hdspm) 6623e23e7a14SBill Pemberton { 66240dca1793SAdrian Knoth 6625763f356cSTakashi Iwai struct pci_dev *pci = hdspm->pci; 6626763f356cSTakashi Iwai int err; 6627763f356cSTakashi Iwai unsigned long io_extent; 6628763f356cSTakashi Iwai 6629763f356cSTakashi Iwai hdspm->irq = -1; 6630763f356cSTakashi Iwai hdspm->card = card; 6631763f356cSTakashi Iwai 6632763f356cSTakashi Iwai spin_lock_init(&hdspm->lock); 6633763f356cSTakashi Iwai 6634763f356cSTakashi Iwai pci_read_config_word(hdspm->pci, 6635763f356cSTakashi Iwai PCI_CLASS_REVISION, &hdspm->firmware_rev); 6636763f356cSTakashi Iwai 6637763f356cSTakashi Iwai strcpy(card->mixername, "Xilinx FPGA"); 66383cee5a60SRemy Bruno strcpy(card->driver, "HDSPM"); 66390dca1793SAdrian Knoth 66400dca1793SAdrian Knoth switch (hdspm->firmware_rev) { 66410dca1793SAdrian Knoth case HDSPM_RAYDAT_REV: 66420dca1793SAdrian Knoth hdspm->io_type = RayDAT; 66430dca1793SAdrian Knoth hdspm->card_name = "RME RayDAT"; 66440dca1793SAdrian Knoth hdspm->midiPorts = 2; 66450dca1793SAdrian Knoth break; 66460dca1793SAdrian Knoth case HDSPM_AIO_REV: 66470dca1793SAdrian Knoth hdspm->io_type = AIO; 66480dca1793SAdrian Knoth hdspm->card_name = "RME AIO"; 66490dca1793SAdrian Knoth hdspm->midiPorts = 1; 66500dca1793SAdrian Knoth break; 66510dca1793SAdrian Knoth case HDSPM_MADIFACE_REV: 66520dca1793SAdrian Knoth hdspm->io_type = MADIface; 66530dca1793SAdrian Knoth hdspm->card_name = "RME MADIface"; 66540dca1793SAdrian Knoth hdspm->midiPorts = 1; 66550dca1793SAdrian Knoth break; 6656c09403dcSAdrian Knoth default: 6657c09403dcSAdrian Knoth if ((hdspm->firmware_rev == 0xf0) || 6658c09403dcSAdrian Knoth ((hdspm->firmware_rev >= 0xe6) && 6659c09403dcSAdrian Knoth (hdspm->firmware_rev <= 0xea))) { 66600dca1793SAdrian Knoth hdspm->io_type = AES32; 66610dca1793SAdrian Knoth hdspm->card_name = "RME AES32"; 66620dca1793SAdrian Knoth hdspm->midiPorts = 2; 666305c7cc9cSAdrian Knoth } else if ((hdspm->firmware_rev == 0xd2) || 6664c09403dcSAdrian Knoth ((hdspm->firmware_rev >= 0xc8) && 6665c09403dcSAdrian Knoth (hdspm->firmware_rev <= 0xcf))) { 6666c09403dcSAdrian Knoth hdspm->io_type = MADI; 6667c09403dcSAdrian Knoth hdspm->card_name = "RME MADI"; 6668c09403dcSAdrian Knoth hdspm->midiPorts = 3; 6669c09403dcSAdrian Knoth } else { 6670c09403dcSAdrian Knoth snd_printk(KERN_ERR 6671c09403dcSAdrian Knoth "HDSPM: unknown firmware revision %x\n", 66725027f347SAdrian Knoth hdspm->firmware_rev); 66735027f347SAdrian Knoth return -ENODEV; 66743cee5a60SRemy Bruno } 6675c09403dcSAdrian Knoth } 6676763f356cSTakashi Iwai 6677ef5fa1a4STakashi Iwai err = pci_enable_device(pci); 6678ef5fa1a4STakashi Iwai if (err < 0) 6679763f356cSTakashi Iwai return err; 6680763f356cSTakashi Iwai 6681763f356cSTakashi Iwai pci_set_master(hdspm->pci); 6682763f356cSTakashi Iwai 6683ef5fa1a4STakashi Iwai err = pci_request_regions(pci, "hdspm"); 6684ef5fa1a4STakashi Iwai if (err < 0) 6685763f356cSTakashi Iwai return err; 6686763f356cSTakashi Iwai 6687763f356cSTakashi Iwai hdspm->port = pci_resource_start(pci, 0); 6688763f356cSTakashi Iwai io_extent = pci_resource_len(pci, 0); 6689763f356cSTakashi Iwai 6690763f356cSTakashi Iwai snd_printdd("grabbed memory region 0x%lx-0x%lx\n", 6691763f356cSTakashi Iwai hdspm->port, hdspm->port + io_extent - 1); 6692763f356cSTakashi Iwai 6693ef5fa1a4STakashi Iwai hdspm->iobase = ioremap_nocache(hdspm->port, io_extent); 6694ef5fa1a4STakashi Iwai if (!hdspm->iobase) { 6695ef5fa1a4STakashi Iwai snd_printk(KERN_ERR "HDSPM: " 6696ef5fa1a4STakashi Iwai "unable to remap region 0x%lx-0x%lx\n", 6697763f356cSTakashi Iwai hdspm->port, hdspm->port + io_extent - 1); 6698763f356cSTakashi Iwai return -EBUSY; 6699763f356cSTakashi Iwai } 6700763f356cSTakashi Iwai snd_printdd("remapped region (0x%lx) 0x%lx-0x%lx\n", 6701763f356cSTakashi Iwai (unsigned long)hdspm->iobase, hdspm->port, 6702763f356cSTakashi Iwai hdspm->port + io_extent - 1); 6703763f356cSTakashi Iwai 6704763f356cSTakashi Iwai if (request_irq(pci->irq, snd_hdspm_interrupt, 6705934c2b6dSTakashi Iwai IRQF_SHARED, KBUILD_MODNAME, hdspm)) { 6706763f356cSTakashi Iwai snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq); 6707763f356cSTakashi Iwai return -EBUSY; 6708763f356cSTakashi Iwai } 6709763f356cSTakashi Iwai 6710763f356cSTakashi Iwai snd_printdd("use IRQ %d\n", pci->irq); 6711763f356cSTakashi Iwai 6712763f356cSTakashi Iwai hdspm->irq = pci->irq; 6713763f356cSTakashi Iwai 6714e2eba3e7SAndrew Morton snd_printdd("kmalloc Mixer memory of %zd Bytes\n", 671598274f07STakashi Iwai sizeof(struct hdspm_mixer)); 6716ef5fa1a4STakashi Iwai hdspm->mixer = kzalloc(sizeof(struct hdspm_mixer), GFP_KERNEL); 6717ef5fa1a4STakashi Iwai if (!hdspm->mixer) { 6718ef5fa1a4STakashi Iwai snd_printk(KERN_ERR "HDSPM: " 6719ef5fa1a4STakashi Iwai "unable to kmalloc Mixer memory of %d Bytes\n", 672098274f07STakashi Iwai (int)sizeof(struct hdspm_mixer)); 6721b17cbdd8SJulia Lawall return -ENOMEM; 6722763f356cSTakashi Iwai } 6723763f356cSTakashi Iwai 67240dca1793SAdrian Knoth hdspm->port_names_in = NULL; 67250dca1793SAdrian Knoth hdspm->port_names_out = NULL; 67260dca1793SAdrian Knoth 67270dca1793SAdrian Knoth switch (hdspm->io_type) { 67280dca1793SAdrian Knoth case AES32: 6729d2d10a21SAdrian Knoth hdspm->ss_in_channels = hdspm->ss_out_channels = AES32_CHANNELS; 6730d2d10a21SAdrian Knoth hdspm->ds_in_channels = hdspm->ds_out_channels = AES32_CHANNELS; 6731d2d10a21SAdrian Knoth hdspm->qs_in_channels = hdspm->qs_out_channels = AES32_CHANNELS; 6732432d2500SAdrian Knoth 6733432d2500SAdrian Knoth hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 6734432d2500SAdrian Knoth channel_map_aes32; 6735432d2500SAdrian Knoth hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 6736432d2500SAdrian Knoth channel_map_aes32; 6737432d2500SAdrian Knoth hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 6738432d2500SAdrian Knoth channel_map_aes32; 6739432d2500SAdrian Knoth hdspm->port_names_in_ss = hdspm->port_names_out_ss = 6740432d2500SAdrian Knoth texts_ports_aes32; 6741432d2500SAdrian Knoth hdspm->port_names_in_ds = hdspm->port_names_out_ds = 6742432d2500SAdrian Knoth texts_ports_aes32; 6743432d2500SAdrian Knoth hdspm->port_names_in_qs = hdspm->port_names_out_qs = 6744432d2500SAdrian Knoth texts_ports_aes32; 6745432d2500SAdrian Knoth 6746d2d10a21SAdrian Knoth hdspm->max_channels_out = hdspm->max_channels_in = 6747d2d10a21SAdrian Knoth AES32_CHANNELS; 6748432d2500SAdrian Knoth hdspm->port_names_in = hdspm->port_names_out = 6749432d2500SAdrian Knoth texts_ports_aes32; 6750432d2500SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_out = 6751432d2500SAdrian Knoth channel_map_aes32; 6752432d2500SAdrian Knoth 67530dca1793SAdrian Knoth break; 67540dca1793SAdrian Knoth 67550dca1793SAdrian Knoth case MADI: 67560dca1793SAdrian Knoth case MADIface: 67570dca1793SAdrian Knoth hdspm->ss_in_channels = hdspm->ss_out_channels = 67580dca1793SAdrian Knoth MADI_SS_CHANNELS; 67590dca1793SAdrian Knoth hdspm->ds_in_channels = hdspm->ds_out_channels = 67600dca1793SAdrian Knoth MADI_DS_CHANNELS; 67610dca1793SAdrian Knoth hdspm->qs_in_channels = hdspm->qs_out_channels = 67620dca1793SAdrian Knoth MADI_QS_CHANNELS; 67630dca1793SAdrian Knoth 67640dca1793SAdrian Knoth hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 67650dca1793SAdrian Knoth channel_map_unity_ss; 676601e96078SAdrian Knoth hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 67670dca1793SAdrian Knoth channel_map_unity_ss; 676801e96078SAdrian Knoth hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 67690dca1793SAdrian Knoth channel_map_unity_ss; 67700dca1793SAdrian Knoth 67710dca1793SAdrian Knoth hdspm->port_names_in_ss = hdspm->port_names_out_ss = 67720dca1793SAdrian Knoth texts_ports_madi; 67730dca1793SAdrian Knoth hdspm->port_names_in_ds = hdspm->port_names_out_ds = 67740dca1793SAdrian Knoth texts_ports_madi; 67750dca1793SAdrian Knoth hdspm->port_names_in_qs = hdspm->port_names_out_qs = 67760dca1793SAdrian Knoth texts_ports_madi; 67770dca1793SAdrian Knoth break; 67780dca1793SAdrian Knoth 67790dca1793SAdrian Knoth case AIO: 67800dca1793SAdrian Knoth hdspm->ss_in_channels = AIO_IN_SS_CHANNELS; 67810dca1793SAdrian Knoth hdspm->ds_in_channels = AIO_IN_DS_CHANNELS; 67820dca1793SAdrian Knoth hdspm->qs_in_channels = AIO_IN_QS_CHANNELS; 67830dca1793SAdrian Knoth hdspm->ss_out_channels = AIO_OUT_SS_CHANNELS; 67840dca1793SAdrian Knoth hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS; 67850dca1793SAdrian Knoth hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS; 67860dca1793SAdrian Knoth 67873de9db26SAdrian Knoth if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { 67883de9db26SAdrian Knoth snd_printk(KERN_INFO "HDSPM: AEB input board found\n"); 67893de9db26SAdrian Knoth hdspm->ss_in_channels += 4; 67903de9db26SAdrian Knoth hdspm->ds_in_channels += 4; 67913de9db26SAdrian Knoth hdspm->qs_in_channels += 4; 67923de9db26SAdrian Knoth } 67933de9db26SAdrian Knoth 67943de9db26SAdrian Knoth if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) { 67953de9db26SAdrian Knoth snd_printk(KERN_INFO "HDSPM: AEB output board found\n"); 67963de9db26SAdrian Knoth hdspm->ss_out_channels += 4; 67973de9db26SAdrian Knoth hdspm->ds_out_channels += 4; 67983de9db26SAdrian Knoth hdspm->qs_out_channels += 4; 67993de9db26SAdrian Knoth } 68003de9db26SAdrian Knoth 68010dca1793SAdrian Knoth hdspm->channel_map_out_ss = channel_map_aio_out_ss; 68020dca1793SAdrian Knoth hdspm->channel_map_out_ds = channel_map_aio_out_ds; 68030dca1793SAdrian Knoth hdspm->channel_map_out_qs = channel_map_aio_out_qs; 68040dca1793SAdrian Knoth 68050dca1793SAdrian Knoth hdspm->channel_map_in_ss = channel_map_aio_in_ss; 68060dca1793SAdrian Knoth hdspm->channel_map_in_ds = channel_map_aio_in_ds; 68070dca1793SAdrian Knoth hdspm->channel_map_in_qs = channel_map_aio_in_qs; 68080dca1793SAdrian Knoth 68090dca1793SAdrian Knoth hdspm->port_names_in_ss = texts_ports_aio_in_ss; 68100dca1793SAdrian Knoth hdspm->port_names_out_ss = texts_ports_aio_out_ss; 68110dca1793SAdrian Knoth hdspm->port_names_in_ds = texts_ports_aio_in_ds; 68120dca1793SAdrian Knoth hdspm->port_names_out_ds = texts_ports_aio_out_ds; 68130dca1793SAdrian Knoth hdspm->port_names_in_qs = texts_ports_aio_in_qs; 68140dca1793SAdrian Knoth hdspm->port_names_out_qs = texts_ports_aio_out_qs; 68150dca1793SAdrian Knoth 68160dca1793SAdrian Knoth break; 68170dca1793SAdrian Knoth 68180dca1793SAdrian Knoth case RayDAT: 68190dca1793SAdrian Knoth hdspm->ss_in_channels = hdspm->ss_out_channels = 68200dca1793SAdrian Knoth RAYDAT_SS_CHANNELS; 68210dca1793SAdrian Knoth hdspm->ds_in_channels = hdspm->ds_out_channels = 68220dca1793SAdrian Knoth RAYDAT_DS_CHANNELS; 68230dca1793SAdrian Knoth hdspm->qs_in_channels = hdspm->qs_out_channels = 68240dca1793SAdrian Knoth RAYDAT_QS_CHANNELS; 68250dca1793SAdrian Knoth 68260dca1793SAdrian Knoth hdspm->max_channels_in = RAYDAT_SS_CHANNELS; 68270dca1793SAdrian Knoth hdspm->max_channels_out = RAYDAT_SS_CHANNELS; 68280dca1793SAdrian Knoth 68290dca1793SAdrian Knoth hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 68300dca1793SAdrian Knoth channel_map_raydat_ss; 68310dca1793SAdrian Knoth hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 68320dca1793SAdrian Knoth channel_map_raydat_ds; 68330dca1793SAdrian Knoth hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 68340dca1793SAdrian Knoth channel_map_raydat_qs; 68350dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_out = 68360dca1793SAdrian Knoth channel_map_raydat_ss; 68370dca1793SAdrian Knoth 68380dca1793SAdrian Knoth hdspm->port_names_in_ss = hdspm->port_names_out_ss = 68390dca1793SAdrian Knoth texts_ports_raydat_ss; 68400dca1793SAdrian Knoth hdspm->port_names_in_ds = hdspm->port_names_out_ds = 68410dca1793SAdrian Knoth texts_ports_raydat_ds; 68420dca1793SAdrian Knoth hdspm->port_names_in_qs = hdspm->port_names_out_qs = 68430dca1793SAdrian Knoth texts_ports_raydat_qs; 68440dca1793SAdrian Knoth 68450dca1793SAdrian Knoth 68460dca1793SAdrian Knoth break; 68470dca1793SAdrian Knoth 68480dca1793SAdrian Knoth } 68490dca1793SAdrian Knoth 68500dca1793SAdrian Knoth /* TCO detection */ 68510dca1793SAdrian Knoth switch (hdspm->io_type) { 68520dca1793SAdrian Knoth case AIO: 68530dca1793SAdrian Knoth case RayDAT: 68540dca1793SAdrian Knoth if (hdspm_read(hdspm, HDSPM_statusRegister2) & 68550dca1793SAdrian Knoth HDSPM_s2_tco_detect) { 68560dca1793SAdrian Knoth hdspm->midiPorts++; 68570dca1793SAdrian Knoth hdspm->tco = kzalloc(sizeof(struct hdspm_tco), 68580dca1793SAdrian Knoth GFP_KERNEL); 68590dca1793SAdrian Knoth if (NULL != hdspm->tco) { 68600dca1793SAdrian Knoth hdspm_tco_write(hdspm); 68610dca1793SAdrian Knoth } 68620dca1793SAdrian Knoth snd_printk(KERN_INFO "HDSPM: AIO/RayDAT TCO module found\n"); 68630dca1793SAdrian Knoth } else { 68640dca1793SAdrian Knoth hdspm->tco = NULL; 68650dca1793SAdrian Knoth } 68660dca1793SAdrian Knoth break; 68670dca1793SAdrian Knoth 68680dca1793SAdrian Knoth case MADI: 68690dc831b9SAdrian Knoth case AES32: 68700dca1793SAdrian Knoth if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) { 68710dca1793SAdrian Knoth hdspm->midiPorts++; 68720dca1793SAdrian Knoth hdspm->tco = kzalloc(sizeof(struct hdspm_tco), 68730dca1793SAdrian Knoth GFP_KERNEL); 68740dca1793SAdrian Knoth if (NULL != hdspm->tco) { 68750dca1793SAdrian Knoth hdspm_tco_write(hdspm); 68760dca1793SAdrian Knoth } 6877e71b95adSAdrian Knoth snd_printk(KERN_INFO "HDSPM: MADI/AES TCO module found\n"); 68780dca1793SAdrian Knoth } else { 68790dca1793SAdrian Knoth hdspm->tco = NULL; 68800dca1793SAdrian Knoth } 68810dca1793SAdrian Knoth break; 68820dca1793SAdrian Knoth 68830dca1793SAdrian Knoth default: 68840dca1793SAdrian Knoth hdspm->tco = NULL; 68850dca1793SAdrian Knoth } 68860dca1793SAdrian Knoth 68870dca1793SAdrian Knoth /* texts */ 68880dca1793SAdrian Knoth switch (hdspm->io_type) { 68890dca1793SAdrian Knoth case AES32: 68900dca1793SAdrian Knoth if (hdspm->tco) { 68910dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aes_tco; 6892e71b95adSAdrian Knoth hdspm->texts_autosync_items = 6893e71b95adSAdrian Knoth ARRAY_SIZE(texts_autosync_aes_tco); 68940dca1793SAdrian Knoth } else { 68950dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aes; 6896e71b95adSAdrian Knoth hdspm->texts_autosync_items = 6897e71b95adSAdrian Knoth ARRAY_SIZE(texts_autosync_aes); 68980dca1793SAdrian Knoth } 68990dca1793SAdrian Knoth break; 69000dca1793SAdrian Knoth 69010dca1793SAdrian Knoth case MADI: 69020dca1793SAdrian Knoth if (hdspm->tco) { 69030dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_madi_tco; 69040dca1793SAdrian Knoth hdspm->texts_autosync_items = 4; 69050dca1793SAdrian Knoth } else { 69060dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_madi; 69070dca1793SAdrian Knoth hdspm->texts_autosync_items = 3; 69080dca1793SAdrian Knoth } 69090dca1793SAdrian Knoth break; 69100dca1793SAdrian Knoth 69110dca1793SAdrian Knoth case MADIface: 69120dca1793SAdrian Knoth 69130dca1793SAdrian Knoth break; 69140dca1793SAdrian Knoth 69150dca1793SAdrian Knoth case RayDAT: 69160dca1793SAdrian Knoth if (hdspm->tco) { 69170dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_raydat_tco; 69180dca1793SAdrian Knoth hdspm->texts_autosync_items = 9; 69190dca1793SAdrian Knoth } else { 69200dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_raydat; 69210dca1793SAdrian Knoth hdspm->texts_autosync_items = 8; 69220dca1793SAdrian Knoth } 69230dca1793SAdrian Knoth break; 69240dca1793SAdrian Knoth 69250dca1793SAdrian Knoth case AIO: 69260dca1793SAdrian Knoth if (hdspm->tco) { 69270dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aio_tco; 69280dca1793SAdrian Knoth hdspm->texts_autosync_items = 6; 69290dca1793SAdrian Knoth } else { 69300dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aio; 69310dca1793SAdrian Knoth hdspm->texts_autosync_items = 5; 69320dca1793SAdrian Knoth } 69330dca1793SAdrian Knoth break; 69340dca1793SAdrian Knoth 69350dca1793SAdrian Knoth } 69360dca1793SAdrian Knoth 69370dca1793SAdrian Knoth tasklet_init(&hdspm->midi_tasklet, 69380dca1793SAdrian Knoth hdspm_midi_tasklet, (unsigned long) hdspm); 6939763f356cSTakashi Iwai 6940f7de8ba3SAdrian Knoth 6941f7de8ba3SAdrian Knoth if (hdspm->io_type != MADIface) { 6942f7de8ba3SAdrian Knoth hdspm->serial = (hdspm_read(hdspm, 6943f7de8ba3SAdrian Knoth HDSPM_midiStatusIn0)>>8) & 0xFFFFFF; 6944f7de8ba3SAdrian Knoth /* id contains either a user-provided value or the default 6945f7de8ba3SAdrian Knoth * NULL. If it's the default, we're safe to 6946f7de8ba3SAdrian Knoth * fill card->id with the serial number. 6947f7de8ba3SAdrian Knoth * 6948f7de8ba3SAdrian Knoth * If the serial number is 0xFFFFFF, then we're dealing with 6949f7de8ba3SAdrian Knoth * an old PCI revision that comes without a sane number. In 6950f7de8ba3SAdrian Knoth * this case, we don't set card->id to avoid collisions 6951f7de8ba3SAdrian Knoth * when running with multiple cards. 6952f7de8ba3SAdrian Knoth */ 6953f7de8ba3SAdrian Knoth if (NULL == id[hdspm->dev] && hdspm->serial != 0xFFFFFF) { 6954f7de8ba3SAdrian Knoth sprintf(card->id, "HDSPMx%06x", hdspm->serial); 6955f7de8ba3SAdrian Knoth snd_card_set_id(card, card->id); 6956f7de8ba3SAdrian Knoth } 6957f7de8ba3SAdrian Knoth } 6958f7de8ba3SAdrian Knoth 6959763f356cSTakashi Iwai snd_printdd("create alsa devices.\n"); 6960ef5fa1a4STakashi Iwai err = snd_hdspm_create_alsa_devices(card, hdspm); 6961ef5fa1a4STakashi Iwai if (err < 0) 6962763f356cSTakashi Iwai return err; 6963763f356cSTakashi Iwai 6964763f356cSTakashi Iwai snd_hdspm_initialize_midi_flush(hdspm); 6965763f356cSTakashi Iwai 6966763f356cSTakashi Iwai return 0; 6967763f356cSTakashi Iwai } 6968763f356cSTakashi Iwai 69690dca1793SAdrian Knoth 697098274f07STakashi Iwai static int snd_hdspm_free(struct hdspm * hdspm) 6971763f356cSTakashi Iwai { 6972763f356cSTakashi Iwai 6973763f356cSTakashi Iwai if (hdspm->port) { 6974763f356cSTakashi Iwai 6975763f356cSTakashi Iwai /* stop th audio, and cancel all interrupts */ 6976763f356cSTakashi Iwai hdspm->control_register &= 6977ef5fa1a4STakashi Iwai ~(HDSPM_Start | HDSPM_AudioInterruptEnable | 69780dca1793SAdrian Knoth HDSPM_Midi0InterruptEnable | HDSPM_Midi1InterruptEnable | 69790dca1793SAdrian Knoth HDSPM_Midi2InterruptEnable | HDSPM_Midi3InterruptEnable); 6980763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, 6981763f356cSTakashi Iwai hdspm->control_register); 6982763f356cSTakashi Iwai } 6983763f356cSTakashi Iwai 6984763f356cSTakashi Iwai if (hdspm->irq >= 0) 6985763f356cSTakashi Iwai free_irq(hdspm->irq, (void *) hdspm); 6986763f356cSTakashi Iwai 6987763f356cSTakashi Iwai kfree(hdspm->mixer); 6988763f356cSTakashi Iwai 6989763f356cSTakashi Iwai if (hdspm->iobase) 6990763f356cSTakashi Iwai iounmap(hdspm->iobase); 6991763f356cSTakashi Iwai 6992763f356cSTakashi Iwai if (hdspm->port) 6993763f356cSTakashi Iwai pci_release_regions(hdspm->pci); 6994763f356cSTakashi Iwai 6995763f356cSTakashi Iwai pci_disable_device(hdspm->pci); 6996763f356cSTakashi Iwai return 0; 6997763f356cSTakashi Iwai } 6998763f356cSTakashi Iwai 69990dca1793SAdrian Knoth 700098274f07STakashi Iwai static void snd_hdspm_card_free(struct snd_card *card) 7001763f356cSTakashi Iwai { 7002ef5fa1a4STakashi Iwai struct hdspm *hdspm = card->private_data; 7003763f356cSTakashi Iwai 7004763f356cSTakashi Iwai if (hdspm) 7005763f356cSTakashi Iwai snd_hdspm_free(hdspm); 7006763f356cSTakashi Iwai } 7007763f356cSTakashi Iwai 70080dca1793SAdrian Knoth 7009e23e7a14SBill Pemberton static int snd_hdspm_probe(struct pci_dev *pci, 7010763f356cSTakashi Iwai const struct pci_device_id *pci_id) 7011763f356cSTakashi Iwai { 7012763f356cSTakashi Iwai static int dev; 701398274f07STakashi Iwai struct hdspm *hdspm; 701498274f07STakashi Iwai struct snd_card *card; 7015763f356cSTakashi Iwai int err; 7016763f356cSTakashi Iwai 7017763f356cSTakashi Iwai if (dev >= SNDRV_CARDS) 7018763f356cSTakashi Iwai return -ENODEV; 7019763f356cSTakashi Iwai if (!enable[dev]) { 7020763f356cSTakashi Iwai dev++; 7021763f356cSTakashi Iwai return -ENOENT; 7022763f356cSTakashi Iwai } 7023763f356cSTakashi Iwai 7024e58de7baSTakashi Iwai err = snd_card_create(index[dev], id[dev], 7025e58de7baSTakashi Iwai THIS_MODULE, sizeof(struct hdspm), &card); 7026e58de7baSTakashi Iwai if (err < 0) 7027e58de7baSTakashi Iwai return err; 7028763f356cSTakashi Iwai 7029ef5fa1a4STakashi Iwai hdspm = card->private_data; 7030763f356cSTakashi Iwai card->private_free = snd_hdspm_card_free; 7031763f356cSTakashi Iwai hdspm->dev = dev; 7032763f356cSTakashi Iwai hdspm->pci = pci; 7033763f356cSTakashi Iwai 7034c187c041STakashi Iwai snd_card_set_dev(card, &pci->dev); 7035c187c041STakashi Iwai 70360dca1793SAdrian Knoth err = snd_hdspm_create(card, hdspm); 7037ef5fa1a4STakashi Iwai if (err < 0) { 7038763f356cSTakashi Iwai snd_card_free(card); 7039763f356cSTakashi Iwai return err; 7040763f356cSTakashi Iwai } 7041763f356cSTakashi Iwai 70420dca1793SAdrian Knoth if (hdspm->io_type != MADIface) { 70430dca1793SAdrian Knoth sprintf(card->shortname, "%s_%x", 70440dca1793SAdrian Knoth hdspm->card_name, 70457d53a631SAdrian Knoth hdspm->serial); 70460dca1793SAdrian Knoth sprintf(card->longname, "%s S/N 0x%x at 0x%lx, irq %d", 70470dca1793SAdrian Knoth hdspm->card_name, 70487d53a631SAdrian Knoth hdspm->serial, 7049763f356cSTakashi Iwai hdspm->port, hdspm->irq); 70500dca1793SAdrian Knoth } else { 70510dca1793SAdrian Knoth sprintf(card->shortname, "%s", hdspm->card_name); 70520dca1793SAdrian Knoth sprintf(card->longname, "%s at 0x%lx, irq %d", 70530dca1793SAdrian Knoth hdspm->card_name, hdspm->port, hdspm->irq); 70540dca1793SAdrian Knoth } 7055763f356cSTakashi Iwai 7056ef5fa1a4STakashi Iwai err = snd_card_register(card); 7057ef5fa1a4STakashi Iwai if (err < 0) { 7058763f356cSTakashi Iwai snd_card_free(card); 7059763f356cSTakashi Iwai return err; 7060763f356cSTakashi Iwai } 7061763f356cSTakashi Iwai 7062763f356cSTakashi Iwai pci_set_drvdata(pci, card); 7063763f356cSTakashi Iwai 7064763f356cSTakashi Iwai dev++; 7065763f356cSTakashi Iwai return 0; 7066763f356cSTakashi Iwai } 7067763f356cSTakashi Iwai 7068e23e7a14SBill Pemberton static void snd_hdspm_remove(struct pci_dev *pci) 7069763f356cSTakashi Iwai { 7070763f356cSTakashi Iwai snd_card_free(pci_get_drvdata(pci)); 7071763f356cSTakashi Iwai } 7072763f356cSTakashi Iwai 7073e9f66d9bSTakashi Iwai static struct pci_driver hdspm_driver = { 70743733e424STakashi Iwai .name = KBUILD_MODNAME, 7075763f356cSTakashi Iwai .id_table = snd_hdspm_ids, 7076763f356cSTakashi Iwai .probe = snd_hdspm_probe, 7077e23e7a14SBill Pemberton .remove = snd_hdspm_remove, 7078763f356cSTakashi Iwai }; 7079763f356cSTakashi Iwai 7080e9f66d9bSTakashi Iwai module_pci_driver(hdspm_driver); 7081