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 */ 41763f356cSTakashi Iwai #include <linux/init.h> 42763f356cSTakashi Iwai #include <linux/delay.h> 43763f356cSTakashi Iwai #include <linux/interrupt.h> 44763f356cSTakashi Iwai #include <linux/moduleparam.h> 45763f356cSTakashi Iwai #include <linux/slab.h> 46763f356cSTakashi Iwai #include <linux/pci.h> 473f7440a6STakashi Iwai #include <linux/math64.h> 48763f356cSTakashi Iwai #include <asm/io.h> 49763f356cSTakashi Iwai 50763f356cSTakashi Iwai #include <sound/core.h> 51763f356cSTakashi Iwai #include <sound/control.h> 52763f356cSTakashi Iwai #include <sound/pcm.h> 530dca1793SAdrian Knoth #include <sound/pcm_params.h> 54763f356cSTakashi Iwai #include <sound/info.h> 55763f356cSTakashi Iwai #include <sound/asoundef.h> 56763f356cSTakashi Iwai #include <sound/rawmidi.h> 57763f356cSTakashi Iwai #include <sound/hwdep.h> 58763f356cSTakashi Iwai #include <sound/initval.h> 59763f356cSTakashi Iwai 60763f356cSTakashi Iwai #include <sound/hdspm.h> 61763f356cSTakashi Iwai 62763f356cSTakashi Iwai static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 63763f356cSTakashi Iwai static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 64763f356cSTakashi Iwai static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ 65763f356cSTakashi Iwai 66763f356cSTakashi Iwai module_param_array(index, int, NULL, 0444); 67763f356cSTakashi Iwai MODULE_PARM_DESC(index, "Index value for RME HDSPM interface."); 68763f356cSTakashi Iwai 69763f356cSTakashi Iwai module_param_array(id, charp, NULL, 0444); 70763f356cSTakashi Iwai MODULE_PARM_DESC(id, "ID string for RME HDSPM interface."); 71763f356cSTakashi Iwai 72763f356cSTakashi Iwai module_param_array(enable, bool, NULL, 0444); 73763f356cSTakashi Iwai MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards."); 74763f356cSTakashi Iwai 75763f356cSTakashi Iwai 76763f356cSTakashi Iwai MODULE_AUTHOR 770dca1793SAdrian Knoth ( 780dca1793SAdrian Knoth "Winfried Ritsch <ritsch_AT_iem.at>, " 79ef5fa1a4STakashi Iwai "Paul Davis <paul@linuxaudiosystems.com>, " 803cee5a60SRemy Bruno "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, " 810dca1793SAdrian Knoth "Remy Bruno <remy.bruno@trinnov.com>, " 820dca1793SAdrian Knoth "Florian Faber <faberman@linuxproaudio.org>, " 830dca1793SAdrian Knoth "Adrian Knoth <adi@drcomp.erfurt.thur.de>" 840dca1793SAdrian Knoth ); 85763f356cSTakashi Iwai MODULE_DESCRIPTION("RME HDSPM"); 86763f356cSTakashi Iwai MODULE_LICENSE("GPL"); 87763f356cSTakashi Iwai MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); 88763f356cSTakashi Iwai 89763f356cSTakashi Iwai /* --- Write registers. --- 90763f356cSTakashi Iwai These are defined as byte-offsets from the iobase value. */ 91763f356cSTakashi Iwai 920dca1793SAdrian Knoth #define HDSPM_WR_SETTINGS 0 930dca1793SAdrian Knoth #define HDSPM_outputBufferAddress 32 940dca1793SAdrian Knoth #define HDSPM_inputBufferAddress 36 95763f356cSTakashi Iwai #define HDSPM_controlRegister 64 96763f356cSTakashi Iwai #define HDSPM_interruptConfirmation 96 97763f356cSTakashi Iwai #define HDSPM_control2Reg 256 /* not in specs ???????? */ 98ffb2c3c0SRemy Bruno #define HDSPM_freqReg 256 /* for AES32 */ 99763f356cSTakashi Iwai #define HDSPM_midiDataOut0 352 /* just believe in old code */ 100763f356cSTakashi Iwai #define HDSPM_midiDataOut1 356 101ffb2c3c0SRemy Bruno #define HDSPM_eeprom_wr 384 /* for AES32 */ 102763f356cSTakashi Iwai 103763f356cSTakashi Iwai /* DMA enable for 64 channels, only Bit 0 is relevant */ 104763f356cSTakashi Iwai #define HDSPM_outputEnableBase 512 /* 512-767 input DMA */ 105763f356cSTakashi Iwai #define HDSPM_inputEnableBase 768 /* 768-1023 output DMA */ 106763f356cSTakashi Iwai 107763f356cSTakashi Iwai /* 16 page addresses for each of the 64 channels DMA buffer in and out 108763f356cSTakashi Iwai (each 64k=16*4k) Buffer must be 4k aligned (which is default i386 ????) */ 109763f356cSTakashi Iwai #define HDSPM_pageAddressBufferOut 8192 110763f356cSTakashi Iwai #define HDSPM_pageAddressBufferIn (HDSPM_pageAddressBufferOut+64*16*4) 111763f356cSTakashi Iwai 112763f356cSTakashi Iwai #define HDSPM_MADI_mixerBase 32768 /* 32768-65535 for 2x64x64 Fader */ 113763f356cSTakashi Iwai 114763f356cSTakashi Iwai #define HDSPM_MATRIX_MIXER_SIZE 8192 /* = 2*64*64 * 4 Byte => 32kB */ 115763f356cSTakashi Iwai 116763f356cSTakashi Iwai /* --- Read registers. --- 117763f356cSTakashi Iwai These are defined as byte-offsets from the iobase value */ 118763f356cSTakashi Iwai #define HDSPM_statusRegister 0 1193cee5a60SRemy Bruno /*#define HDSPM_statusRegister2 96 */ 1203cee5a60SRemy Bruno /* after RME Windows driver sources, status2 is 4-byte word # 48 = word at 1213cee5a60SRemy Bruno * offset 192, for AES32 *and* MADI 1223cee5a60SRemy Bruno * => need to check that offset 192 is working on MADI */ 1233cee5a60SRemy Bruno #define HDSPM_statusRegister2 192 1243cee5a60SRemy Bruno #define HDSPM_timecodeRegister 128 125763f356cSTakashi Iwai 1260dca1793SAdrian Knoth /* AIO, RayDAT */ 1270dca1793SAdrian Knoth #define HDSPM_RD_STATUS_0 0 1280dca1793SAdrian Knoth #define HDSPM_RD_STATUS_1 64 1290dca1793SAdrian Knoth #define HDSPM_RD_STATUS_2 128 1300dca1793SAdrian Knoth #define HDSPM_RD_STATUS_3 192 1310dca1793SAdrian Knoth 1320dca1793SAdrian Knoth #define HDSPM_RD_TCO 256 1330dca1793SAdrian Knoth #define HDSPM_RD_PLL_FREQ 512 1340dca1793SAdrian Knoth #define HDSPM_WR_TCO 128 1350dca1793SAdrian Knoth 1360dca1793SAdrian Knoth #define HDSPM_TCO1_TCO_lock 0x00000001 1370dca1793SAdrian Knoth #define HDSPM_TCO1_WCK_Input_Range_LSB 0x00000002 1380dca1793SAdrian Knoth #define HDSPM_TCO1_WCK_Input_Range_MSB 0x00000004 1390dca1793SAdrian Knoth #define HDSPM_TCO1_LTC_Input_valid 0x00000008 1400dca1793SAdrian Knoth #define HDSPM_TCO1_WCK_Input_valid 0x00000010 1410dca1793SAdrian Knoth #define HDSPM_TCO1_Video_Input_Format_NTSC 0x00000020 1420dca1793SAdrian Knoth #define HDSPM_TCO1_Video_Input_Format_PAL 0x00000040 1430dca1793SAdrian Knoth 1440dca1793SAdrian Knoth #define HDSPM_TCO1_set_TC 0x00000100 1450dca1793SAdrian Knoth #define HDSPM_TCO1_set_drop_frame_flag 0x00000200 1460dca1793SAdrian Knoth #define HDSPM_TCO1_LTC_Format_LSB 0x00000400 1470dca1793SAdrian Knoth #define HDSPM_TCO1_LTC_Format_MSB 0x00000800 1480dca1793SAdrian Knoth 1490dca1793SAdrian Knoth #define HDSPM_TCO2_TC_run 0x00010000 1500dca1793SAdrian Knoth #define HDSPM_TCO2_WCK_IO_ratio_LSB 0x00020000 1510dca1793SAdrian Knoth #define HDSPM_TCO2_WCK_IO_ratio_MSB 0x00040000 1520dca1793SAdrian Knoth #define HDSPM_TCO2_set_num_drop_frames_LSB 0x00080000 1530dca1793SAdrian Knoth #define HDSPM_TCO2_set_num_drop_frames_MSB 0x00100000 1540dca1793SAdrian Knoth #define HDSPM_TCO2_set_jam_sync 0x00200000 1550dca1793SAdrian Knoth #define HDSPM_TCO2_set_flywheel 0x00400000 1560dca1793SAdrian Knoth 1570dca1793SAdrian Knoth #define HDSPM_TCO2_set_01_4 0x01000000 1580dca1793SAdrian Knoth #define HDSPM_TCO2_set_pull_down 0x02000000 1590dca1793SAdrian Knoth #define HDSPM_TCO2_set_pull_up 0x04000000 1600dca1793SAdrian Knoth #define HDSPM_TCO2_set_freq 0x08000000 1610dca1793SAdrian Knoth #define HDSPM_TCO2_set_term_75R 0x10000000 1620dca1793SAdrian Knoth #define HDSPM_TCO2_set_input_LSB 0x20000000 1630dca1793SAdrian Knoth #define HDSPM_TCO2_set_input_MSB 0x40000000 1640dca1793SAdrian Knoth #define HDSPM_TCO2_set_freq_from_app 0x80000000 1650dca1793SAdrian Knoth 1660dca1793SAdrian Knoth 1670dca1793SAdrian Knoth #define HDSPM_midiDataOut0 352 1680dca1793SAdrian Knoth #define HDSPM_midiDataOut1 356 1690dca1793SAdrian Knoth #define HDSPM_midiDataOut2 368 1700dca1793SAdrian Knoth 171763f356cSTakashi Iwai #define HDSPM_midiDataIn0 360 172763f356cSTakashi Iwai #define HDSPM_midiDataIn1 364 1730dca1793SAdrian Knoth #define HDSPM_midiDataIn2 372 1740dca1793SAdrian Knoth #define HDSPM_midiDataIn3 376 175763f356cSTakashi Iwai 176763f356cSTakashi Iwai /* status is data bytes in MIDI-FIFO (0-128) */ 177763f356cSTakashi Iwai #define HDSPM_midiStatusOut0 384 178763f356cSTakashi Iwai #define HDSPM_midiStatusOut1 388 1790dca1793SAdrian Knoth #define HDSPM_midiStatusOut2 400 1800dca1793SAdrian Knoth 181763f356cSTakashi Iwai #define HDSPM_midiStatusIn0 392 182763f356cSTakashi Iwai #define HDSPM_midiStatusIn1 396 1830dca1793SAdrian Knoth #define HDSPM_midiStatusIn2 404 1840dca1793SAdrian Knoth #define HDSPM_midiStatusIn3 408 185763f356cSTakashi Iwai 186763f356cSTakashi Iwai 187763f356cSTakashi Iwai /* the meters are regular i/o-mapped registers, but offset 188763f356cSTakashi Iwai considerably from the rest. the peak registers are reset 189763f356cSTakashi Iwai when read; the least-significant 4 bits are full-scale counters; 190763f356cSTakashi Iwai the actual peak value is in the most-significant 24 bits. 191763f356cSTakashi Iwai */ 1920dca1793SAdrian Knoth 1930dca1793SAdrian Knoth #define HDSPM_MADI_INPUT_PEAK 4096 1940dca1793SAdrian Knoth #define HDSPM_MADI_PLAYBACK_PEAK 4352 1950dca1793SAdrian Knoth #define HDSPM_MADI_OUTPUT_PEAK 4608 1960dca1793SAdrian Knoth 1970dca1793SAdrian Knoth #define HDSPM_MADI_INPUT_RMS_L 6144 1980dca1793SAdrian Knoth #define HDSPM_MADI_PLAYBACK_RMS_L 6400 1990dca1793SAdrian Knoth #define HDSPM_MADI_OUTPUT_RMS_L 6656 2000dca1793SAdrian Knoth 2010dca1793SAdrian Knoth #define HDSPM_MADI_INPUT_RMS_H 7168 2020dca1793SAdrian Knoth #define HDSPM_MADI_PLAYBACK_RMS_H 7424 2030dca1793SAdrian Knoth #define HDSPM_MADI_OUTPUT_RMS_H 7680 204763f356cSTakashi Iwai 205763f356cSTakashi Iwai /* --- Control Register bits --------- */ 206763f356cSTakashi Iwai #define HDSPM_Start (1<<0) /* start engine */ 207763f356cSTakashi Iwai 208763f356cSTakashi Iwai #define HDSPM_Latency0 (1<<1) /* buffer size = 2^n */ 209763f356cSTakashi Iwai #define HDSPM_Latency1 (1<<2) /* where n is defined */ 210763f356cSTakashi Iwai #define HDSPM_Latency2 (1<<3) /* by Latency{2,1,0} */ 211763f356cSTakashi Iwai 2120dca1793SAdrian Knoth #define HDSPM_ClockModeMaster (1<<4) /* 1=Master, 0=Autosync */ 2130dca1793SAdrian Knoth #define HDSPM_c0Master 0x1 /* Master clock bit in settings 2140dca1793SAdrian Knoth register [RayDAT, AIO] */ 215763f356cSTakashi Iwai 216763f356cSTakashi Iwai #define HDSPM_AudioInterruptEnable (1<<5) /* what do you think ? */ 217763f356cSTakashi Iwai 218763f356cSTakashi Iwai #define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ 219763f356cSTakashi Iwai #define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */ 220763f356cSTakashi Iwai #define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ 2213cee5a60SRemy Bruno #define HDSPM_QuadSpeed (1<<31) /* quad speed bit */ 222763f356cSTakashi Iwai 2233cee5a60SRemy Bruno #define HDSPM_Professional (1<<9) /* Professional */ /* AES32 ONLY */ 224763f356cSTakashi Iwai #define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1, 2253cee5a60SRemy Bruno 56channelMODE=0 */ /* MADI ONLY*/ 2263cee5a60SRemy Bruno #define HDSPM_Emphasis (1<<10) /* Emphasis */ /* AES32 ONLY */ 227763f356cSTakashi Iwai 228763f356cSTakashi Iwai #define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode, 2293cee5a60SRemy Bruno 0=off, 1=on */ /* MADI ONLY */ 2303cee5a60SRemy Bruno #define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */ 231763f356cSTakashi Iwai 232ef5fa1a4STakashi Iwai #define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax 233ef5fa1a4STakashi Iwai * -- MADI ONLY 234ef5fa1a4STakashi Iwai */ 235763f356cSTakashi Iwai #define HDSPM_InputSelect1 (1<<15) /* should be 0 */ 236763f356cSTakashi Iwai 2373cee5a60SRemy Bruno #define HDSPM_SyncRef2 (1<<13) 2383cee5a60SRemy Bruno #define HDSPM_SyncRef3 (1<<25) 239763f356cSTakashi Iwai 2403cee5a60SRemy Bruno #define HDSPM_SMUX (1<<18) /* Frame ??? */ /* MADI ONY */ 241763f356cSTakashi Iwai #define HDSPM_clr_tms (1<<19) /* clear track marker, do not use 242763f356cSTakashi Iwai AES additional bits in 243763f356cSTakashi Iwai lower 5 Audiodatabits ??? */ 2443cee5a60SRemy Bruno #define HDSPM_taxi_reset (1<<20) /* ??? */ /* MADI ONLY ? */ 2453cee5a60SRemy Bruno #define HDSPM_WCK48 (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */ 246763f356cSTakashi Iwai 2470dca1793SAdrian Knoth #define HDSPM_Midi0InterruptEnable 0x0400000 2480dca1793SAdrian Knoth #define HDSPM_Midi1InterruptEnable 0x0800000 2490dca1793SAdrian Knoth #define HDSPM_Midi2InterruptEnable 0x0200000 2500dca1793SAdrian Knoth #define HDSPM_Midi3InterruptEnable 0x4000000 251763f356cSTakashi Iwai 252763f356cSTakashi Iwai #define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */ 2530dca1793SAdrian Knoth #define HDSPe_FLOAT_FORMAT 0x2000000 254763f356cSTakashi Iwai 2553cee5a60SRemy Bruno #define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */ 2563cee5a60SRemy Bruno #define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */ 2573cee5a60SRemy Bruno #define HDSPM_QS_QuadWire (1<<28) /* AES32 ONLY */ 2583cee5a60SRemy Bruno 2593cee5a60SRemy Bruno #define HDSPM_wclk_sel (1<<30) 260763f356cSTakashi Iwai 261763f356cSTakashi Iwai /* --- bit helper defines */ 262763f356cSTakashi Iwai #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) 263ef5fa1a4STakashi Iwai #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ 264ef5fa1a4STakashi Iwai HDSPM_DoubleSpeed|HDSPM_QuadSpeed) 265763f356cSTakashi Iwai #define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) 266763f356cSTakashi Iwai #define HDSPM_InputOptical 0 267763f356cSTakashi Iwai #define HDSPM_InputCoaxial (HDSPM_InputSelect0) 268ef5fa1a4STakashi Iwai #define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|\ 269ef5fa1a4STakashi Iwai HDSPM_SyncRef2|HDSPM_SyncRef3) 2700dca1793SAdrian Knoth 2710dca1793SAdrian Knoth #define HDSPM_c0_SyncRef0 0x2 2720dca1793SAdrian Knoth #define HDSPM_c0_SyncRef1 0x4 2730dca1793SAdrian Knoth #define HDSPM_c0_SyncRef2 0x8 2740dca1793SAdrian Knoth #define HDSPM_c0_SyncRef3 0x10 2750dca1793SAdrian Knoth #define HDSPM_c0_SyncRefMask (HDSPM_c0_SyncRef0 | HDSPM_c0_SyncRef1 |\ 2760dca1793SAdrian Knoth HDSPM_c0_SyncRef2 | HDSPM_c0_SyncRef3) 277763f356cSTakashi Iwai 278763f356cSTakashi Iwai #define HDSPM_SYNC_FROM_WORD 0 /* Preferred sync reference */ 279763f356cSTakashi Iwai #define HDSPM_SYNC_FROM_MADI 1 /* choices - used by "pref_sync_ref" */ 2800dca1793SAdrian Knoth #define HDSPM_SYNC_FROM_TCO 2 2810dca1793SAdrian Knoth #define HDSPM_SYNC_FROM_SYNC_IN 3 282763f356cSTakashi Iwai 283763f356cSTakashi Iwai #define HDSPM_Frequency32KHz HDSPM_Frequency0 284763f356cSTakashi Iwai #define HDSPM_Frequency44_1KHz HDSPM_Frequency1 285763f356cSTakashi Iwai #define HDSPM_Frequency48KHz (HDSPM_Frequency1|HDSPM_Frequency0) 286763f356cSTakashi Iwai #define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) 287763f356cSTakashi Iwai #define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) 288ef5fa1a4STakashi Iwai #define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|\ 289ef5fa1a4STakashi Iwai HDSPM_Frequency0) 2903cee5a60SRemy Bruno #define HDSPM_Frequency128KHz (HDSPM_QuadSpeed|HDSPM_Frequency0) 2913cee5a60SRemy Bruno #define HDSPM_Frequency176_4KHz (HDSPM_QuadSpeed|HDSPM_Frequency1) 292ef5fa1a4STakashi Iwai #define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|\ 293ef5fa1a4STakashi Iwai HDSPM_Frequency0) 294763f356cSTakashi Iwai 295763f356cSTakashi Iwai 296763f356cSTakashi Iwai /* Synccheck Status */ 297763f356cSTakashi Iwai #define HDSPM_SYNC_CHECK_NO_LOCK 0 298763f356cSTakashi Iwai #define HDSPM_SYNC_CHECK_LOCK 1 299763f356cSTakashi Iwai #define HDSPM_SYNC_CHECK_SYNC 2 300763f356cSTakashi Iwai 301763f356cSTakashi Iwai /* AutoSync References - used by "autosync_ref" control switch */ 302763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_FROM_WORD 0 303763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_FROM_MADI 1 3040dca1793SAdrian Knoth #define HDSPM_AUTOSYNC_FROM_TCO 2 3050dca1793SAdrian Knoth #define HDSPM_AUTOSYNC_FROM_SYNC_IN 3 3060dca1793SAdrian Knoth #define HDSPM_AUTOSYNC_FROM_NONE 4 307763f356cSTakashi Iwai 308763f356cSTakashi Iwai /* Possible sources of MADI input */ 309763f356cSTakashi Iwai #define HDSPM_OPTICAL 0 /* optical */ 310763f356cSTakashi Iwai #define HDSPM_COAXIAL 1 /* BNC */ 311763f356cSTakashi Iwai 312763f356cSTakashi Iwai #define hdspm_encode_latency(x) (((x)<<1) & HDSPM_LatencyMask) 3130dca1793SAdrian Knoth #define hdspm_decode_latency(x) ((((x) & HDSPM_LatencyMask)>>1)) 314763f356cSTakashi Iwai 315763f356cSTakashi Iwai #define hdspm_encode_in(x) (((x)&0x3)<<14) 316763f356cSTakashi Iwai #define hdspm_decode_in(x) (((x)>>14)&0x3) 317763f356cSTakashi Iwai 318763f356cSTakashi Iwai /* --- control2 register bits --- */ 319763f356cSTakashi Iwai #define HDSPM_TMS (1<<0) 320763f356cSTakashi Iwai #define HDSPM_TCK (1<<1) 321763f356cSTakashi Iwai #define HDSPM_TDI (1<<2) 322763f356cSTakashi Iwai #define HDSPM_JTAG (1<<3) 323763f356cSTakashi Iwai #define HDSPM_PWDN (1<<4) 324763f356cSTakashi Iwai #define HDSPM_PROGRAM (1<<5) 325763f356cSTakashi Iwai #define HDSPM_CONFIG_MODE_0 (1<<6) 326763f356cSTakashi Iwai #define HDSPM_CONFIG_MODE_1 (1<<7) 327763f356cSTakashi Iwai /*#define HDSPM_VERSION_BIT (1<<8) not defined any more*/ 328763f356cSTakashi Iwai #define HDSPM_BIGENDIAN_MODE (1<<9) 329763f356cSTakashi Iwai #define HDSPM_RD_MULTIPLE (1<<10) 330763f356cSTakashi Iwai 3313cee5a60SRemy Bruno /* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and 332ef5fa1a4STakashi Iwai that do not conflict with specific bits for AES32 seem to be valid also 333ef5fa1a4STakashi Iwai for the AES32 334ef5fa1a4STakashi Iwai */ 335763f356cSTakashi Iwai #define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ 336ef5fa1a4STakashi Iwai #define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn MODE=0 */ 337ef5fa1a4STakashi Iwai #define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 338ef5fa1a4STakashi Iwai * (like inp0) 339ef5fa1a4STakashi Iwai */ 3400dca1793SAdrian Knoth 341763f356cSTakashi Iwai #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ 3420dca1793SAdrian Knoth #define HDSPM_madiSync (1<<18) /* MADI is in sync */ 3430dca1793SAdrian Knoth 3440dca1793SAdrian Knoth #define HDSPM_tcoLock 0x00000020 /* Optional TCO locked status FOR HDSPe MADI! */ 3450dca1793SAdrian Knoth #define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status */ 3460dca1793SAdrian Knoth 3470dca1793SAdrian Knoth #define HDSPM_syncInLock 0x00010000 /* Sync In lock status FOR HDSPe MADI! */ 3480dca1793SAdrian Knoth #define HDSPM_syncInSync 0x00020000 /* Sync In sync status FOR HDSPe MADI! */ 349763f356cSTakashi Iwai 350763f356cSTakashi Iwai #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ 3510dca1793SAdrian Knoth /* since 64byte accurate, last 6 bits are not used */ 352763f356cSTakashi Iwai 3530dca1793SAdrian Knoth 3540dca1793SAdrian Knoth 355763f356cSTakashi Iwai #define HDSPM_DoubleSpeedStatus (1<<19) /* (input) card in double speed */ 356763f356cSTakashi Iwai 357763f356cSTakashi Iwai #define HDSPM_madiFreq0 (1<<22) /* system freq 0=error */ 358763f356cSTakashi Iwai #define HDSPM_madiFreq1 (1<<23) /* 1=32, 2=44.1 3=48 */ 359763f356cSTakashi Iwai #define HDSPM_madiFreq2 (1<<24) /* 4=64, 5=88.2 6=96 */ 360763f356cSTakashi Iwai #define HDSPM_madiFreq3 (1<<25) /* 7=128, 8=176.4 9=192 */ 361763f356cSTakashi Iwai 362ef5fa1a4STakashi Iwai #define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with 363ef5fa1a4STakashi Iwai * Interrupt 364ef5fa1a4STakashi Iwai */ 3650dca1793SAdrian Knoth #define HDSPM_tco_detect 0x08000000 3660dca1793SAdrian Knoth #define HDSPM_tco_lock 0x20000000 3670dca1793SAdrian Knoth 3680dca1793SAdrian Knoth #define HDSPM_s2_tco_detect 0x00000040 3690dca1793SAdrian Knoth #define HDSPM_s2_AEBO_D 0x00000080 3700dca1793SAdrian Knoth #define HDSPM_s2_AEBI_D 0x00000100 3710dca1793SAdrian Knoth 3720dca1793SAdrian Knoth 3730dca1793SAdrian Knoth #define HDSPM_midi0IRQPending 0x40000000 3740dca1793SAdrian Knoth #define HDSPM_midi1IRQPending 0x80000000 3750dca1793SAdrian Knoth #define HDSPM_midi2IRQPending 0x20000000 3760dca1793SAdrian Knoth #define HDSPM_midi2IRQPendingAES 0x00000020 3770dca1793SAdrian Knoth #define HDSPM_midi3IRQPending 0x00200000 378763f356cSTakashi Iwai 379763f356cSTakashi Iwai /* --- status bit helpers */ 380ef5fa1a4STakashi Iwai #define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|\ 381ef5fa1a4STakashi Iwai HDSPM_madiFreq2|HDSPM_madiFreq3) 382763f356cSTakashi Iwai #define HDSPM_madiFreq32 (HDSPM_madiFreq0) 383763f356cSTakashi Iwai #define HDSPM_madiFreq44_1 (HDSPM_madiFreq1) 384763f356cSTakashi Iwai #define HDSPM_madiFreq48 (HDSPM_madiFreq0|HDSPM_madiFreq1) 385763f356cSTakashi Iwai #define HDSPM_madiFreq64 (HDSPM_madiFreq2) 386763f356cSTakashi Iwai #define HDSPM_madiFreq88_2 (HDSPM_madiFreq0|HDSPM_madiFreq2) 387763f356cSTakashi Iwai #define HDSPM_madiFreq96 (HDSPM_madiFreq1|HDSPM_madiFreq2) 388763f356cSTakashi Iwai #define HDSPM_madiFreq128 (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2) 389763f356cSTakashi Iwai #define HDSPM_madiFreq176_4 (HDSPM_madiFreq3) 390763f356cSTakashi Iwai #define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0) 391763f356cSTakashi Iwai 3923cee5a60SRemy Bruno /* Status2 Register bits */ /* MADI ONLY */ 393763f356cSTakashi Iwai 394763f356cSTakashi Iwai #define HDSPM_version0 (1<<0) /* not realy defined but I guess */ 395763f356cSTakashi Iwai #define HDSPM_version1 (1<<1) /* in former cards it was ??? */ 396763f356cSTakashi Iwai #define HDSPM_version2 (1<<2) 397763f356cSTakashi Iwai 398763f356cSTakashi Iwai #define HDSPM_wcLock (1<<3) /* Wordclock is detected and locked */ 399763f356cSTakashi Iwai #define HDSPM_wcSync (1<<4) /* Wordclock is in sync with systemclock */ 400763f356cSTakashi Iwai 401763f356cSTakashi Iwai #define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */ 402763f356cSTakashi Iwai #define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */ 403763f356cSTakashi Iwai #define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, */ 404763f356cSTakashi Iwai /* missing Bit for 111=128, 1000=176.4, 1001=192 */ 405763f356cSTakashi Iwai 4060dca1793SAdrian Knoth #define HDSPM_SyncRef0 0x10000 /* Sync Reference */ 4070dca1793SAdrian Knoth #define HDSPM_SyncRef1 0x20000 4080dca1793SAdrian Knoth 4090dca1793SAdrian Knoth #define HDSPM_SelSyncRef0 (1<<8) /* AutoSync Source */ 410763f356cSTakashi Iwai #define HDSPM_SelSyncRef1 (1<<9) /* 000=word, 001=MADI, */ 411763f356cSTakashi Iwai #define HDSPM_SelSyncRef2 (1<<10) /* 111=no valid signal */ 412763f356cSTakashi Iwai 413763f356cSTakashi Iwai #define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync) 414763f356cSTakashi Iwai 415763f356cSTakashi Iwai #define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) 416763f356cSTakashi Iwai #define HDSPM_wcFreq32 (HDSPM_wc_freq0) 417763f356cSTakashi Iwai #define HDSPM_wcFreq44_1 (HDSPM_wc_freq1) 418763f356cSTakashi Iwai #define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1) 419763f356cSTakashi Iwai #define HDSPM_wcFreq64 (HDSPM_wc_freq2) 420763f356cSTakashi Iwai #define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2) 421763f356cSTakashi Iwai #define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) 422763f356cSTakashi Iwai 4230dca1793SAdrian Knoth #define HDSPM_status1_F_0 0x0400000 4240dca1793SAdrian Knoth #define HDSPM_status1_F_1 0x0800000 4250dca1793SAdrian Knoth #define HDSPM_status1_F_2 0x1000000 4260dca1793SAdrian Knoth #define HDSPM_status1_F_3 0x2000000 4270dca1793SAdrian Knoth #define HDSPM_status1_freqMask (HDSPM_status1_F_0|HDSPM_status1_F_1|HDSPM_status1_F_2|HDSPM_status1_F_3) 4280dca1793SAdrian Knoth 429763f356cSTakashi Iwai 430ef5fa1a4STakashi Iwai #define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ 431ef5fa1a4STakashi Iwai HDSPM_SelSyncRef2) 432763f356cSTakashi Iwai #define HDSPM_SelSyncRef_WORD 0 433763f356cSTakashi Iwai #define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) 4340dca1793SAdrian Knoth #define HDSPM_SelSyncRef_TCO (HDSPM_SelSyncRef1) 4350dca1793SAdrian Knoth #define HDSPM_SelSyncRef_SyncIn (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1) 436ef5fa1a4STakashi Iwai #define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ 437ef5fa1a4STakashi Iwai HDSPM_SelSyncRef2) 438763f356cSTakashi Iwai 4393cee5a60SRemy Bruno /* 4403cee5a60SRemy Bruno For AES32, bits for status, status2 and timecode are different 4413cee5a60SRemy Bruno */ 4423cee5a60SRemy Bruno /* status */ 4433cee5a60SRemy Bruno #define HDSPM_AES32_wcLock 0x0200000 4443cee5a60SRemy Bruno #define HDSPM_AES32_wcFreq_bit 22 4453cee5a60SRemy Bruno /* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function 4463cee5a60SRemy Bruno HDSPM_bit2freq */ 4473cee5a60SRemy Bruno #define HDSPM_AES32_syncref_bit 16 4483cee5a60SRemy Bruno /* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */ 4493cee5a60SRemy Bruno 4503cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_WORD 0 4513cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES1 1 4523cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES2 2 4533cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES3 3 4543cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES4 4 4553cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES5 5 4563cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 4573cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 4583cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 4596534599dSRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_NONE 9 4603cee5a60SRemy Bruno 4613cee5a60SRemy Bruno /* status2 */ 4623cee5a60SRemy Bruno /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ 4633cee5a60SRemy Bruno #define HDSPM_LockAES 0x80 4643cee5a60SRemy Bruno #define HDSPM_LockAES1 0x80 4653cee5a60SRemy Bruno #define HDSPM_LockAES2 0x40 4663cee5a60SRemy Bruno #define HDSPM_LockAES3 0x20 4673cee5a60SRemy Bruno #define HDSPM_LockAES4 0x10 4683cee5a60SRemy Bruno #define HDSPM_LockAES5 0x8 4693cee5a60SRemy Bruno #define HDSPM_LockAES6 0x4 4703cee5a60SRemy Bruno #define HDSPM_LockAES7 0x2 4713cee5a60SRemy Bruno #define HDSPM_LockAES8 0x1 4723cee5a60SRemy Bruno /* 4733cee5a60SRemy Bruno Timecode 4743cee5a60SRemy Bruno After windows driver sources, bits 4*i to 4*i+3 give the input frequency on 4753cee5a60SRemy Bruno AES i+1 4763cee5a60SRemy Bruno bits 3210 4773cee5a60SRemy Bruno 0001 32kHz 4783cee5a60SRemy Bruno 0010 44.1kHz 4793cee5a60SRemy Bruno 0011 48kHz 4803cee5a60SRemy Bruno 0100 64kHz 4813cee5a60SRemy Bruno 0101 88.2kHz 4823cee5a60SRemy Bruno 0110 96kHz 4833cee5a60SRemy Bruno 0111 128kHz 4843cee5a60SRemy Bruno 1000 176.4kHz 4853cee5a60SRemy Bruno 1001 192kHz 4863cee5a60SRemy Bruno NB: Timecode register doesn't seem to work on AES32 card revision 230 4873cee5a60SRemy Bruno */ 4883cee5a60SRemy Bruno 489763f356cSTakashi Iwai /* Mixer Values */ 490763f356cSTakashi Iwai #define UNITY_GAIN 32768 /* = 65536/2 */ 491763f356cSTakashi Iwai #define MINUS_INFINITY_GAIN 0 492763f356cSTakashi Iwai 493763f356cSTakashi Iwai /* Number of channels for different Speed Modes */ 494763f356cSTakashi Iwai #define MADI_SS_CHANNELS 64 495763f356cSTakashi Iwai #define MADI_DS_CHANNELS 32 496763f356cSTakashi Iwai #define MADI_QS_CHANNELS 16 497763f356cSTakashi Iwai 4980dca1793SAdrian Knoth #define RAYDAT_SS_CHANNELS 36 4990dca1793SAdrian Knoth #define RAYDAT_DS_CHANNELS 20 5000dca1793SAdrian Knoth #define RAYDAT_QS_CHANNELS 12 5010dca1793SAdrian Knoth 5020dca1793SAdrian Knoth #define AIO_IN_SS_CHANNELS 14 5030dca1793SAdrian Knoth #define AIO_IN_DS_CHANNELS 10 5040dca1793SAdrian Knoth #define AIO_IN_QS_CHANNELS 8 5050dca1793SAdrian Knoth #define AIO_OUT_SS_CHANNELS 16 5060dca1793SAdrian Knoth #define AIO_OUT_DS_CHANNELS 12 5070dca1793SAdrian Knoth #define AIO_OUT_QS_CHANNELS 10 5080dca1793SAdrian Knoth 509763f356cSTakashi Iwai /* the size of a substream (1 mono data stream) */ 510763f356cSTakashi Iwai #define HDSPM_CHANNEL_BUFFER_SAMPLES (16*1024) 511763f356cSTakashi Iwai #define HDSPM_CHANNEL_BUFFER_BYTES (4*HDSPM_CHANNEL_BUFFER_SAMPLES) 512763f356cSTakashi Iwai 513763f356cSTakashi Iwai /* the size of the area we need to allocate for DMA transfers. the 514763f356cSTakashi Iwai size is the same regardless of the number of channels, and 515763f356cSTakashi Iwai also the latency to use. 516763f356cSTakashi Iwai for one direction !!! 517763f356cSTakashi Iwai */ 518ffb2c3c0SRemy Bruno #define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) 519763f356cSTakashi Iwai #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) 520763f356cSTakashi Iwai 5213cee5a60SRemy Bruno /* revisions >= 230 indicate AES32 card */ 5220dca1793SAdrian Knoth #define HDSPM_MADI_REV 210 5230dca1793SAdrian Knoth #define HDSPM_RAYDAT_REV 211 5240dca1793SAdrian Knoth #define HDSPM_AIO_REV 212 5250dca1793SAdrian Knoth #define HDSPM_MADIFACE_REV 213 5260dca1793SAdrian Knoth #define HDSPM_AES_REV 240 5273cee5a60SRemy Bruno 5286534599dSRemy Bruno /* speed factor modes */ 5296534599dSRemy Bruno #define HDSPM_SPEED_SINGLE 0 5306534599dSRemy Bruno #define HDSPM_SPEED_DOUBLE 1 5316534599dSRemy Bruno #define HDSPM_SPEED_QUAD 2 5320dca1793SAdrian Knoth 5336534599dSRemy Bruno /* names for speed modes */ 5346534599dSRemy Bruno static char *hdspm_speed_names[] = { "single", "double", "quad" }; 5356534599dSRemy Bruno 5360dca1793SAdrian Knoth static char *texts_autosync_aes_tco[] = { "Word Clock", 5370dca1793SAdrian Knoth "AES1", "AES2", "AES3", "AES4", 5380dca1793SAdrian Knoth "AES5", "AES6", "AES7", "AES8", 5390dca1793SAdrian Knoth "TCO" }; 5400dca1793SAdrian Knoth static char *texts_autosync_aes[] = { "Word Clock", 5410dca1793SAdrian Knoth "AES1", "AES2", "AES3", "AES4", 5420dca1793SAdrian Knoth "AES5", "AES6", "AES7", "AES8" }; 5430dca1793SAdrian Knoth static char *texts_autosync_madi_tco[] = { "Word Clock", 5440dca1793SAdrian Knoth "MADI", "TCO", "Sync In" }; 5450dca1793SAdrian Knoth static char *texts_autosync_madi[] = { "Word Clock", 5460dca1793SAdrian Knoth "MADI", "Sync In" }; 5470dca1793SAdrian Knoth 5480dca1793SAdrian Knoth static char *texts_autosync_raydat_tco[] = { 5490dca1793SAdrian Knoth "Word Clock", 5500dca1793SAdrian Knoth "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", 5510dca1793SAdrian Knoth "AES", "SPDIF", "TCO", "Sync In" 5520dca1793SAdrian Knoth }; 5530dca1793SAdrian Knoth static char *texts_autosync_raydat[] = { 5540dca1793SAdrian Knoth "Word Clock", 5550dca1793SAdrian Knoth "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", 5560dca1793SAdrian Knoth "AES", "SPDIF", "Sync In" 5570dca1793SAdrian Knoth }; 5580dca1793SAdrian Knoth static char *texts_autosync_aio_tco[] = { 5590dca1793SAdrian Knoth "Word Clock", 5600dca1793SAdrian Knoth "ADAT", "AES", "SPDIF", "TCO", "Sync In" 5610dca1793SAdrian Knoth }; 5620dca1793SAdrian Knoth static char *texts_autosync_aio[] = { "Word Clock", 5630dca1793SAdrian Knoth "ADAT", "AES", "SPDIF", "Sync In" }; 5640dca1793SAdrian Knoth 5650dca1793SAdrian Knoth static char *texts_freq[] = { 5660dca1793SAdrian Knoth "No Lock", 5670dca1793SAdrian Knoth "32 kHz", 5680dca1793SAdrian Knoth "44.1 kHz", 5690dca1793SAdrian Knoth "48 kHz", 5700dca1793SAdrian Knoth "64 kHz", 5710dca1793SAdrian Knoth "88.2 kHz", 5720dca1793SAdrian Knoth "96 kHz", 5730dca1793SAdrian Knoth "128 kHz", 5740dca1793SAdrian Knoth "176.4 kHz", 5750dca1793SAdrian Knoth "192 kHz" 5760dca1793SAdrian Knoth }; 5770dca1793SAdrian Knoth 5780dca1793SAdrian Knoth static char *texts_ports_madi[] = { 5790dca1793SAdrian Knoth "MADI.1", "MADI.2", "MADI.3", "MADI.4", "MADI.5", "MADI.6", 5800dca1793SAdrian Knoth "MADI.7", "MADI.8", "MADI.9", "MADI.10", "MADI.11", "MADI.12", 5810dca1793SAdrian Knoth "MADI.13", "MADI.14", "MADI.15", "MADI.16", "MADI.17", "MADI.18", 5820dca1793SAdrian Knoth "MADI.19", "MADI.20", "MADI.21", "MADI.22", "MADI.23", "MADI.24", 5830dca1793SAdrian Knoth "MADI.25", "MADI.26", "MADI.27", "MADI.28", "MADI.29", "MADI.30", 5840dca1793SAdrian Knoth "MADI.31", "MADI.32", "MADI.33", "MADI.34", "MADI.35", "MADI.36", 5850dca1793SAdrian Knoth "MADI.37", "MADI.38", "MADI.39", "MADI.40", "MADI.41", "MADI.42", 5860dca1793SAdrian Knoth "MADI.43", "MADI.44", "MADI.45", "MADI.46", "MADI.47", "MADI.48", 5870dca1793SAdrian Knoth "MADI.49", "MADI.50", "MADI.51", "MADI.52", "MADI.53", "MADI.54", 5880dca1793SAdrian Knoth "MADI.55", "MADI.56", "MADI.57", "MADI.58", "MADI.59", "MADI.60", 5890dca1793SAdrian Knoth "MADI.61", "MADI.62", "MADI.63", "MADI.64", 5900dca1793SAdrian Knoth }; 5910dca1793SAdrian Knoth 5920dca1793SAdrian Knoth 5930dca1793SAdrian Knoth static char *texts_ports_raydat_ss[] = { 5940dca1793SAdrian Knoth "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4", "ADAT1.5", "ADAT1.6", 5950dca1793SAdrian Knoth "ADAT1.7", "ADAT1.8", "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4", 5960dca1793SAdrian Knoth "ADAT2.5", "ADAT2.6", "ADAT2.7", "ADAT2.8", "ADAT3.1", "ADAT3.2", 5970dca1793SAdrian Knoth "ADAT3.3", "ADAT3.4", "ADAT3.5", "ADAT3.6", "ADAT3.7", "ADAT3.8", 5980dca1793SAdrian Knoth "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4", "ADAT4.5", "ADAT4.6", 5990dca1793SAdrian Knoth "ADAT4.7", "ADAT4.8", 6000dca1793SAdrian Knoth "AES.L", "AES.R", 6010dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R" 6020dca1793SAdrian Knoth }; 6030dca1793SAdrian Knoth 6040dca1793SAdrian Knoth static char *texts_ports_raydat_ds[] = { 6050dca1793SAdrian Knoth "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4", 6060dca1793SAdrian Knoth "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4", 6070dca1793SAdrian Knoth "ADAT3.1", "ADAT3.2", "ADAT3.3", "ADAT3.4", 6080dca1793SAdrian Knoth "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4", 6090dca1793SAdrian Knoth "AES.L", "AES.R", 6100dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R" 6110dca1793SAdrian Knoth }; 6120dca1793SAdrian Knoth 6130dca1793SAdrian Knoth static char *texts_ports_raydat_qs[] = { 6140dca1793SAdrian Knoth "ADAT1.1", "ADAT1.2", 6150dca1793SAdrian Knoth "ADAT2.1", "ADAT2.2", 6160dca1793SAdrian Knoth "ADAT3.1", "ADAT3.2", 6170dca1793SAdrian Knoth "ADAT4.1", "ADAT4.2", 6180dca1793SAdrian Knoth "AES.L", "AES.R", 6190dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R" 6200dca1793SAdrian Knoth }; 6210dca1793SAdrian Knoth 6220dca1793SAdrian Knoth 6230dca1793SAdrian Knoth static char *texts_ports_aio_in_ss[] = { 6240dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 6250dca1793SAdrian Knoth "AES.L", "AES.R", 6260dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 6270dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", 6280dca1793SAdrian Knoth "ADAT.7", "ADAT.8" 6290dca1793SAdrian Knoth }; 6300dca1793SAdrian Knoth 6310dca1793SAdrian Knoth static char *texts_ports_aio_out_ss[] = { 6320dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 6330dca1793SAdrian Knoth "AES.L", "AES.R", 6340dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 6350dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", 6360dca1793SAdrian Knoth "ADAT.7", "ADAT.8", 6370dca1793SAdrian Knoth "Phone.L", "Phone.R" 6380dca1793SAdrian Knoth }; 6390dca1793SAdrian Knoth 6400dca1793SAdrian Knoth static char *texts_ports_aio_in_ds[] = { 6410dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 6420dca1793SAdrian Knoth "AES.L", "AES.R", 6430dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 6440dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" 6450dca1793SAdrian Knoth }; 6460dca1793SAdrian Knoth 6470dca1793SAdrian Knoth static char *texts_ports_aio_out_ds[] = { 6480dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 6490dca1793SAdrian Knoth "AES.L", "AES.R", 6500dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 6510dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 6520dca1793SAdrian Knoth "Phone.L", "Phone.R" 6530dca1793SAdrian Knoth }; 6540dca1793SAdrian Knoth 6550dca1793SAdrian Knoth static char *texts_ports_aio_in_qs[] = { 6560dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 6570dca1793SAdrian Knoth "AES.L", "AES.R", 6580dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 6590dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" 6600dca1793SAdrian Knoth }; 6610dca1793SAdrian Knoth 6620dca1793SAdrian Knoth static char *texts_ports_aio_out_qs[] = { 6630dca1793SAdrian Knoth "Analogue.L", "Analogue.R", 6640dca1793SAdrian Knoth "AES.L", "AES.R", 6650dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R", 6660dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 6670dca1793SAdrian Knoth "Phone.L", "Phone.R" 6680dca1793SAdrian Knoth }; 6690dca1793SAdrian Knoth 670432d2500SAdrian Knoth static char *texts_ports_aes32[] = { 671432d2500SAdrian Knoth "AES.1", "AES.2", "AES.3", "AES.4", "AES.5", "AES.6", "AES.7", 672432d2500SAdrian Knoth "AES.8", "AES.9.", "AES.10", "AES.11", "AES.12", "AES.13", "AES.14", 673432d2500SAdrian Knoth "AES.15", "AES.16" 674432d2500SAdrian Knoth }; 675432d2500SAdrian Knoth 67655a57606SAdrian Knoth /* These tables map the ALSA channels 1..N to the channels that we 67755a57606SAdrian Knoth need to use in order to find the relevant channel buffer. RME 67855a57606SAdrian Knoth refers to this kind of mapping as between "the ADAT channel and 67955a57606SAdrian Knoth the DMA channel." We index it using the logical audio channel, 68055a57606SAdrian Knoth and the value is the DMA channel (i.e. channel buffer number) 68155a57606SAdrian Knoth where the data for that channel can be read/written from/to. 68255a57606SAdrian Knoth */ 68355a57606SAdrian Knoth 68455a57606SAdrian Knoth static char channel_map_unity_ss[HDSPM_MAX_CHANNELS] = { 68555a57606SAdrian Knoth 0, 1, 2, 3, 4, 5, 6, 7, 68655a57606SAdrian Knoth 8, 9, 10, 11, 12, 13, 14, 15, 68755a57606SAdrian Knoth 16, 17, 18, 19, 20, 21, 22, 23, 68855a57606SAdrian Knoth 24, 25, 26, 27, 28, 29, 30, 31, 68955a57606SAdrian Knoth 32, 33, 34, 35, 36, 37, 38, 39, 69055a57606SAdrian Knoth 40, 41, 42, 43, 44, 45, 46, 47, 69155a57606SAdrian Knoth 48, 49, 50, 51, 52, 53, 54, 55, 69255a57606SAdrian Knoth 56, 57, 58, 59, 60, 61, 62, 63 69355a57606SAdrian Knoth }; 69455a57606SAdrian Knoth 69555a57606SAdrian Knoth static char channel_map_raydat_ss[HDSPM_MAX_CHANNELS] = { 69655a57606SAdrian Knoth 4, 5, 6, 7, 8, 9, 10, 11, /* ADAT 1 */ 69755a57606SAdrian Knoth 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT 2 */ 69855a57606SAdrian Knoth 20, 21, 22, 23, 24, 25, 26, 27, /* ADAT 3 */ 69955a57606SAdrian Knoth 28, 29, 30, 31, 32, 33, 34, 35, /* ADAT 4 */ 70055a57606SAdrian Knoth 0, 1, /* AES */ 70155a57606SAdrian Knoth 2, 3, /* SPDIF */ 70255a57606SAdrian Knoth -1, -1, -1, -1, 70355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 70455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 70555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 70655a57606SAdrian Knoth }; 70755a57606SAdrian Knoth 70855a57606SAdrian Knoth static char channel_map_raydat_ds[HDSPM_MAX_CHANNELS] = { 70955a57606SAdrian Knoth 4, 5, 6, 7, /* ADAT 1 */ 71055a57606SAdrian Knoth 8, 9, 10, 11, /* ADAT 2 */ 71155a57606SAdrian Knoth 12, 13, 14, 15, /* ADAT 3 */ 71255a57606SAdrian Knoth 16, 17, 18, 19, /* ADAT 4 */ 71355a57606SAdrian Knoth 0, 1, /* AES */ 71455a57606SAdrian Knoth 2, 3, /* SPDIF */ 71555a57606SAdrian Knoth -1, -1, -1, -1, 71655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 71755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 71855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 71955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 72055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 72155a57606SAdrian Knoth }; 72255a57606SAdrian Knoth 72355a57606SAdrian Knoth static char channel_map_raydat_qs[HDSPM_MAX_CHANNELS] = { 72455a57606SAdrian Knoth 4, 5, /* ADAT 1 */ 72555a57606SAdrian Knoth 6, 7, /* ADAT 2 */ 72655a57606SAdrian Knoth 8, 9, /* ADAT 3 */ 72755a57606SAdrian Knoth 10, 11, /* ADAT 4 */ 72855a57606SAdrian Knoth 0, 1, /* AES */ 72955a57606SAdrian Knoth 2, 3, /* SPDIF */ 73055a57606SAdrian Knoth -1, -1, -1, -1, 73155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 73255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 73355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 73455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 73555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 73655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 73755a57606SAdrian Knoth }; 73855a57606SAdrian Knoth 73955a57606SAdrian Knoth static char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = { 74055a57606SAdrian Knoth 0, 1, /* line in */ 74155a57606SAdrian Knoth 8, 9, /* aes in, */ 74255a57606SAdrian Knoth 10, 11, /* spdif in */ 74355a57606SAdrian Knoth 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */ 74455a57606SAdrian Knoth -1, -1, 74555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 74655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 74755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 74855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 74955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 75055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 75155a57606SAdrian Knoth }; 75255a57606SAdrian Knoth 75355a57606SAdrian Knoth static char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = { 75455a57606SAdrian Knoth 0, 1, /* line out */ 75555a57606SAdrian Knoth 8, 9, /* aes out */ 75655a57606SAdrian Knoth 10, 11, /* spdif out */ 75755a57606SAdrian Knoth 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */ 75855a57606SAdrian Knoth 6, 7, /* phone out */ 75955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 76055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 76155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 76255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 76355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 76455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 76555a57606SAdrian Knoth }; 76655a57606SAdrian Knoth 76755a57606SAdrian Knoth static char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = { 76855a57606SAdrian Knoth 0, 1, /* line in */ 76955a57606SAdrian Knoth 8, 9, /* aes in */ 77055a57606SAdrian Knoth 10, 11, /* spdif in */ 77155a57606SAdrian Knoth 12, 14, 16, 18, /* adat in */ 77255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, 77355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 77455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 77555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 77655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 77755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 77855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1 77955a57606SAdrian Knoth }; 78055a57606SAdrian Knoth 78155a57606SAdrian Knoth static char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = { 78255a57606SAdrian Knoth 0, 1, /* line out */ 78355a57606SAdrian Knoth 8, 9, /* aes out */ 78455a57606SAdrian Knoth 10, 11, /* spdif out */ 78555a57606SAdrian Knoth 12, 14, 16, 18, /* adat out */ 78655a57606SAdrian Knoth 6, 7, /* phone out */ 78755a57606SAdrian Knoth -1, -1, -1, -1, 78855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 78955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 79055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 79155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 79255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 79355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1 79455a57606SAdrian Knoth }; 79555a57606SAdrian Knoth 79655a57606SAdrian Knoth static char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = { 79755a57606SAdrian Knoth 0, 1, /* line in */ 79855a57606SAdrian Knoth 8, 9, /* aes in */ 79955a57606SAdrian Knoth 10, 11, /* spdif in */ 80055a57606SAdrian Knoth 12, 16, /* adat in */ 80155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 80255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 80355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 80455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 80555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 80655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 80755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1 80855a57606SAdrian Knoth }; 80955a57606SAdrian Knoth 81055a57606SAdrian Knoth static char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = { 81155a57606SAdrian Knoth 0, 1, /* line out */ 81255a57606SAdrian Knoth 8, 9, /* aes out */ 81355a57606SAdrian Knoth 10, 11, /* spdif out */ 81455a57606SAdrian Knoth 12, 16, /* adat out */ 81555a57606SAdrian Knoth 6, 7, /* phone out */ 81655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, 81755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 81855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 81955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 82055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 82155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 82255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1 82355a57606SAdrian Knoth }; 82455a57606SAdrian Knoth 825432d2500SAdrian Knoth static char channel_map_aes32[HDSPM_MAX_CHANNELS] = { 826432d2500SAdrian Knoth 0, 1, 2, 3, 4, 5, 6, 7, 827432d2500SAdrian Knoth 8, 9, 10, 11, 12, 13, 14, 15, 828432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 829432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 830432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 831432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 832432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1, 833432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1 834432d2500SAdrian Knoth }; 835432d2500SAdrian Knoth 83698274f07STakashi Iwai struct hdspm_midi { 83798274f07STakashi Iwai struct hdspm *hdspm; 838763f356cSTakashi Iwai int id; 83998274f07STakashi Iwai struct snd_rawmidi *rmidi; 84098274f07STakashi Iwai struct snd_rawmidi_substream *input; 84198274f07STakashi Iwai struct snd_rawmidi_substream *output; 842763f356cSTakashi Iwai char istimer; /* timer in use */ 843763f356cSTakashi Iwai struct timer_list timer; 844763f356cSTakashi Iwai spinlock_t lock; 845763f356cSTakashi Iwai int pending; 8460dca1793SAdrian Knoth int dataIn; 8470dca1793SAdrian Knoth int statusIn; 8480dca1793SAdrian Knoth int dataOut; 8490dca1793SAdrian Knoth int statusOut; 8500dca1793SAdrian Knoth int ie; 8510dca1793SAdrian Knoth int irq; 8520dca1793SAdrian Knoth }; 8530dca1793SAdrian Knoth 8540dca1793SAdrian Knoth struct hdspm_tco { 8550dca1793SAdrian Knoth int input; 8560dca1793SAdrian Knoth int framerate; 8570dca1793SAdrian Knoth int wordclock; 8580dca1793SAdrian Knoth int samplerate; 8590dca1793SAdrian Knoth int pull; 8600dca1793SAdrian Knoth int term; /* 0 = off, 1 = on */ 861763f356cSTakashi Iwai }; 862763f356cSTakashi Iwai 86398274f07STakashi Iwai struct hdspm { 864763f356cSTakashi Iwai spinlock_t lock; 865ef5fa1a4STakashi Iwai /* only one playback and/or capture stream */ 866ef5fa1a4STakashi Iwai struct snd_pcm_substream *capture_substream; 867ef5fa1a4STakashi Iwai struct snd_pcm_substream *playback_substream; 868763f356cSTakashi Iwai 869763f356cSTakashi Iwai char *card_name; /* for procinfo */ 8703cee5a60SRemy Bruno unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/ 8713cee5a60SRemy Bruno 8720dca1793SAdrian Knoth uint8_t io_type; 873763f356cSTakashi Iwai 874763f356cSTakashi Iwai int monitor_outs; /* set up monitoring outs init flag */ 875763f356cSTakashi Iwai 876763f356cSTakashi Iwai u32 control_register; /* cached value */ 877763f356cSTakashi Iwai u32 control2_register; /* cached value */ 8780dca1793SAdrian Knoth u32 settings_register; 879763f356cSTakashi Iwai 8800dca1793SAdrian Knoth struct hdspm_midi midi[4]; 881763f356cSTakashi Iwai struct tasklet_struct midi_tasklet; 882763f356cSTakashi Iwai 883763f356cSTakashi Iwai size_t period_bytes; 8840dca1793SAdrian Knoth unsigned char ss_in_channels; 8850dca1793SAdrian Knoth unsigned char ds_in_channels; 8860dca1793SAdrian Knoth unsigned char qs_in_channels; 8870dca1793SAdrian Knoth unsigned char ss_out_channels; 8880dca1793SAdrian Knoth unsigned char ds_out_channels; 8890dca1793SAdrian Knoth unsigned char qs_out_channels; 8900dca1793SAdrian Knoth 8910dca1793SAdrian Knoth unsigned char max_channels_in; 8920dca1793SAdrian Knoth unsigned char max_channels_out; 8930dca1793SAdrian Knoth 8940dca1793SAdrian Knoth char *channel_map_in; 8950dca1793SAdrian Knoth char *channel_map_out; 8960dca1793SAdrian Knoth 8970dca1793SAdrian Knoth char *channel_map_in_ss, *channel_map_in_ds, *channel_map_in_qs; 8980dca1793SAdrian Knoth char *channel_map_out_ss, *channel_map_out_ds, *channel_map_out_qs; 8990dca1793SAdrian Knoth 9000dca1793SAdrian Knoth char **port_names_in; 9010dca1793SAdrian Knoth char **port_names_out; 9020dca1793SAdrian Knoth 9030dca1793SAdrian Knoth char **port_names_in_ss, **port_names_in_ds, **port_names_in_qs; 9040dca1793SAdrian Knoth char **port_names_out_ss, **port_names_out_ds, **port_names_out_qs; 905763f356cSTakashi Iwai 906763f356cSTakashi Iwai unsigned char *playback_buffer; /* suitably aligned address */ 907763f356cSTakashi Iwai unsigned char *capture_buffer; /* suitably aligned address */ 908763f356cSTakashi Iwai 909763f356cSTakashi Iwai pid_t capture_pid; /* process id which uses capture */ 910763f356cSTakashi Iwai pid_t playback_pid; /* process id which uses capture */ 911763f356cSTakashi Iwai int running; /* running status */ 912763f356cSTakashi Iwai 913763f356cSTakashi Iwai int last_external_sample_rate; /* samplerate mystic ... */ 914763f356cSTakashi Iwai int last_internal_sample_rate; 915763f356cSTakashi Iwai int system_sample_rate; 916763f356cSTakashi Iwai 917763f356cSTakashi Iwai int dev; /* Hardware vars... */ 918763f356cSTakashi Iwai int irq; 919763f356cSTakashi Iwai unsigned long port; 920763f356cSTakashi Iwai void __iomem *iobase; 921763f356cSTakashi Iwai 922763f356cSTakashi Iwai int irq_count; /* for debug */ 9230dca1793SAdrian Knoth int midiPorts; 924763f356cSTakashi Iwai 92598274f07STakashi Iwai struct snd_card *card; /* one card */ 92698274f07STakashi Iwai struct snd_pcm *pcm; /* has one pcm */ 92798274f07STakashi Iwai struct snd_hwdep *hwdep; /* and a hwdep for additional ioctl */ 928763f356cSTakashi Iwai struct pci_dev *pci; /* and an pci info */ 929763f356cSTakashi Iwai 930763f356cSTakashi Iwai /* Mixer vars */ 931ef5fa1a4STakashi Iwai /* fast alsa mixer */ 932ef5fa1a4STakashi Iwai struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; 933ef5fa1a4STakashi Iwai /* but input to much, so not used */ 934ef5fa1a4STakashi Iwai struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS]; 9350dca1793SAdrian Knoth /* full mixer accessable over mixer ioctl or hwdep-device */ 936ef5fa1a4STakashi Iwai struct hdspm_mixer *mixer; 937763f356cSTakashi Iwai 9380dca1793SAdrian Knoth struct hdspm_tco *tco; /* NULL if no TCO detected */ 939763f356cSTakashi Iwai 9400dca1793SAdrian Knoth char **texts_autosync; 9410dca1793SAdrian Knoth int texts_autosync_items; 942763f356cSTakashi Iwai 9430dca1793SAdrian Knoth cycles_t last_interrupt; 944730a5865SJaroslav Kysela 945730a5865SJaroslav Kysela struct hdspm_peak_rms peak_rms; 946763f356cSTakashi Iwai }; 947763f356cSTakashi Iwai 948763f356cSTakashi Iwai 949cebe41d4SAlexey Dobriyan static DEFINE_PCI_DEVICE_TABLE(snd_hdspm_ids) = { 950763f356cSTakashi Iwai { 951763f356cSTakashi Iwai .vendor = PCI_VENDOR_ID_XILINX, 952763f356cSTakashi Iwai .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, 953763f356cSTakashi Iwai .subvendor = PCI_ANY_ID, 954763f356cSTakashi Iwai .subdevice = PCI_ANY_ID, 955763f356cSTakashi Iwai .class = 0, 956763f356cSTakashi Iwai .class_mask = 0, 957763f356cSTakashi Iwai .driver_data = 0}, 958763f356cSTakashi Iwai {0,} 959763f356cSTakashi Iwai }; 960763f356cSTakashi Iwai 961763f356cSTakashi Iwai MODULE_DEVICE_TABLE(pci, snd_hdspm_ids); 962763f356cSTakashi Iwai 963763f356cSTakashi Iwai /* prototypes */ 96498274f07STakashi Iwai static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, 96598274f07STakashi Iwai struct hdspm * hdspm); 96698274f07STakashi Iwai static int __devinit snd_hdspm_create_pcm(struct snd_card *card, 96798274f07STakashi Iwai struct hdspm * hdspm); 968763f356cSTakashi Iwai 96998274f07STakashi Iwai static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm); 97098274f07STakashi Iwai static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); 97198274f07STakashi Iwai static int hdspm_autosync_ref(struct hdspm *hdspm); 97298274f07STakashi Iwai static int snd_hdspm_set_defaults(struct hdspm *hdspm); 97377a23f26STakashi Iwai static void hdspm_set_sgbuf(struct hdspm *hdspm, 97477a23f26STakashi Iwai struct snd_pcm_substream *substream, 975763f356cSTakashi Iwai unsigned int reg, int channels); 976763f356cSTakashi Iwai 9773cee5a60SRemy Bruno static inline int HDSPM_bit2freq(int n) 9783cee5a60SRemy Bruno { 97962cef821SDenys Vlasenko static const int bit2freq_tab[] = { 98062cef821SDenys Vlasenko 0, 32000, 44100, 48000, 64000, 88200, 9813cee5a60SRemy Bruno 96000, 128000, 176400, 192000 }; 9823cee5a60SRemy Bruno if (n < 1 || n > 9) 9833cee5a60SRemy Bruno return 0; 9843cee5a60SRemy Bruno return bit2freq_tab[n]; 9853cee5a60SRemy Bruno } 9863cee5a60SRemy Bruno 9870dca1793SAdrian Knoth /* Write/read to/from HDSPM with Adresses in Bytes 988763f356cSTakashi Iwai not words but only 32Bit writes are allowed */ 989763f356cSTakashi Iwai 99098274f07STakashi Iwai static inline void hdspm_write(struct hdspm * hdspm, unsigned int reg, 991763f356cSTakashi Iwai unsigned int val) 992763f356cSTakashi Iwai { 993763f356cSTakashi Iwai writel(val, hdspm->iobase + reg); 994763f356cSTakashi Iwai } 995763f356cSTakashi Iwai 99698274f07STakashi Iwai static inline unsigned int hdspm_read(struct hdspm * hdspm, unsigned int reg) 997763f356cSTakashi Iwai { 998763f356cSTakashi Iwai return readl(hdspm->iobase + reg); 999763f356cSTakashi Iwai } 1000763f356cSTakashi Iwai 1001763f356cSTakashi Iwai /* for each output channel (chan) I have an Input (in) and Playback (pb) Fader 1002763f356cSTakashi Iwai mixer is write only on hardware so we have to cache him for read 1003763f356cSTakashi Iwai each fader is a u32, but uses only the first 16 bit */ 1004763f356cSTakashi Iwai 100598274f07STakashi Iwai static inline int hdspm_read_in_gain(struct hdspm * hdspm, unsigned int chan, 1006763f356cSTakashi Iwai unsigned int in) 1007763f356cSTakashi Iwai { 10085bab2482SAdrian Bunk if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) 1009763f356cSTakashi Iwai return 0; 1010763f356cSTakashi Iwai 1011763f356cSTakashi Iwai return hdspm->mixer->ch[chan].in[in]; 1012763f356cSTakashi Iwai } 1013763f356cSTakashi Iwai 101498274f07STakashi Iwai static inline int hdspm_read_pb_gain(struct hdspm * hdspm, unsigned int chan, 1015763f356cSTakashi Iwai unsigned int pb) 1016763f356cSTakashi Iwai { 10175bab2482SAdrian Bunk if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) 1018763f356cSTakashi Iwai return 0; 1019763f356cSTakashi Iwai return hdspm->mixer->ch[chan].pb[pb]; 1020763f356cSTakashi Iwai } 1021763f356cSTakashi Iwai 102262cef821SDenys Vlasenko static int hdspm_write_in_gain(struct hdspm *hdspm, unsigned int chan, 1023763f356cSTakashi Iwai unsigned int in, unsigned short data) 1024763f356cSTakashi Iwai { 1025763f356cSTakashi Iwai if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) 1026763f356cSTakashi Iwai return -1; 1027763f356cSTakashi Iwai 1028763f356cSTakashi Iwai hdspm_write(hdspm, 1029763f356cSTakashi Iwai HDSPM_MADI_mixerBase + 1030763f356cSTakashi Iwai ((in + 128 * chan) * sizeof(u32)), 1031763f356cSTakashi Iwai (hdspm->mixer->ch[chan].in[in] = data & 0xFFFF)); 1032763f356cSTakashi Iwai return 0; 1033763f356cSTakashi Iwai } 1034763f356cSTakashi Iwai 103562cef821SDenys Vlasenko static int hdspm_write_pb_gain(struct hdspm *hdspm, unsigned int chan, 1036763f356cSTakashi Iwai unsigned int pb, unsigned short data) 1037763f356cSTakashi Iwai { 1038763f356cSTakashi Iwai if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) 1039763f356cSTakashi Iwai return -1; 1040763f356cSTakashi Iwai 1041763f356cSTakashi Iwai hdspm_write(hdspm, 1042763f356cSTakashi Iwai HDSPM_MADI_mixerBase + 1043763f356cSTakashi Iwai ((64 + pb + 128 * chan) * sizeof(u32)), 1044763f356cSTakashi Iwai (hdspm->mixer->ch[chan].pb[pb] = data & 0xFFFF)); 1045763f356cSTakashi Iwai return 0; 1046763f356cSTakashi Iwai } 1047763f356cSTakashi Iwai 1048763f356cSTakashi Iwai 1049763f356cSTakashi Iwai /* enable DMA for specific channels, now available for DSP-MADI */ 105098274f07STakashi Iwai static inline void snd_hdspm_enable_in(struct hdspm * hdspm, int i, int v) 1051763f356cSTakashi Iwai { 1052763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_inputEnableBase + (4 * i), v); 1053763f356cSTakashi Iwai } 1054763f356cSTakashi Iwai 105598274f07STakashi Iwai static inline void snd_hdspm_enable_out(struct hdspm * hdspm, int i, int v) 1056763f356cSTakashi Iwai { 1057763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_outputEnableBase + (4 * i), v); 1058763f356cSTakashi Iwai } 1059763f356cSTakashi Iwai 1060763f356cSTakashi Iwai /* check if same process is writing and reading */ 106162cef821SDenys Vlasenko static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm) 1062763f356cSTakashi Iwai { 1063763f356cSTakashi Iwai unsigned long flags; 1064763f356cSTakashi Iwai int ret = 1; 1065763f356cSTakashi Iwai 1066763f356cSTakashi Iwai spin_lock_irqsave(&hdspm->lock, flags); 1067763f356cSTakashi Iwai if ((hdspm->playback_pid != hdspm->capture_pid) && 1068763f356cSTakashi Iwai (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) { 1069763f356cSTakashi Iwai ret = 0; 1070763f356cSTakashi Iwai } 1071763f356cSTakashi Iwai spin_unlock_irqrestore(&hdspm->lock, flags); 1072763f356cSTakashi Iwai return ret; 1073763f356cSTakashi Iwai } 1074763f356cSTakashi Iwai 1075763f356cSTakashi Iwai /* check for external sample rate */ 107662cef821SDenys Vlasenko static int hdspm_external_sample_rate(struct hdspm *hdspm) 1077763f356cSTakashi Iwai { 10780dca1793SAdrian Knoth unsigned int status, status2, timecode; 10790dca1793SAdrian Knoth int syncref, rate = 0, rate_bits; 10803cee5a60SRemy Bruno 10810dca1793SAdrian Knoth switch (hdspm->io_type) { 10820dca1793SAdrian Knoth case AES32: 10830dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 10840dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 10850dca1793SAdrian Knoth timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); 10860dca1793SAdrian Knoth 10870dca1793SAdrian Knoth syncref = hdspm_autosync_ref(hdspm); 10883cee5a60SRemy Bruno 10893cee5a60SRemy Bruno if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD && 10903cee5a60SRemy Bruno status & HDSPM_AES32_wcLock) 10910dca1793SAdrian Knoth return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF); 10920dca1793SAdrian Knoth 10933cee5a60SRemy Bruno if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 && 10943cee5a60SRemy Bruno syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 && 10953cee5a60SRemy Bruno status2 & (HDSPM_LockAES >> 10963cee5a60SRemy Bruno (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))) 10970dca1793SAdrian Knoth return HDSPM_bit2freq((timecode >> (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF); 10983cee5a60SRemy Bruno return 0; 10990dca1793SAdrian Knoth break; 11000dca1793SAdrian Knoth 11010dca1793SAdrian Knoth case MADIface: 11020dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 11030dca1793SAdrian Knoth 11040dca1793SAdrian Knoth if (!(status & HDSPM_madiLock)) { 11050dca1793SAdrian Knoth rate = 0; /* no lock */ 11063cee5a60SRemy Bruno } else { 11070dca1793SAdrian Knoth switch (status & (HDSPM_status1_freqMask)) { 11080dca1793SAdrian Knoth case HDSPM_status1_F_0*1: 11090dca1793SAdrian Knoth rate = 32000; break; 11100dca1793SAdrian Knoth case HDSPM_status1_F_0*2: 11110dca1793SAdrian Knoth rate = 44100; break; 11120dca1793SAdrian Knoth case HDSPM_status1_F_0*3: 11130dca1793SAdrian Knoth rate = 48000; break; 11140dca1793SAdrian Knoth case HDSPM_status1_F_0*4: 11150dca1793SAdrian Knoth rate = 64000; break; 11160dca1793SAdrian Knoth case HDSPM_status1_F_0*5: 11170dca1793SAdrian Knoth rate = 88200; break; 11180dca1793SAdrian Knoth case HDSPM_status1_F_0*6: 11190dca1793SAdrian Knoth rate = 96000; break; 11200dca1793SAdrian Knoth case HDSPM_status1_F_0*7: 11210dca1793SAdrian Knoth rate = 128000; break; 11220dca1793SAdrian Knoth case HDSPM_status1_F_0*8: 11230dca1793SAdrian Knoth rate = 176400; break; 11240dca1793SAdrian Knoth case HDSPM_status1_F_0*9: 11250dca1793SAdrian Knoth rate = 192000; break; 11260dca1793SAdrian Knoth default: 11270dca1793SAdrian Knoth rate = 0; break; 11280dca1793SAdrian Knoth } 11290dca1793SAdrian Knoth } 11300dca1793SAdrian Knoth 11310dca1793SAdrian Knoth break; 11320dca1793SAdrian Knoth 11330dca1793SAdrian Knoth case MADI: 11340dca1793SAdrian Knoth case AIO: 11350dca1793SAdrian Knoth case RayDAT: 11360dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 11370dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 11380dca1793SAdrian Knoth rate = 0; 1139763f356cSTakashi Iwai 1140763f356cSTakashi Iwai /* if wordclock has synced freq and wordclock is valid */ 1141763f356cSTakashi Iwai if ((status2 & HDSPM_wcLock) != 0 && 1142763f356cSTakashi Iwai (status & HDSPM_SelSyncRef0) == 0) { 1143763f356cSTakashi Iwai 1144763f356cSTakashi Iwai rate_bits = status2 & HDSPM_wcFreqMask; 1145763f356cSTakashi Iwai 11460dca1793SAdrian Knoth 1147763f356cSTakashi Iwai switch (rate_bits) { 1148763f356cSTakashi Iwai case HDSPM_wcFreq32: 1149763f356cSTakashi Iwai rate = 32000; 1150763f356cSTakashi Iwai break; 1151763f356cSTakashi Iwai case HDSPM_wcFreq44_1: 1152763f356cSTakashi Iwai rate = 44100; 1153763f356cSTakashi Iwai break; 1154763f356cSTakashi Iwai case HDSPM_wcFreq48: 1155763f356cSTakashi Iwai rate = 48000; 1156763f356cSTakashi Iwai break; 1157763f356cSTakashi Iwai case HDSPM_wcFreq64: 1158763f356cSTakashi Iwai rate = 64000; 1159763f356cSTakashi Iwai break; 1160763f356cSTakashi Iwai case HDSPM_wcFreq88_2: 1161763f356cSTakashi Iwai rate = 88200; 1162763f356cSTakashi Iwai break; 1163763f356cSTakashi Iwai case HDSPM_wcFreq96: 1164763f356cSTakashi Iwai rate = 96000; 1165763f356cSTakashi Iwai break; 1166763f356cSTakashi Iwai default: 1167763f356cSTakashi Iwai rate = 0; 1168763f356cSTakashi Iwai break; 1169763f356cSTakashi Iwai } 1170763f356cSTakashi Iwai } 1171763f356cSTakashi Iwai 1172ef5fa1a4STakashi Iwai /* if rate detected and Syncref is Word than have it, 1173ef5fa1a4STakashi Iwai * word has priority to MADI 1174ef5fa1a4STakashi Iwai */ 11753cee5a60SRemy Bruno if (rate != 0 && 11763cee5a60SRemy Bruno (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) 1177763f356cSTakashi Iwai return rate; 1178763f356cSTakashi Iwai 11790dca1793SAdrian Knoth /* maybe a madi input (which is taken if sel sync is madi) */ 1180763f356cSTakashi Iwai if (status & HDSPM_madiLock) { 1181763f356cSTakashi Iwai rate_bits = status & HDSPM_madiFreqMask; 1182763f356cSTakashi Iwai 1183763f356cSTakashi Iwai switch (rate_bits) { 1184763f356cSTakashi Iwai case HDSPM_madiFreq32: 1185763f356cSTakashi Iwai rate = 32000; 1186763f356cSTakashi Iwai break; 1187763f356cSTakashi Iwai case HDSPM_madiFreq44_1: 1188763f356cSTakashi Iwai rate = 44100; 1189763f356cSTakashi Iwai break; 1190763f356cSTakashi Iwai case HDSPM_madiFreq48: 1191763f356cSTakashi Iwai rate = 48000; 1192763f356cSTakashi Iwai break; 1193763f356cSTakashi Iwai case HDSPM_madiFreq64: 1194763f356cSTakashi Iwai rate = 64000; 1195763f356cSTakashi Iwai break; 1196763f356cSTakashi Iwai case HDSPM_madiFreq88_2: 1197763f356cSTakashi Iwai rate = 88200; 1198763f356cSTakashi Iwai break; 1199763f356cSTakashi Iwai case HDSPM_madiFreq96: 1200763f356cSTakashi Iwai rate = 96000; 1201763f356cSTakashi Iwai break; 1202763f356cSTakashi Iwai case HDSPM_madiFreq128: 1203763f356cSTakashi Iwai rate = 128000; 1204763f356cSTakashi Iwai break; 1205763f356cSTakashi Iwai case HDSPM_madiFreq176_4: 1206763f356cSTakashi Iwai rate = 176400; 1207763f356cSTakashi Iwai break; 1208763f356cSTakashi Iwai case HDSPM_madiFreq192: 1209763f356cSTakashi Iwai rate = 192000; 1210763f356cSTakashi Iwai break; 1211763f356cSTakashi Iwai default: 1212763f356cSTakashi Iwai rate = 0; 1213763f356cSTakashi Iwai break; 1214763f356cSTakashi Iwai } 1215763f356cSTakashi Iwai } 12160dca1793SAdrian Knoth break; 1217763f356cSTakashi Iwai } 12180dca1793SAdrian Knoth 12190dca1793SAdrian Knoth return rate; 12203cee5a60SRemy Bruno } 1221763f356cSTakashi Iwai 1222763f356cSTakashi Iwai /* Latency function */ 122398274f07STakashi Iwai static inline void hdspm_compute_period_size(struct hdspm *hdspm) 1224763f356cSTakashi Iwai { 12250dca1793SAdrian Knoth hdspm->period_bytes = 1 << ((hdspm_decode_latency(hdspm->control_register) + 8)); 1226763f356cSTakashi Iwai } 1227763f356cSTakashi Iwai 12280dca1793SAdrian Knoth 122998274f07STakashi Iwai static snd_pcm_uframes_t hdspm_hw_pointer(struct hdspm *hdspm) 1230763f356cSTakashi Iwai { 1231763f356cSTakashi Iwai int position; 1232763f356cSTakashi Iwai 1233763f356cSTakashi Iwai position = hdspm_read(hdspm, HDSPM_statusRegister); 1234483cee77SAdrian Knoth 1235483cee77SAdrian Knoth switch (hdspm->io_type) { 1236483cee77SAdrian Knoth case RayDAT: 1237483cee77SAdrian Knoth case AIO: 1238763f356cSTakashi Iwai position &= HDSPM_BufferPositionMask; 12390dca1793SAdrian Knoth position /= 4; /* Bytes per sample */ 1240483cee77SAdrian Knoth break; 1241483cee77SAdrian Knoth default: 1242483cee77SAdrian Knoth position = (position & HDSPM_BufferID) ? 1243483cee77SAdrian Knoth (hdspm->period_bytes / 4) : 0; 1244483cee77SAdrian Knoth } 1245763f356cSTakashi Iwai 1246763f356cSTakashi Iwai return position; 1247763f356cSTakashi Iwai } 1248763f356cSTakashi Iwai 1249763f356cSTakashi Iwai 125098274f07STakashi Iwai static inline void hdspm_start_audio(struct hdspm * s) 1251763f356cSTakashi Iwai { 1252763f356cSTakashi Iwai s->control_register |= (HDSPM_AudioInterruptEnable | HDSPM_Start); 1253763f356cSTakashi Iwai hdspm_write(s, HDSPM_controlRegister, s->control_register); 1254763f356cSTakashi Iwai } 1255763f356cSTakashi Iwai 125698274f07STakashi Iwai static inline void hdspm_stop_audio(struct hdspm * s) 1257763f356cSTakashi Iwai { 1258763f356cSTakashi Iwai s->control_register &= ~(HDSPM_Start | HDSPM_AudioInterruptEnable); 1259763f356cSTakashi Iwai hdspm_write(s, HDSPM_controlRegister, s->control_register); 1260763f356cSTakashi Iwai } 1261763f356cSTakashi Iwai 1262763f356cSTakashi Iwai /* should I silence all or only opened ones ? doit all for first even is 4MB*/ 126362cef821SDenys Vlasenko static void hdspm_silence_playback(struct hdspm *hdspm) 1264763f356cSTakashi Iwai { 1265763f356cSTakashi Iwai int i; 1266763f356cSTakashi Iwai int n = hdspm->period_bytes; 1267763f356cSTakashi Iwai void *buf = hdspm->playback_buffer; 1268763f356cSTakashi Iwai 12693cee5a60SRemy Bruno if (buf == NULL) 12703cee5a60SRemy Bruno return; 1271763f356cSTakashi Iwai 1272763f356cSTakashi Iwai for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { 1273763f356cSTakashi Iwai memset(buf, 0, n); 1274763f356cSTakashi Iwai buf += HDSPM_CHANNEL_BUFFER_BYTES; 1275763f356cSTakashi Iwai } 1276763f356cSTakashi Iwai } 1277763f356cSTakashi Iwai 127898274f07STakashi Iwai static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames) 1279763f356cSTakashi Iwai { 1280763f356cSTakashi Iwai int n; 1281763f356cSTakashi Iwai 1282763f356cSTakashi Iwai spin_lock_irq(&s->lock); 1283763f356cSTakashi Iwai 1284763f356cSTakashi Iwai frames >>= 7; 1285763f356cSTakashi Iwai n = 0; 1286763f356cSTakashi Iwai while (frames) { 1287763f356cSTakashi Iwai n++; 1288763f356cSTakashi Iwai frames >>= 1; 1289763f356cSTakashi Iwai } 1290763f356cSTakashi Iwai s->control_register &= ~HDSPM_LatencyMask; 1291763f356cSTakashi Iwai s->control_register |= hdspm_encode_latency(n); 1292763f356cSTakashi Iwai 1293763f356cSTakashi Iwai hdspm_write(s, HDSPM_controlRegister, s->control_register); 1294763f356cSTakashi Iwai 1295763f356cSTakashi Iwai hdspm_compute_period_size(s); 1296763f356cSTakashi Iwai 1297763f356cSTakashi Iwai spin_unlock_irq(&s->lock); 1298763f356cSTakashi Iwai 1299763f356cSTakashi Iwai return 0; 1300763f356cSTakashi Iwai } 1301763f356cSTakashi Iwai 13020dca1793SAdrian Knoth static u64 hdspm_calc_dds_value(struct hdspm *hdspm, u64 period) 13030dca1793SAdrian Knoth { 13040dca1793SAdrian Knoth u64 freq_const; 13050dca1793SAdrian Knoth 13060dca1793SAdrian Knoth if (period == 0) 13070dca1793SAdrian Knoth return 0; 13080dca1793SAdrian Knoth 13090dca1793SAdrian Knoth switch (hdspm->io_type) { 13100dca1793SAdrian Knoth case MADI: 13110dca1793SAdrian Knoth case AES32: 13120dca1793SAdrian Knoth freq_const = 110069313433624ULL; 13130dca1793SAdrian Knoth break; 13140dca1793SAdrian Knoth case RayDAT: 13150dca1793SAdrian Knoth case AIO: 13160dca1793SAdrian Knoth freq_const = 104857600000000ULL; 13170dca1793SAdrian Knoth break; 13180dca1793SAdrian Knoth case MADIface: 13190dca1793SAdrian Knoth freq_const = 131072000000000ULL; 13200dca1793SAdrian Knoth } 13210dca1793SAdrian Knoth 13220dca1793SAdrian Knoth return div_u64(freq_const, period); 13230dca1793SAdrian Knoth } 13240dca1793SAdrian Knoth 13250dca1793SAdrian Knoth 1326ffb2c3c0SRemy Bruno static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) 1327ffb2c3c0SRemy Bruno { 1328ffb2c3c0SRemy Bruno u64 n; 1329ffb2c3c0SRemy Bruno 1330ffb2c3c0SRemy Bruno if (rate >= 112000) 1331ffb2c3c0SRemy Bruno rate /= 4; 1332ffb2c3c0SRemy Bruno else if (rate >= 56000) 1333ffb2c3c0SRemy Bruno rate /= 2; 1334ffb2c3c0SRemy Bruno 13350dca1793SAdrian Knoth switch (hdspm->io_type) { 13360dca1793SAdrian Knoth case MADIface: 13370dca1793SAdrian Knoth n = 131072000000000ULL; /* 125 MHz */ 13380dca1793SAdrian Knoth break; 13390dca1793SAdrian Knoth case MADI: 13400dca1793SAdrian Knoth case AES32: 13410dca1793SAdrian Knoth n = 110069313433624ULL; /* 105 MHz */ 13420dca1793SAdrian Knoth break; 13430dca1793SAdrian Knoth case RayDAT: 13440dca1793SAdrian Knoth case AIO: 13450dca1793SAdrian Knoth n = 104857600000000ULL; /* 100 MHz */ 13460dca1793SAdrian Knoth break; 13470dca1793SAdrian Knoth } 13480dca1793SAdrian Knoth 13493f7440a6STakashi Iwai n = div_u64(n, rate); 1350ffb2c3c0SRemy Bruno /* n should be less than 2^32 for being written to FREQ register */ 1351da3cec35STakashi Iwai snd_BUG_ON(n >> 32); 1352ffb2c3c0SRemy Bruno hdspm_write(hdspm, HDSPM_freqReg, (u32)n); 1353ffb2c3c0SRemy Bruno } 1354763f356cSTakashi Iwai 1355763f356cSTakashi Iwai /* dummy set rate lets see what happens */ 135698274f07STakashi Iwai static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) 1357763f356cSTakashi Iwai { 1358763f356cSTakashi Iwai int current_rate; 1359763f356cSTakashi Iwai int rate_bits; 1360763f356cSTakashi Iwai int not_set = 0; 13616534599dSRemy Bruno int current_speed, target_speed; 1362763f356cSTakashi Iwai 1363763f356cSTakashi Iwai /* ASSUMPTION: hdspm->lock is either set, or there is no need for 1364763f356cSTakashi Iwai it (e.g. during module initialization). 1365763f356cSTakashi Iwai */ 1366763f356cSTakashi Iwai 1367763f356cSTakashi Iwai if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { 1368763f356cSTakashi Iwai 1369763f356cSTakashi Iwai /* SLAVE --- */ 1370763f356cSTakashi Iwai if (called_internally) { 1371763f356cSTakashi Iwai 1372763f356cSTakashi Iwai /* request from ctl or card initialization 1373763f356cSTakashi Iwai just make a warning an remember setting 1374763f356cSTakashi Iwai for future master mode switching */ 1375763f356cSTakashi Iwai 1376ef5fa1a4STakashi Iwai snd_printk(KERN_WARNING "HDSPM: " 1377ef5fa1a4STakashi Iwai "Warning: device is not running " 1378ef5fa1a4STakashi Iwai "as a clock master.\n"); 1379763f356cSTakashi Iwai not_set = 1; 1380763f356cSTakashi Iwai } else { 1381763f356cSTakashi Iwai 1382763f356cSTakashi Iwai /* hw_param request while in AutoSync mode */ 1383763f356cSTakashi Iwai int external_freq = 1384763f356cSTakashi Iwai hdspm_external_sample_rate(hdspm); 1385763f356cSTakashi Iwai 1386ef5fa1a4STakashi Iwai if (hdspm_autosync_ref(hdspm) == 1387ef5fa1a4STakashi Iwai HDSPM_AUTOSYNC_FROM_NONE) { 1388763f356cSTakashi Iwai 1389ef5fa1a4STakashi Iwai snd_printk(KERN_WARNING "HDSPM: " 1390ef5fa1a4STakashi Iwai "Detected no Externel Sync \n"); 1391763f356cSTakashi Iwai not_set = 1; 1392763f356cSTakashi Iwai 1393763f356cSTakashi Iwai } else if (rate != external_freq) { 1394763f356cSTakashi Iwai 1395ef5fa1a4STakashi Iwai snd_printk(KERN_WARNING "HDSPM: " 1396ef5fa1a4STakashi Iwai "Warning: No AutoSync source for " 1397ef5fa1a4STakashi Iwai "requested rate\n"); 1398763f356cSTakashi Iwai not_set = 1; 1399763f356cSTakashi Iwai } 1400763f356cSTakashi Iwai } 1401763f356cSTakashi Iwai } 1402763f356cSTakashi Iwai 1403763f356cSTakashi Iwai current_rate = hdspm->system_sample_rate; 1404763f356cSTakashi Iwai 1405763f356cSTakashi Iwai /* Changing between Singe, Double and Quad speed is not 1406763f356cSTakashi Iwai allowed if any substreams are open. This is because such a change 1407763f356cSTakashi Iwai causes a shift in the location of the DMA buffers and a reduction 1408763f356cSTakashi Iwai in the number of available buffers. 1409763f356cSTakashi Iwai 1410763f356cSTakashi Iwai Note that a similar but essentially insoluble problem exists for 1411763f356cSTakashi Iwai externally-driven rate changes. All we can do is to flag rate 1412763f356cSTakashi Iwai changes in the read/write routines. 1413763f356cSTakashi Iwai */ 1414763f356cSTakashi Iwai 14156534599dSRemy Bruno if (current_rate <= 48000) 14166534599dSRemy Bruno current_speed = HDSPM_SPEED_SINGLE; 14176534599dSRemy Bruno else if (current_rate <= 96000) 14186534599dSRemy Bruno current_speed = HDSPM_SPEED_DOUBLE; 14196534599dSRemy Bruno else 14206534599dSRemy Bruno current_speed = HDSPM_SPEED_QUAD; 14216534599dSRemy Bruno 14226534599dSRemy Bruno if (rate <= 48000) 14236534599dSRemy Bruno target_speed = HDSPM_SPEED_SINGLE; 14246534599dSRemy Bruno else if (rate <= 96000) 14256534599dSRemy Bruno target_speed = HDSPM_SPEED_DOUBLE; 14266534599dSRemy Bruno else 14276534599dSRemy Bruno target_speed = HDSPM_SPEED_QUAD; 14283cee5a60SRemy Bruno 1429763f356cSTakashi Iwai switch (rate) { 1430763f356cSTakashi Iwai case 32000: 1431763f356cSTakashi Iwai rate_bits = HDSPM_Frequency32KHz; 1432763f356cSTakashi Iwai break; 1433763f356cSTakashi Iwai case 44100: 1434763f356cSTakashi Iwai rate_bits = HDSPM_Frequency44_1KHz; 1435763f356cSTakashi Iwai break; 1436763f356cSTakashi Iwai case 48000: 1437763f356cSTakashi Iwai rate_bits = HDSPM_Frequency48KHz; 1438763f356cSTakashi Iwai break; 1439763f356cSTakashi Iwai case 64000: 1440763f356cSTakashi Iwai rate_bits = HDSPM_Frequency64KHz; 1441763f356cSTakashi Iwai break; 1442763f356cSTakashi Iwai case 88200: 1443763f356cSTakashi Iwai rate_bits = HDSPM_Frequency88_2KHz; 1444763f356cSTakashi Iwai break; 1445763f356cSTakashi Iwai case 96000: 1446763f356cSTakashi Iwai rate_bits = HDSPM_Frequency96KHz; 1447763f356cSTakashi Iwai break; 14483cee5a60SRemy Bruno case 128000: 14493cee5a60SRemy Bruno rate_bits = HDSPM_Frequency128KHz; 14503cee5a60SRemy Bruno break; 14513cee5a60SRemy Bruno case 176400: 14523cee5a60SRemy Bruno rate_bits = HDSPM_Frequency176_4KHz; 14533cee5a60SRemy Bruno break; 14543cee5a60SRemy Bruno case 192000: 14553cee5a60SRemy Bruno rate_bits = HDSPM_Frequency192KHz; 14563cee5a60SRemy Bruno break; 1457763f356cSTakashi Iwai default: 1458763f356cSTakashi Iwai return -EINVAL; 1459763f356cSTakashi Iwai } 1460763f356cSTakashi Iwai 14616534599dSRemy Bruno if (current_speed != target_speed 1462763f356cSTakashi Iwai && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { 1463763f356cSTakashi Iwai snd_printk 1464ef5fa1a4STakashi Iwai (KERN_ERR "HDSPM: " 14656534599dSRemy Bruno "cannot change from %s speed to %s speed mode " 1466ef5fa1a4STakashi Iwai "(capture PID = %d, playback PID = %d)\n", 14676534599dSRemy Bruno hdspm_speed_names[current_speed], 14686534599dSRemy Bruno hdspm_speed_names[target_speed], 1469763f356cSTakashi Iwai hdspm->capture_pid, hdspm->playback_pid); 1470763f356cSTakashi Iwai return -EBUSY; 1471763f356cSTakashi Iwai } 1472763f356cSTakashi Iwai 1473763f356cSTakashi Iwai hdspm->control_register &= ~HDSPM_FrequencyMask; 1474763f356cSTakashi Iwai hdspm->control_register |= rate_bits; 1475763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 1476763f356cSTakashi Iwai 1477ffb2c3c0SRemy Bruno /* For AES32, need to set DDS value in FREQ register 1478ffb2c3c0SRemy Bruno For MADI, also apparently */ 1479ffb2c3c0SRemy Bruno hdspm_set_dds_value(hdspm, rate); 1480ffb2c3c0SRemy Bruno 14810dca1793SAdrian Knoth if (AES32 == hdspm->io_type && rate != current_rate) 1482ffb2c3c0SRemy Bruno hdspm_write(hdspm, HDSPM_eeprom_wr, 0); 1483ffb2c3c0SRemy Bruno 1484763f356cSTakashi Iwai hdspm->system_sample_rate = rate; 1485763f356cSTakashi Iwai 14860dca1793SAdrian Knoth if (rate <= 48000) { 14870dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_in_ss; 14880dca1793SAdrian Knoth hdspm->channel_map_out = hdspm->channel_map_out_ss; 14890dca1793SAdrian Knoth hdspm->max_channels_in = hdspm->ss_in_channels; 14900dca1793SAdrian Knoth hdspm->max_channels_out = hdspm->ss_out_channels; 14910dca1793SAdrian Knoth hdspm->port_names_in = hdspm->port_names_in_ss; 14920dca1793SAdrian Knoth hdspm->port_names_out = hdspm->port_names_out_ss; 14930dca1793SAdrian Knoth } else if (rate <= 96000) { 14940dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_in_ds; 14950dca1793SAdrian Knoth hdspm->channel_map_out = hdspm->channel_map_out_ds; 14960dca1793SAdrian Knoth hdspm->max_channels_in = hdspm->ds_in_channels; 14970dca1793SAdrian Knoth hdspm->max_channels_out = hdspm->ds_out_channels; 14980dca1793SAdrian Knoth hdspm->port_names_in = hdspm->port_names_in_ds; 14990dca1793SAdrian Knoth hdspm->port_names_out = hdspm->port_names_out_ds; 15000dca1793SAdrian Knoth } else { 15010dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_in_qs; 15020dca1793SAdrian Knoth hdspm->channel_map_out = hdspm->channel_map_out_qs; 15030dca1793SAdrian Knoth hdspm->max_channels_in = hdspm->qs_in_channels; 15040dca1793SAdrian Knoth hdspm->max_channels_out = hdspm->qs_out_channels; 15050dca1793SAdrian Knoth hdspm->port_names_in = hdspm->port_names_in_qs; 15060dca1793SAdrian Knoth hdspm->port_names_out = hdspm->port_names_out_qs; 15070dca1793SAdrian Knoth } 15080dca1793SAdrian Knoth 1509763f356cSTakashi Iwai if (not_set != 0) 1510763f356cSTakashi Iwai return -1; 1511763f356cSTakashi Iwai 1512763f356cSTakashi Iwai return 0; 1513763f356cSTakashi Iwai } 1514763f356cSTakashi Iwai 1515763f356cSTakashi Iwai /* mainly for init to 0 on load */ 151698274f07STakashi Iwai static void all_in_all_mixer(struct hdspm * hdspm, int sgain) 1517763f356cSTakashi Iwai { 1518763f356cSTakashi Iwai int i, j; 1519ef5fa1a4STakashi Iwai unsigned int gain; 1520ef5fa1a4STakashi Iwai 1521ef5fa1a4STakashi Iwai if (sgain > UNITY_GAIN) 1522ef5fa1a4STakashi Iwai gain = UNITY_GAIN; 1523ef5fa1a4STakashi Iwai else if (sgain < 0) 1524ef5fa1a4STakashi Iwai gain = 0; 1525ef5fa1a4STakashi Iwai else 1526ef5fa1a4STakashi Iwai gain = sgain; 1527763f356cSTakashi Iwai 1528763f356cSTakashi Iwai for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) 1529763f356cSTakashi Iwai for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) { 1530763f356cSTakashi Iwai hdspm_write_in_gain(hdspm, i, j, gain); 1531763f356cSTakashi Iwai hdspm_write_pb_gain(hdspm, i, j, gain); 1532763f356cSTakashi Iwai } 1533763f356cSTakashi Iwai } 1534763f356cSTakashi Iwai 1535763f356cSTakashi Iwai /*---------------------------------------------------------------------------- 1536763f356cSTakashi Iwai MIDI 1537763f356cSTakashi Iwai ----------------------------------------------------------------------------*/ 1538763f356cSTakashi Iwai 1539ef5fa1a4STakashi Iwai static inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm, 1540ef5fa1a4STakashi Iwai int id) 1541763f356cSTakashi Iwai { 1542763f356cSTakashi Iwai /* the hardware already does the relevant bit-mask with 0xff */ 15430dca1793SAdrian Knoth return hdspm_read(hdspm, hdspm->midi[id].dataIn); 1544763f356cSTakashi Iwai } 1545763f356cSTakashi Iwai 1546ef5fa1a4STakashi Iwai static inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id, 1547ef5fa1a4STakashi Iwai int val) 1548763f356cSTakashi Iwai { 1549763f356cSTakashi Iwai /* the hardware already does the relevant bit-mask with 0xff */ 15500dca1793SAdrian Knoth return hdspm_write(hdspm, hdspm->midi[id].dataOut, val); 1551763f356cSTakashi Iwai } 1552763f356cSTakashi Iwai 155398274f07STakashi Iwai static inline int snd_hdspm_midi_input_available (struct hdspm *hdspm, int id) 1554763f356cSTakashi Iwai { 15550dca1793SAdrian Knoth return hdspm_read(hdspm, hdspm->midi[id].statusIn) & 0xFF; 1556763f356cSTakashi Iwai } 1557763f356cSTakashi Iwai 155898274f07STakashi Iwai static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id) 1559763f356cSTakashi Iwai { 1560763f356cSTakashi Iwai int fifo_bytes_used; 1561763f356cSTakashi Iwai 15620dca1793SAdrian Knoth fifo_bytes_used = hdspm_read(hdspm, hdspm->midi[id].statusOut) & 0xFF; 1563763f356cSTakashi Iwai 1564763f356cSTakashi Iwai if (fifo_bytes_used < 128) 1565763f356cSTakashi Iwai return 128 - fifo_bytes_used; 1566763f356cSTakashi Iwai else 1567763f356cSTakashi Iwai return 0; 1568763f356cSTakashi Iwai } 1569763f356cSTakashi Iwai 157062cef821SDenys Vlasenko static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id) 1571763f356cSTakashi Iwai { 1572763f356cSTakashi Iwai while (snd_hdspm_midi_input_available (hdspm, id)) 1573763f356cSTakashi Iwai snd_hdspm_midi_read_byte (hdspm, id); 1574763f356cSTakashi Iwai } 1575763f356cSTakashi Iwai 157698274f07STakashi Iwai static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) 1577763f356cSTakashi Iwai { 1578763f356cSTakashi Iwai unsigned long flags; 1579763f356cSTakashi Iwai int n_pending; 1580763f356cSTakashi Iwai int to_write; 1581763f356cSTakashi Iwai int i; 1582763f356cSTakashi Iwai unsigned char buf[128]; 1583763f356cSTakashi Iwai 1584763f356cSTakashi Iwai /* Output is not interrupt driven */ 1585763f356cSTakashi Iwai 1586763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags); 1587ef5fa1a4STakashi Iwai if (hmidi->output && 1588ef5fa1a4STakashi Iwai !snd_rawmidi_transmit_empty (hmidi->output)) { 1589ef5fa1a4STakashi Iwai n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, 1590ef5fa1a4STakashi Iwai hmidi->id); 1591ef5fa1a4STakashi Iwai if (n_pending > 0) { 1592763f356cSTakashi Iwai if (n_pending > (int)sizeof (buf)) 1593763f356cSTakashi Iwai n_pending = sizeof (buf); 1594763f356cSTakashi Iwai 1595ef5fa1a4STakashi Iwai to_write = snd_rawmidi_transmit (hmidi->output, buf, 1596ef5fa1a4STakashi Iwai n_pending); 1597ef5fa1a4STakashi Iwai if (to_write > 0) { 1598763f356cSTakashi Iwai for (i = 0; i < to_write; ++i) 1599ef5fa1a4STakashi Iwai snd_hdspm_midi_write_byte (hmidi->hdspm, 1600ef5fa1a4STakashi Iwai hmidi->id, 1601ef5fa1a4STakashi Iwai buf[i]); 1602763f356cSTakashi Iwai } 1603763f356cSTakashi Iwai } 1604763f356cSTakashi Iwai } 1605763f356cSTakashi Iwai spin_unlock_irqrestore (&hmidi->lock, flags); 1606763f356cSTakashi Iwai return 0; 1607763f356cSTakashi Iwai } 1608763f356cSTakashi Iwai 160998274f07STakashi Iwai static int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi) 1610763f356cSTakashi Iwai { 1611ef5fa1a4STakashi Iwai unsigned char buf[128]; /* this buffer is designed to match the MIDI 1612ef5fa1a4STakashi Iwai * input FIFO size 1613ef5fa1a4STakashi Iwai */ 1614763f356cSTakashi Iwai unsigned long flags; 1615763f356cSTakashi Iwai int n_pending; 1616763f356cSTakashi Iwai int i; 1617763f356cSTakashi Iwai 1618763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags); 1619ef5fa1a4STakashi Iwai n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id); 1620ef5fa1a4STakashi Iwai if (n_pending > 0) { 1621763f356cSTakashi Iwai if (hmidi->input) { 1622ef5fa1a4STakashi Iwai if (n_pending > (int)sizeof (buf)) 1623763f356cSTakashi Iwai n_pending = sizeof (buf); 1624ef5fa1a4STakashi Iwai for (i = 0; i < n_pending; ++i) 1625ef5fa1a4STakashi Iwai buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, 1626ef5fa1a4STakashi Iwai hmidi->id); 1627ef5fa1a4STakashi Iwai if (n_pending) 1628ef5fa1a4STakashi Iwai snd_rawmidi_receive (hmidi->input, buf, 1629ef5fa1a4STakashi Iwai n_pending); 1630763f356cSTakashi Iwai } else { 1631763f356cSTakashi Iwai /* flush the MIDI input FIFO */ 1632ef5fa1a4STakashi Iwai while (n_pending--) 1633ef5fa1a4STakashi Iwai snd_hdspm_midi_read_byte (hmidi->hdspm, 1634ef5fa1a4STakashi Iwai hmidi->id); 1635763f356cSTakashi Iwai } 1636763f356cSTakashi Iwai } 1637763f356cSTakashi Iwai hmidi->pending = 0; 16380dca1793SAdrian Knoth 16390dca1793SAdrian Knoth hmidi->hdspm->control_register |= hmidi->ie; 1640ef5fa1a4STakashi Iwai hdspm_write(hmidi->hdspm, HDSPM_controlRegister, 1641ef5fa1a4STakashi Iwai hmidi->hdspm->control_register); 16420dca1793SAdrian Knoth 1643763f356cSTakashi Iwai spin_unlock_irqrestore (&hmidi->lock, flags); 1644763f356cSTakashi Iwai return snd_hdspm_midi_output_write (hmidi); 1645763f356cSTakashi Iwai } 1646763f356cSTakashi Iwai 1647ef5fa1a4STakashi Iwai static void 1648ef5fa1a4STakashi Iwai snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) 1649763f356cSTakashi Iwai { 165098274f07STakashi Iwai struct hdspm *hdspm; 165198274f07STakashi Iwai struct hdspm_midi *hmidi; 1652763f356cSTakashi Iwai unsigned long flags; 1653763f356cSTakashi Iwai 1654ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 1655763f356cSTakashi Iwai hdspm = hmidi->hdspm; 16560dca1793SAdrian Knoth 1657763f356cSTakashi Iwai spin_lock_irqsave (&hdspm->lock, flags); 1658763f356cSTakashi Iwai if (up) { 16590dca1793SAdrian Knoth if (!(hdspm->control_register & hmidi->ie)) { 1660763f356cSTakashi Iwai snd_hdspm_flush_midi_input (hdspm, hmidi->id); 16610dca1793SAdrian Knoth hdspm->control_register |= hmidi->ie; 1662763f356cSTakashi Iwai } 1663763f356cSTakashi Iwai } else { 16640dca1793SAdrian Knoth hdspm->control_register &= ~hmidi->ie; 1665763f356cSTakashi Iwai } 1666763f356cSTakashi Iwai 1667763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 1668763f356cSTakashi Iwai spin_unlock_irqrestore (&hdspm->lock, flags); 1669763f356cSTakashi Iwai } 1670763f356cSTakashi Iwai 1671763f356cSTakashi Iwai static void snd_hdspm_midi_output_timer(unsigned long data) 1672763f356cSTakashi Iwai { 167398274f07STakashi Iwai struct hdspm_midi *hmidi = (struct hdspm_midi *) data; 1674763f356cSTakashi Iwai unsigned long flags; 1675763f356cSTakashi Iwai 1676763f356cSTakashi Iwai snd_hdspm_midi_output_write(hmidi); 1677763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags); 1678763f356cSTakashi Iwai 1679763f356cSTakashi Iwai /* this does not bump hmidi->istimer, because the 1680763f356cSTakashi Iwai kernel automatically removed the timer when it 1681763f356cSTakashi Iwai expired, and we are now adding it back, thus 1682763f356cSTakashi Iwai leaving istimer wherever it was set before. 1683763f356cSTakashi Iwai */ 1684763f356cSTakashi Iwai 1685763f356cSTakashi Iwai if (hmidi->istimer) { 1686763f356cSTakashi Iwai hmidi->timer.expires = 1 + jiffies; 1687763f356cSTakashi Iwai add_timer(&hmidi->timer); 1688763f356cSTakashi Iwai } 1689763f356cSTakashi Iwai 1690763f356cSTakashi Iwai spin_unlock_irqrestore (&hmidi->lock, flags); 1691763f356cSTakashi Iwai } 1692763f356cSTakashi Iwai 1693ef5fa1a4STakashi Iwai static void 1694ef5fa1a4STakashi Iwai snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) 1695763f356cSTakashi Iwai { 169698274f07STakashi Iwai struct hdspm_midi *hmidi; 1697763f356cSTakashi Iwai unsigned long flags; 1698763f356cSTakashi Iwai 1699ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 1700763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags); 1701763f356cSTakashi Iwai if (up) { 1702763f356cSTakashi Iwai if (!hmidi->istimer) { 1703763f356cSTakashi Iwai init_timer(&hmidi->timer); 1704763f356cSTakashi Iwai hmidi->timer.function = snd_hdspm_midi_output_timer; 1705763f356cSTakashi Iwai hmidi->timer.data = (unsigned long) hmidi; 1706763f356cSTakashi Iwai hmidi->timer.expires = 1 + jiffies; 1707763f356cSTakashi Iwai add_timer(&hmidi->timer); 1708763f356cSTakashi Iwai hmidi->istimer++; 1709763f356cSTakashi Iwai } 1710763f356cSTakashi Iwai } else { 1711ef5fa1a4STakashi Iwai if (hmidi->istimer && --hmidi->istimer <= 0) 1712763f356cSTakashi Iwai del_timer (&hmidi->timer); 1713763f356cSTakashi Iwai } 1714763f356cSTakashi Iwai spin_unlock_irqrestore (&hmidi->lock, flags); 1715763f356cSTakashi Iwai if (up) 1716763f356cSTakashi Iwai snd_hdspm_midi_output_write(hmidi); 1717763f356cSTakashi Iwai } 1718763f356cSTakashi Iwai 171998274f07STakashi Iwai static int snd_hdspm_midi_input_open(struct snd_rawmidi_substream *substream) 1720763f356cSTakashi Iwai { 172198274f07STakashi Iwai struct hdspm_midi *hmidi; 1722763f356cSTakashi Iwai 1723ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 1724763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock); 1725763f356cSTakashi Iwai snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id); 1726763f356cSTakashi Iwai hmidi->input = substream; 1727763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock); 1728763f356cSTakashi Iwai 1729763f356cSTakashi Iwai return 0; 1730763f356cSTakashi Iwai } 1731763f356cSTakashi Iwai 173298274f07STakashi Iwai static int snd_hdspm_midi_output_open(struct snd_rawmidi_substream *substream) 1733763f356cSTakashi Iwai { 173498274f07STakashi Iwai struct hdspm_midi *hmidi; 1735763f356cSTakashi Iwai 1736ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 1737763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock); 1738763f356cSTakashi Iwai hmidi->output = substream; 1739763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock); 1740763f356cSTakashi Iwai 1741763f356cSTakashi Iwai return 0; 1742763f356cSTakashi Iwai } 1743763f356cSTakashi Iwai 174498274f07STakashi Iwai static int snd_hdspm_midi_input_close(struct snd_rawmidi_substream *substream) 1745763f356cSTakashi Iwai { 174698274f07STakashi Iwai struct hdspm_midi *hmidi; 1747763f356cSTakashi Iwai 1748763f356cSTakashi Iwai snd_hdspm_midi_input_trigger (substream, 0); 1749763f356cSTakashi Iwai 1750ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 1751763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock); 1752763f356cSTakashi Iwai hmidi->input = NULL; 1753763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock); 1754763f356cSTakashi Iwai 1755763f356cSTakashi Iwai return 0; 1756763f356cSTakashi Iwai } 1757763f356cSTakashi Iwai 175898274f07STakashi Iwai static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream) 1759763f356cSTakashi Iwai { 176098274f07STakashi Iwai struct hdspm_midi *hmidi; 1761763f356cSTakashi Iwai 1762763f356cSTakashi Iwai snd_hdspm_midi_output_trigger (substream, 0); 1763763f356cSTakashi Iwai 1764ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data; 1765763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock); 1766763f356cSTakashi Iwai hmidi->output = NULL; 1767763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock); 1768763f356cSTakashi Iwai 1769763f356cSTakashi Iwai return 0; 1770763f356cSTakashi Iwai } 1771763f356cSTakashi Iwai 177298274f07STakashi Iwai static struct snd_rawmidi_ops snd_hdspm_midi_output = 1773763f356cSTakashi Iwai { 1774763f356cSTakashi Iwai .open = snd_hdspm_midi_output_open, 1775763f356cSTakashi Iwai .close = snd_hdspm_midi_output_close, 1776763f356cSTakashi Iwai .trigger = snd_hdspm_midi_output_trigger, 1777763f356cSTakashi Iwai }; 1778763f356cSTakashi Iwai 177998274f07STakashi Iwai static struct snd_rawmidi_ops snd_hdspm_midi_input = 1780763f356cSTakashi Iwai { 1781763f356cSTakashi Iwai .open = snd_hdspm_midi_input_open, 1782763f356cSTakashi Iwai .close = snd_hdspm_midi_input_close, 1783763f356cSTakashi Iwai .trigger = snd_hdspm_midi_input_trigger, 1784763f356cSTakashi Iwai }; 1785763f356cSTakashi Iwai 1786ef5fa1a4STakashi Iwai static int __devinit snd_hdspm_create_midi (struct snd_card *card, 1787ef5fa1a4STakashi Iwai struct hdspm *hdspm, int id) 1788763f356cSTakashi Iwai { 1789763f356cSTakashi Iwai int err; 1790763f356cSTakashi Iwai char buf[32]; 1791763f356cSTakashi Iwai 1792763f356cSTakashi Iwai hdspm->midi[id].id = id; 1793763f356cSTakashi Iwai hdspm->midi[id].hdspm = hdspm; 1794763f356cSTakashi Iwai spin_lock_init (&hdspm->midi[id].lock); 1795763f356cSTakashi Iwai 17960dca1793SAdrian Knoth if (0 == id) { 17970dca1793SAdrian Knoth if (MADIface == hdspm->io_type) { 17980dca1793SAdrian Knoth /* MIDI-over-MADI on HDSPe MADIface */ 17990dca1793SAdrian Knoth hdspm->midi[0].dataIn = HDSPM_midiDataIn2; 18000dca1793SAdrian Knoth hdspm->midi[0].statusIn = HDSPM_midiStatusIn2; 18010dca1793SAdrian Knoth hdspm->midi[0].dataOut = HDSPM_midiDataOut2; 18020dca1793SAdrian Knoth hdspm->midi[0].statusOut = HDSPM_midiStatusOut2; 18030dca1793SAdrian Knoth hdspm->midi[0].ie = HDSPM_Midi2InterruptEnable; 18040dca1793SAdrian Knoth hdspm->midi[0].irq = HDSPM_midi2IRQPending; 18050dca1793SAdrian Knoth } else { 18060dca1793SAdrian Knoth hdspm->midi[0].dataIn = HDSPM_midiDataIn0; 18070dca1793SAdrian Knoth hdspm->midi[0].statusIn = HDSPM_midiStatusIn0; 18080dca1793SAdrian Knoth hdspm->midi[0].dataOut = HDSPM_midiDataOut0; 18090dca1793SAdrian Knoth hdspm->midi[0].statusOut = HDSPM_midiStatusOut0; 18100dca1793SAdrian Knoth hdspm->midi[0].ie = HDSPM_Midi0InterruptEnable; 18110dca1793SAdrian Knoth hdspm->midi[0].irq = HDSPM_midi0IRQPending; 18120dca1793SAdrian Knoth } 18130dca1793SAdrian Knoth } else if (1 == id) { 18140dca1793SAdrian Knoth hdspm->midi[1].dataIn = HDSPM_midiDataIn1; 18150dca1793SAdrian Knoth hdspm->midi[1].statusIn = HDSPM_midiStatusIn1; 18160dca1793SAdrian Knoth hdspm->midi[1].dataOut = HDSPM_midiDataOut1; 18170dca1793SAdrian Knoth hdspm->midi[1].statusOut = HDSPM_midiStatusOut1; 18180dca1793SAdrian Knoth hdspm->midi[1].ie = HDSPM_Midi1InterruptEnable; 18190dca1793SAdrian Knoth hdspm->midi[1].irq = HDSPM_midi1IRQPending; 18200dca1793SAdrian Knoth } else if ((2 == id) && (MADI == hdspm->io_type)) { 18210dca1793SAdrian Knoth /* MIDI-over-MADI on HDSPe MADI */ 18220dca1793SAdrian Knoth hdspm->midi[2].dataIn = HDSPM_midiDataIn2; 18230dca1793SAdrian Knoth hdspm->midi[2].statusIn = HDSPM_midiStatusIn2; 18240dca1793SAdrian Knoth hdspm->midi[2].dataOut = HDSPM_midiDataOut2; 18250dca1793SAdrian Knoth hdspm->midi[2].statusOut = HDSPM_midiStatusOut2; 18260dca1793SAdrian Knoth hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable; 18270dca1793SAdrian Knoth hdspm->midi[2].irq = HDSPM_midi2IRQPending; 18280dca1793SAdrian Knoth } else if (2 == id) { 18290dca1793SAdrian Knoth /* TCO MTC, read only */ 18300dca1793SAdrian Knoth hdspm->midi[2].dataIn = HDSPM_midiDataIn2; 18310dca1793SAdrian Knoth hdspm->midi[2].statusIn = HDSPM_midiStatusIn2; 18320dca1793SAdrian Knoth hdspm->midi[2].dataOut = -1; 18330dca1793SAdrian Knoth hdspm->midi[2].statusOut = -1; 18340dca1793SAdrian Knoth hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable; 18350dca1793SAdrian Knoth hdspm->midi[2].irq = HDSPM_midi2IRQPendingAES; 18360dca1793SAdrian Knoth } else if (3 == id) { 18370dca1793SAdrian Knoth /* TCO MTC on HDSPe MADI */ 18380dca1793SAdrian Knoth hdspm->midi[3].dataIn = HDSPM_midiDataIn3; 18390dca1793SAdrian Knoth hdspm->midi[3].statusIn = HDSPM_midiStatusIn3; 18400dca1793SAdrian Knoth hdspm->midi[3].dataOut = -1; 18410dca1793SAdrian Knoth hdspm->midi[3].statusOut = -1; 18420dca1793SAdrian Knoth hdspm->midi[3].ie = HDSPM_Midi3InterruptEnable; 18430dca1793SAdrian Knoth hdspm->midi[3].irq = HDSPM_midi3IRQPending; 18440dca1793SAdrian Knoth } 18450dca1793SAdrian Knoth 18460dca1793SAdrian Knoth if ((id < 2) || ((2 == id) && ((MADI == hdspm->io_type) || 18470dca1793SAdrian Knoth (MADIface == hdspm->io_type)))) { 18480dca1793SAdrian Knoth if ((id == 0) && (MADIface == hdspm->io_type)) { 18490dca1793SAdrian Knoth sprintf(buf, "%s MIDIoverMADI", card->shortname); 18500dca1793SAdrian Knoth } else if ((id == 2) && (MADI == hdspm->io_type)) { 18510dca1793SAdrian Knoth sprintf(buf, "%s MIDIoverMADI", card->shortname); 18520dca1793SAdrian Knoth } else { 1853763f356cSTakashi Iwai sprintf(buf, "%s MIDI %d", card->shortname, id+1); 18540dca1793SAdrian Knoth } 18550dca1793SAdrian Knoth err = snd_rawmidi_new(card, buf, id, 1, 1, 18560dca1793SAdrian Knoth &hdspm->midi[id].rmidi); 1857ef5fa1a4STakashi Iwai if (err < 0) 1858763f356cSTakashi Iwai return err; 1859763f356cSTakashi Iwai 18600dca1793SAdrian Knoth sprintf(hdspm->midi[id].rmidi->name, "%s MIDI %d", 18610dca1793SAdrian Knoth card->id, id+1); 1862763f356cSTakashi Iwai hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; 1863763f356cSTakashi Iwai 18640dca1793SAdrian Knoth snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 18650dca1793SAdrian Knoth SNDRV_RAWMIDI_STREAM_OUTPUT, 1866ef5fa1a4STakashi Iwai &snd_hdspm_midi_output); 18670dca1793SAdrian Knoth snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 18680dca1793SAdrian Knoth SNDRV_RAWMIDI_STREAM_INPUT, 1869ef5fa1a4STakashi Iwai &snd_hdspm_midi_input); 1870763f356cSTakashi Iwai 18710dca1793SAdrian Knoth hdspm->midi[id].rmidi->info_flags |= 18720dca1793SAdrian Knoth SNDRV_RAWMIDI_INFO_OUTPUT | 1873763f356cSTakashi Iwai SNDRV_RAWMIDI_INFO_INPUT | 1874763f356cSTakashi Iwai SNDRV_RAWMIDI_INFO_DUPLEX; 18750dca1793SAdrian Knoth } else { 18760dca1793SAdrian Knoth /* TCO MTC, read only */ 18770dca1793SAdrian Knoth sprintf(buf, "%s MTC %d", card->shortname, id+1); 18780dca1793SAdrian Knoth err = snd_rawmidi_new(card, buf, id, 1, 1, 18790dca1793SAdrian Knoth &hdspm->midi[id].rmidi); 18800dca1793SAdrian Knoth if (err < 0) 18810dca1793SAdrian Knoth return err; 18820dca1793SAdrian Knoth 18830dca1793SAdrian Knoth sprintf(hdspm->midi[id].rmidi->name, 18840dca1793SAdrian Knoth "%s MTC %d", card->id, id+1); 18850dca1793SAdrian Knoth hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; 18860dca1793SAdrian Knoth 18870dca1793SAdrian Knoth snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 18880dca1793SAdrian Knoth SNDRV_RAWMIDI_STREAM_INPUT, 18890dca1793SAdrian Knoth &snd_hdspm_midi_input); 18900dca1793SAdrian Knoth 18910dca1793SAdrian Knoth hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; 18920dca1793SAdrian Knoth } 1893763f356cSTakashi Iwai 1894763f356cSTakashi Iwai return 0; 1895763f356cSTakashi Iwai } 1896763f356cSTakashi Iwai 1897763f356cSTakashi Iwai 1898763f356cSTakashi Iwai static void hdspm_midi_tasklet(unsigned long arg) 1899763f356cSTakashi Iwai { 190098274f07STakashi Iwai struct hdspm *hdspm = (struct hdspm *)arg; 19010dca1793SAdrian Knoth int i = 0; 1902763f356cSTakashi Iwai 19030dca1793SAdrian Knoth while (i < hdspm->midiPorts) { 19040dca1793SAdrian Knoth if (hdspm->midi[i].pending) 19050dca1793SAdrian Knoth snd_hdspm_midi_input_read(&hdspm->midi[i]); 19060dca1793SAdrian Knoth 19070dca1793SAdrian Knoth i++; 19080dca1793SAdrian Knoth } 1909763f356cSTakashi Iwai } 1910763f356cSTakashi Iwai 1911763f356cSTakashi Iwai 1912763f356cSTakashi Iwai /*----------------------------------------------------------------------------- 1913763f356cSTakashi Iwai Status Interface 1914763f356cSTakashi Iwai ----------------------------------------------------------------------------*/ 1915763f356cSTakashi Iwai 1916763f356cSTakashi Iwai /* get the system sample rate which is set */ 1917763f356cSTakashi Iwai 19180dca1793SAdrian Knoth 19190dca1793SAdrian Knoth /** 19200dca1793SAdrian Knoth * Calculate the real sample rate from the 19210dca1793SAdrian Knoth * current DDS value. 19220dca1793SAdrian Knoth **/ 19230dca1793SAdrian Knoth static int hdspm_get_system_sample_rate(struct hdspm *hdspm) 19240dca1793SAdrian Knoth { 19250dca1793SAdrian Knoth unsigned int period, rate; 19260dca1793SAdrian Knoth 19270dca1793SAdrian Knoth period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 19280dca1793SAdrian Knoth rate = hdspm_calc_dds_value(hdspm, period); 19290dca1793SAdrian Knoth 19300dca1793SAdrian Knoth return rate; 19310dca1793SAdrian Knoth } 19320dca1793SAdrian Knoth 19330dca1793SAdrian Knoth 1934763f356cSTakashi Iwai #define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \ 193567ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 1936763f356cSTakashi Iwai .name = xname, \ 1937763f356cSTakashi Iwai .index = xindex, \ 1938763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ, \ 1939763f356cSTakashi Iwai .info = snd_hdspm_info_system_sample_rate, \ 1940763f356cSTakashi Iwai .get = snd_hdspm_get_system_sample_rate \ 1941763f356cSTakashi Iwai } 1942763f356cSTakashi Iwai 194398274f07STakashi Iwai static int snd_hdspm_info_system_sample_rate(struct snd_kcontrol *kcontrol, 194498274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 1945763f356cSTakashi Iwai { 1946763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1947763f356cSTakashi Iwai uinfo->count = 1; 19480dca1793SAdrian Knoth uinfo->value.integer.min = 27000; 19490dca1793SAdrian Knoth uinfo->value.integer.max = 207000; 19500dca1793SAdrian Knoth uinfo->value.integer.step = 1; 1951763f356cSTakashi Iwai return 0; 1952763f356cSTakashi Iwai } 1953763f356cSTakashi Iwai 19540dca1793SAdrian Knoth 195598274f07STakashi Iwai static int snd_hdspm_get_system_sample_rate(struct snd_kcontrol *kcontrol, 195698274f07STakashi Iwai struct snd_ctl_elem_value * 1957763f356cSTakashi Iwai ucontrol) 1958763f356cSTakashi Iwai { 195998274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 1960763f356cSTakashi Iwai 19610dca1793SAdrian Knoth ucontrol->value.integer.value[0] = hdspm_get_system_sample_rate(hdspm); 1962763f356cSTakashi Iwai return 0; 1963763f356cSTakashi Iwai } 1964763f356cSTakashi Iwai 19650dca1793SAdrian Knoth 19660dca1793SAdrian Knoth /** 19670dca1793SAdrian Knoth * Returns the WordClock sample rate class for the given card. 19680dca1793SAdrian Knoth **/ 19690dca1793SAdrian Knoth static int hdspm_get_wc_sample_rate(struct hdspm *hdspm) 19700dca1793SAdrian Knoth { 19710dca1793SAdrian Knoth int status; 19720dca1793SAdrian Knoth 19730dca1793SAdrian Knoth switch (hdspm->io_type) { 19740dca1793SAdrian Knoth case RayDAT: 19750dca1793SAdrian Knoth case AIO: 19760dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 19770dca1793SAdrian Knoth return (status >> 16) & 0xF; 19780dca1793SAdrian Knoth break; 19790dca1793SAdrian Knoth default: 19800dca1793SAdrian Knoth break; 19810dca1793SAdrian Knoth } 19820dca1793SAdrian Knoth 19830dca1793SAdrian Knoth 19840dca1793SAdrian Knoth return 0; 19850dca1793SAdrian Knoth } 19860dca1793SAdrian Knoth 19870dca1793SAdrian Knoth 19880dca1793SAdrian Knoth /** 19890dca1793SAdrian Knoth * Returns the TCO sample rate class for the given card. 19900dca1793SAdrian Knoth **/ 19910dca1793SAdrian Knoth static int hdspm_get_tco_sample_rate(struct hdspm *hdspm) 19920dca1793SAdrian Knoth { 19930dca1793SAdrian Knoth int status; 19940dca1793SAdrian Knoth 19950dca1793SAdrian Knoth if (hdspm->tco) { 19960dca1793SAdrian Knoth switch (hdspm->io_type) { 19970dca1793SAdrian Knoth case RayDAT: 19980dca1793SAdrian Knoth case AIO: 19990dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 20000dca1793SAdrian Knoth return (status >> 20) & 0xF; 20010dca1793SAdrian Knoth break; 20020dca1793SAdrian Knoth default: 20030dca1793SAdrian Knoth break; 20040dca1793SAdrian Knoth } 20050dca1793SAdrian Knoth } 20060dca1793SAdrian Knoth 20070dca1793SAdrian Knoth return 0; 20080dca1793SAdrian Knoth } 20090dca1793SAdrian Knoth 20100dca1793SAdrian Knoth 20110dca1793SAdrian Knoth /** 20120dca1793SAdrian Knoth * Returns the SYNC_IN sample rate class for the given card. 20130dca1793SAdrian Knoth **/ 20140dca1793SAdrian Knoth static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) 20150dca1793SAdrian Knoth { 20160dca1793SAdrian Knoth int status; 20170dca1793SAdrian Knoth 20180dca1793SAdrian Knoth if (hdspm->tco) { 20190dca1793SAdrian Knoth switch (hdspm->io_type) { 20200dca1793SAdrian Knoth case RayDAT: 20210dca1793SAdrian Knoth case AIO: 20220dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_2); 20230dca1793SAdrian Knoth return (status >> 12) & 0xF; 20240dca1793SAdrian Knoth break; 20250dca1793SAdrian Knoth default: 20260dca1793SAdrian Knoth break; 20270dca1793SAdrian Knoth } 20280dca1793SAdrian Knoth } 20290dca1793SAdrian Knoth 20300dca1793SAdrian Knoth return 0; 20310dca1793SAdrian Knoth } 20320dca1793SAdrian Knoth 20330dca1793SAdrian Knoth 20340dca1793SAdrian Knoth /** 20350dca1793SAdrian Knoth * Returns the sample rate class for input source <idx> for 20360dca1793SAdrian Knoth * 'new style' cards like the AIO and RayDAT. 20370dca1793SAdrian Knoth **/ 20380dca1793SAdrian Knoth static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) 20390dca1793SAdrian Knoth { 20400dca1793SAdrian Knoth int status = hdspm_read(hdspm, HDSPM_RD_STATUS_2); 20410dca1793SAdrian Knoth 20420dca1793SAdrian Knoth return (status >> (idx*4)) & 0xF; 20430dca1793SAdrian Knoth } 20440dca1793SAdrian Knoth 20450dca1793SAdrian Knoth 20460dca1793SAdrian Knoth 2047763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ 204867ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2049763f356cSTakashi Iwai .name = xname, \ 20500dca1793SAdrian Knoth .private_value = xindex, \ 2051763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ, \ 2052763f356cSTakashi Iwai .info = snd_hdspm_info_autosync_sample_rate, \ 2053763f356cSTakashi Iwai .get = snd_hdspm_get_autosync_sample_rate \ 2054763f356cSTakashi Iwai } 2055763f356cSTakashi Iwai 20560dca1793SAdrian Knoth 205798274f07STakashi Iwai static int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, 205898274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 2059763f356cSTakashi Iwai { 2060763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2061763f356cSTakashi Iwai uinfo->count = 1; 2062763f356cSTakashi Iwai uinfo->value.enumerated.items = 10; 20630dca1793SAdrian Knoth 2064763f356cSTakashi Iwai if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 20650dca1793SAdrian Knoth uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 2066763f356cSTakashi Iwai strcpy(uinfo->value.enumerated.name, 20670dca1793SAdrian Knoth texts_freq[uinfo->value.enumerated.item]); 2068763f356cSTakashi Iwai return 0; 2069763f356cSTakashi Iwai } 2070763f356cSTakashi Iwai 20710dca1793SAdrian Knoth 207298274f07STakashi Iwai static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, 207398274f07STakashi Iwai struct snd_ctl_elem_value * 2074763f356cSTakashi Iwai ucontrol) 2075763f356cSTakashi Iwai { 207698274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2077763f356cSTakashi Iwai 20780dca1793SAdrian Knoth switch (hdspm->io_type) { 20790dca1793SAdrian Knoth case RayDAT: 20800dca1793SAdrian Knoth switch (kcontrol->private_value) { 20810dca1793SAdrian Knoth case 0: 20820dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 20830dca1793SAdrian Knoth hdspm_get_wc_sample_rate(hdspm); 2084763f356cSTakashi Iwai break; 20850dca1793SAdrian Knoth case 7: 20860dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 20870dca1793SAdrian Knoth hdspm_get_tco_sample_rate(hdspm); 2088763f356cSTakashi Iwai break; 20890dca1793SAdrian Knoth case 8: 20900dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 20910dca1793SAdrian Knoth hdspm_get_sync_in_sample_rate(hdspm); 2092763f356cSTakashi Iwai break; 2093763f356cSTakashi Iwai default: 20940dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 20950dca1793SAdrian Knoth hdspm_get_s1_sample_rate(hdspm, 20960dca1793SAdrian Knoth kcontrol->private_value-1); 2097763f356cSTakashi Iwai } 20980dca1793SAdrian Knoth 20990dca1793SAdrian Knoth case AIO: 21000dca1793SAdrian Knoth switch (kcontrol->private_value) { 21010dca1793SAdrian Knoth case 0: /* WC */ 21020dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 21030dca1793SAdrian Knoth hdspm_get_wc_sample_rate(hdspm); 21040dca1793SAdrian Knoth break; 21050dca1793SAdrian Knoth case 4: /* TCO */ 21060dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 21070dca1793SAdrian Knoth hdspm_get_tco_sample_rate(hdspm); 21080dca1793SAdrian Knoth break; 21090dca1793SAdrian Knoth case 5: /* SYNC_IN */ 21100dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 21110dca1793SAdrian Knoth hdspm_get_sync_in_sample_rate(hdspm); 21120dca1793SAdrian Knoth break; 21130dca1793SAdrian Knoth default: 21140dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = 21150dca1793SAdrian Knoth hdspm_get_s1_sample_rate(hdspm, 21160dca1793SAdrian Knoth ucontrol->id.index-1); 21170dca1793SAdrian Knoth } 21187c4a95b5SAdrian Knoth 21197c4a95b5SAdrian Knoth case AES32: 21207c4a95b5SAdrian Knoth 21217c4a95b5SAdrian Knoth switch (kcontrol->private_value) { 21227c4a95b5SAdrian Knoth case 0: /* WC */ 21237c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] = 21247c4a95b5SAdrian Knoth hdspm_get_wc_sample_rate(hdspm); 21257c4a95b5SAdrian Knoth break; 21267c4a95b5SAdrian Knoth case 9: /* TCO */ 21277c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] = 21287c4a95b5SAdrian Knoth hdspm_get_tco_sample_rate(hdspm); 21297c4a95b5SAdrian Knoth break; 21307c4a95b5SAdrian Knoth case 10: /* SYNC_IN */ 21317c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] = 21327c4a95b5SAdrian Knoth hdspm_get_sync_in_sample_rate(hdspm); 21337c4a95b5SAdrian Knoth break; 21347c4a95b5SAdrian Knoth default: /* AES1 to AES8 */ 21357c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] = 21367c4a95b5SAdrian Knoth hdspm_get_s1_sample_rate(hdspm, 21377c4a95b5SAdrian Knoth kcontrol->private_value-1); 21387c4a95b5SAdrian Knoth break; 21397c4a95b5SAdrian Knoth 21407c4a95b5SAdrian Knoth } 21410dca1793SAdrian Knoth default: 21420dca1793SAdrian Knoth break; 21430dca1793SAdrian Knoth } 21440dca1793SAdrian Knoth 2145763f356cSTakashi Iwai return 0; 2146763f356cSTakashi Iwai } 2147763f356cSTakashi Iwai 21480dca1793SAdrian Knoth 2149763f356cSTakashi Iwai #define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \ 215067ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2151763f356cSTakashi Iwai .name = xname, \ 2152763f356cSTakashi Iwai .index = xindex, \ 21530dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 21540dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 2155763f356cSTakashi Iwai .info = snd_hdspm_info_system_clock_mode, \ 2156763f356cSTakashi Iwai .get = snd_hdspm_get_system_clock_mode, \ 21570dca1793SAdrian Knoth .put = snd_hdspm_put_system_clock_mode, \ 2158763f356cSTakashi Iwai } 2159763f356cSTakashi Iwai 2160763f356cSTakashi Iwai 21610dca1793SAdrian Knoth /** 21620dca1793SAdrian Knoth * Returns the system clock mode for the given card. 21630dca1793SAdrian Knoth * @returns 0 - master, 1 - slave 21640dca1793SAdrian Knoth **/ 216598274f07STakashi Iwai static int hdspm_system_clock_mode(struct hdspm *hdspm) 2166763f356cSTakashi Iwai { 21670dca1793SAdrian Knoth switch (hdspm->io_type) { 21680dca1793SAdrian Knoth case AIO: 21690dca1793SAdrian Knoth case RayDAT: 21700dca1793SAdrian Knoth if (hdspm->settings_register & HDSPM_c0Master) 21710dca1793SAdrian Knoth return 0; 21720dca1793SAdrian Knoth break; 2173763f356cSTakashi Iwai 21740dca1793SAdrian Knoth default: 2175763f356cSTakashi Iwai if (hdspm->control_register & HDSPM_ClockModeMaster) 2176763f356cSTakashi Iwai return 0; 21770dca1793SAdrian Knoth } 21780dca1793SAdrian Knoth 2179763f356cSTakashi Iwai return 1; 2180763f356cSTakashi Iwai } 2181763f356cSTakashi Iwai 21820dca1793SAdrian Knoth 21830dca1793SAdrian Knoth /** 21840dca1793SAdrian Knoth * Sets the system clock mode. 21850dca1793SAdrian Knoth * @param mode 0 - master, 1 - slave 21860dca1793SAdrian Knoth **/ 21870dca1793SAdrian Knoth static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) 21880dca1793SAdrian Knoth { 21890dca1793SAdrian Knoth switch (hdspm->io_type) { 21900dca1793SAdrian Knoth case AIO: 21910dca1793SAdrian Knoth case RayDAT: 21920dca1793SAdrian Knoth if (0 == mode) 21930dca1793SAdrian Knoth hdspm->settings_register |= HDSPM_c0Master; 21940dca1793SAdrian Knoth else 21950dca1793SAdrian Knoth hdspm->settings_register &= ~HDSPM_c0Master; 21960dca1793SAdrian Knoth 21970dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 21980dca1793SAdrian Knoth break; 21990dca1793SAdrian Knoth 22000dca1793SAdrian Knoth default: 22010dca1793SAdrian Knoth if (0 == mode) 22020dca1793SAdrian Knoth hdspm->control_register |= HDSPM_ClockModeMaster; 22030dca1793SAdrian Knoth else 22040dca1793SAdrian Knoth hdspm->control_register &= ~HDSPM_ClockModeMaster; 22050dca1793SAdrian Knoth 22060dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_controlRegister, 22070dca1793SAdrian Knoth hdspm->control_register); 22080dca1793SAdrian Knoth } 22090dca1793SAdrian Knoth } 22100dca1793SAdrian Knoth 22110dca1793SAdrian Knoth 221298274f07STakashi Iwai static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, 221398274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 2214763f356cSTakashi Iwai { 22150dca1793SAdrian Knoth static char *texts[] = { "Master", "AutoSync" }; 2216763f356cSTakashi Iwai 2217763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2218763f356cSTakashi Iwai uinfo->count = 1; 2219763f356cSTakashi Iwai uinfo->value.enumerated.items = 2; 2220763f356cSTakashi Iwai if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 2221763f356cSTakashi Iwai uinfo->value.enumerated.item = 2222763f356cSTakashi Iwai uinfo->value.enumerated.items - 1; 2223763f356cSTakashi Iwai strcpy(uinfo->value.enumerated.name, 2224763f356cSTakashi Iwai texts[uinfo->value.enumerated.item]); 2225763f356cSTakashi Iwai return 0; 2226763f356cSTakashi Iwai } 2227763f356cSTakashi Iwai 222898274f07STakashi Iwai static int snd_hdspm_get_system_clock_mode(struct snd_kcontrol *kcontrol, 222998274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2230763f356cSTakashi Iwai { 223198274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2232763f356cSTakashi Iwai 22330dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm_system_clock_mode(hdspm); 2234763f356cSTakashi Iwai return 0; 2235763f356cSTakashi Iwai } 2236763f356cSTakashi Iwai 22370dca1793SAdrian Knoth static int snd_hdspm_put_system_clock_mode(struct snd_kcontrol *kcontrol, 22380dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 22390dca1793SAdrian Knoth { 22400dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 22410dca1793SAdrian Knoth int val; 22420dca1793SAdrian Knoth 22430dca1793SAdrian Knoth if (!snd_hdspm_use_is_exclusive(hdspm)) 22440dca1793SAdrian Knoth return -EBUSY; 22450dca1793SAdrian Knoth 22460dca1793SAdrian Knoth val = ucontrol->value.enumerated.item[0]; 22470dca1793SAdrian Knoth if (val < 0) 22480dca1793SAdrian Knoth val = 0; 22490dca1793SAdrian Knoth else if (val > 1) 22500dca1793SAdrian Knoth val = 1; 22510dca1793SAdrian Knoth 22520dca1793SAdrian Knoth hdspm_set_system_clock_mode(hdspm, val); 22530dca1793SAdrian Knoth 22540dca1793SAdrian Knoth return 0; 22550dca1793SAdrian Knoth } 22560dca1793SAdrian Knoth 22570dca1793SAdrian Knoth 22580dca1793SAdrian Knoth #define HDSPM_INTERNAL_CLOCK(xname, xindex) \ 225967ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2260763f356cSTakashi Iwai .name = xname, \ 2261763f356cSTakashi Iwai .index = xindex, \ 2262763f356cSTakashi Iwai .info = snd_hdspm_info_clock_source, \ 2263763f356cSTakashi Iwai .get = snd_hdspm_get_clock_source, \ 2264763f356cSTakashi Iwai .put = snd_hdspm_put_clock_source \ 2265763f356cSTakashi Iwai } 2266763f356cSTakashi Iwai 22670dca1793SAdrian Knoth 226898274f07STakashi Iwai static int hdspm_clock_source(struct hdspm * hdspm) 2269763f356cSTakashi Iwai { 2270763f356cSTakashi Iwai switch (hdspm->system_sample_rate) { 22710dca1793SAdrian Knoth case 32000: return 0; 22720dca1793SAdrian Knoth case 44100: return 1; 22730dca1793SAdrian Knoth case 48000: return 2; 22740dca1793SAdrian Knoth case 64000: return 3; 22750dca1793SAdrian Knoth case 88200: return 4; 22760dca1793SAdrian Knoth case 96000: return 5; 22770dca1793SAdrian Knoth case 128000: return 6; 22780dca1793SAdrian Knoth case 176400: return 7; 22790dca1793SAdrian Knoth case 192000: return 8; 2280763f356cSTakashi Iwai } 22810dca1793SAdrian Knoth 22820dca1793SAdrian Knoth return -1; 2283763f356cSTakashi Iwai } 2284763f356cSTakashi Iwai 228598274f07STakashi Iwai static int hdspm_set_clock_source(struct hdspm * hdspm, int mode) 2286763f356cSTakashi Iwai { 2287763f356cSTakashi Iwai int rate; 2288763f356cSTakashi Iwai switch (mode) { 22890dca1793SAdrian Knoth case 0: 22900dca1793SAdrian Knoth rate = 32000; break; 22910dca1793SAdrian Knoth case 1: 22920dca1793SAdrian Knoth rate = 44100; break; 22930dca1793SAdrian Knoth case 2: 22940dca1793SAdrian Knoth rate = 48000; break; 22950dca1793SAdrian Knoth case 3: 22960dca1793SAdrian Knoth rate = 64000; break; 22970dca1793SAdrian Knoth case 4: 22980dca1793SAdrian Knoth rate = 88200; break; 22990dca1793SAdrian Knoth case 5: 23000dca1793SAdrian Knoth rate = 96000; break; 23010dca1793SAdrian Knoth case 6: 23020dca1793SAdrian Knoth rate = 128000; break; 23030dca1793SAdrian Knoth case 7: 23040dca1793SAdrian Knoth rate = 176400; break; 23050dca1793SAdrian Knoth case 8: 23060dca1793SAdrian Knoth rate = 192000; break; 2307763f356cSTakashi Iwai default: 23080dca1793SAdrian Knoth rate = 48000; 2309763f356cSTakashi Iwai } 2310763f356cSTakashi Iwai hdspm_set_rate(hdspm, rate, 1); 2311763f356cSTakashi Iwai return 0; 2312763f356cSTakashi Iwai } 2313763f356cSTakashi Iwai 231498274f07STakashi Iwai static int snd_hdspm_info_clock_source(struct snd_kcontrol *kcontrol, 231598274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 2316763f356cSTakashi Iwai { 2317763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2318763f356cSTakashi Iwai uinfo->count = 1; 23190dca1793SAdrian Knoth uinfo->value.enumerated.items = 9; 2320763f356cSTakashi Iwai 2321763f356cSTakashi Iwai if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 2322763f356cSTakashi Iwai uinfo->value.enumerated.item = 2323763f356cSTakashi Iwai uinfo->value.enumerated.items - 1; 2324763f356cSTakashi Iwai 2325763f356cSTakashi Iwai strcpy(uinfo->value.enumerated.name, 23260dca1793SAdrian Knoth texts_freq[uinfo->value.enumerated.item+1]); 2327763f356cSTakashi Iwai 2328763f356cSTakashi Iwai return 0; 2329763f356cSTakashi Iwai } 2330763f356cSTakashi Iwai 233198274f07STakashi Iwai static int snd_hdspm_get_clock_source(struct snd_kcontrol *kcontrol, 233298274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2333763f356cSTakashi Iwai { 233498274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2335763f356cSTakashi Iwai 2336763f356cSTakashi Iwai ucontrol->value.enumerated.item[0] = hdspm_clock_source(hdspm); 2337763f356cSTakashi Iwai return 0; 2338763f356cSTakashi Iwai } 2339763f356cSTakashi Iwai 234098274f07STakashi Iwai static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol, 234198274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2342763f356cSTakashi Iwai { 234398274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2344763f356cSTakashi Iwai int change; 2345763f356cSTakashi Iwai int val; 2346763f356cSTakashi Iwai 2347763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 2348763f356cSTakashi Iwai return -EBUSY; 2349763f356cSTakashi Iwai val = ucontrol->value.enumerated.item[0]; 2350763f356cSTakashi Iwai if (val < 0) 2351763f356cSTakashi Iwai val = 0; 23526534599dSRemy Bruno if (val > 9) 23536534599dSRemy Bruno val = 9; 2354763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 2355763f356cSTakashi Iwai if (val != hdspm_clock_source(hdspm)) 2356763f356cSTakashi Iwai change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0; 2357763f356cSTakashi Iwai else 2358763f356cSTakashi Iwai change = 0; 2359763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 2360763f356cSTakashi Iwai return change; 2361763f356cSTakashi Iwai } 2362763f356cSTakashi Iwai 23630dca1793SAdrian Knoth 2364763f356cSTakashi Iwai #define HDSPM_PREF_SYNC_REF(xname, xindex) \ 236567ed4161SClemens Ladisch {.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2366763f356cSTakashi Iwai .name = xname, \ 2367763f356cSTakashi Iwai .index = xindex, \ 23680dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 23690dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 2370763f356cSTakashi Iwai .info = snd_hdspm_info_pref_sync_ref, \ 2371763f356cSTakashi Iwai .get = snd_hdspm_get_pref_sync_ref, \ 2372763f356cSTakashi Iwai .put = snd_hdspm_put_pref_sync_ref \ 2373763f356cSTakashi Iwai } 2374763f356cSTakashi Iwai 23750dca1793SAdrian Knoth 23760dca1793SAdrian Knoth /** 23770dca1793SAdrian Knoth * Returns the current preferred sync reference setting. 23780dca1793SAdrian Knoth * The semantics of the return value are depending on the 23790dca1793SAdrian Knoth * card, please see the comments for clarification. 23800dca1793SAdrian Knoth **/ 238198274f07STakashi Iwai static int hdspm_pref_sync_ref(struct hdspm * hdspm) 2382763f356cSTakashi Iwai { 23830dca1793SAdrian Knoth switch (hdspm->io_type) { 23840dca1793SAdrian Knoth case AES32: 23853cee5a60SRemy Bruno switch (hdspm->control_register & HDSPM_SyncRefMask) { 23860dca1793SAdrian Knoth case 0: return 0; /* WC */ 23870dca1793SAdrian Knoth case HDSPM_SyncRef0: return 1; /* AES 1 */ 23880dca1793SAdrian Knoth case HDSPM_SyncRef1: return 2; /* AES 2 */ 23890dca1793SAdrian Knoth case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3; /* AES 3 */ 23900dca1793SAdrian Knoth case HDSPM_SyncRef2: return 4; /* AES 4 */ 23910dca1793SAdrian Knoth case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5; /* AES 5 */ 23920dca1793SAdrian Knoth case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6; /* AES 6 */ 23930dca1793SAdrian Knoth case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0: 23940dca1793SAdrian Knoth return 7; /* AES 7 */ 23950dca1793SAdrian Knoth case HDSPM_SyncRef3: return 8; /* AES 8 */ 23960dca1793SAdrian Knoth case HDSPM_SyncRef3+HDSPM_SyncRef0: return 9; /* TCO */ 23970dca1793SAdrian Knoth } 23980dca1793SAdrian Knoth break; 23990dca1793SAdrian Knoth 24000dca1793SAdrian Knoth case MADI: 24010dca1793SAdrian Knoth case MADIface: 24020dca1793SAdrian Knoth if (hdspm->tco) { 24030dca1793SAdrian Knoth switch (hdspm->control_register & HDSPM_SyncRefMask) { 24040dca1793SAdrian Knoth case 0: return 0; /* WC */ 24050dca1793SAdrian Knoth case HDSPM_SyncRef0: return 1; /* MADI */ 24060dca1793SAdrian Knoth case HDSPM_SyncRef1: return 2; /* TCO */ 24070dca1793SAdrian Knoth case HDSPM_SyncRef1+HDSPM_SyncRef0: 24080dca1793SAdrian Knoth return 3; /* SYNC_IN */ 24093cee5a60SRemy Bruno } 24103cee5a60SRemy Bruno } else { 2411763f356cSTakashi Iwai switch (hdspm->control_register & HDSPM_SyncRefMask) { 24120dca1793SAdrian Knoth case 0: return 0; /* WC */ 24130dca1793SAdrian Knoth case HDSPM_SyncRef0: return 1; /* MADI */ 24140dca1793SAdrian Knoth case HDSPM_SyncRef1+HDSPM_SyncRef0: 24150dca1793SAdrian Knoth return 2; /* SYNC_IN */ 24160dca1793SAdrian Knoth } 24170dca1793SAdrian Knoth } 24180dca1793SAdrian Knoth break; 24190dca1793SAdrian Knoth 24200dca1793SAdrian Knoth case RayDAT: 24210dca1793SAdrian Knoth if (hdspm->tco) { 24220dca1793SAdrian Knoth switch ((hdspm->settings_register & 24230dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 24240dca1793SAdrian Knoth case 0: return 0; /* WC */ 24250dca1793SAdrian Knoth case 3: return 1; /* ADAT 1 */ 24260dca1793SAdrian Knoth case 4: return 2; /* ADAT 2 */ 24270dca1793SAdrian Knoth case 5: return 3; /* ADAT 3 */ 24280dca1793SAdrian Knoth case 6: return 4; /* ADAT 4 */ 24290dca1793SAdrian Knoth case 1: return 5; /* AES */ 24300dca1793SAdrian Knoth case 2: return 6; /* SPDIF */ 24310dca1793SAdrian Knoth case 9: return 7; /* TCO */ 24320dca1793SAdrian Knoth case 10: return 8; /* SYNC_IN */ 24330dca1793SAdrian Knoth } 24340dca1793SAdrian Knoth } else { 24350dca1793SAdrian Knoth switch ((hdspm->settings_register & 24360dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 24370dca1793SAdrian Knoth case 0: return 0; /* WC */ 24380dca1793SAdrian Knoth case 3: return 1; /* ADAT 1 */ 24390dca1793SAdrian Knoth case 4: return 2; /* ADAT 2 */ 24400dca1793SAdrian Knoth case 5: return 3; /* ADAT 3 */ 24410dca1793SAdrian Knoth case 6: return 4; /* ADAT 4 */ 24420dca1793SAdrian Knoth case 1: return 5; /* AES */ 24430dca1793SAdrian Knoth case 2: return 6; /* SPDIF */ 24440dca1793SAdrian Knoth case 10: return 7; /* SYNC_IN */ 2445763f356cSTakashi Iwai } 24463cee5a60SRemy Bruno } 2447763f356cSTakashi Iwai 24480dca1793SAdrian Knoth break; 24490dca1793SAdrian Knoth 24500dca1793SAdrian Knoth case AIO: 24510dca1793SAdrian Knoth if (hdspm->tco) { 24520dca1793SAdrian Knoth switch ((hdspm->settings_register & 24530dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 24540dca1793SAdrian Knoth case 0: return 0; /* WC */ 24550dca1793SAdrian Knoth case 3: return 1; /* ADAT */ 24560dca1793SAdrian Knoth case 1: return 2; /* AES */ 24570dca1793SAdrian Knoth case 2: return 3; /* SPDIF */ 24580dca1793SAdrian Knoth case 9: return 4; /* TCO */ 24590dca1793SAdrian Knoth case 10: return 5; /* SYNC_IN */ 24600dca1793SAdrian Knoth } 24610dca1793SAdrian Knoth } else { 24620dca1793SAdrian Knoth switch ((hdspm->settings_register & 24630dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 24640dca1793SAdrian Knoth case 0: return 0; /* WC */ 24650dca1793SAdrian Knoth case 3: return 1; /* ADAT */ 24660dca1793SAdrian Knoth case 1: return 2; /* AES */ 24670dca1793SAdrian Knoth case 2: return 3; /* SPDIF */ 24680dca1793SAdrian Knoth case 10: return 4; /* SYNC_IN */ 24690dca1793SAdrian Knoth } 2470763f356cSTakashi Iwai } 2471763f356cSTakashi Iwai 24720dca1793SAdrian Knoth break; 24730dca1793SAdrian Knoth } 24740dca1793SAdrian Knoth 24750dca1793SAdrian Knoth return -1; 24760dca1793SAdrian Knoth } 24770dca1793SAdrian Knoth 24780dca1793SAdrian Knoth 24790dca1793SAdrian Knoth /** 24800dca1793SAdrian Knoth * Set the preferred sync reference to <pref>. The semantics 24810dca1793SAdrian Knoth * of <pref> are depending on the card type, see the comments 24820dca1793SAdrian Knoth * for clarification. 24830dca1793SAdrian Knoth **/ 248498274f07STakashi Iwai static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref) 2485763f356cSTakashi Iwai { 24860dca1793SAdrian Knoth int p = 0; 2487763f356cSTakashi Iwai 24880dca1793SAdrian Knoth switch (hdspm->io_type) { 24890dca1793SAdrian Knoth case AES32: 24900dca1793SAdrian Knoth hdspm->control_register &= ~HDSPM_SyncRefMask; 24913cee5a60SRemy Bruno switch (pref) { 24920dca1793SAdrian Knoth case 0: /* WC */ 24933cee5a60SRemy Bruno break; 24940dca1793SAdrian Knoth case 1: /* AES 1 */ 24953cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef0; 24963cee5a60SRemy Bruno break; 24970dca1793SAdrian Knoth case 2: /* AES 2 */ 24983cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef1; 24993cee5a60SRemy Bruno break; 25000dca1793SAdrian Knoth case 3: /* AES 3 */ 25010dca1793SAdrian Knoth hdspm->control_register |= 25020dca1793SAdrian Knoth HDSPM_SyncRef1+HDSPM_SyncRef0; 25033cee5a60SRemy Bruno break; 25040dca1793SAdrian Knoth case 4: /* AES 4 */ 25053cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef2; 25063cee5a60SRemy Bruno break; 25070dca1793SAdrian Knoth case 5: /* AES 5 */ 25080dca1793SAdrian Knoth hdspm->control_register |= 25090dca1793SAdrian Knoth HDSPM_SyncRef2+HDSPM_SyncRef0; 25103cee5a60SRemy Bruno break; 25110dca1793SAdrian Knoth case 6: /* AES 6 */ 25120dca1793SAdrian Knoth hdspm->control_register |= 25130dca1793SAdrian Knoth HDSPM_SyncRef2+HDSPM_SyncRef1; 25143cee5a60SRemy Bruno break; 25150dca1793SAdrian Knoth case 7: /* AES 7 */ 2516ef5fa1a4STakashi Iwai hdspm->control_register |= 2517ef5fa1a4STakashi Iwai HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0; 25183cee5a60SRemy Bruno break; 25190dca1793SAdrian Knoth case 8: /* AES 8 */ 25203cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef3; 25213cee5a60SRemy Bruno break; 25220dca1793SAdrian Knoth case 9: /* TCO */ 25230dca1793SAdrian Knoth hdspm->control_register |= 25240dca1793SAdrian Knoth HDSPM_SyncRef3+HDSPM_SyncRef0; 25250dca1793SAdrian Knoth break; 25260dca1793SAdrian Knoth default: 25270dca1793SAdrian Knoth return -1; 25280dca1793SAdrian Knoth } 25290dca1793SAdrian Knoth 25300dca1793SAdrian Knoth break; 25310dca1793SAdrian Knoth 25320dca1793SAdrian Knoth case MADI: 25330dca1793SAdrian Knoth case MADIface: 25340dca1793SAdrian Knoth hdspm->control_register &= ~HDSPM_SyncRefMask; 25350dca1793SAdrian Knoth if (hdspm->tco) { 25360dca1793SAdrian Knoth switch (pref) { 25370dca1793SAdrian Knoth case 0: /* WC */ 25380dca1793SAdrian Knoth break; 25390dca1793SAdrian Knoth case 1: /* MADI */ 25400dca1793SAdrian Knoth hdspm->control_register |= HDSPM_SyncRef0; 25410dca1793SAdrian Knoth break; 25420dca1793SAdrian Knoth case 2: /* TCO */ 25430dca1793SAdrian Knoth hdspm->control_register |= HDSPM_SyncRef1; 25440dca1793SAdrian Knoth break; 25450dca1793SAdrian Knoth case 3: /* SYNC_IN */ 25460dca1793SAdrian Knoth hdspm->control_register |= 25470dca1793SAdrian Knoth HDSPM_SyncRef0+HDSPM_SyncRef1; 25480dca1793SAdrian Knoth break; 25493cee5a60SRemy Bruno default: 25503cee5a60SRemy Bruno return -1; 25513cee5a60SRemy Bruno } 25523cee5a60SRemy Bruno } else { 2553763f356cSTakashi Iwai switch (pref) { 25540dca1793SAdrian Knoth case 0: /* WC */ 2555763f356cSTakashi Iwai break; 25560dca1793SAdrian Knoth case 1: /* MADI */ 25570dca1793SAdrian Knoth hdspm->control_register |= HDSPM_SyncRef0; 25580dca1793SAdrian Knoth break; 25590dca1793SAdrian Knoth case 2: /* SYNC_IN */ 25600dca1793SAdrian Knoth hdspm->control_register |= 25610dca1793SAdrian Knoth HDSPM_SyncRef0+HDSPM_SyncRef1; 2562763f356cSTakashi Iwai break; 2563763f356cSTakashi Iwai default: 2564763f356cSTakashi Iwai return -1; 2565763f356cSTakashi Iwai } 25663cee5a60SRemy Bruno } 25670dca1793SAdrian Knoth 25680dca1793SAdrian Knoth break; 25690dca1793SAdrian Knoth 25700dca1793SAdrian Knoth case RayDAT: 25710dca1793SAdrian Knoth if (hdspm->tco) { 25720dca1793SAdrian Knoth switch (pref) { 25730dca1793SAdrian Knoth case 0: p = 0; break; /* WC */ 25740dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT 1 */ 25750dca1793SAdrian Knoth case 2: p = 4; break; /* ADAT 2 */ 25760dca1793SAdrian Knoth case 3: p = 5; break; /* ADAT 3 */ 25770dca1793SAdrian Knoth case 4: p = 6; break; /* ADAT 4 */ 25780dca1793SAdrian Knoth case 5: p = 1; break; /* AES */ 25790dca1793SAdrian Knoth case 6: p = 2; break; /* SPDIF */ 25800dca1793SAdrian Knoth case 7: p = 9; break; /* TCO */ 25810dca1793SAdrian Knoth case 8: p = 10; break; /* SYNC_IN */ 25820dca1793SAdrian Knoth default: return -1; 25830dca1793SAdrian Knoth } 25840dca1793SAdrian Knoth } else { 25850dca1793SAdrian Knoth switch (pref) { 25860dca1793SAdrian Knoth case 0: p = 0; break; /* WC */ 25870dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT 1 */ 25880dca1793SAdrian Knoth case 2: p = 4; break; /* ADAT 2 */ 25890dca1793SAdrian Knoth case 3: p = 5; break; /* ADAT 3 */ 25900dca1793SAdrian Knoth case 4: p = 6; break; /* ADAT 4 */ 25910dca1793SAdrian Knoth case 5: p = 1; break; /* AES */ 25920dca1793SAdrian Knoth case 6: p = 2; break; /* SPDIF */ 25930dca1793SAdrian Knoth case 7: p = 10; break; /* SYNC_IN */ 25940dca1793SAdrian Knoth default: return -1; 25950dca1793SAdrian Knoth } 25960dca1793SAdrian Knoth } 25970dca1793SAdrian Knoth break; 25980dca1793SAdrian Knoth 25990dca1793SAdrian Knoth case AIO: 26000dca1793SAdrian Knoth if (hdspm->tco) { 26010dca1793SAdrian Knoth switch (pref) { 26020dca1793SAdrian Knoth case 0: p = 0; break; /* WC */ 26030dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT */ 26040dca1793SAdrian Knoth case 2: p = 1; break; /* AES */ 26050dca1793SAdrian Knoth case 3: p = 2; break; /* SPDIF */ 26060dca1793SAdrian Knoth case 4: p = 9; break; /* TCO */ 26070dca1793SAdrian Knoth case 5: p = 10; break; /* SYNC_IN */ 26080dca1793SAdrian Knoth default: return -1; 26090dca1793SAdrian Knoth } 26100dca1793SAdrian Knoth } else { 26110dca1793SAdrian Knoth switch (pref) { 26120dca1793SAdrian Knoth case 0: p = 0; break; /* WC */ 26130dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT */ 26140dca1793SAdrian Knoth case 2: p = 1; break; /* AES */ 26150dca1793SAdrian Knoth case 3: p = 2; break; /* SPDIF */ 26160dca1793SAdrian Knoth case 4: p = 10; break; /* SYNC_IN */ 26170dca1793SAdrian Knoth default: return -1; 26180dca1793SAdrian Knoth } 26190dca1793SAdrian Knoth } 26200dca1793SAdrian Knoth break; 26210dca1793SAdrian Knoth } 26220dca1793SAdrian Knoth 26230dca1793SAdrian Knoth switch (hdspm->io_type) { 26240dca1793SAdrian Knoth case RayDAT: 26250dca1793SAdrian Knoth case AIO: 26260dca1793SAdrian Knoth hdspm->settings_register &= ~HDSPM_c0_SyncRefMask; 26270dca1793SAdrian Knoth hdspm->settings_register |= HDSPM_c0_SyncRef0 * p; 26280dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 26290dca1793SAdrian Knoth break; 26300dca1793SAdrian Knoth 26310dca1793SAdrian Knoth case MADI: 26320dca1793SAdrian Knoth case MADIface: 26330dca1793SAdrian Knoth case AES32: 26340dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_controlRegister, 26350dca1793SAdrian Knoth hdspm->control_register); 26360dca1793SAdrian Knoth } 26370dca1793SAdrian Knoth 2638763f356cSTakashi Iwai return 0; 2639763f356cSTakashi Iwai } 2640763f356cSTakashi Iwai 26410dca1793SAdrian Knoth 264298274f07STakashi Iwai static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, 264398274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 2644763f356cSTakashi Iwai { 26453cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 26463cee5a60SRemy Bruno 26473cee5a60SRemy Bruno uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 26483cee5a60SRemy Bruno uinfo->count = 1; 26490dca1793SAdrian Knoth uinfo->value.enumerated.items = hdspm->texts_autosync_items; 26503cee5a60SRemy Bruno 26510dca1793SAdrian Knoth if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 26523cee5a60SRemy Bruno uinfo->value.enumerated.item = 26533cee5a60SRemy Bruno uinfo->value.enumerated.items - 1; 26540dca1793SAdrian Knoth 26553cee5a60SRemy Bruno strcpy(uinfo->value.enumerated.name, 26560dca1793SAdrian Knoth hdspm->texts_autosync[uinfo->value.enumerated.item]); 2657763f356cSTakashi Iwai 2658763f356cSTakashi Iwai return 0; 2659763f356cSTakashi Iwai } 2660763f356cSTakashi Iwai 266198274f07STakashi Iwai static int snd_hdspm_get_pref_sync_ref(struct snd_kcontrol *kcontrol, 266298274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2663763f356cSTakashi Iwai { 266498274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 26650dca1793SAdrian Knoth int psf = hdspm_pref_sync_ref(hdspm); 2666763f356cSTakashi Iwai 26670dca1793SAdrian Knoth if (psf >= 0) { 26680dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = psf; 2669763f356cSTakashi Iwai return 0; 2670763f356cSTakashi Iwai } 2671763f356cSTakashi Iwai 26720dca1793SAdrian Knoth return -1; 26730dca1793SAdrian Knoth } 26740dca1793SAdrian Knoth 267598274f07STakashi Iwai static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, 267698274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2677763f356cSTakashi Iwai { 267898274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 26790dca1793SAdrian Knoth int val, change = 0; 2680763f356cSTakashi Iwai 2681763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 2682763f356cSTakashi Iwai return -EBUSY; 2683763f356cSTakashi Iwai 26840dca1793SAdrian Knoth val = ucontrol->value.enumerated.item[0]; 26850dca1793SAdrian Knoth 26860dca1793SAdrian Knoth if (val < 0) 26870dca1793SAdrian Knoth val = 0; 26880dca1793SAdrian Knoth else if (val >= hdspm->texts_autosync_items) 26890dca1793SAdrian Knoth val = hdspm->texts_autosync_items-1; 2690763f356cSTakashi Iwai 2691763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 26920dca1793SAdrian Knoth if (val != hdspm_pref_sync_ref(hdspm)) 26930dca1793SAdrian Knoth change = (0 == hdspm_set_pref_sync_ref(hdspm, val)) ? 1 : 0; 26940dca1793SAdrian Knoth 2695763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 2696763f356cSTakashi Iwai return change; 2697763f356cSTakashi Iwai } 2698763f356cSTakashi Iwai 26990dca1793SAdrian Knoth 2700763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_REF(xname, xindex) \ 270167ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2702763f356cSTakashi Iwai .name = xname, \ 2703763f356cSTakashi Iwai .index = xindex, \ 2704763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ, \ 2705763f356cSTakashi Iwai .info = snd_hdspm_info_autosync_ref, \ 2706763f356cSTakashi Iwai .get = snd_hdspm_get_autosync_ref, \ 2707763f356cSTakashi Iwai } 2708763f356cSTakashi Iwai 270998274f07STakashi Iwai static int hdspm_autosync_ref(struct hdspm *hdspm) 2710763f356cSTakashi Iwai { 27110dca1793SAdrian Knoth if (AES32 == hdspm->io_type) { 27123cee5a60SRemy Bruno unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); 27130dca1793SAdrian Knoth unsigned int syncref = 27140dca1793SAdrian Knoth (status >> HDSPM_AES32_syncref_bit) & 0xF; 27153cee5a60SRemy Bruno if (syncref == 0) 27163cee5a60SRemy Bruno return HDSPM_AES32_AUTOSYNC_FROM_WORD; 27173cee5a60SRemy Bruno if (syncref <= 8) 27183cee5a60SRemy Bruno return syncref; 27193cee5a60SRemy Bruno return HDSPM_AES32_AUTOSYNC_FROM_NONE; 27200dca1793SAdrian Knoth } else if (MADI == hdspm->io_type) { 2721763f356cSTakashi Iwai /* This looks at the autosync selected sync reference */ 2722763f356cSTakashi Iwai unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 2723763f356cSTakashi Iwai 2724763f356cSTakashi Iwai switch (status2 & HDSPM_SelSyncRefMask) { 2725763f356cSTakashi Iwai case HDSPM_SelSyncRef_WORD: 2726763f356cSTakashi Iwai return HDSPM_AUTOSYNC_FROM_WORD; 2727763f356cSTakashi Iwai case HDSPM_SelSyncRef_MADI: 2728763f356cSTakashi Iwai return HDSPM_AUTOSYNC_FROM_MADI; 27290dca1793SAdrian Knoth case HDSPM_SelSyncRef_TCO: 27300dca1793SAdrian Knoth return HDSPM_AUTOSYNC_FROM_TCO; 27310dca1793SAdrian Knoth case HDSPM_SelSyncRef_SyncIn: 27320dca1793SAdrian Knoth return HDSPM_AUTOSYNC_FROM_SYNC_IN; 2733763f356cSTakashi Iwai case HDSPM_SelSyncRef_NVALID: 2734763f356cSTakashi Iwai return HDSPM_AUTOSYNC_FROM_NONE; 2735763f356cSTakashi Iwai default: 2736763f356cSTakashi Iwai return 0; 2737763f356cSTakashi Iwai } 2738763f356cSTakashi Iwai 27390dca1793SAdrian Knoth } 2740763f356cSTakashi Iwai return 0; 2741763f356cSTakashi Iwai } 27420dca1793SAdrian Knoth 2743763f356cSTakashi Iwai 274498274f07STakashi Iwai static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, 274598274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 2746763f356cSTakashi Iwai { 27473cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 27483cee5a60SRemy Bruno 27490dca1793SAdrian Knoth if (AES32 == hdspm->io_type) { 27503cee5a60SRemy Bruno static char *texts[] = { "WordClock", "AES1", "AES2", "AES3", 27513cee5a60SRemy Bruno "AES4", "AES5", "AES6", "AES7", "AES8", "None"}; 27523cee5a60SRemy Bruno 27533cee5a60SRemy Bruno uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 27543cee5a60SRemy Bruno uinfo->count = 1; 27553cee5a60SRemy Bruno uinfo->value.enumerated.items = 10; 2756ef5fa1a4STakashi Iwai if (uinfo->value.enumerated.item >= 2757ef5fa1a4STakashi Iwai uinfo->value.enumerated.items) 27583cee5a60SRemy Bruno uinfo->value.enumerated.item = 27593cee5a60SRemy Bruno uinfo->value.enumerated.items - 1; 27603cee5a60SRemy Bruno strcpy(uinfo->value.enumerated.name, 27613cee5a60SRemy Bruno texts[uinfo->value.enumerated.item]); 27620dca1793SAdrian Knoth } else if (MADI == hdspm->io_type) { 27630dca1793SAdrian Knoth static char *texts[] = {"Word Clock", "MADI", "TCO", 27640dca1793SAdrian Knoth "Sync In", "None" }; 2765763f356cSTakashi Iwai 2766763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2767763f356cSTakashi Iwai uinfo->count = 1; 27680dca1793SAdrian Knoth uinfo->value.enumerated.items = 5; 2769ef5fa1a4STakashi Iwai if (uinfo->value.enumerated.item >= 2770ef5fa1a4STakashi Iwai uinfo->value.enumerated.items) 2771763f356cSTakashi Iwai uinfo->value.enumerated.item = 2772763f356cSTakashi Iwai uinfo->value.enumerated.items - 1; 2773763f356cSTakashi Iwai strcpy(uinfo->value.enumerated.name, 2774763f356cSTakashi Iwai texts[uinfo->value.enumerated.item]); 27753cee5a60SRemy Bruno } 2776763f356cSTakashi Iwai return 0; 2777763f356cSTakashi Iwai } 2778763f356cSTakashi Iwai 277998274f07STakashi Iwai static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, 278098274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2781763f356cSTakashi Iwai { 278298274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2783763f356cSTakashi Iwai 27846534599dSRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_autosync_ref(hdspm); 2785763f356cSTakashi Iwai return 0; 2786763f356cSTakashi Iwai } 2787763f356cSTakashi Iwai 27880dca1793SAdrian Knoth 2789763f356cSTakashi Iwai #define HDSPM_LINE_OUT(xname, xindex) \ 279067ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2791763f356cSTakashi Iwai .name = xname, \ 2792763f356cSTakashi Iwai .index = xindex, \ 2793763f356cSTakashi Iwai .info = snd_hdspm_info_line_out, \ 2794763f356cSTakashi Iwai .get = snd_hdspm_get_line_out, \ 2795763f356cSTakashi Iwai .put = snd_hdspm_put_line_out \ 2796763f356cSTakashi Iwai } 2797763f356cSTakashi Iwai 279898274f07STakashi Iwai static int hdspm_line_out(struct hdspm * hdspm) 2799763f356cSTakashi Iwai { 2800763f356cSTakashi Iwai return (hdspm->control_register & HDSPM_LineOut) ? 1 : 0; 2801763f356cSTakashi Iwai } 2802763f356cSTakashi Iwai 2803763f356cSTakashi Iwai 280498274f07STakashi Iwai static int hdspm_set_line_output(struct hdspm * hdspm, int out) 2805763f356cSTakashi Iwai { 2806763f356cSTakashi Iwai if (out) 2807763f356cSTakashi Iwai hdspm->control_register |= HDSPM_LineOut; 2808763f356cSTakashi Iwai else 2809763f356cSTakashi Iwai hdspm->control_register &= ~HDSPM_LineOut; 2810763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 2811763f356cSTakashi Iwai 2812763f356cSTakashi Iwai return 0; 2813763f356cSTakashi Iwai } 2814763f356cSTakashi Iwai 2815a5ce8890STakashi Iwai #define snd_hdspm_info_line_out snd_ctl_boolean_mono_info 2816763f356cSTakashi Iwai 281798274f07STakashi Iwai static int snd_hdspm_get_line_out(struct snd_kcontrol *kcontrol, 281898274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2819763f356cSTakashi Iwai { 282098274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2821763f356cSTakashi Iwai 2822763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 2823763f356cSTakashi Iwai ucontrol->value.integer.value[0] = hdspm_line_out(hdspm); 2824763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 2825763f356cSTakashi Iwai return 0; 2826763f356cSTakashi Iwai } 2827763f356cSTakashi Iwai 282898274f07STakashi Iwai static int snd_hdspm_put_line_out(struct snd_kcontrol *kcontrol, 282998274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2830763f356cSTakashi Iwai { 283198274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2832763f356cSTakashi Iwai int change; 2833763f356cSTakashi Iwai unsigned int val; 2834763f356cSTakashi Iwai 2835763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 2836763f356cSTakashi Iwai return -EBUSY; 2837763f356cSTakashi Iwai val = ucontrol->value.integer.value[0] & 1; 2838763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 2839763f356cSTakashi Iwai change = (int) val != hdspm_line_out(hdspm); 2840763f356cSTakashi Iwai hdspm_set_line_output(hdspm, val); 2841763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 2842763f356cSTakashi Iwai return change; 2843763f356cSTakashi Iwai } 2844763f356cSTakashi Iwai 28450dca1793SAdrian Knoth 2846763f356cSTakashi Iwai #define HDSPM_TX_64(xname, xindex) \ 284767ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2848763f356cSTakashi Iwai .name = xname, \ 2849763f356cSTakashi Iwai .index = xindex, \ 2850763f356cSTakashi Iwai .info = snd_hdspm_info_tx_64, \ 2851763f356cSTakashi Iwai .get = snd_hdspm_get_tx_64, \ 2852763f356cSTakashi Iwai .put = snd_hdspm_put_tx_64 \ 2853763f356cSTakashi Iwai } 2854763f356cSTakashi Iwai 285598274f07STakashi Iwai static int hdspm_tx_64(struct hdspm * hdspm) 2856763f356cSTakashi Iwai { 2857763f356cSTakashi Iwai return (hdspm->control_register & HDSPM_TX_64ch) ? 1 : 0; 2858763f356cSTakashi Iwai } 2859763f356cSTakashi Iwai 286098274f07STakashi Iwai static int hdspm_set_tx_64(struct hdspm * hdspm, int out) 2861763f356cSTakashi Iwai { 2862763f356cSTakashi Iwai if (out) 2863763f356cSTakashi Iwai hdspm->control_register |= HDSPM_TX_64ch; 2864763f356cSTakashi Iwai else 2865763f356cSTakashi Iwai hdspm->control_register &= ~HDSPM_TX_64ch; 2866763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 2867763f356cSTakashi Iwai 2868763f356cSTakashi Iwai return 0; 2869763f356cSTakashi Iwai } 2870763f356cSTakashi Iwai 2871a5ce8890STakashi Iwai #define snd_hdspm_info_tx_64 snd_ctl_boolean_mono_info 2872763f356cSTakashi Iwai 287398274f07STakashi Iwai static int snd_hdspm_get_tx_64(struct snd_kcontrol *kcontrol, 287498274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2875763f356cSTakashi Iwai { 287698274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2877763f356cSTakashi Iwai 2878763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 2879763f356cSTakashi Iwai ucontrol->value.integer.value[0] = hdspm_tx_64(hdspm); 2880763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 2881763f356cSTakashi Iwai return 0; 2882763f356cSTakashi Iwai } 2883763f356cSTakashi Iwai 288498274f07STakashi Iwai static int snd_hdspm_put_tx_64(struct snd_kcontrol *kcontrol, 288598274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2886763f356cSTakashi Iwai { 288798274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2888763f356cSTakashi Iwai int change; 2889763f356cSTakashi Iwai unsigned int val; 2890763f356cSTakashi Iwai 2891763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 2892763f356cSTakashi Iwai return -EBUSY; 2893763f356cSTakashi Iwai val = ucontrol->value.integer.value[0] & 1; 2894763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 2895763f356cSTakashi Iwai change = (int) val != hdspm_tx_64(hdspm); 2896763f356cSTakashi Iwai hdspm_set_tx_64(hdspm, val); 2897763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 2898763f356cSTakashi Iwai return change; 2899763f356cSTakashi Iwai } 2900763f356cSTakashi Iwai 29010dca1793SAdrian Knoth 2902763f356cSTakashi Iwai #define HDSPM_C_TMS(xname, xindex) \ 290367ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2904763f356cSTakashi Iwai .name = xname, \ 2905763f356cSTakashi Iwai .index = xindex, \ 2906763f356cSTakashi Iwai .info = snd_hdspm_info_c_tms, \ 2907763f356cSTakashi Iwai .get = snd_hdspm_get_c_tms, \ 2908763f356cSTakashi Iwai .put = snd_hdspm_put_c_tms \ 2909763f356cSTakashi Iwai } 2910763f356cSTakashi Iwai 291198274f07STakashi Iwai static int hdspm_c_tms(struct hdspm * hdspm) 2912763f356cSTakashi Iwai { 2913763f356cSTakashi Iwai return (hdspm->control_register & HDSPM_clr_tms) ? 1 : 0; 2914763f356cSTakashi Iwai } 2915763f356cSTakashi Iwai 291698274f07STakashi Iwai static int hdspm_set_c_tms(struct hdspm * hdspm, int out) 2917763f356cSTakashi Iwai { 2918763f356cSTakashi Iwai if (out) 2919763f356cSTakashi Iwai hdspm->control_register |= HDSPM_clr_tms; 2920763f356cSTakashi Iwai else 2921763f356cSTakashi Iwai hdspm->control_register &= ~HDSPM_clr_tms; 2922763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 2923763f356cSTakashi Iwai 2924763f356cSTakashi Iwai return 0; 2925763f356cSTakashi Iwai } 2926763f356cSTakashi Iwai 2927a5ce8890STakashi Iwai #define snd_hdspm_info_c_tms snd_ctl_boolean_mono_info 2928763f356cSTakashi Iwai 292998274f07STakashi Iwai static int snd_hdspm_get_c_tms(struct snd_kcontrol *kcontrol, 293098274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2931763f356cSTakashi Iwai { 293298274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2933763f356cSTakashi Iwai 2934763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 2935763f356cSTakashi Iwai ucontrol->value.integer.value[0] = hdspm_c_tms(hdspm); 2936763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 2937763f356cSTakashi Iwai return 0; 2938763f356cSTakashi Iwai } 2939763f356cSTakashi Iwai 294098274f07STakashi Iwai static int snd_hdspm_put_c_tms(struct snd_kcontrol *kcontrol, 294198274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2942763f356cSTakashi Iwai { 294398274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2944763f356cSTakashi Iwai int change; 2945763f356cSTakashi Iwai unsigned int val; 2946763f356cSTakashi Iwai 2947763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 2948763f356cSTakashi Iwai return -EBUSY; 2949763f356cSTakashi Iwai val = ucontrol->value.integer.value[0] & 1; 2950763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 2951763f356cSTakashi Iwai change = (int) val != hdspm_c_tms(hdspm); 2952763f356cSTakashi Iwai hdspm_set_c_tms(hdspm, val); 2953763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 2954763f356cSTakashi Iwai return change; 2955763f356cSTakashi Iwai } 2956763f356cSTakashi Iwai 29570dca1793SAdrian Knoth 2958763f356cSTakashi Iwai #define HDSPM_SAFE_MODE(xname, xindex) \ 295967ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 2960763f356cSTakashi Iwai .name = xname, \ 2961763f356cSTakashi Iwai .index = xindex, \ 2962763f356cSTakashi Iwai .info = snd_hdspm_info_safe_mode, \ 2963763f356cSTakashi Iwai .get = snd_hdspm_get_safe_mode, \ 2964763f356cSTakashi Iwai .put = snd_hdspm_put_safe_mode \ 2965763f356cSTakashi Iwai } 2966763f356cSTakashi Iwai 296798274f07STakashi Iwai static int hdspm_safe_mode(struct hdspm * hdspm) 2968763f356cSTakashi Iwai { 2969763f356cSTakashi Iwai return (hdspm->control_register & HDSPM_AutoInp) ? 1 : 0; 2970763f356cSTakashi Iwai } 2971763f356cSTakashi Iwai 297298274f07STakashi Iwai static int hdspm_set_safe_mode(struct hdspm * hdspm, int out) 2973763f356cSTakashi Iwai { 2974763f356cSTakashi Iwai if (out) 2975763f356cSTakashi Iwai hdspm->control_register |= HDSPM_AutoInp; 2976763f356cSTakashi Iwai else 2977763f356cSTakashi Iwai hdspm->control_register &= ~HDSPM_AutoInp; 2978763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 2979763f356cSTakashi Iwai 2980763f356cSTakashi Iwai return 0; 2981763f356cSTakashi Iwai } 2982763f356cSTakashi Iwai 2983a5ce8890STakashi Iwai #define snd_hdspm_info_safe_mode snd_ctl_boolean_mono_info 2984763f356cSTakashi Iwai 298598274f07STakashi Iwai static int snd_hdspm_get_safe_mode(struct snd_kcontrol *kcontrol, 298698274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2987763f356cSTakashi Iwai { 298898274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 2989763f356cSTakashi Iwai 2990763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 2991763f356cSTakashi Iwai ucontrol->value.integer.value[0] = hdspm_safe_mode(hdspm); 2992763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 2993763f356cSTakashi Iwai return 0; 2994763f356cSTakashi Iwai } 2995763f356cSTakashi Iwai 299698274f07STakashi Iwai static int snd_hdspm_put_safe_mode(struct snd_kcontrol *kcontrol, 299798274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2998763f356cSTakashi Iwai { 299998274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3000763f356cSTakashi Iwai int change; 3001763f356cSTakashi Iwai unsigned int val; 3002763f356cSTakashi Iwai 3003763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 3004763f356cSTakashi Iwai return -EBUSY; 3005763f356cSTakashi Iwai val = ucontrol->value.integer.value[0] & 1; 3006763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3007763f356cSTakashi Iwai change = (int) val != hdspm_safe_mode(hdspm); 3008763f356cSTakashi Iwai hdspm_set_safe_mode(hdspm, val); 3009763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3010763f356cSTakashi Iwai return change; 3011763f356cSTakashi Iwai } 3012763f356cSTakashi Iwai 30130dca1793SAdrian Knoth 30143cee5a60SRemy Bruno #define HDSPM_EMPHASIS(xname, xindex) \ 30153cee5a60SRemy Bruno { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 30163cee5a60SRemy Bruno .name = xname, \ 30173cee5a60SRemy Bruno .index = xindex, \ 30183cee5a60SRemy Bruno .info = snd_hdspm_info_emphasis, \ 30193cee5a60SRemy Bruno .get = snd_hdspm_get_emphasis, \ 30203cee5a60SRemy Bruno .put = snd_hdspm_put_emphasis \ 30213cee5a60SRemy Bruno } 30223cee5a60SRemy Bruno 30233cee5a60SRemy Bruno static int hdspm_emphasis(struct hdspm * hdspm) 30243cee5a60SRemy Bruno { 30253cee5a60SRemy Bruno return (hdspm->control_register & HDSPM_Emphasis) ? 1 : 0; 30263cee5a60SRemy Bruno } 30273cee5a60SRemy Bruno 30283cee5a60SRemy Bruno static int hdspm_set_emphasis(struct hdspm * hdspm, int emp) 30293cee5a60SRemy Bruno { 30303cee5a60SRemy Bruno if (emp) 30313cee5a60SRemy Bruno hdspm->control_register |= HDSPM_Emphasis; 30323cee5a60SRemy Bruno else 30333cee5a60SRemy Bruno hdspm->control_register &= ~HDSPM_Emphasis; 30343cee5a60SRemy Bruno hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 30353cee5a60SRemy Bruno 30363cee5a60SRemy Bruno return 0; 30373cee5a60SRemy Bruno } 30383cee5a60SRemy Bruno 3039a5ce8890STakashi Iwai #define snd_hdspm_info_emphasis snd_ctl_boolean_mono_info 30403cee5a60SRemy Bruno 30413cee5a60SRemy Bruno static int snd_hdspm_get_emphasis(struct snd_kcontrol *kcontrol, 30423cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 30433cee5a60SRemy Bruno { 30443cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 30453cee5a60SRemy Bruno 30463cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 30473cee5a60SRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_emphasis(hdspm); 30483cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 30493cee5a60SRemy Bruno return 0; 30503cee5a60SRemy Bruno } 30513cee5a60SRemy Bruno 30523cee5a60SRemy Bruno static int snd_hdspm_put_emphasis(struct snd_kcontrol *kcontrol, 30533cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 30543cee5a60SRemy Bruno { 30553cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 30563cee5a60SRemy Bruno int change; 30573cee5a60SRemy Bruno unsigned int val; 30583cee5a60SRemy Bruno 30593cee5a60SRemy Bruno if (!snd_hdspm_use_is_exclusive(hdspm)) 30603cee5a60SRemy Bruno return -EBUSY; 30613cee5a60SRemy Bruno val = ucontrol->value.integer.value[0] & 1; 30623cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 30633cee5a60SRemy Bruno change = (int) val != hdspm_emphasis(hdspm); 30643cee5a60SRemy Bruno hdspm_set_emphasis(hdspm, val); 30653cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 30663cee5a60SRemy Bruno return change; 30673cee5a60SRemy Bruno } 30683cee5a60SRemy Bruno 30690dca1793SAdrian Knoth 30703cee5a60SRemy Bruno #define HDSPM_DOLBY(xname, xindex) \ 30713cee5a60SRemy Bruno { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 30723cee5a60SRemy Bruno .name = xname, \ 30733cee5a60SRemy Bruno .index = xindex, \ 30743cee5a60SRemy Bruno .info = snd_hdspm_info_dolby, \ 30753cee5a60SRemy Bruno .get = snd_hdspm_get_dolby, \ 30763cee5a60SRemy Bruno .put = snd_hdspm_put_dolby \ 30773cee5a60SRemy Bruno } 30783cee5a60SRemy Bruno 30793cee5a60SRemy Bruno static int hdspm_dolby(struct hdspm * hdspm) 30803cee5a60SRemy Bruno { 30813cee5a60SRemy Bruno return (hdspm->control_register & HDSPM_Dolby) ? 1 : 0; 30823cee5a60SRemy Bruno } 30833cee5a60SRemy Bruno 30843cee5a60SRemy Bruno static int hdspm_set_dolby(struct hdspm * hdspm, int dol) 30853cee5a60SRemy Bruno { 30863cee5a60SRemy Bruno if (dol) 30873cee5a60SRemy Bruno hdspm->control_register |= HDSPM_Dolby; 30883cee5a60SRemy Bruno else 30893cee5a60SRemy Bruno hdspm->control_register &= ~HDSPM_Dolby; 30903cee5a60SRemy Bruno hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 30913cee5a60SRemy Bruno 30923cee5a60SRemy Bruno return 0; 30933cee5a60SRemy Bruno } 30943cee5a60SRemy Bruno 3095a5ce8890STakashi Iwai #define snd_hdspm_info_dolby snd_ctl_boolean_mono_info 30963cee5a60SRemy Bruno 30973cee5a60SRemy Bruno static int snd_hdspm_get_dolby(struct snd_kcontrol *kcontrol, 30983cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 30993cee5a60SRemy Bruno { 31003cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 31013cee5a60SRemy Bruno 31023cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 31033cee5a60SRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_dolby(hdspm); 31043cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 31053cee5a60SRemy Bruno return 0; 31063cee5a60SRemy Bruno } 31073cee5a60SRemy Bruno 31083cee5a60SRemy Bruno static int snd_hdspm_put_dolby(struct snd_kcontrol *kcontrol, 31093cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 31103cee5a60SRemy Bruno { 31113cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 31123cee5a60SRemy Bruno int change; 31133cee5a60SRemy Bruno unsigned int val; 31143cee5a60SRemy Bruno 31153cee5a60SRemy Bruno if (!snd_hdspm_use_is_exclusive(hdspm)) 31163cee5a60SRemy Bruno return -EBUSY; 31173cee5a60SRemy Bruno val = ucontrol->value.integer.value[0] & 1; 31183cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 31193cee5a60SRemy Bruno change = (int) val != hdspm_dolby(hdspm); 31203cee5a60SRemy Bruno hdspm_set_dolby(hdspm, val); 31213cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 31223cee5a60SRemy Bruno return change; 31233cee5a60SRemy Bruno } 31243cee5a60SRemy Bruno 31250dca1793SAdrian Knoth 31263cee5a60SRemy Bruno #define HDSPM_PROFESSIONAL(xname, xindex) \ 31273cee5a60SRemy Bruno { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 31283cee5a60SRemy Bruno .name = xname, \ 31293cee5a60SRemy Bruno .index = xindex, \ 31303cee5a60SRemy Bruno .info = snd_hdspm_info_professional, \ 31313cee5a60SRemy Bruno .get = snd_hdspm_get_professional, \ 31323cee5a60SRemy Bruno .put = snd_hdspm_put_professional \ 31333cee5a60SRemy Bruno } 31343cee5a60SRemy Bruno 31353cee5a60SRemy Bruno static int hdspm_professional(struct hdspm * hdspm) 31363cee5a60SRemy Bruno { 31373cee5a60SRemy Bruno return (hdspm->control_register & HDSPM_Professional) ? 1 : 0; 31383cee5a60SRemy Bruno } 31393cee5a60SRemy Bruno 31403cee5a60SRemy Bruno static int hdspm_set_professional(struct hdspm * hdspm, int dol) 31413cee5a60SRemy Bruno { 31423cee5a60SRemy Bruno if (dol) 31433cee5a60SRemy Bruno hdspm->control_register |= HDSPM_Professional; 31443cee5a60SRemy Bruno else 31453cee5a60SRemy Bruno hdspm->control_register &= ~HDSPM_Professional; 31463cee5a60SRemy Bruno hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 31473cee5a60SRemy Bruno 31483cee5a60SRemy Bruno return 0; 31493cee5a60SRemy Bruno } 31503cee5a60SRemy Bruno 3151a5ce8890STakashi Iwai #define snd_hdspm_info_professional snd_ctl_boolean_mono_info 31523cee5a60SRemy Bruno 31533cee5a60SRemy Bruno static int snd_hdspm_get_professional(struct snd_kcontrol *kcontrol, 31543cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 31553cee5a60SRemy Bruno { 31563cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 31573cee5a60SRemy Bruno 31583cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 31593cee5a60SRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_professional(hdspm); 31603cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 31613cee5a60SRemy Bruno return 0; 31623cee5a60SRemy Bruno } 31633cee5a60SRemy Bruno 31643cee5a60SRemy Bruno static int snd_hdspm_put_professional(struct snd_kcontrol *kcontrol, 31653cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 31663cee5a60SRemy Bruno { 31673cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 31683cee5a60SRemy Bruno int change; 31693cee5a60SRemy Bruno unsigned int val; 31703cee5a60SRemy Bruno 31713cee5a60SRemy Bruno if (!snd_hdspm_use_is_exclusive(hdspm)) 31723cee5a60SRemy Bruno return -EBUSY; 31733cee5a60SRemy Bruno val = ucontrol->value.integer.value[0] & 1; 31743cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 31753cee5a60SRemy Bruno change = (int) val != hdspm_professional(hdspm); 31763cee5a60SRemy Bruno hdspm_set_professional(hdspm, val); 31773cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 31783cee5a60SRemy Bruno return change; 31793cee5a60SRemy Bruno } 31803cee5a60SRemy Bruno 3181763f356cSTakashi Iwai #define HDSPM_INPUT_SELECT(xname, xindex) \ 318267ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3183763f356cSTakashi Iwai .name = xname, \ 3184763f356cSTakashi Iwai .index = xindex, \ 3185763f356cSTakashi Iwai .info = snd_hdspm_info_input_select, \ 3186763f356cSTakashi Iwai .get = snd_hdspm_get_input_select, \ 3187763f356cSTakashi Iwai .put = snd_hdspm_put_input_select \ 3188763f356cSTakashi Iwai } 3189763f356cSTakashi Iwai 319098274f07STakashi Iwai static int hdspm_input_select(struct hdspm * hdspm) 3191763f356cSTakashi Iwai { 3192763f356cSTakashi Iwai return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0; 3193763f356cSTakashi Iwai } 3194763f356cSTakashi Iwai 319598274f07STakashi Iwai static int hdspm_set_input_select(struct hdspm * hdspm, int out) 3196763f356cSTakashi Iwai { 3197763f356cSTakashi Iwai if (out) 3198763f356cSTakashi Iwai hdspm->control_register |= HDSPM_InputSelect0; 3199763f356cSTakashi Iwai else 3200763f356cSTakashi Iwai hdspm->control_register &= ~HDSPM_InputSelect0; 3201763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 3202763f356cSTakashi Iwai 3203763f356cSTakashi Iwai return 0; 3204763f356cSTakashi Iwai } 3205763f356cSTakashi Iwai 320698274f07STakashi Iwai static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, 320798274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 3208763f356cSTakashi Iwai { 3209763f356cSTakashi Iwai static char *texts[] = { "optical", "coaxial" }; 3210763f356cSTakashi Iwai 3211763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 3212763f356cSTakashi Iwai uinfo->count = 1; 3213763f356cSTakashi Iwai uinfo->value.enumerated.items = 2; 3214763f356cSTakashi Iwai 3215763f356cSTakashi Iwai if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 3216763f356cSTakashi Iwai uinfo->value.enumerated.item = 3217763f356cSTakashi Iwai uinfo->value.enumerated.items - 1; 3218763f356cSTakashi Iwai strcpy(uinfo->value.enumerated.name, 3219763f356cSTakashi Iwai texts[uinfo->value.enumerated.item]); 3220763f356cSTakashi Iwai 3221763f356cSTakashi Iwai return 0; 3222763f356cSTakashi Iwai } 3223763f356cSTakashi Iwai 322498274f07STakashi Iwai static int snd_hdspm_get_input_select(struct snd_kcontrol *kcontrol, 322598274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3226763f356cSTakashi Iwai { 322798274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3228763f356cSTakashi Iwai 3229763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3230763f356cSTakashi Iwai ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm); 3231763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3232763f356cSTakashi Iwai return 0; 3233763f356cSTakashi Iwai } 3234763f356cSTakashi Iwai 323598274f07STakashi Iwai static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol, 323698274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3237763f356cSTakashi Iwai { 323898274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3239763f356cSTakashi Iwai int change; 3240763f356cSTakashi Iwai unsigned int val; 3241763f356cSTakashi Iwai 3242763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 3243763f356cSTakashi Iwai return -EBUSY; 3244763f356cSTakashi Iwai val = ucontrol->value.integer.value[0] & 1; 3245763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3246763f356cSTakashi Iwai change = (int) val != hdspm_input_select(hdspm); 3247763f356cSTakashi Iwai hdspm_set_input_select(hdspm, val); 3248763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3249763f356cSTakashi Iwai return change; 3250763f356cSTakashi Iwai } 3251763f356cSTakashi Iwai 32520dca1793SAdrian Knoth 32533cee5a60SRemy Bruno #define HDSPM_DS_WIRE(xname, xindex) \ 32543cee5a60SRemy Bruno { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 32553cee5a60SRemy Bruno .name = xname, \ 32563cee5a60SRemy Bruno .index = xindex, \ 32573cee5a60SRemy Bruno .info = snd_hdspm_info_ds_wire, \ 32583cee5a60SRemy Bruno .get = snd_hdspm_get_ds_wire, \ 32593cee5a60SRemy Bruno .put = snd_hdspm_put_ds_wire \ 32603cee5a60SRemy Bruno } 32613cee5a60SRemy Bruno 32623cee5a60SRemy Bruno static int hdspm_ds_wire(struct hdspm * hdspm) 32633cee5a60SRemy Bruno { 32643cee5a60SRemy Bruno return (hdspm->control_register & HDSPM_DS_DoubleWire) ? 1 : 0; 32653cee5a60SRemy Bruno } 32663cee5a60SRemy Bruno 32673cee5a60SRemy Bruno static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds) 32683cee5a60SRemy Bruno { 32693cee5a60SRemy Bruno if (ds) 32703cee5a60SRemy Bruno hdspm->control_register |= HDSPM_DS_DoubleWire; 32713cee5a60SRemy Bruno else 32723cee5a60SRemy Bruno hdspm->control_register &= ~HDSPM_DS_DoubleWire; 32733cee5a60SRemy Bruno hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 32743cee5a60SRemy Bruno 32753cee5a60SRemy Bruno return 0; 32763cee5a60SRemy Bruno } 32773cee5a60SRemy Bruno 32783cee5a60SRemy Bruno static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, 32793cee5a60SRemy Bruno struct snd_ctl_elem_info *uinfo) 32803cee5a60SRemy Bruno { 32813cee5a60SRemy Bruno static char *texts[] = { "Single", "Double" }; 32823cee5a60SRemy Bruno 32833cee5a60SRemy Bruno uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 32843cee5a60SRemy Bruno uinfo->count = 1; 32853cee5a60SRemy Bruno uinfo->value.enumerated.items = 2; 32863cee5a60SRemy Bruno 32873cee5a60SRemy Bruno if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 32883cee5a60SRemy Bruno uinfo->value.enumerated.item = 32893cee5a60SRemy Bruno uinfo->value.enumerated.items - 1; 32903cee5a60SRemy Bruno strcpy(uinfo->value.enumerated.name, 32913cee5a60SRemy Bruno texts[uinfo->value.enumerated.item]); 32923cee5a60SRemy Bruno 32933cee5a60SRemy Bruno return 0; 32943cee5a60SRemy Bruno } 32953cee5a60SRemy Bruno 32963cee5a60SRemy Bruno static int snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol, 32973cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 32983cee5a60SRemy Bruno { 32993cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 33003cee5a60SRemy Bruno 33013cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 33023cee5a60SRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm); 33033cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 33043cee5a60SRemy Bruno return 0; 33053cee5a60SRemy Bruno } 33063cee5a60SRemy Bruno 33073cee5a60SRemy Bruno static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol, 33083cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 33093cee5a60SRemy Bruno { 33103cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 33113cee5a60SRemy Bruno int change; 33123cee5a60SRemy Bruno unsigned int val; 33133cee5a60SRemy Bruno 33143cee5a60SRemy Bruno if (!snd_hdspm_use_is_exclusive(hdspm)) 33153cee5a60SRemy Bruno return -EBUSY; 33163cee5a60SRemy Bruno val = ucontrol->value.integer.value[0] & 1; 33173cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 33183cee5a60SRemy Bruno change = (int) val != hdspm_ds_wire(hdspm); 33193cee5a60SRemy Bruno hdspm_set_ds_wire(hdspm, val); 33203cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 33213cee5a60SRemy Bruno return change; 33223cee5a60SRemy Bruno } 33233cee5a60SRemy Bruno 33240dca1793SAdrian Knoth 33253cee5a60SRemy Bruno #define HDSPM_QS_WIRE(xname, xindex) \ 33263cee5a60SRemy Bruno { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 33273cee5a60SRemy Bruno .name = xname, \ 33283cee5a60SRemy Bruno .index = xindex, \ 33293cee5a60SRemy Bruno .info = snd_hdspm_info_qs_wire, \ 33303cee5a60SRemy Bruno .get = snd_hdspm_get_qs_wire, \ 33313cee5a60SRemy Bruno .put = snd_hdspm_put_qs_wire \ 33323cee5a60SRemy Bruno } 33333cee5a60SRemy Bruno 33343cee5a60SRemy Bruno static int hdspm_qs_wire(struct hdspm * hdspm) 33353cee5a60SRemy Bruno { 33363cee5a60SRemy Bruno if (hdspm->control_register & HDSPM_QS_DoubleWire) 33373cee5a60SRemy Bruno return 1; 33383cee5a60SRemy Bruno if (hdspm->control_register & HDSPM_QS_QuadWire) 33393cee5a60SRemy Bruno return 2; 33403cee5a60SRemy Bruno return 0; 33413cee5a60SRemy Bruno } 33423cee5a60SRemy Bruno 33433cee5a60SRemy Bruno static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode) 33443cee5a60SRemy Bruno { 33453cee5a60SRemy Bruno hdspm->control_register &= ~(HDSPM_QS_DoubleWire | HDSPM_QS_QuadWire); 33463cee5a60SRemy Bruno switch (mode) { 33473cee5a60SRemy Bruno case 0: 33483cee5a60SRemy Bruno break; 33493cee5a60SRemy Bruno case 1: 33503cee5a60SRemy Bruno hdspm->control_register |= HDSPM_QS_DoubleWire; 33513cee5a60SRemy Bruno break; 33523cee5a60SRemy Bruno case 2: 33533cee5a60SRemy Bruno hdspm->control_register |= HDSPM_QS_QuadWire; 33543cee5a60SRemy Bruno break; 33553cee5a60SRemy Bruno } 33563cee5a60SRemy Bruno hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 33573cee5a60SRemy Bruno 33583cee5a60SRemy Bruno return 0; 33593cee5a60SRemy Bruno } 33603cee5a60SRemy Bruno 33613cee5a60SRemy Bruno static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, 33623cee5a60SRemy Bruno struct snd_ctl_elem_info *uinfo) 33633cee5a60SRemy Bruno { 33643cee5a60SRemy Bruno static char *texts[] = { "Single", "Double", "Quad" }; 33653cee5a60SRemy Bruno 33663cee5a60SRemy Bruno uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 33673cee5a60SRemy Bruno uinfo->count = 1; 33683cee5a60SRemy Bruno uinfo->value.enumerated.items = 3; 33693cee5a60SRemy Bruno 33703cee5a60SRemy Bruno if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 33713cee5a60SRemy Bruno uinfo->value.enumerated.item = 33723cee5a60SRemy Bruno uinfo->value.enumerated.items - 1; 33733cee5a60SRemy Bruno strcpy(uinfo->value.enumerated.name, 33743cee5a60SRemy Bruno texts[uinfo->value.enumerated.item]); 33753cee5a60SRemy Bruno 33763cee5a60SRemy Bruno return 0; 33773cee5a60SRemy Bruno } 33783cee5a60SRemy Bruno 33793cee5a60SRemy Bruno static int snd_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol, 33803cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 33813cee5a60SRemy Bruno { 33823cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 33833cee5a60SRemy Bruno 33843cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 33853cee5a60SRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm); 33863cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 33873cee5a60SRemy Bruno return 0; 33883cee5a60SRemy Bruno } 33893cee5a60SRemy Bruno 33903cee5a60SRemy Bruno static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, 33913cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 33923cee5a60SRemy Bruno { 33933cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 33943cee5a60SRemy Bruno int change; 33953cee5a60SRemy Bruno int val; 33963cee5a60SRemy Bruno 33973cee5a60SRemy Bruno if (!snd_hdspm_use_is_exclusive(hdspm)) 33983cee5a60SRemy Bruno return -EBUSY; 33993cee5a60SRemy Bruno val = ucontrol->value.integer.value[0]; 34003cee5a60SRemy Bruno if (val < 0) 34013cee5a60SRemy Bruno val = 0; 34023cee5a60SRemy Bruno if (val > 2) 34033cee5a60SRemy Bruno val = 2; 34043cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock); 3405ef5fa1a4STakashi Iwai change = val != hdspm_qs_wire(hdspm); 34063cee5a60SRemy Bruno hdspm_set_qs_wire(hdspm, val); 34073cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock); 34083cee5a60SRemy Bruno return change; 34093cee5a60SRemy Bruno } 34103cee5a60SRemy Bruno 3411763f356cSTakashi Iwai 3412763f356cSTakashi Iwai #define HDSPM_MIXER(xname, xindex) \ 3413763f356cSTakashi Iwai { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ 3414763f356cSTakashi Iwai .name = xname, \ 3415763f356cSTakashi Iwai .index = xindex, \ 341667ed4161SClemens Ladisch .device = 0, \ 3417763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 3418763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 3419763f356cSTakashi Iwai .info = snd_hdspm_info_mixer, \ 3420763f356cSTakashi Iwai .get = snd_hdspm_get_mixer, \ 3421763f356cSTakashi Iwai .put = snd_hdspm_put_mixer \ 3422763f356cSTakashi Iwai } 3423763f356cSTakashi Iwai 342498274f07STakashi Iwai static int snd_hdspm_info_mixer(struct snd_kcontrol *kcontrol, 342598274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 3426763f356cSTakashi Iwai { 3427763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 3428763f356cSTakashi Iwai uinfo->count = 3; 3429763f356cSTakashi Iwai uinfo->value.integer.min = 0; 3430763f356cSTakashi Iwai uinfo->value.integer.max = 65535; 3431763f356cSTakashi Iwai uinfo->value.integer.step = 1; 3432763f356cSTakashi Iwai return 0; 3433763f356cSTakashi Iwai } 3434763f356cSTakashi Iwai 343598274f07STakashi Iwai static int snd_hdspm_get_mixer(struct snd_kcontrol *kcontrol, 343698274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3437763f356cSTakashi Iwai { 343898274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3439763f356cSTakashi Iwai int source; 3440763f356cSTakashi Iwai int destination; 3441763f356cSTakashi Iwai 3442763f356cSTakashi Iwai source = ucontrol->value.integer.value[0]; 3443763f356cSTakashi Iwai if (source < 0) 3444763f356cSTakashi Iwai source = 0; 3445763f356cSTakashi Iwai else if (source >= 2 * HDSPM_MAX_CHANNELS) 3446763f356cSTakashi Iwai source = 2 * HDSPM_MAX_CHANNELS - 1; 3447763f356cSTakashi Iwai 3448763f356cSTakashi Iwai destination = ucontrol->value.integer.value[1]; 3449763f356cSTakashi Iwai if (destination < 0) 3450763f356cSTakashi Iwai destination = 0; 3451763f356cSTakashi Iwai else if (destination >= HDSPM_MAX_CHANNELS) 3452763f356cSTakashi Iwai destination = HDSPM_MAX_CHANNELS - 1; 3453763f356cSTakashi Iwai 3454763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3455763f356cSTakashi Iwai if (source >= HDSPM_MAX_CHANNELS) 3456763f356cSTakashi Iwai ucontrol->value.integer.value[2] = 3457763f356cSTakashi Iwai hdspm_read_pb_gain(hdspm, destination, 3458763f356cSTakashi Iwai source - HDSPM_MAX_CHANNELS); 3459763f356cSTakashi Iwai else 3460763f356cSTakashi Iwai ucontrol->value.integer.value[2] = 3461763f356cSTakashi Iwai hdspm_read_in_gain(hdspm, destination, source); 3462763f356cSTakashi Iwai 3463763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3464763f356cSTakashi Iwai 3465763f356cSTakashi Iwai return 0; 3466763f356cSTakashi Iwai } 3467763f356cSTakashi Iwai 346898274f07STakashi Iwai static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol, 346998274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3470763f356cSTakashi Iwai { 347198274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3472763f356cSTakashi Iwai int change; 3473763f356cSTakashi Iwai int source; 3474763f356cSTakashi Iwai int destination; 3475763f356cSTakashi Iwai int gain; 3476763f356cSTakashi Iwai 3477763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 3478763f356cSTakashi Iwai return -EBUSY; 3479763f356cSTakashi Iwai 3480763f356cSTakashi Iwai source = ucontrol->value.integer.value[0]; 3481763f356cSTakashi Iwai destination = ucontrol->value.integer.value[1]; 3482763f356cSTakashi Iwai 3483763f356cSTakashi Iwai if (source < 0 || source >= 2 * HDSPM_MAX_CHANNELS) 3484763f356cSTakashi Iwai return -1; 3485763f356cSTakashi Iwai if (destination < 0 || destination >= HDSPM_MAX_CHANNELS) 3486763f356cSTakashi Iwai return -1; 3487763f356cSTakashi Iwai 3488763f356cSTakashi Iwai gain = ucontrol->value.integer.value[2]; 3489763f356cSTakashi Iwai 3490763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3491763f356cSTakashi Iwai 3492763f356cSTakashi Iwai if (source >= HDSPM_MAX_CHANNELS) 3493763f356cSTakashi Iwai change = gain != hdspm_read_pb_gain(hdspm, destination, 3494763f356cSTakashi Iwai source - 3495763f356cSTakashi Iwai HDSPM_MAX_CHANNELS); 3496763f356cSTakashi Iwai else 3497ef5fa1a4STakashi Iwai change = gain != hdspm_read_in_gain(hdspm, destination, 3498ef5fa1a4STakashi Iwai source); 3499763f356cSTakashi Iwai 3500763f356cSTakashi Iwai if (change) { 3501763f356cSTakashi Iwai if (source >= HDSPM_MAX_CHANNELS) 3502763f356cSTakashi Iwai hdspm_write_pb_gain(hdspm, destination, 3503763f356cSTakashi Iwai source - HDSPM_MAX_CHANNELS, 3504763f356cSTakashi Iwai gain); 3505763f356cSTakashi Iwai else 3506763f356cSTakashi Iwai hdspm_write_in_gain(hdspm, destination, source, 3507763f356cSTakashi Iwai gain); 3508763f356cSTakashi Iwai } 3509763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3510763f356cSTakashi Iwai 3511763f356cSTakashi Iwai return change; 3512763f356cSTakashi Iwai } 3513763f356cSTakashi Iwai 3514763f356cSTakashi Iwai /* The simple mixer control(s) provide gain control for the 3515763f356cSTakashi Iwai basic 1:1 mappings of playback streams to output 3516763f356cSTakashi Iwai streams. 3517763f356cSTakashi Iwai */ 3518763f356cSTakashi Iwai 3519763f356cSTakashi Iwai #define HDSPM_PLAYBACK_MIXER \ 3520763f356cSTakashi Iwai { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3521763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ 3522763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 3523763f356cSTakashi Iwai .info = snd_hdspm_info_playback_mixer, \ 3524763f356cSTakashi Iwai .get = snd_hdspm_get_playback_mixer, \ 3525763f356cSTakashi Iwai .put = snd_hdspm_put_playback_mixer \ 3526763f356cSTakashi Iwai } 3527763f356cSTakashi Iwai 352898274f07STakashi Iwai static int snd_hdspm_info_playback_mixer(struct snd_kcontrol *kcontrol, 352998274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 3530763f356cSTakashi Iwai { 3531763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 3532763f356cSTakashi Iwai uinfo->count = 1; 3533763f356cSTakashi Iwai uinfo->value.integer.min = 0; 35340dca1793SAdrian Knoth uinfo->value.integer.max = 64; 3535763f356cSTakashi Iwai uinfo->value.integer.step = 1; 3536763f356cSTakashi Iwai return 0; 3537763f356cSTakashi Iwai } 3538763f356cSTakashi Iwai 353998274f07STakashi Iwai static int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol, 354098274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3541763f356cSTakashi Iwai { 354298274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3543763f356cSTakashi Iwai int channel; 3544763f356cSTakashi Iwai 3545763f356cSTakashi Iwai channel = ucontrol->id.index - 1; 3546763f356cSTakashi Iwai 3547da3cec35STakashi Iwai if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS)) 3548da3cec35STakashi Iwai return -EINVAL; 3549763f356cSTakashi Iwai 3550763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3551763f356cSTakashi Iwai ucontrol->value.integer.value[0] = 35520dca1793SAdrian Knoth (hdspm_read_pb_gain(hdspm, channel, channel)*64)/UNITY_GAIN; 3553763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3554763f356cSTakashi Iwai 3555763f356cSTakashi Iwai return 0; 3556763f356cSTakashi Iwai } 3557763f356cSTakashi Iwai 355898274f07STakashi Iwai static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, 355998274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3560763f356cSTakashi Iwai { 356198274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 3562763f356cSTakashi Iwai int change; 3563763f356cSTakashi Iwai int channel; 3564763f356cSTakashi Iwai int gain; 3565763f356cSTakashi Iwai 3566763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm)) 3567763f356cSTakashi Iwai return -EBUSY; 3568763f356cSTakashi Iwai 3569763f356cSTakashi Iwai channel = ucontrol->id.index - 1; 3570763f356cSTakashi Iwai 3571da3cec35STakashi Iwai if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS)) 3572da3cec35STakashi Iwai return -EINVAL; 3573763f356cSTakashi Iwai 35740dca1793SAdrian Knoth gain = ucontrol->value.integer.value[0]*UNITY_GAIN/64; 3575763f356cSTakashi Iwai 3576763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 3577763f356cSTakashi Iwai change = 35780dca1793SAdrian Knoth gain != hdspm_read_pb_gain(hdspm, channel, 35790dca1793SAdrian Knoth channel); 3580763f356cSTakashi Iwai if (change) 35810dca1793SAdrian Knoth hdspm_write_pb_gain(hdspm, channel, channel, 3582763f356cSTakashi Iwai gain); 3583763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 3584763f356cSTakashi Iwai return change; 3585763f356cSTakashi Iwai } 3586763f356cSTakashi Iwai 35870dca1793SAdrian Knoth #define HDSPM_SYNC_CHECK(xname, xindex) \ 358867ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 3589763f356cSTakashi Iwai .name = xname, \ 35900dca1793SAdrian Knoth .private_value = xindex, \ 3591763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 3592763f356cSTakashi Iwai .info = snd_hdspm_info_sync_check, \ 35930dca1793SAdrian Knoth .get = snd_hdspm_get_sync_check \ 3594763f356cSTakashi Iwai } 3595763f356cSTakashi Iwai 35960dca1793SAdrian Knoth 359798274f07STakashi Iwai static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, 359898274f07STakashi Iwai struct snd_ctl_elem_info *uinfo) 3599763f356cSTakashi Iwai { 36000dca1793SAdrian Knoth static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" }; 3601763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 3602763f356cSTakashi Iwai uinfo->count = 1; 36030dca1793SAdrian Knoth uinfo->value.enumerated.items = 4; 3604763f356cSTakashi Iwai if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 3605763f356cSTakashi Iwai uinfo->value.enumerated.item = 3606763f356cSTakashi Iwai uinfo->value.enumerated.items - 1; 3607763f356cSTakashi Iwai strcpy(uinfo->value.enumerated.name, 3608763f356cSTakashi Iwai texts[uinfo->value.enumerated.item]); 3609763f356cSTakashi Iwai return 0; 3610763f356cSTakashi Iwai } 3611763f356cSTakashi Iwai 361298274f07STakashi Iwai static int hdspm_wc_sync_check(struct hdspm *hdspm) 3613763f356cSTakashi Iwai { 36140dca1793SAdrian Knoth int status, status2; 36150dca1793SAdrian Knoth 36160dca1793SAdrian Knoth switch (hdspm->io_type) { 36170dca1793SAdrian Knoth case AES32: 36180dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 36190dca1793SAdrian Knoth if (status & HDSPM_wcSync) 36203cee5a60SRemy Bruno return 2; 36210dca1793SAdrian Knoth else if (status & HDSPM_wcLock) 36220dca1793SAdrian Knoth return 1; 36233cee5a60SRemy Bruno return 0; 36240dca1793SAdrian Knoth break; 36250dca1793SAdrian Knoth 36260dca1793SAdrian Knoth case MADI: 36270dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 3628763f356cSTakashi Iwai if (status2 & HDSPM_wcLock) { 3629763f356cSTakashi Iwai if (status2 & HDSPM_wcSync) 3630763f356cSTakashi Iwai return 2; 3631763f356cSTakashi Iwai else 3632763f356cSTakashi Iwai return 1; 3633763f356cSTakashi Iwai } 3634763f356cSTakashi Iwai return 0; 36350dca1793SAdrian Knoth break; 3636763f356cSTakashi Iwai 36370dca1793SAdrian Knoth case RayDAT: 36380dca1793SAdrian Knoth case AIO: 36390dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 3640763f356cSTakashi Iwai 36410dca1793SAdrian Knoth if (status & 0x2000000) 36420dca1793SAdrian Knoth return 2; 36430dca1793SAdrian Knoth else if (status & 0x1000000) 36440dca1793SAdrian Knoth return 1; 3645763f356cSTakashi Iwai return 0; 36460dca1793SAdrian Knoth 36470dca1793SAdrian Knoth break; 36480dca1793SAdrian Knoth 36490dca1793SAdrian Knoth case MADIface: 36500dca1793SAdrian Knoth break; 3651763f356cSTakashi Iwai } 3652763f356cSTakashi Iwai 3653763f356cSTakashi Iwai 36540dca1793SAdrian Knoth return 3; 3655763f356cSTakashi Iwai } 3656763f356cSTakashi Iwai 36570dca1793SAdrian Knoth 36580dca1793SAdrian Knoth static int hdspm_madi_sync_check(struct hdspm *hdspm) 3659763f356cSTakashi Iwai { 3660763f356cSTakashi Iwai int status = hdspm_read(hdspm, HDSPM_statusRegister); 3661763f356cSTakashi Iwai if (status & HDSPM_madiLock) { 3662763f356cSTakashi Iwai if (status & HDSPM_madiSync) 3663763f356cSTakashi Iwai return 2; 3664763f356cSTakashi Iwai else 3665763f356cSTakashi Iwai return 1; 3666763f356cSTakashi Iwai } 3667763f356cSTakashi Iwai return 0; 3668763f356cSTakashi Iwai } 3669763f356cSTakashi Iwai 3670763f356cSTakashi Iwai 36710dca1793SAdrian Knoth static int hdspm_s1_sync_check(struct hdspm *hdspm, int idx) 36720dca1793SAdrian Knoth { 36730dca1793SAdrian Knoth int status, lock, sync; 36740dca1793SAdrian Knoth 36750dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 36760dca1793SAdrian Knoth 36770dca1793SAdrian Knoth lock = (status & (0x1<<idx)) ? 1 : 0; 36780dca1793SAdrian Knoth sync = (status & (0x100<<idx)) ? 1 : 0; 36790dca1793SAdrian Knoth 36800dca1793SAdrian Knoth if (lock && sync) 36810dca1793SAdrian Knoth return 2; 36820dca1793SAdrian Knoth else if (lock) 36830dca1793SAdrian Knoth return 1; 3684763f356cSTakashi Iwai return 0; 3685763f356cSTakashi Iwai } 3686763f356cSTakashi Iwai 3687763f356cSTakashi Iwai 36880dca1793SAdrian Knoth static int hdspm_sync_in_sync_check(struct hdspm *hdspm) 36890dca1793SAdrian Knoth { 36900dca1793SAdrian Knoth int status, lock = 0, sync = 0; 36910dca1793SAdrian Knoth 36920dca1793SAdrian Knoth switch (hdspm->io_type) { 36930dca1793SAdrian Knoth case RayDAT: 36940dca1793SAdrian Knoth case AIO: 36950dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_3); 36960dca1793SAdrian Knoth lock = (status & 0x400) ? 1 : 0; 36970dca1793SAdrian Knoth sync = (status & 0x800) ? 1 : 0; 36980dca1793SAdrian Knoth break; 36990dca1793SAdrian Knoth 37000dca1793SAdrian Knoth case MADI: 37010dca1793SAdrian Knoth case AES32: 37020dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister2); 37030dca1793SAdrian Knoth lock = (status & 0x400000) ? 1 : 0; 37040dca1793SAdrian Knoth sync = (status & 0x800000) ? 1 : 0; 37050dca1793SAdrian Knoth break; 37060dca1793SAdrian Knoth 37070dca1793SAdrian Knoth case MADIface: 37080dca1793SAdrian Knoth break; 37090dca1793SAdrian Knoth } 37100dca1793SAdrian Knoth 37110dca1793SAdrian Knoth if (lock && sync) 37120dca1793SAdrian Knoth return 2; 37130dca1793SAdrian Knoth else if (lock) 37140dca1793SAdrian Knoth return 1; 37150dca1793SAdrian Knoth 37160dca1793SAdrian Knoth return 0; 37173cee5a60SRemy Bruno } 37183cee5a60SRemy Bruno 37193cee5a60SRemy Bruno static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx) 37203cee5a60SRemy Bruno { 37210dca1793SAdrian Knoth int status2, lock, sync; 37220dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 37230dca1793SAdrian Knoth 37240dca1793SAdrian Knoth lock = (status2 & (0x0080 >> idx)) ? 1 : 0; 37250dca1793SAdrian Knoth sync = (status2 & (0x8000 >> idx)) ? 1 : 0; 37260dca1793SAdrian Knoth 37270dca1793SAdrian Knoth if (sync) 37283cee5a60SRemy Bruno return 2; 37290dca1793SAdrian Knoth else if (lock) 37300dca1793SAdrian Knoth return 1; 37313cee5a60SRemy Bruno return 0; 37323cee5a60SRemy Bruno } 37333cee5a60SRemy Bruno 37340dca1793SAdrian Knoth 37350dca1793SAdrian Knoth static int hdspm_tco_sync_check(struct hdspm *hdspm) 37360dca1793SAdrian Knoth { 37370dca1793SAdrian Knoth int status; 37380dca1793SAdrian Knoth 37390dca1793SAdrian Knoth if (hdspm->tco) { 37400dca1793SAdrian Knoth switch (hdspm->io_type) { 37410dca1793SAdrian Knoth case MADI: 37420dca1793SAdrian Knoth case AES32: 37430dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister); 37440dca1793SAdrian Knoth if (status & HDSPM_tcoLock) { 37450dca1793SAdrian Knoth if (status & HDSPM_tcoSync) 37460dca1793SAdrian Knoth return 2; 37470dca1793SAdrian Knoth else 37480dca1793SAdrian Knoth return 1; 37490dca1793SAdrian Knoth } 37500dca1793SAdrian Knoth return 0; 37510dca1793SAdrian Knoth 37520dca1793SAdrian Knoth break; 37530dca1793SAdrian Knoth 37540dca1793SAdrian Knoth case RayDAT: 37550dca1793SAdrian Knoth case AIO: 37560dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 37570dca1793SAdrian Knoth 37580dca1793SAdrian Knoth if (status & 0x8000000) 37590dca1793SAdrian Knoth return 2; /* Sync */ 37600dca1793SAdrian Knoth if (status & 0x4000000) 37610dca1793SAdrian Knoth return 1; /* Lock */ 37620dca1793SAdrian Knoth return 0; /* No signal */ 37630dca1793SAdrian Knoth break; 37640dca1793SAdrian Knoth 37650dca1793SAdrian Knoth default: 37660dca1793SAdrian Knoth break; 37670dca1793SAdrian Knoth } 37680dca1793SAdrian Knoth } 37690dca1793SAdrian Knoth 37700dca1793SAdrian Knoth return 3; /* N/A */ 37710dca1793SAdrian Knoth } 37720dca1793SAdrian Knoth 37730dca1793SAdrian Knoth 37740dca1793SAdrian Knoth static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, 37753cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol) 37763cee5a60SRemy Bruno { 37773cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 37780dca1793SAdrian Knoth int val = -1; 37793cee5a60SRemy Bruno 37800dca1793SAdrian Knoth switch (hdspm->io_type) { 37810dca1793SAdrian Knoth case RayDAT: 37820dca1793SAdrian Knoth switch (kcontrol->private_value) { 37830dca1793SAdrian Knoth case 0: /* WC */ 37840dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break; 37850dca1793SAdrian Knoth case 7: /* TCO */ 37860dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break; 37870dca1793SAdrian Knoth case 8: /* SYNC IN */ 37880dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break; 37890dca1793SAdrian Knoth default: 37900dca1793SAdrian Knoth val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1); 37910dca1793SAdrian Knoth } 37923cee5a60SRemy Bruno 37930dca1793SAdrian Knoth case AIO: 37940dca1793SAdrian Knoth switch (kcontrol->private_value) { 37950dca1793SAdrian Knoth case 0: /* WC */ 37960dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break; 37970dca1793SAdrian Knoth case 4: /* TCO */ 37980dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break; 37990dca1793SAdrian Knoth case 5: /* SYNC IN */ 38000dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break; 38010dca1793SAdrian Knoth default: 38020dca1793SAdrian Knoth val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1); 38030dca1793SAdrian Knoth } 38040dca1793SAdrian Knoth 38050dca1793SAdrian Knoth case MADI: 38060dca1793SAdrian Knoth switch (kcontrol->private_value) { 38070dca1793SAdrian Knoth case 0: /* WC */ 38080dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break; 38090dca1793SAdrian Knoth case 1: /* MADI */ 38100dca1793SAdrian Knoth val = hdspm_madi_sync_check(hdspm); break; 38110dca1793SAdrian Knoth case 2: /* TCO */ 38120dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break; 38130dca1793SAdrian Knoth case 3: /* SYNC_IN */ 38140dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break; 38150dca1793SAdrian Knoth } 38160dca1793SAdrian Knoth 38170dca1793SAdrian Knoth case MADIface: 38180dca1793SAdrian Knoth val = hdspm_madi_sync_check(hdspm); /* MADI */ 38190dca1793SAdrian Knoth break; 38200dca1793SAdrian Knoth 38210dca1793SAdrian Knoth case AES32: 38220dca1793SAdrian Knoth switch (kcontrol->private_value) { 38230dca1793SAdrian Knoth case 0: /* WC */ 38240dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break; 38250dca1793SAdrian Knoth case 9: /* TCO */ 38260dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break; 38270dca1793SAdrian Knoth case 10 /* SYNC IN */: 38280dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break; 38297c4a95b5SAdrian Knoth default: /* AES1 to AES8 */ 38300dca1793SAdrian Knoth val = hdspm_aes_sync_check(hdspm, 38317c4a95b5SAdrian Knoth kcontrol->private_value-1); 38320dca1793SAdrian Knoth } 38330dca1793SAdrian Knoth 38340dca1793SAdrian Knoth } 38350dca1793SAdrian Knoth 38360dca1793SAdrian Knoth if (-1 == val) 38370dca1793SAdrian Knoth val = 3; 38380dca1793SAdrian Knoth 38390dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = val; 38403cee5a60SRemy Bruno return 0; 38413cee5a60SRemy Bruno } 3842763f356cSTakashi Iwai 3843763f356cSTakashi Iwai 38440dca1793SAdrian Knoth 38450dca1793SAdrian Knoth /** 38460dca1793SAdrian Knoth * TCO controls 38470dca1793SAdrian Knoth **/ 38480dca1793SAdrian Knoth static void hdspm_tco_write(struct hdspm *hdspm) 38490dca1793SAdrian Knoth { 38500dca1793SAdrian Knoth unsigned int tc[4] = { 0, 0, 0, 0}; 38510dca1793SAdrian Knoth 38520dca1793SAdrian Knoth switch (hdspm->tco->input) { 38530dca1793SAdrian Knoth case 0: 38540dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_input_MSB; 38550dca1793SAdrian Knoth break; 38560dca1793SAdrian Knoth case 1: 38570dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_input_LSB; 38580dca1793SAdrian Knoth break; 38590dca1793SAdrian Knoth default: 38600dca1793SAdrian Knoth break; 38610dca1793SAdrian Knoth } 38620dca1793SAdrian Knoth 38630dca1793SAdrian Knoth switch (hdspm->tco->framerate) { 38640dca1793SAdrian Knoth case 1: 38650dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_LSB; 38660dca1793SAdrian Knoth break; 38670dca1793SAdrian Knoth case 2: 38680dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_MSB; 38690dca1793SAdrian Knoth break; 38700dca1793SAdrian Knoth case 3: 38710dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_MSB + 38720dca1793SAdrian Knoth HDSPM_TCO1_set_drop_frame_flag; 38730dca1793SAdrian Knoth break; 38740dca1793SAdrian Knoth case 4: 38750dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_LSB + 38760dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB; 38770dca1793SAdrian Knoth break; 38780dca1793SAdrian Knoth case 5: 38790dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_LSB + 38800dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB + 38810dca1793SAdrian Knoth HDSPM_TCO1_set_drop_frame_flag; 38820dca1793SAdrian Knoth break; 38830dca1793SAdrian Knoth default: 38840dca1793SAdrian Knoth break; 38850dca1793SAdrian Knoth } 38860dca1793SAdrian Knoth 38870dca1793SAdrian Knoth switch (hdspm->tco->wordclock) { 38880dca1793SAdrian Knoth case 1: 38890dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_WCK_IO_ratio_LSB; 38900dca1793SAdrian Knoth break; 38910dca1793SAdrian Knoth case 2: 38920dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_WCK_IO_ratio_MSB; 38930dca1793SAdrian Knoth break; 38940dca1793SAdrian Knoth default: 38950dca1793SAdrian Knoth break; 38960dca1793SAdrian Knoth } 38970dca1793SAdrian Knoth 38980dca1793SAdrian Knoth switch (hdspm->tco->samplerate) { 38990dca1793SAdrian Knoth case 1: 39000dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_freq; 39010dca1793SAdrian Knoth break; 39020dca1793SAdrian Knoth case 2: 39030dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_freq_from_app; 39040dca1793SAdrian Knoth break; 39050dca1793SAdrian Knoth default: 39060dca1793SAdrian Knoth break; 39070dca1793SAdrian Knoth } 39080dca1793SAdrian Knoth 39090dca1793SAdrian Knoth switch (hdspm->tco->pull) { 39100dca1793SAdrian Knoth case 1: 39110dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_up; 39120dca1793SAdrian Knoth break; 39130dca1793SAdrian Knoth case 2: 39140dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_down; 39150dca1793SAdrian Knoth break; 39160dca1793SAdrian Knoth case 3: 39170dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_up + HDSPM_TCO2_set_01_4; 39180dca1793SAdrian Knoth break; 39190dca1793SAdrian Knoth case 4: 39200dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_down + HDSPM_TCO2_set_01_4; 39210dca1793SAdrian Knoth break; 39220dca1793SAdrian Knoth default: 39230dca1793SAdrian Knoth break; 39240dca1793SAdrian Knoth } 39250dca1793SAdrian Knoth 39260dca1793SAdrian Knoth if (1 == hdspm->tco->term) { 39270dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_term_75R; 39280dca1793SAdrian Knoth } 39290dca1793SAdrian Knoth 39300dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO, tc[0]); 39310dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO+4, tc[1]); 39320dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO+8, tc[2]); 39330dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO+12, tc[3]); 39340dca1793SAdrian Knoth } 39350dca1793SAdrian Knoth 39360dca1793SAdrian Knoth 39370dca1793SAdrian Knoth #define HDSPM_TCO_SAMPLE_RATE(xname, xindex) \ 39380dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 39390dca1793SAdrian Knoth .name = xname, \ 39400dca1793SAdrian Knoth .index = xindex, \ 39410dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 39420dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 39430dca1793SAdrian Knoth .info = snd_hdspm_info_tco_sample_rate, \ 39440dca1793SAdrian Knoth .get = snd_hdspm_get_tco_sample_rate, \ 39450dca1793SAdrian Knoth .put = snd_hdspm_put_tco_sample_rate \ 39460dca1793SAdrian Knoth } 39470dca1793SAdrian Knoth 39480dca1793SAdrian Knoth static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, 39490dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 39500dca1793SAdrian Knoth { 39510dca1793SAdrian Knoth static char *texts[] = { "44.1 kHz", "48 kHz" }; 39520dca1793SAdrian Knoth uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 39530dca1793SAdrian Knoth uinfo->count = 1; 39540dca1793SAdrian Knoth uinfo->value.enumerated.items = 2; 39550dca1793SAdrian Knoth 39560dca1793SAdrian Knoth if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 39570dca1793SAdrian Knoth uinfo->value.enumerated.item = 39580dca1793SAdrian Knoth uinfo->value.enumerated.items - 1; 39590dca1793SAdrian Knoth 39600dca1793SAdrian Knoth strcpy(uinfo->value.enumerated.name, 39610dca1793SAdrian Knoth texts[uinfo->value.enumerated.item]); 39620dca1793SAdrian Knoth 39630dca1793SAdrian Knoth return 0; 39640dca1793SAdrian Knoth } 39650dca1793SAdrian Knoth 39660dca1793SAdrian Knoth static int snd_hdspm_get_tco_sample_rate(struct snd_kcontrol *kcontrol, 39670dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 39680dca1793SAdrian Knoth { 39690dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 39700dca1793SAdrian Knoth 39710dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->samplerate; 39720dca1793SAdrian Knoth 39730dca1793SAdrian Knoth return 0; 39740dca1793SAdrian Knoth } 39750dca1793SAdrian Knoth 39760dca1793SAdrian Knoth static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol, 39770dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 39780dca1793SAdrian Knoth { 39790dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 39800dca1793SAdrian Knoth 39810dca1793SAdrian Knoth if (hdspm->tco->samplerate != ucontrol->value.enumerated.item[0]) { 39820dca1793SAdrian Knoth hdspm->tco->samplerate = ucontrol->value.enumerated.item[0]; 39830dca1793SAdrian Knoth 39840dca1793SAdrian Knoth hdspm_tco_write(hdspm); 39850dca1793SAdrian Knoth 39860dca1793SAdrian Knoth return 1; 39870dca1793SAdrian Knoth } 39880dca1793SAdrian Knoth 39890dca1793SAdrian Knoth return 0; 39900dca1793SAdrian Knoth } 39910dca1793SAdrian Knoth 39920dca1793SAdrian Knoth 39930dca1793SAdrian Knoth #define HDSPM_TCO_PULL(xname, xindex) \ 39940dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 39950dca1793SAdrian Knoth .name = xname, \ 39960dca1793SAdrian Knoth .index = xindex, \ 39970dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 39980dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 39990dca1793SAdrian Knoth .info = snd_hdspm_info_tco_pull, \ 40000dca1793SAdrian Knoth .get = snd_hdspm_get_tco_pull, \ 40010dca1793SAdrian Knoth .put = snd_hdspm_put_tco_pull \ 40020dca1793SAdrian Knoth } 40030dca1793SAdrian Knoth 40040dca1793SAdrian Knoth static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, 40050dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 40060dca1793SAdrian Knoth { 40070dca1793SAdrian Knoth static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" }; 40080dca1793SAdrian Knoth uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 40090dca1793SAdrian Knoth uinfo->count = 1; 40100dca1793SAdrian Knoth uinfo->value.enumerated.items = 5; 40110dca1793SAdrian Knoth 40120dca1793SAdrian Knoth if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 40130dca1793SAdrian Knoth uinfo->value.enumerated.item = 40140dca1793SAdrian Knoth uinfo->value.enumerated.items - 1; 40150dca1793SAdrian Knoth 40160dca1793SAdrian Knoth strcpy(uinfo->value.enumerated.name, 40170dca1793SAdrian Knoth texts[uinfo->value.enumerated.item]); 40180dca1793SAdrian Knoth 40190dca1793SAdrian Knoth return 0; 40200dca1793SAdrian Knoth } 40210dca1793SAdrian Knoth 40220dca1793SAdrian Knoth static int snd_hdspm_get_tco_pull(struct snd_kcontrol *kcontrol, 40230dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 40240dca1793SAdrian Knoth { 40250dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 40260dca1793SAdrian Knoth 40270dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->pull; 40280dca1793SAdrian Knoth 40290dca1793SAdrian Knoth return 0; 40300dca1793SAdrian Knoth } 40310dca1793SAdrian Knoth 40320dca1793SAdrian Knoth static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol, 40330dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 40340dca1793SAdrian Knoth { 40350dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 40360dca1793SAdrian Knoth 40370dca1793SAdrian Knoth if (hdspm->tco->pull != ucontrol->value.enumerated.item[0]) { 40380dca1793SAdrian Knoth hdspm->tco->pull = ucontrol->value.enumerated.item[0]; 40390dca1793SAdrian Knoth 40400dca1793SAdrian Knoth hdspm_tco_write(hdspm); 40410dca1793SAdrian Knoth 40420dca1793SAdrian Knoth return 1; 40430dca1793SAdrian Knoth } 40440dca1793SAdrian Knoth 40450dca1793SAdrian Knoth return 0; 40460dca1793SAdrian Knoth } 40470dca1793SAdrian Knoth 40480dca1793SAdrian Knoth #define HDSPM_TCO_WCK_CONVERSION(xname, xindex) \ 40490dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 40500dca1793SAdrian Knoth .name = xname, \ 40510dca1793SAdrian Knoth .index = xindex, \ 40520dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 40530dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 40540dca1793SAdrian Knoth .info = snd_hdspm_info_tco_wck_conversion, \ 40550dca1793SAdrian Knoth .get = snd_hdspm_get_tco_wck_conversion, \ 40560dca1793SAdrian Knoth .put = snd_hdspm_put_tco_wck_conversion \ 40570dca1793SAdrian Knoth } 40580dca1793SAdrian Knoth 40590dca1793SAdrian Knoth static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, 40600dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 40610dca1793SAdrian Knoth { 40620dca1793SAdrian Knoth static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; 40630dca1793SAdrian Knoth uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 40640dca1793SAdrian Knoth uinfo->count = 1; 40650dca1793SAdrian Knoth uinfo->value.enumerated.items = 3; 40660dca1793SAdrian Knoth 40670dca1793SAdrian Knoth if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 40680dca1793SAdrian Knoth uinfo->value.enumerated.item = 40690dca1793SAdrian Knoth uinfo->value.enumerated.items - 1; 40700dca1793SAdrian Knoth 40710dca1793SAdrian Knoth strcpy(uinfo->value.enumerated.name, 40720dca1793SAdrian Knoth texts[uinfo->value.enumerated.item]); 40730dca1793SAdrian Knoth 40740dca1793SAdrian Knoth return 0; 40750dca1793SAdrian Knoth } 40760dca1793SAdrian Knoth 40770dca1793SAdrian Knoth static int snd_hdspm_get_tco_wck_conversion(struct snd_kcontrol *kcontrol, 40780dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 40790dca1793SAdrian Knoth { 40800dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 40810dca1793SAdrian Knoth 40820dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->wordclock; 40830dca1793SAdrian Knoth 40840dca1793SAdrian Knoth return 0; 40850dca1793SAdrian Knoth } 40860dca1793SAdrian Knoth 40870dca1793SAdrian Knoth static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol, 40880dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 40890dca1793SAdrian Knoth { 40900dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 40910dca1793SAdrian Knoth 40920dca1793SAdrian Knoth if (hdspm->tco->wordclock != ucontrol->value.enumerated.item[0]) { 40930dca1793SAdrian Knoth hdspm->tco->wordclock = ucontrol->value.enumerated.item[0]; 40940dca1793SAdrian Knoth 40950dca1793SAdrian Knoth hdspm_tco_write(hdspm); 40960dca1793SAdrian Knoth 40970dca1793SAdrian Knoth return 1; 40980dca1793SAdrian Knoth } 40990dca1793SAdrian Knoth 41000dca1793SAdrian Knoth return 0; 41010dca1793SAdrian Knoth } 41020dca1793SAdrian Knoth 41030dca1793SAdrian Knoth 41040dca1793SAdrian Knoth #define HDSPM_TCO_FRAME_RATE(xname, xindex) \ 41050dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 41060dca1793SAdrian Knoth .name = xname, \ 41070dca1793SAdrian Knoth .index = xindex, \ 41080dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 41090dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 41100dca1793SAdrian Knoth .info = snd_hdspm_info_tco_frame_rate, \ 41110dca1793SAdrian Knoth .get = snd_hdspm_get_tco_frame_rate, \ 41120dca1793SAdrian Knoth .put = snd_hdspm_put_tco_frame_rate \ 41130dca1793SAdrian Knoth } 41140dca1793SAdrian Knoth 41150dca1793SAdrian Knoth static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, 41160dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 41170dca1793SAdrian Knoth { 41180dca1793SAdrian Knoth static char *texts[] = { "24 fps", "25 fps", "29.97fps", 41190dca1793SAdrian Knoth "29.97 dfps", "30 fps", "30 dfps" }; 41200dca1793SAdrian Knoth uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 41210dca1793SAdrian Knoth uinfo->count = 1; 41220dca1793SAdrian Knoth uinfo->value.enumerated.items = 6; 41230dca1793SAdrian Knoth 41240dca1793SAdrian Knoth if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 41250dca1793SAdrian Knoth uinfo->value.enumerated.item = 41260dca1793SAdrian Knoth uinfo->value.enumerated.items - 1; 41270dca1793SAdrian Knoth 41280dca1793SAdrian Knoth strcpy(uinfo->value.enumerated.name, 41290dca1793SAdrian Knoth texts[uinfo->value.enumerated.item]); 41300dca1793SAdrian Knoth 41310dca1793SAdrian Knoth return 0; 41320dca1793SAdrian Knoth } 41330dca1793SAdrian Knoth 41340dca1793SAdrian Knoth static int snd_hdspm_get_tco_frame_rate(struct snd_kcontrol *kcontrol, 41350dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 41360dca1793SAdrian Knoth { 41370dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 41380dca1793SAdrian Knoth 41390dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->framerate; 41400dca1793SAdrian Knoth 41410dca1793SAdrian Knoth return 0; 41420dca1793SAdrian Knoth } 41430dca1793SAdrian Knoth 41440dca1793SAdrian Knoth static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol, 41450dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 41460dca1793SAdrian Knoth { 41470dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 41480dca1793SAdrian Knoth 41490dca1793SAdrian Knoth if (hdspm->tco->framerate != ucontrol->value.enumerated.item[0]) { 41500dca1793SAdrian Knoth hdspm->tco->framerate = ucontrol->value.enumerated.item[0]; 41510dca1793SAdrian Knoth 41520dca1793SAdrian Knoth hdspm_tco_write(hdspm); 41530dca1793SAdrian Knoth 41540dca1793SAdrian Knoth return 1; 41550dca1793SAdrian Knoth } 41560dca1793SAdrian Knoth 41570dca1793SAdrian Knoth return 0; 41580dca1793SAdrian Knoth } 41590dca1793SAdrian Knoth 41600dca1793SAdrian Knoth 41610dca1793SAdrian Knoth #define HDSPM_TCO_SYNC_SOURCE(xname, xindex) \ 41620dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 41630dca1793SAdrian Knoth .name = xname, \ 41640dca1793SAdrian Knoth .index = xindex, \ 41650dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 41660dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 41670dca1793SAdrian Knoth .info = snd_hdspm_info_tco_sync_source, \ 41680dca1793SAdrian Knoth .get = snd_hdspm_get_tco_sync_source, \ 41690dca1793SAdrian Knoth .put = snd_hdspm_put_tco_sync_source \ 41700dca1793SAdrian Knoth } 41710dca1793SAdrian Knoth 41720dca1793SAdrian Knoth static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, 41730dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 41740dca1793SAdrian Knoth { 41750dca1793SAdrian Knoth static char *texts[] = { "LTC", "Video", "WCK" }; 41760dca1793SAdrian Knoth uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 41770dca1793SAdrian Knoth uinfo->count = 1; 41780dca1793SAdrian Knoth uinfo->value.enumerated.items = 3; 41790dca1793SAdrian Knoth 41800dca1793SAdrian Knoth if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 41810dca1793SAdrian Knoth uinfo->value.enumerated.item = 41820dca1793SAdrian Knoth uinfo->value.enumerated.items - 1; 41830dca1793SAdrian Knoth 41840dca1793SAdrian Knoth strcpy(uinfo->value.enumerated.name, 41850dca1793SAdrian Knoth texts[uinfo->value.enumerated.item]); 41860dca1793SAdrian Knoth 41870dca1793SAdrian Knoth return 0; 41880dca1793SAdrian Knoth } 41890dca1793SAdrian Knoth 41900dca1793SAdrian Knoth static int snd_hdspm_get_tco_sync_source(struct snd_kcontrol *kcontrol, 41910dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 41920dca1793SAdrian Knoth { 41930dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 41940dca1793SAdrian Knoth 41950dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->input; 41960dca1793SAdrian Knoth 41970dca1793SAdrian Knoth return 0; 41980dca1793SAdrian Knoth } 41990dca1793SAdrian Knoth 42000dca1793SAdrian Knoth static int snd_hdspm_put_tco_sync_source(struct snd_kcontrol *kcontrol, 42010dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 42020dca1793SAdrian Knoth { 42030dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 42040dca1793SAdrian Knoth 42050dca1793SAdrian Knoth if (hdspm->tco->input != ucontrol->value.enumerated.item[0]) { 42060dca1793SAdrian Knoth hdspm->tco->input = ucontrol->value.enumerated.item[0]; 42070dca1793SAdrian Knoth 42080dca1793SAdrian Knoth hdspm_tco_write(hdspm); 42090dca1793SAdrian Knoth 42100dca1793SAdrian Knoth return 1; 42110dca1793SAdrian Knoth } 42120dca1793SAdrian Knoth 42130dca1793SAdrian Knoth return 0; 42140dca1793SAdrian Knoth } 42150dca1793SAdrian Knoth 42160dca1793SAdrian Knoth 42170dca1793SAdrian Knoth #define HDSPM_TCO_WORD_TERM(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_word_term, \ 42240dca1793SAdrian Knoth .get = snd_hdspm_get_tco_word_term, \ 42250dca1793SAdrian Knoth .put = snd_hdspm_put_tco_word_term \ 42260dca1793SAdrian Knoth } 42270dca1793SAdrian Knoth 42280dca1793SAdrian Knoth static int snd_hdspm_info_tco_word_term(struct snd_kcontrol *kcontrol, 42290dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo) 42300dca1793SAdrian Knoth { 42310dca1793SAdrian Knoth uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 42320dca1793SAdrian Knoth uinfo->count = 1; 42330dca1793SAdrian Knoth uinfo->value.integer.min = 0; 42340dca1793SAdrian Knoth uinfo->value.integer.max = 1; 42350dca1793SAdrian Knoth 42360dca1793SAdrian Knoth return 0; 42370dca1793SAdrian Knoth } 42380dca1793SAdrian Knoth 42390dca1793SAdrian Knoth 42400dca1793SAdrian Knoth static int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol, 42410dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 42420dca1793SAdrian Knoth { 42430dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 42440dca1793SAdrian Knoth 42450dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->term; 42460dca1793SAdrian Knoth 42470dca1793SAdrian Knoth return 0; 42480dca1793SAdrian Knoth } 42490dca1793SAdrian Knoth 42500dca1793SAdrian Knoth 42510dca1793SAdrian Knoth static int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol, 42520dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol) 42530dca1793SAdrian Knoth { 42540dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 42550dca1793SAdrian Knoth 42560dca1793SAdrian Knoth if (hdspm->tco->term != ucontrol->value.enumerated.item[0]) { 42570dca1793SAdrian Knoth hdspm->tco->term = ucontrol->value.enumerated.item[0]; 42580dca1793SAdrian Knoth 42590dca1793SAdrian Knoth hdspm_tco_write(hdspm); 42600dca1793SAdrian Knoth 42610dca1793SAdrian Knoth return 1; 42620dca1793SAdrian Knoth } 42630dca1793SAdrian Knoth 42640dca1793SAdrian Knoth return 0; 42650dca1793SAdrian Knoth } 42660dca1793SAdrian Knoth 42670dca1793SAdrian Knoth 42680dca1793SAdrian Knoth 42690dca1793SAdrian Knoth 42703cee5a60SRemy Bruno static struct snd_kcontrol_new snd_hdspm_controls_madi[] = { 4271763f356cSTakashi Iwai HDSPM_MIXER("Mixer", 0), 42720dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 4273763f356cSTakashi Iwai HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 4274763f356cSTakashi Iwai HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 4275763f356cSTakashi Iwai HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), 4276763f356cSTakashi Iwai HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 42770dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC SyncCheck", 0), 42780dca1793SAdrian Knoth HDSPM_SYNC_CHECK("MADI SyncCheck", 1), 42790dca1793SAdrian Knoth HDSPM_SYNC_CHECK("TCO SyncCHeck", 2), 42800dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3), 4281763f356cSTakashi Iwai HDSPM_LINE_OUT("Line Out", 0), 4282763f356cSTakashi Iwai HDSPM_TX_64("TX 64 channels mode", 0), 4283763f356cSTakashi Iwai HDSPM_C_TMS("Clear Track Marker", 0), 4284763f356cSTakashi Iwai HDSPM_SAFE_MODE("Safe Mode", 0), 42850dca1793SAdrian Knoth HDSPM_INPUT_SELECT("Input Select", 0) 42860dca1793SAdrian Knoth }; 42870dca1793SAdrian Knoth 42880dca1793SAdrian Knoth 42890dca1793SAdrian Knoth static struct snd_kcontrol_new snd_hdspm_controls_madiface[] = { 42900dca1793SAdrian Knoth HDSPM_MIXER("Mixer", 0), 42910dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 42920dca1793SAdrian Knoth HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 42930dca1793SAdrian Knoth HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 42940dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 42950dca1793SAdrian Knoth HDSPM_SYNC_CHECK("MADI SyncCheck", 0), 42960dca1793SAdrian Knoth HDSPM_TX_64("TX 64 channels mode", 0), 42970dca1793SAdrian Knoth HDSPM_C_TMS("Clear Track Marker", 0), 4298f6ea805fSAdrian Knoth HDSPM_SAFE_MODE("Safe Mode", 0) 4299763f356cSTakashi Iwai }; 4300763f356cSTakashi Iwai 43010dca1793SAdrian Knoth static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { 43023cee5a60SRemy Bruno HDSPM_MIXER("Mixer", 0), 43030dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 43043cee5a60SRemy Bruno HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 43053cee5a60SRemy Bruno HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 43063cee5a60SRemy Bruno HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), 43073cee5a60SRemy Bruno HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 43083cee5a60SRemy Bruno HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 43090dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC SyncCheck", 0), 43100dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES SyncCheck", 1), 43110dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2), 43120dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT SyncCheck", 3), 43130dca1793SAdrian Knoth HDSPM_SYNC_CHECK("TCO SyncCheck", 4), 43140dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 5), 43150dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 43160dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1), 43170dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), 43180dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), 43190dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), 43200dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5) 43210dca1793SAdrian Knoth 43220dca1793SAdrian Knoth /* 43230dca1793SAdrian Knoth HDSPM_INPUT_SELECT("Input Select", 0), 43240dca1793SAdrian Knoth HDSPM_SPDIF_OPTICAL("SPDIF Out Optical", 0), 43250dca1793SAdrian Knoth HDSPM_PROFESSIONAL("SPDIF Out Professional", 0); 43260dca1793SAdrian Knoth HDSPM_SPDIF_IN("SPDIF In", 0); 43270dca1793SAdrian Knoth HDSPM_BREAKOUT_CABLE("Breakout Cable", 0); 43280dca1793SAdrian Knoth HDSPM_INPUT_LEVEL("Input Level", 0); 43290dca1793SAdrian Knoth HDSPM_OUTPUT_LEVEL("Output Level", 0); 43300dca1793SAdrian Knoth HDSPM_PHONES("Phones", 0); 43310dca1793SAdrian Knoth */ 43320dca1793SAdrian Knoth }; 43330dca1793SAdrian Knoth 43340dca1793SAdrian Knoth static struct snd_kcontrol_new snd_hdspm_controls_raydat[] = { 43350dca1793SAdrian Knoth HDSPM_MIXER("Mixer", 0), 43360dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 43370dca1793SAdrian Knoth HDSPM_SYSTEM_CLOCK_MODE("Clock Mode", 0), 43380dca1793SAdrian Knoth HDSPM_PREF_SYNC_REF("Pref Sync Ref", 0), 43390dca1793SAdrian Knoth HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 43400dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC SyncCheck", 0), 43410dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES SyncCheck", 1), 43420dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2), 43430dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT1 SyncCheck", 3), 43440dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT2 SyncCheck", 4), 43450dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT3 SyncCheck", 5), 43460dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT4 SyncCheck", 6), 43470dca1793SAdrian Knoth HDSPM_SYNC_CHECK("TCO SyncCheck", 7), 43480dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 8), 43490dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 43500dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1), 43510dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), 43520dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT1 Frequency", 3), 43530dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT2 Frequency", 4), 43540dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5), 43550dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6), 43560dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7), 43570dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8) 43580dca1793SAdrian Knoth }; 43590dca1793SAdrian Knoth 43600dca1793SAdrian Knoth static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { 43610dca1793SAdrian Knoth HDSPM_MIXER("Mixer", 0), 43620dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 43630dca1793SAdrian Knoth HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 43640dca1793SAdrian Knoth HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 43650dca1793SAdrian Knoth HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), 43660dca1793SAdrian Knoth HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 43670dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 43680dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC Sync Check", 0), 43690dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES1 Sync Check", 1), 43700dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES2 Sync Check", 2), 43710dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES3 Sync Check", 3), 43720dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES4 Sync Check", 4), 43730dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES5 Sync Check", 5), 43740dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES6 Sync Check", 6), 43750dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES7 Sync Check", 7), 43760dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES8 Sync Check", 8), 43770dca1793SAdrian Knoth HDSPM_SYNC_CHECK("TCO Sync Check", 9), 43780dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN Sync Check", 10), 43790dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 43800dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES1 Frequency", 1), 43810dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES2 Frequency", 2), 43820dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES3 Frequency", 3), 43830dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES4 Frequency", 4), 43840dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES5 Frequency", 5), 43850dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES6 Frequency", 6), 43860dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES7 Frequency", 7), 43870dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES8 Frequency", 8), 43880dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 9), 43890dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 10), 43903cee5a60SRemy Bruno HDSPM_LINE_OUT("Line Out", 0), 43913cee5a60SRemy Bruno HDSPM_EMPHASIS("Emphasis", 0), 43923cee5a60SRemy Bruno HDSPM_DOLBY("Non Audio", 0), 43933cee5a60SRemy Bruno HDSPM_PROFESSIONAL("Professional", 0), 43943cee5a60SRemy Bruno HDSPM_C_TMS("Clear Track Marker", 0), 43953cee5a60SRemy Bruno HDSPM_DS_WIRE("Double Speed Wire Mode", 0), 43963cee5a60SRemy Bruno HDSPM_QS_WIRE("Quad Speed Wire Mode", 0), 43973cee5a60SRemy Bruno }; 43983cee5a60SRemy Bruno 43990dca1793SAdrian Knoth 44000dca1793SAdrian Knoth 44010dca1793SAdrian Knoth /* Control elements for the optional TCO module */ 44020dca1793SAdrian Knoth static struct snd_kcontrol_new snd_hdspm_controls_tco[] = { 44030dca1793SAdrian Knoth HDSPM_TCO_SAMPLE_RATE("TCO Sample Rate", 0), 44040dca1793SAdrian Knoth HDSPM_TCO_PULL("TCO Pull", 0), 44050dca1793SAdrian Knoth HDSPM_TCO_WCK_CONVERSION("TCO WCK Conversion", 0), 44060dca1793SAdrian Knoth HDSPM_TCO_FRAME_RATE("TCO Frame Rate", 0), 44070dca1793SAdrian Knoth HDSPM_TCO_SYNC_SOURCE("TCO Sync Source", 0), 44080dca1793SAdrian Knoth HDSPM_TCO_WORD_TERM("TCO Word Term", 0) 44090dca1793SAdrian Knoth }; 44100dca1793SAdrian Knoth 44110dca1793SAdrian Knoth 441298274f07STakashi Iwai static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER; 4413763f356cSTakashi Iwai 4414763f356cSTakashi Iwai 441598274f07STakashi Iwai static int hdspm_update_simple_mixer_controls(struct hdspm * hdspm) 4416763f356cSTakashi Iwai { 4417763f356cSTakashi Iwai int i; 4418763f356cSTakashi Iwai 44190dca1793SAdrian Knoth for (i = hdspm->ds_out_channels; i < hdspm->ss_out_channels; ++i) { 4420763f356cSTakashi Iwai if (hdspm->system_sample_rate > 48000) { 4421763f356cSTakashi Iwai hdspm->playback_mixer_ctls[i]->vd[0].access = 4422763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_INACTIVE | 4423763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_READ | 4424763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE; 4425763f356cSTakashi Iwai } else { 4426763f356cSTakashi Iwai hdspm->playback_mixer_ctls[i]->vd[0].access = 4427763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_READWRITE | 4428763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE; 4429763f356cSTakashi Iwai } 4430763f356cSTakashi Iwai snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE | 4431763f356cSTakashi Iwai SNDRV_CTL_EVENT_MASK_INFO, 4432763f356cSTakashi Iwai &hdspm->playback_mixer_ctls[i]->id); 4433763f356cSTakashi Iwai } 4434763f356cSTakashi Iwai 4435763f356cSTakashi Iwai return 0; 4436763f356cSTakashi Iwai } 4437763f356cSTakashi Iwai 4438763f356cSTakashi Iwai 44390dca1793SAdrian Knoth static int snd_hdspm_create_controls(struct snd_card *card, 44400dca1793SAdrian Knoth struct hdspm *hdspm) 4441763f356cSTakashi Iwai { 4442763f356cSTakashi Iwai unsigned int idx, limit; 4443763f356cSTakashi Iwai int err; 444498274f07STakashi Iwai struct snd_kcontrol *kctl; 44450dca1793SAdrian Knoth struct snd_kcontrol_new *list = NULL; 4446763f356cSTakashi Iwai 44470dca1793SAdrian Knoth switch (hdspm->io_type) { 44480dca1793SAdrian Knoth case MADI: 44490dca1793SAdrian Knoth list = snd_hdspm_controls_madi; 44500dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_madi); 44510dca1793SAdrian Knoth break; 44520dca1793SAdrian Knoth case MADIface: 44530dca1793SAdrian Knoth list = snd_hdspm_controls_madiface; 44540dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_madiface); 44550dca1793SAdrian Knoth break; 44560dca1793SAdrian Knoth case AIO: 44570dca1793SAdrian Knoth list = snd_hdspm_controls_aio; 44580dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_aio); 44590dca1793SAdrian Knoth break; 44600dca1793SAdrian Knoth case RayDAT: 44610dca1793SAdrian Knoth list = snd_hdspm_controls_raydat; 44620dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_raydat); 44630dca1793SAdrian Knoth break; 44640dca1793SAdrian Knoth case AES32: 44650dca1793SAdrian Knoth list = snd_hdspm_controls_aes32; 44660dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_aes32); 44670dca1793SAdrian Knoth break; 44680dca1793SAdrian Knoth } 4469763f356cSTakashi Iwai 44700dca1793SAdrian Knoth if (NULL != list) { 44710dca1793SAdrian Knoth for (idx = 0; idx < limit; idx++) { 44723cee5a60SRemy Bruno err = snd_ctl_add(card, 44730dca1793SAdrian Knoth snd_ctl_new1(&list[idx], hdspm)); 44743cee5a60SRemy Bruno if (err < 0) 4475763f356cSTakashi Iwai return err; 4476763f356cSTakashi Iwai } 4477763f356cSTakashi Iwai } 4478763f356cSTakashi Iwai 4479763f356cSTakashi Iwai 44800dca1793SAdrian Knoth /* create simple 1:1 playback mixer controls */ 4481763f356cSTakashi Iwai snd_hdspm_playback_mixer.name = "Chn"; 44820dca1793SAdrian Knoth if (hdspm->system_sample_rate >= 128000) { 44830dca1793SAdrian Knoth limit = hdspm->qs_out_channels; 44840dca1793SAdrian Knoth } else if (hdspm->system_sample_rate >= 64000) { 44850dca1793SAdrian Knoth limit = hdspm->ds_out_channels; 44860dca1793SAdrian Knoth } else { 44870dca1793SAdrian Knoth limit = hdspm->ss_out_channels; 44880dca1793SAdrian Knoth } 4489763f356cSTakashi Iwai for (idx = 0; idx < limit; ++idx) { 4490763f356cSTakashi Iwai snd_hdspm_playback_mixer.index = idx + 1; 4491ef5fa1a4STakashi Iwai kctl = snd_ctl_new1(&snd_hdspm_playback_mixer, hdspm); 4492ef5fa1a4STakashi Iwai err = snd_ctl_add(card, kctl); 4493ef5fa1a4STakashi Iwai if (err < 0) 4494763f356cSTakashi Iwai return err; 4495763f356cSTakashi Iwai hdspm->playback_mixer_ctls[idx] = kctl; 4496763f356cSTakashi Iwai } 4497763f356cSTakashi Iwai 44980dca1793SAdrian Knoth 44990dca1793SAdrian Knoth if (hdspm->tco) { 45000dca1793SAdrian Knoth /* add tco control elements */ 45010dca1793SAdrian Knoth list = snd_hdspm_controls_tco; 45020dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_tco); 45030dca1793SAdrian Knoth for (idx = 0; idx < limit; idx++) { 45040dca1793SAdrian Knoth err = snd_ctl_add(card, 45050dca1793SAdrian Knoth snd_ctl_new1(&list[idx], hdspm)); 45060dca1793SAdrian Knoth if (err < 0) 45070dca1793SAdrian Knoth return err; 45080dca1793SAdrian Knoth } 45090dca1793SAdrian Knoth } 45100dca1793SAdrian Knoth 4511763f356cSTakashi Iwai return 0; 4512763f356cSTakashi Iwai } 4513763f356cSTakashi Iwai 4514763f356cSTakashi Iwai /*------------------------------------------------------------ 4515763f356cSTakashi Iwai /proc interface 4516763f356cSTakashi Iwai ------------------------------------------------------------*/ 4517763f356cSTakashi Iwai 4518763f356cSTakashi Iwai static void 45193cee5a60SRemy Bruno snd_hdspm_proc_read_madi(struct snd_info_entry * entry, 45203cee5a60SRemy Bruno struct snd_info_buffer *buffer) 4521763f356cSTakashi Iwai { 4522ef5fa1a4STakashi Iwai struct hdspm *hdspm = entry->private_data; 45230dca1793SAdrian Knoth unsigned int status, status2, control, freq; 45240dca1793SAdrian Knoth 4525763f356cSTakashi Iwai char *pref_sync_ref; 4526763f356cSTakashi Iwai char *autosync_ref; 4527763f356cSTakashi Iwai char *system_clock_mode; 4528763f356cSTakashi Iwai char *insel; 4529763f356cSTakashi Iwai int x, x2; 4530763f356cSTakashi Iwai 45310dca1793SAdrian Knoth /* TCO stuff */ 45320dca1793SAdrian Knoth int a, ltc, frames, seconds, minutes, hours; 45330dca1793SAdrian Knoth unsigned int period; 45340dca1793SAdrian Knoth u64 freq_const = 0; 45350dca1793SAdrian Knoth u32 rate; 45360dca1793SAdrian Knoth 4537763f356cSTakashi Iwai status = hdspm_read(hdspm, HDSPM_statusRegister); 4538763f356cSTakashi Iwai status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 45390dca1793SAdrian Knoth control = hdspm->control_register; 45400dca1793SAdrian Knoth freq = hdspm_read(hdspm, HDSPM_timecodeRegister); 4541763f356cSTakashi Iwai 4542763f356cSTakashi Iwai snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", 4543763f356cSTakashi Iwai hdspm->card_name, hdspm->card->number + 1, 4544763f356cSTakashi Iwai hdspm->firmware_rev, 4545763f356cSTakashi Iwai (status2 & HDSPM_version0) | 4546763f356cSTakashi Iwai (status2 & HDSPM_version1) | (status2 & 4547763f356cSTakashi Iwai HDSPM_version2)); 4548763f356cSTakashi Iwai 45490dca1793SAdrian Knoth snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", 45500dca1793SAdrian Knoth (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, 45510dca1793SAdrian Knoth (hdspm_read(hdspm, HDSPM_midiStatusIn0)>>8) & 0xFFFFFF); 45520dca1793SAdrian Knoth 4553763f356cSTakashi Iwai snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", 4554763f356cSTakashi Iwai hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); 4555763f356cSTakashi Iwai 4556763f356cSTakashi Iwai snd_iprintf(buffer, "--- System ---\n"); 4557763f356cSTakashi Iwai 4558763f356cSTakashi Iwai snd_iprintf(buffer, 4559763f356cSTakashi Iwai "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", 4560763f356cSTakashi Iwai status & HDSPM_audioIRQPending, 4561763f356cSTakashi Iwai (status & HDSPM_midi0IRQPending) ? 1 : 0, 4562763f356cSTakashi Iwai (status & HDSPM_midi1IRQPending) ? 1 : 0, 4563763f356cSTakashi Iwai hdspm->irq_count); 4564763f356cSTakashi Iwai snd_iprintf(buffer, 4565ef5fa1a4STakashi Iwai "HW pointer: id = %d, rawptr = %d (%d->%d) " 4566ef5fa1a4STakashi Iwai "estimated= %ld (bytes)\n", 4567763f356cSTakashi Iwai ((status & HDSPM_BufferID) ? 1 : 0), 4568763f356cSTakashi Iwai (status & HDSPM_BufferPositionMask), 4569ef5fa1a4STakashi Iwai (status & HDSPM_BufferPositionMask) % 4570ef5fa1a4STakashi Iwai (2 * (int)hdspm->period_bytes), 4571ef5fa1a4STakashi Iwai ((status & HDSPM_BufferPositionMask) - 64) % 4572ef5fa1a4STakashi Iwai (2 * (int)hdspm->period_bytes), 4573763f356cSTakashi Iwai (long) hdspm_hw_pointer(hdspm) * 4); 4574763f356cSTakashi Iwai 4575763f356cSTakashi Iwai snd_iprintf(buffer, 4576763f356cSTakashi Iwai "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", 4577763f356cSTakashi Iwai hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, 4578763f356cSTakashi Iwai hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, 4579763f356cSTakashi Iwai hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, 4580763f356cSTakashi Iwai hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); 4581763f356cSTakashi Iwai snd_iprintf(buffer, 45820dca1793SAdrian Knoth "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", 45830dca1793SAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, 45840dca1793SAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); 45850dca1793SAdrian Knoth snd_iprintf(buffer, 4586ef5fa1a4STakashi Iwai "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " 4587ef5fa1a4STakashi Iwai "status2=0x%x\n", 4588763f356cSTakashi Iwai hdspm->control_register, hdspm->control2_register, 4589763f356cSTakashi Iwai status, status2); 45900dca1793SAdrian Knoth if (status & HDSPM_tco_detect) { 45910dca1793SAdrian Knoth snd_iprintf(buffer, "TCO module detected.\n"); 45920dca1793SAdrian Knoth a = hdspm_read(hdspm, HDSPM_RD_TCO+4); 45930dca1793SAdrian Knoth if (a & HDSPM_TCO1_LTC_Input_valid) { 45940dca1793SAdrian Knoth snd_iprintf(buffer, " LTC valid, "); 45950dca1793SAdrian Knoth switch (a & (HDSPM_TCO1_LTC_Format_LSB | 45960dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB)) { 45970dca1793SAdrian Knoth case 0: 45980dca1793SAdrian Knoth snd_iprintf(buffer, "24 fps, "); 45990dca1793SAdrian Knoth break; 46000dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_LSB: 46010dca1793SAdrian Knoth snd_iprintf(buffer, "25 fps, "); 46020dca1793SAdrian Knoth break; 46030dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_MSB: 46040dca1793SAdrian Knoth snd_iprintf(buffer, "29.97 fps, "); 46050dca1793SAdrian Knoth break; 46060dca1793SAdrian Knoth default: 46070dca1793SAdrian Knoth snd_iprintf(buffer, "30 fps, "); 46080dca1793SAdrian Knoth break; 46090dca1793SAdrian Knoth } 46100dca1793SAdrian Knoth if (a & HDSPM_TCO1_set_drop_frame_flag) { 46110dca1793SAdrian Knoth snd_iprintf(buffer, "drop frame\n"); 46120dca1793SAdrian Knoth } else { 46130dca1793SAdrian Knoth snd_iprintf(buffer, "full frame\n"); 46140dca1793SAdrian Knoth } 46150dca1793SAdrian Knoth } else { 46160dca1793SAdrian Knoth snd_iprintf(buffer, " no LTC\n"); 46170dca1793SAdrian Knoth } 46180dca1793SAdrian Knoth if (a & HDSPM_TCO1_Video_Input_Format_NTSC) { 46190dca1793SAdrian Knoth snd_iprintf(buffer, " Video: NTSC\n"); 46200dca1793SAdrian Knoth } else if (a & HDSPM_TCO1_Video_Input_Format_PAL) { 46210dca1793SAdrian Knoth snd_iprintf(buffer, " Video: PAL\n"); 46220dca1793SAdrian Knoth } else { 46230dca1793SAdrian Knoth snd_iprintf(buffer, " No video\n"); 46240dca1793SAdrian Knoth } 46250dca1793SAdrian Knoth if (a & HDSPM_TCO1_TCO_lock) { 46260dca1793SAdrian Knoth snd_iprintf(buffer, " Sync: lock\n"); 46270dca1793SAdrian Knoth } else { 46280dca1793SAdrian Knoth snd_iprintf(buffer, " Sync: no lock\n"); 46290dca1793SAdrian Knoth } 46300dca1793SAdrian Knoth 46310dca1793SAdrian Knoth switch (hdspm->io_type) { 46320dca1793SAdrian Knoth case MADI: 46330dca1793SAdrian Knoth case AES32: 46340dca1793SAdrian Knoth freq_const = 110069313433624ULL; 46350dca1793SAdrian Knoth break; 46360dca1793SAdrian Knoth case RayDAT: 46370dca1793SAdrian Knoth case AIO: 46380dca1793SAdrian Knoth freq_const = 104857600000000ULL; 46390dca1793SAdrian Knoth break; 46400dca1793SAdrian Knoth case MADIface: 46410dca1793SAdrian Knoth break; /* no TCO possible */ 46420dca1793SAdrian Knoth } 46430dca1793SAdrian Knoth 46440dca1793SAdrian Knoth period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 46450dca1793SAdrian Knoth snd_iprintf(buffer, " period: %u\n", period); 46460dca1793SAdrian Knoth 46470dca1793SAdrian Knoth 46480dca1793SAdrian Knoth /* rate = freq_const/period; */ 46490dca1793SAdrian Knoth rate = div_u64(freq_const, period); 46500dca1793SAdrian Knoth 46510dca1793SAdrian Knoth if (control & HDSPM_QuadSpeed) { 46520dca1793SAdrian Knoth rate *= 4; 46530dca1793SAdrian Knoth } else if (control & HDSPM_DoubleSpeed) { 46540dca1793SAdrian Knoth rate *= 2; 46550dca1793SAdrian Knoth } 46560dca1793SAdrian Knoth 46570dca1793SAdrian Knoth snd_iprintf(buffer, " Frequency: %u Hz\n", 46580dca1793SAdrian Knoth (unsigned int) rate); 46590dca1793SAdrian Knoth 46600dca1793SAdrian Knoth ltc = hdspm_read(hdspm, HDSPM_RD_TCO); 46610dca1793SAdrian Knoth frames = ltc & 0xF; 46620dca1793SAdrian Knoth ltc >>= 4; 46630dca1793SAdrian Knoth frames += (ltc & 0x3) * 10; 46640dca1793SAdrian Knoth ltc >>= 4; 46650dca1793SAdrian Knoth seconds = ltc & 0xF; 46660dca1793SAdrian Knoth ltc >>= 4; 46670dca1793SAdrian Knoth seconds += (ltc & 0x7) * 10; 46680dca1793SAdrian Knoth ltc >>= 4; 46690dca1793SAdrian Knoth minutes = ltc & 0xF; 46700dca1793SAdrian Knoth ltc >>= 4; 46710dca1793SAdrian Knoth minutes += (ltc & 0x7) * 10; 46720dca1793SAdrian Knoth ltc >>= 4; 46730dca1793SAdrian Knoth hours = ltc & 0xF; 46740dca1793SAdrian Knoth ltc >>= 4; 46750dca1793SAdrian Knoth hours += (ltc & 0x3) * 10; 46760dca1793SAdrian Knoth snd_iprintf(buffer, 46770dca1793SAdrian Knoth " LTC In: %02d:%02d:%02d:%02d\n", 46780dca1793SAdrian Knoth hours, minutes, seconds, frames); 46790dca1793SAdrian Knoth 46800dca1793SAdrian Knoth } else { 46810dca1793SAdrian Knoth snd_iprintf(buffer, "No TCO module detected.\n"); 46820dca1793SAdrian Knoth } 4683763f356cSTakashi Iwai 4684763f356cSTakashi Iwai snd_iprintf(buffer, "--- Settings ---\n"); 4685763f356cSTakashi Iwai 4686ef5fa1a4STakashi Iwai x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & 4687763f356cSTakashi Iwai HDSPM_LatencyMask)); 4688763f356cSTakashi Iwai 4689763f356cSTakashi Iwai snd_iprintf(buffer, 4690763f356cSTakashi Iwai "Size (Latency): %d samples (2 periods of %lu bytes)\n", 4691763f356cSTakashi Iwai x, (unsigned long) hdspm->period_bytes); 4692763f356cSTakashi Iwai 46930dca1793SAdrian Knoth snd_iprintf(buffer, "Line out: %s\n", 46940dca1793SAdrian Knoth (hdspm->control_register & HDSPM_LineOut) ? "on " : "off"); 4695763f356cSTakashi Iwai 4696763f356cSTakashi Iwai switch (hdspm->control_register & HDSPM_InputMask) { 4697763f356cSTakashi Iwai case HDSPM_InputOptical: 4698763f356cSTakashi Iwai insel = "Optical"; 4699763f356cSTakashi Iwai break; 4700763f356cSTakashi Iwai case HDSPM_InputCoaxial: 4701763f356cSTakashi Iwai insel = "Coaxial"; 4702763f356cSTakashi Iwai break; 4703763f356cSTakashi Iwai default: 47040dca1793SAdrian Knoth insel = "Unkown"; 4705763f356cSTakashi Iwai } 4706763f356cSTakashi Iwai 4707763f356cSTakashi Iwai snd_iprintf(buffer, 4708ef5fa1a4STakashi Iwai "ClearTrackMarker = %s, Transmit in %s Channel Mode, " 4709ef5fa1a4STakashi Iwai "Auto Input %s\n", 47100dca1793SAdrian Knoth (hdspm->control_register & HDSPM_clr_tms) ? "on" : "off", 47110dca1793SAdrian Knoth (hdspm->control_register & HDSPM_TX_64ch) ? "64" : "56", 47120dca1793SAdrian Knoth (hdspm->control_register & HDSPM_AutoInp) ? "on" : "off"); 4713763f356cSTakashi Iwai 47140dca1793SAdrian Knoth 47153cee5a60SRemy Bruno if (!(hdspm->control_register & HDSPM_ClockModeMaster)) 47160dca1793SAdrian Knoth system_clock_mode = "AutoSync"; 47173cee5a60SRemy Bruno else 4718763f356cSTakashi Iwai system_clock_mode = "Master"; 47190dca1793SAdrian Knoth snd_iprintf(buffer, "AutoSync Reference: %s\n", system_clock_mode); 4720763f356cSTakashi Iwai 4721763f356cSTakashi Iwai switch (hdspm_pref_sync_ref(hdspm)) { 4722763f356cSTakashi Iwai case HDSPM_SYNC_FROM_WORD: 4723763f356cSTakashi Iwai pref_sync_ref = "Word Clock"; 4724763f356cSTakashi Iwai break; 4725763f356cSTakashi Iwai case HDSPM_SYNC_FROM_MADI: 4726763f356cSTakashi Iwai pref_sync_ref = "MADI Sync"; 4727763f356cSTakashi Iwai break; 47280dca1793SAdrian Knoth case HDSPM_SYNC_FROM_TCO: 47290dca1793SAdrian Knoth pref_sync_ref = "TCO"; 47300dca1793SAdrian Knoth break; 47310dca1793SAdrian Knoth case HDSPM_SYNC_FROM_SYNC_IN: 47320dca1793SAdrian Knoth pref_sync_ref = "Sync In"; 47330dca1793SAdrian Knoth break; 4734763f356cSTakashi Iwai default: 4735763f356cSTakashi Iwai pref_sync_ref = "XXXX Clock"; 4736763f356cSTakashi Iwai break; 4737763f356cSTakashi Iwai } 4738763f356cSTakashi Iwai snd_iprintf(buffer, "Preferred Sync Reference: %s\n", 4739763f356cSTakashi Iwai pref_sync_ref); 4740763f356cSTakashi Iwai 4741763f356cSTakashi Iwai snd_iprintf(buffer, "System Clock Frequency: %d\n", 4742763f356cSTakashi Iwai hdspm->system_sample_rate); 4743763f356cSTakashi Iwai 4744763f356cSTakashi Iwai 4745763f356cSTakashi Iwai snd_iprintf(buffer, "--- Status:\n"); 4746763f356cSTakashi Iwai 4747763f356cSTakashi Iwai x = status & HDSPM_madiSync; 4748763f356cSTakashi Iwai x2 = status2 & HDSPM_wcSync; 4749763f356cSTakashi Iwai 4750763f356cSTakashi Iwai snd_iprintf(buffer, "Inputs MADI=%s, WordClock=%s\n", 4751763f356cSTakashi Iwai (status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") : 4752763f356cSTakashi Iwai "NoLock", 4753763f356cSTakashi Iwai (status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") : 4754763f356cSTakashi Iwai "NoLock"); 4755763f356cSTakashi Iwai 4756763f356cSTakashi Iwai switch (hdspm_autosync_ref(hdspm)) { 47570dca1793SAdrian Knoth case HDSPM_AUTOSYNC_FROM_SYNC_IN: 47580dca1793SAdrian Knoth autosync_ref = "Sync In"; 47590dca1793SAdrian Knoth break; 47600dca1793SAdrian Knoth case HDSPM_AUTOSYNC_FROM_TCO: 47610dca1793SAdrian Knoth autosync_ref = "TCO"; 47620dca1793SAdrian Knoth break; 4763763f356cSTakashi Iwai case HDSPM_AUTOSYNC_FROM_WORD: 4764763f356cSTakashi Iwai autosync_ref = "Word Clock"; 4765763f356cSTakashi Iwai break; 4766763f356cSTakashi Iwai case HDSPM_AUTOSYNC_FROM_MADI: 4767763f356cSTakashi Iwai autosync_ref = "MADI Sync"; 4768763f356cSTakashi Iwai break; 4769763f356cSTakashi Iwai case HDSPM_AUTOSYNC_FROM_NONE: 4770763f356cSTakashi Iwai autosync_ref = "Input not valid"; 4771763f356cSTakashi Iwai break; 4772763f356cSTakashi Iwai default: 4773763f356cSTakashi Iwai autosync_ref = "---"; 4774763f356cSTakashi Iwai break; 4775763f356cSTakashi Iwai } 4776763f356cSTakashi Iwai snd_iprintf(buffer, 4777763f356cSTakashi Iwai "AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n", 4778763f356cSTakashi Iwai autosync_ref, hdspm_external_sample_rate(hdspm), 4779763f356cSTakashi Iwai (status & HDSPM_madiFreqMask) >> 22, 4780763f356cSTakashi Iwai (status2 & HDSPM_wcFreqMask) >> 5); 4781763f356cSTakashi Iwai 4782763f356cSTakashi Iwai snd_iprintf(buffer, "Input: %s, Mode=%s\n", 4783763f356cSTakashi Iwai (status & HDSPM_AB_int) ? "Coax" : "Optical", 4784763f356cSTakashi Iwai (status & HDSPM_RX_64ch) ? "64 channels" : 4785763f356cSTakashi Iwai "56 channels"); 4786763f356cSTakashi Iwai 4787763f356cSTakashi Iwai snd_iprintf(buffer, "\n"); 4788763f356cSTakashi Iwai } 4789763f356cSTakashi Iwai 47903cee5a60SRemy Bruno static void 47913cee5a60SRemy Bruno snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, 47923cee5a60SRemy Bruno struct snd_info_buffer *buffer) 47933cee5a60SRemy Bruno { 4794ef5fa1a4STakashi Iwai struct hdspm *hdspm = entry->private_data; 47953cee5a60SRemy Bruno unsigned int status; 47963cee5a60SRemy Bruno unsigned int status2; 47973cee5a60SRemy Bruno unsigned int timecode; 47983cee5a60SRemy Bruno int pref_syncref; 47993cee5a60SRemy Bruno char *autosync_ref; 48003cee5a60SRemy Bruno int x; 48013cee5a60SRemy Bruno 48023cee5a60SRemy Bruno status = hdspm_read(hdspm, HDSPM_statusRegister); 48033cee5a60SRemy Bruno status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 48043cee5a60SRemy Bruno timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); 48053cee5a60SRemy Bruno 48063cee5a60SRemy Bruno snd_iprintf(buffer, "%s (Card #%d) Rev.%x\n", 48073cee5a60SRemy Bruno hdspm->card_name, hdspm->card->number + 1, 48083cee5a60SRemy Bruno hdspm->firmware_rev); 48093cee5a60SRemy Bruno 48103cee5a60SRemy Bruno snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", 48113cee5a60SRemy Bruno hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); 48123cee5a60SRemy Bruno 48133cee5a60SRemy Bruno snd_iprintf(buffer, "--- System ---\n"); 48143cee5a60SRemy Bruno 48153cee5a60SRemy Bruno snd_iprintf(buffer, 48163cee5a60SRemy Bruno "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", 48173cee5a60SRemy Bruno status & HDSPM_audioIRQPending, 48183cee5a60SRemy Bruno (status & HDSPM_midi0IRQPending) ? 1 : 0, 48193cee5a60SRemy Bruno (status & HDSPM_midi1IRQPending) ? 1 : 0, 48203cee5a60SRemy Bruno hdspm->irq_count); 48213cee5a60SRemy Bruno snd_iprintf(buffer, 4822ef5fa1a4STakashi Iwai "HW pointer: id = %d, rawptr = %d (%d->%d) " 4823ef5fa1a4STakashi Iwai "estimated= %ld (bytes)\n", 48243cee5a60SRemy Bruno ((status & HDSPM_BufferID) ? 1 : 0), 48253cee5a60SRemy Bruno (status & HDSPM_BufferPositionMask), 4826ef5fa1a4STakashi Iwai (status & HDSPM_BufferPositionMask) % 4827ef5fa1a4STakashi Iwai (2 * (int)hdspm->period_bytes), 4828ef5fa1a4STakashi Iwai ((status & HDSPM_BufferPositionMask) - 64) % 4829ef5fa1a4STakashi Iwai (2 * (int)hdspm->period_bytes), 48303cee5a60SRemy Bruno (long) hdspm_hw_pointer(hdspm) * 4); 48313cee5a60SRemy Bruno 48323cee5a60SRemy Bruno snd_iprintf(buffer, 48333cee5a60SRemy Bruno "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", 48343cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, 48353cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, 48363cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, 48373cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); 48383cee5a60SRemy Bruno snd_iprintf(buffer, 48390dca1793SAdrian Knoth "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", 48400dca1793SAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, 48410dca1793SAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); 48420dca1793SAdrian Knoth snd_iprintf(buffer, 48430dca1793SAdrian Knoth "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " 48440dca1793SAdrian Knoth "status2=0x%x\n", 48450dca1793SAdrian Knoth hdspm->control_register, hdspm->control2_register, 48460dca1793SAdrian Knoth status, status2); 48473cee5a60SRemy Bruno 48483cee5a60SRemy Bruno snd_iprintf(buffer, "--- Settings ---\n"); 48493cee5a60SRemy Bruno 4850ef5fa1a4STakashi Iwai x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & 48513cee5a60SRemy Bruno HDSPM_LatencyMask)); 48523cee5a60SRemy Bruno 48533cee5a60SRemy Bruno snd_iprintf(buffer, 48543cee5a60SRemy Bruno "Size (Latency): %d samples (2 periods of %lu bytes)\n", 48553cee5a60SRemy Bruno x, (unsigned long) hdspm->period_bytes); 48563cee5a60SRemy Bruno 48570dca1793SAdrian Knoth snd_iprintf(buffer, "Line out: %s\n", 48583cee5a60SRemy Bruno (hdspm-> 48590dca1793SAdrian Knoth control_register & HDSPM_LineOut) ? "on " : "off"); 48603cee5a60SRemy Bruno 48613cee5a60SRemy Bruno snd_iprintf(buffer, 48623cee5a60SRemy Bruno "ClearTrackMarker %s, Emphasis %s, Dolby %s\n", 48633cee5a60SRemy Bruno (hdspm-> 48643cee5a60SRemy Bruno control_register & HDSPM_clr_tms) ? "on" : "off", 48653cee5a60SRemy Bruno (hdspm-> 48663cee5a60SRemy Bruno control_register & HDSPM_Emphasis) ? "on" : "off", 48673cee5a60SRemy Bruno (hdspm-> 48683cee5a60SRemy Bruno control_register & HDSPM_Dolby) ? "on" : "off"); 48693cee5a60SRemy Bruno 48703cee5a60SRemy Bruno 48713cee5a60SRemy Bruno pref_syncref = hdspm_pref_sync_ref(hdspm); 48723cee5a60SRemy Bruno if (pref_syncref == 0) 48733cee5a60SRemy Bruno snd_iprintf(buffer, "Preferred Sync Reference: Word Clock\n"); 48743cee5a60SRemy Bruno else 48753cee5a60SRemy Bruno snd_iprintf(buffer, "Preferred Sync Reference: AES%d\n", 48763cee5a60SRemy Bruno pref_syncref); 48773cee5a60SRemy Bruno 48783cee5a60SRemy Bruno snd_iprintf(buffer, "System Clock Frequency: %d\n", 48793cee5a60SRemy Bruno hdspm->system_sample_rate); 48803cee5a60SRemy Bruno 48813cee5a60SRemy Bruno snd_iprintf(buffer, "Double speed: %s\n", 48823cee5a60SRemy Bruno hdspm->control_register & HDSPM_DS_DoubleWire? 48833cee5a60SRemy Bruno "Double wire" : "Single wire"); 48843cee5a60SRemy Bruno snd_iprintf(buffer, "Quad speed: %s\n", 48853cee5a60SRemy Bruno hdspm->control_register & HDSPM_QS_DoubleWire? 48863cee5a60SRemy Bruno "Double wire" : 48873cee5a60SRemy Bruno hdspm->control_register & HDSPM_QS_QuadWire? 48883cee5a60SRemy Bruno "Quad wire" : "Single wire"); 48893cee5a60SRemy Bruno 48903cee5a60SRemy Bruno snd_iprintf(buffer, "--- Status:\n"); 48913cee5a60SRemy Bruno 48923cee5a60SRemy Bruno snd_iprintf(buffer, "Word: %s Frequency: %d\n", 48933cee5a60SRemy Bruno (status & HDSPM_AES32_wcLock) ? "Sync " : "No Lock", 48943cee5a60SRemy Bruno HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); 48953cee5a60SRemy Bruno 48963cee5a60SRemy Bruno for (x = 0; x < 8; x++) { 48973cee5a60SRemy Bruno snd_iprintf(buffer, "AES%d: %s Frequency: %d\n", 48983cee5a60SRemy Bruno x+1, 4899ef5fa1a4STakashi Iwai (status2 & (HDSPM_LockAES >> x)) ? 4900ef5fa1a4STakashi Iwai "Sync " : "No Lock", 49013cee5a60SRemy Bruno HDSPM_bit2freq((timecode >> (4*x)) & 0xF)); 49023cee5a60SRemy Bruno } 49033cee5a60SRemy Bruno 49043cee5a60SRemy Bruno switch (hdspm_autosync_ref(hdspm)) { 49050dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_NONE: 49060dca1793SAdrian Knoth autosync_ref = "None"; break; 49070dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_WORD: 49080dca1793SAdrian Knoth autosync_ref = "Word Clock"; break; 49090dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES1: 49100dca1793SAdrian Knoth autosync_ref = "AES1"; break; 49110dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES2: 49120dca1793SAdrian Knoth autosync_ref = "AES2"; break; 49130dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES3: 49140dca1793SAdrian Knoth autosync_ref = "AES3"; break; 49150dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES4: 49160dca1793SAdrian Knoth autosync_ref = "AES4"; break; 49170dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES5: 49180dca1793SAdrian Knoth autosync_ref = "AES5"; break; 49190dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES6: 49200dca1793SAdrian Knoth autosync_ref = "AES6"; break; 49210dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES7: 49220dca1793SAdrian Knoth autosync_ref = "AES7"; break; 49230dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES8: 49240dca1793SAdrian Knoth autosync_ref = "AES8"; break; 49250dca1793SAdrian Knoth default: 49260dca1793SAdrian Knoth autosync_ref = "---"; break; 49273cee5a60SRemy Bruno } 49283cee5a60SRemy Bruno snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); 49293cee5a60SRemy Bruno 49303cee5a60SRemy Bruno snd_iprintf(buffer, "\n"); 49313cee5a60SRemy Bruno } 49323cee5a60SRemy Bruno 49330dca1793SAdrian Knoth static void 49340dca1793SAdrian Knoth snd_hdspm_proc_read_raydat(struct snd_info_entry *entry, 49350dca1793SAdrian Knoth struct snd_info_buffer *buffer) 49360dca1793SAdrian Knoth { 49370dca1793SAdrian Knoth struct hdspm *hdspm = entry->private_data; 49380dca1793SAdrian Knoth unsigned int status1, status2, status3, control, i; 49390dca1793SAdrian Knoth unsigned int lock, sync; 49400dca1793SAdrian Knoth 49410dca1793SAdrian Knoth status1 = hdspm_read(hdspm, HDSPM_RD_STATUS_1); /* s1 */ 49420dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_RD_STATUS_2); /* freq */ 49430dca1793SAdrian Knoth status3 = hdspm_read(hdspm, HDSPM_RD_STATUS_3); /* s2 */ 49440dca1793SAdrian Knoth 49450dca1793SAdrian Knoth control = hdspm->control_register; 49460dca1793SAdrian Knoth 49470dca1793SAdrian Knoth snd_iprintf(buffer, "STATUS1: 0x%08x\n", status1); 49480dca1793SAdrian Knoth snd_iprintf(buffer, "STATUS2: 0x%08x\n", status2); 49490dca1793SAdrian Knoth snd_iprintf(buffer, "STATUS3: 0x%08x\n", status3); 49500dca1793SAdrian Knoth 49510dca1793SAdrian Knoth 49520dca1793SAdrian Knoth snd_iprintf(buffer, "\n*** CLOCK MODE\n\n"); 49530dca1793SAdrian Knoth 49540dca1793SAdrian Knoth snd_iprintf(buffer, "Clock mode : %s\n", 49550dca1793SAdrian Knoth (hdspm_system_clock_mode(hdspm) == 0) ? "master" : "slave"); 49560dca1793SAdrian Knoth snd_iprintf(buffer, "System frequency: %d Hz\n", 49570dca1793SAdrian Knoth hdspm_get_system_sample_rate(hdspm)); 49580dca1793SAdrian Knoth 49590dca1793SAdrian Knoth snd_iprintf(buffer, "\n*** INPUT STATUS\n\n"); 49600dca1793SAdrian Knoth 49610dca1793SAdrian Knoth lock = 0x1; 49620dca1793SAdrian Knoth sync = 0x100; 49630dca1793SAdrian Knoth 49640dca1793SAdrian Knoth for (i = 0; i < 8; i++) { 49650dca1793SAdrian Knoth snd_iprintf(buffer, "s1_input %d: Lock %d, Sync %d, Freq %s\n", 49660dca1793SAdrian Knoth i, 49670dca1793SAdrian Knoth (status1 & lock) ? 1 : 0, 49680dca1793SAdrian Knoth (status1 & sync) ? 1 : 0, 49690dca1793SAdrian Knoth texts_freq[(status2 >> (i * 4)) & 0xF]); 49700dca1793SAdrian Knoth 49710dca1793SAdrian Knoth lock = lock<<1; 49720dca1793SAdrian Knoth sync = sync<<1; 49730dca1793SAdrian Knoth } 49740dca1793SAdrian Knoth 49750dca1793SAdrian Knoth snd_iprintf(buffer, "WC input: Lock %d, Sync %d, Freq %s\n", 49760dca1793SAdrian Knoth (status1 & 0x1000000) ? 1 : 0, 49770dca1793SAdrian Knoth (status1 & 0x2000000) ? 1 : 0, 49780dca1793SAdrian Knoth texts_freq[(status1 >> 16) & 0xF]); 49790dca1793SAdrian Knoth 49800dca1793SAdrian Knoth snd_iprintf(buffer, "TCO input: Lock %d, Sync %d, Freq %s\n", 49810dca1793SAdrian Knoth (status1 & 0x4000000) ? 1 : 0, 49820dca1793SAdrian Knoth (status1 & 0x8000000) ? 1 : 0, 49830dca1793SAdrian Knoth texts_freq[(status1 >> 20) & 0xF]); 49840dca1793SAdrian Knoth 49850dca1793SAdrian Knoth snd_iprintf(buffer, "SYNC IN: Lock %d, Sync %d, Freq %s\n", 49860dca1793SAdrian Knoth (status3 & 0x400) ? 1 : 0, 49870dca1793SAdrian Knoth (status3 & 0x800) ? 1 : 0, 49880dca1793SAdrian Knoth texts_freq[(status2 >> 12) & 0xF]); 49890dca1793SAdrian Knoth 49900dca1793SAdrian Knoth } 49910dca1793SAdrian Knoth 49923cee5a60SRemy Bruno #ifdef CONFIG_SND_DEBUG 49933cee5a60SRemy Bruno static void 49943cee5a60SRemy Bruno snd_hdspm_proc_read_debug(struct snd_info_entry *entry, 49953cee5a60SRemy Bruno struct snd_info_buffer *buffer) 49963cee5a60SRemy Bruno { 4997ef5fa1a4STakashi Iwai struct hdspm *hdspm = entry->private_data; 49983cee5a60SRemy Bruno 49993cee5a60SRemy Bruno int j,i; 50003cee5a60SRemy Bruno 5001ef5fa1a4STakashi Iwai for (i = 0; i < 256 /* 1024*64 */; i += j) { 50023cee5a60SRemy Bruno snd_iprintf(buffer, "0x%08X: ", i); 50033cee5a60SRemy Bruno for (j = 0; j < 16; j += 4) 50043cee5a60SRemy Bruno snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j)); 50053cee5a60SRemy Bruno snd_iprintf(buffer, "\n"); 50063cee5a60SRemy Bruno } 50073cee5a60SRemy Bruno } 50083cee5a60SRemy Bruno #endif 50093cee5a60SRemy Bruno 50103cee5a60SRemy Bruno 50110dca1793SAdrian Knoth static void snd_hdspm_proc_ports_in(struct snd_info_entry *entry, 50120dca1793SAdrian Knoth struct snd_info_buffer *buffer) 50130dca1793SAdrian Knoth { 50140dca1793SAdrian Knoth struct hdspm *hdspm = entry->private_data; 50150dca1793SAdrian Knoth int i; 50160dca1793SAdrian Knoth 50170dca1793SAdrian Knoth snd_iprintf(buffer, "# generated by hdspm\n"); 50180dca1793SAdrian Knoth 50190dca1793SAdrian Knoth for (i = 0; i < hdspm->max_channels_in; i++) { 50200dca1793SAdrian Knoth snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_in[i]); 50210dca1793SAdrian Knoth } 50220dca1793SAdrian Knoth } 50230dca1793SAdrian Knoth 50240dca1793SAdrian Knoth static void snd_hdspm_proc_ports_out(struct snd_info_entry *entry, 50250dca1793SAdrian Knoth struct snd_info_buffer *buffer) 50260dca1793SAdrian Knoth { 50270dca1793SAdrian Knoth struct hdspm *hdspm = entry->private_data; 50280dca1793SAdrian Knoth int i; 50290dca1793SAdrian Knoth 50300dca1793SAdrian Knoth snd_iprintf(buffer, "# generated by hdspm\n"); 50310dca1793SAdrian Knoth 50320dca1793SAdrian Knoth for (i = 0; i < hdspm->max_channels_out; i++) { 50330dca1793SAdrian Knoth snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_out[i]); 50340dca1793SAdrian Knoth } 50350dca1793SAdrian Knoth } 50360dca1793SAdrian Knoth 50373cee5a60SRemy Bruno 503898274f07STakashi Iwai static void __devinit snd_hdspm_proc_init(struct hdspm *hdspm) 5039763f356cSTakashi Iwai { 504098274f07STakashi Iwai struct snd_info_entry *entry; 5041763f356cSTakashi Iwai 50420dca1793SAdrian Knoth if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) { 50430dca1793SAdrian Knoth switch (hdspm->io_type) { 50440dca1793SAdrian Knoth case AES32: 5045bf850204STakashi Iwai snd_info_set_text_ops(entry, hdspm, 50460dca1793SAdrian Knoth snd_hdspm_proc_read_aes32); 50470dca1793SAdrian Knoth break; 50480dca1793SAdrian Knoth case MADI: 50490dca1793SAdrian Knoth snd_info_set_text_ops(entry, hdspm, 50503cee5a60SRemy Bruno snd_hdspm_proc_read_madi); 50510dca1793SAdrian Knoth break; 50520dca1793SAdrian Knoth case MADIface: 50530dca1793SAdrian Knoth /* snd_info_set_text_ops(entry, hdspm, 50540dca1793SAdrian Knoth snd_hdspm_proc_read_madiface); */ 50550dca1793SAdrian Knoth break; 50560dca1793SAdrian Knoth case RayDAT: 50570dca1793SAdrian Knoth snd_info_set_text_ops(entry, hdspm, 50580dca1793SAdrian Knoth snd_hdspm_proc_read_raydat); 50590dca1793SAdrian Knoth break; 50600dca1793SAdrian Knoth case AIO: 50610dca1793SAdrian Knoth break; 50620dca1793SAdrian Knoth } 50630dca1793SAdrian Knoth } 50640dca1793SAdrian Knoth 50650dca1793SAdrian Knoth if (!snd_card_proc_new(hdspm->card, "ports.in", &entry)) { 50660dca1793SAdrian Knoth snd_info_set_text_ops(entry, hdspm, snd_hdspm_proc_ports_in); 50670dca1793SAdrian Knoth } 50680dca1793SAdrian Knoth 50690dca1793SAdrian Knoth if (!snd_card_proc_new(hdspm->card, "ports.out", &entry)) { 50700dca1793SAdrian Knoth snd_info_set_text_ops(entry, hdspm, snd_hdspm_proc_ports_out); 50710dca1793SAdrian Knoth } 50720dca1793SAdrian Knoth 50733cee5a60SRemy Bruno #ifdef CONFIG_SND_DEBUG 50743cee5a60SRemy Bruno /* debug file to read all hdspm registers */ 50753cee5a60SRemy Bruno if (!snd_card_proc_new(hdspm->card, "debug", &entry)) 50763cee5a60SRemy Bruno snd_info_set_text_ops(entry, hdspm, 50773cee5a60SRemy Bruno snd_hdspm_proc_read_debug); 50783cee5a60SRemy Bruno #endif 5079763f356cSTakashi Iwai } 5080763f356cSTakashi Iwai 5081763f356cSTakashi Iwai /*------------------------------------------------------------ 5082763f356cSTakashi Iwai hdspm intitialize 5083763f356cSTakashi Iwai ------------------------------------------------------------*/ 5084763f356cSTakashi Iwai 508598274f07STakashi Iwai static int snd_hdspm_set_defaults(struct hdspm * hdspm) 5086763f356cSTakashi Iwai { 5087763f356cSTakashi Iwai /* ASSUMPTION: hdspm->lock is either held, or there is no need to 5088561de31aSJoe Perches hold it (e.g. during module initialization). 5089763f356cSTakashi Iwai */ 5090763f356cSTakashi Iwai 5091763f356cSTakashi Iwai /* set defaults: */ 5092763f356cSTakashi Iwai 50930dca1793SAdrian Knoth hdspm->settings_register = 0; 50940dca1793SAdrian Knoth 50950dca1793SAdrian Knoth switch (hdspm->io_type) { 50960dca1793SAdrian Knoth case MADI: 50970dca1793SAdrian Knoth case MADIface: 50980dca1793SAdrian Knoth hdspm->control_register = 50990dca1793SAdrian Knoth 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000; 51000dca1793SAdrian Knoth break; 51010dca1793SAdrian Knoth 51020dca1793SAdrian Knoth case RayDAT: 51030dca1793SAdrian Knoth case AIO: 51040dca1793SAdrian Knoth hdspm->settings_register = 0x1 + 0x1000; 51050dca1793SAdrian Knoth /* Magic values are: LAT_0, LAT_2, Master, freq1, tx64ch, inp_0, 51060dca1793SAdrian Knoth * line_out */ 51070dca1793SAdrian Knoth hdspm->control_register = 51080dca1793SAdrian Knoth 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000; 51090dca1793SAdrian Knoth break; 51100dca1793SAdrian Knoth 51110dca1793SAdrian Knoth case AES32: 5112ef5fa1a4STakashi Iwai hdspm->control_register = 5113ef5fa1a4STakashi Iwai HDSPM_ClockModeMaster | /* Master Cloack Mode on */ 51140dca1793SAdrian Knoth hdspm_encode_latency(7) | /* latency max=8192samples */ 51153cee5a60SRemy Bruno HDSPM_SyncRef0 | /* AES1 is syncclock */ 51163cee5a60SRemy Bruno HDSPM_LineOut | /* Analog output in */ 51173cee5a60SRemy Bruno HDSPM_Professional; /* Professional mode */ 51180dca1793SAdrian Knoth break; 51190dca1793SAdrian Knoth } 5120763f356cSTakashi Iwai 5121763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 5122763f356cSTakashi Iwai 51230dca1793SAdrian Knoth if (AES32 == hdspm->io_type) { 5124ffb2c3c0SRemy Bruno /* No control2 register for AES32 */ 5125763f356cSTakashi Iwai #ifdef SNDRV_BIG_ENDIAN 5126763f356cSTakashi Iwai hdspm->control2_register = HDSPM_BIGENDIAN_MODE; 5127763f356cSTakashi Iwai #else 5128763f356cSTakashi Iwai hdspm->control2_register = 0; 5129763f356cSTakashi Iwai #endif 5130763f356cSTakashi Iwai 5131763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register); 5132ffb2c3c0SRemy Bruno } 5133763f356cSTakashi Iwai hdspm_compute_period_size(hdspm); 5134763f356cSTakashi Iwai 5135763f356cSTakashi Iwai /* silence everything */ 5136763f356cSTakashi Iwai 5137763f356cSTakashi Iwai all_in_all_mixer(hdspm, 0 * UNITY_GAIN); 5138763f356cSTakashi Iwai 51390dca1793SAdrian Knoth if (hdspm->io_type == AIO || hdspm->io_type == RayDAT) { 51400dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 5141763f356cSTakashi Iwai } 5142763f356cSTakashi Iwai 5143763f356cSTakashi Iwai /* set a default rate so that the channel map is set up. */ 51440dca1793SAdrian Knoth hdspm_set_rate(hdspm, 48000, 1); 5145763f356cSTakashi Iwai 5146763f356cSTakashi Iwai return 0; 5147763f356cSTakashi Iwai } 5148763f356cSTakashi Iwai 5149763f356cSTakashi Iwai 5150763f356cSTakashi Iwai /*------------------------------------------------------------ 5151561de31aSJoe Perches interrupt 5152763f356cSTakashi Iwai ------------------------------------------------------------*/ 5153763f356cSTakashi Iwai 51547d12e780SDavid Howells static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) 5155763f356cSTakashi Iwai { 515698274f07STakashi Iwai struct hdspm *hdspm = (struct hdspm *) dev_id; 5157763f356cSTakashi Iwai unsigned int status; 51580dca1793SAdrian Knoth int i, audio, midi, schedule = 0; 51590dca1793SAdrian Knoth /* cycles_t now; */ 5160763f356cSTakashi Iwai 5161763f356cSTakashi Iwai status = hdspm_read(hdspm, HDSPM_statusRegister); 5162763f356cSTakashi Iwai 5163763f356cSTakashi Iwai audio = status & HDSPM_audioIRQPending; 51640dca1793SAdrian Knoth midi = status & (HDSPM_midi0IRQPending | HDSPM_midi1IRQPending | 51650dca1793SAdrian Knoth HDSPM_midi2IRQPending | HDSPM_midi3IRQPending); 5166763f356cSTakashi Iwai 51670dca1793SAdrian Knoth /* now = get_cycles(); */ 51680dca1793SAdrian Knoth /** 51690dca1793SAdrian Knoth * LAT_2..LAT_0 period counter (win) counter (mac) 51700dca1793SAdrian Knoth * 6 4096 ~256053425 ~514672358 51710dca1793SAdrian Knoth * 5 2048 ~128024983 ~257373821 51720dca1793SAdrian Knoth * 4 1024 ~64023706 ~128718089 51730dca1793SAdrian Knoth * 3 512 ~32005945 ~64385999 51740dca1793SAdrian Knoth * 2 256 ~16003039 ~32260176 51750dca1793SAdrian Knoth * 1 128 ~7998738 ~16194507 51760dca1793SAdrian Knoth * 0 64 ~3998231 ~8191558 51770dca1793SAdrian Knoth **/ 51780dca1793SAdrian Knoth /* 51790dca1793SAdrian Knoth snd_printk(KERN_INFO "snd_hdspm_interrupt %llu @ %llx\n", 51800dca1793SAdrian Knoth now-hdspm->last_interrupt, status & 0xFFC0); 51810dca1793SAdrian Knoth hdspm->last_interrupt = now; 51820dca1793SAdrian Knoth */ 51830dca1793SAdrian Knoth 51840dca1793SAdrian Knoth if (!audio && !midi) 5185763f356cSTakashi Iwai return IRQ_NONE; 5186763f356cSTakashi Iwai 5187763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_interruptConfirmation, 0); 5188763f356cSTakashi Iwai hdspm->irq_count++; 5189763f356cSTakashi Iwai 5190763f356cSTakashi Iwai 5191763f356cSTakashi Iwai if (audio) { 5192763f356cSTakashi Iwai if (hdspm->capture_substream) 5193ef5fa1a4STakashi Iwai snd_pcm_period_elapsed(hdspm->capture_substream); 5194763f356cSTakashi Iwai 5195763f356cSTakashi Iwai if (hdspm->playback_substream) 5196ef5fa1a4STakashi Iwai snd_pcm_period_elapsed(hdspm->playback_substream); 5197763f356cSTakashi Iwai } 5198763f356cSTakashi Iwai 51990dca1793SAdrian Knoth if (midi) { 52000dca1793SAdrian Knoth i = 0; 52010dca1793SAdrian Knoth while (i < hdspm->midiPorts) { 52020dca1793SAdrian Knoth if ((hdspm_read(hdspm, 52030dca1793SAdrian Knoth hdspm->midi[i].statusIn) & 0xff) && 52040dca1793SAdrian Knoth (status & hdspm->midi[i].irq)) { 52050dca1793SAdrian Knoth /* we disable interrupts for this input until 52060dca1793SAdrian Knoth * processing is done 5207ef5fa1a4STakashi Iwai */ 52080dca1793SAdrian Knoth hdspm->control_register &= ~hdspm->midi[i].ie; 5209763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, 5210763f356cSTakashi Iwai hdspm->control_register); 52110dca1793SAdrian Knoth hdspm->midi[i].pending = 1; 5212763f356cSTakashi Iwai schedule = 1; 5213763f356cSTakashi Iwai } 52140dca1793SAdrian Knoth 52150dca1793SAdrian Knoth i++; 5216763f356cSTakashi Iwai } 52170dca1793SAdrian Knoth 5218763f356cSTakashi Iwai if (schedule) 52190dca1793SAdrian Knoth tasklet_hi_schedule(&hdspm->midi_tasklet); 52200dca1793SAdrian Knoth } 52210dca1793SAdrian Knoth 5222763f356cSTakashi Iwai return IRQ_HANDLED; 5223763f356cSTakashi Iwai } 5224763f356cSTakashi Iwai 5225763f356cSTakashi Iwai /*------------------------------------------------------------ 5226763f356cSTakashi Iwai pcm interface 5227763f356cSTakashi Iwai ------------------------------------------------------------*/ 5228763f356cSTakashi Iwai 5229763f356cSTakashi Iwai 52300dca1793SAdrian Knoth static snd_pcm_uframes_t snd_hdspm_hw_pointer(struct snd_pcm_substream 52310dca1793SAdrian Knoth *substream) 5232763f356cSTakashi Iwai { 523398274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 5234763f356cSTakashi Iwai return hdspm_hw_pointer(hdspm); 5235763f356cSTakashi Iwai } 5236763f356cSTakashi Iwai 5237763f356cSTakashi Iwai 523898274f07STakashi Iwai static int snd_hdspm_reset(struct snd_pcm_substream *substream) 5239763f356cSTakashi Iwai { 524098274f07STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 524198274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 524298274f07STakashi Iwai struct snd_pcm_substream *other; 5243763f356cSTakashi Iwai 5244763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 5245763f356cSTakashi Iwai other = hdspm->capture_substream; 5246763f356cSTakashi Iwai else 5247763f356cSTakashi Iwai other = hdspm->playback_substream; 5248763f356cSTakashi Iwai 5249763f356cSTakashi Iwai if (hdspm->running) 5250763f356cSTakashi Iwai runtime->status->hw_ptr = hdspm_hw_pointer(hdspm); 5251763f356cSTakashi Iwai else 5252763f356cSTakashi Iwai runtime->status->hw_ptr = 0; 5253763f356cSTakashi Iwai if (other) { 525498274f07STakashi Iwai struct snd_pcm_substream *s; 525598274f07STakashi Iwai struct snd_pcm_runtime *oruntime = other->runtime; 5256ef991b95STakashi Iwai snd_pcm_group_for_each_entry(s, substream) { 5257763f356cSTakashi Iwai if (s == other) { 5258763f356cSTakashi Iwai oruntime->status->hw_ptr = 5259763f356cSTakashi Iwai runtime->status->hw_ptr; 5260763f356cSTakashi Iwai break; 5261763f356cSTakashi Iwai } 5262763f356cSTakashi Iwai } 5263763f356cSTakashi Iwai } 5264763f356cSTakashi Iwai return 0; 5265763f356cSTakashi Iwai } 5266763f356cSTakashi Iwai 526798274f07STakashi Iwai static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, 526898274f07STakashi Iwai struct snd_pcm_hw_params *params) 5269763f356cSTakashi Iwai { 527098274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 5271763f356cSTakashi Iwai int err; 5272763f356cSTakashi Iwai int i; 5273763f356cSTakashi Iwai pid_t this_pid; 5274763f356cSTakashi Iwai pid_t other_pid; 5275763f356cSTakashi Iwai 5276763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 5277763f356cSTakashi Iwai 5278763f356cSTakashi Iwai if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5279763f356cSTakashi Iwai this_pid = hdspm->playback_pid; 5280763f356cSTakashi Iwai other_pid = hdspm->capture_pid; 5281763f356cSTakashi Iwai } else { 5282763f356cSTakashi Iwai this_pid = hdspm->capture_pid; 5283763f356cSTakashi Iwai other_pid = hdspm->playback_pid; 5284763f356cSTakashi Iwai } 5285763f356cSTakashi Iwai 5286ef5fa1a4STakashi Iwai if (other_pid > 0 && this_pid != other_pid) { 5287763f356cSTakashi Iwai 5288763f356cSTakashi Iwai /* The other stream is open, and not by the same 5289763f356cSTakashi Iwai task as this one. Make sure that the parameters 5290763f356cSTakashi Iwai that matter are the same. 5291763f356cSTakashi Iwai */ 5292763f356cSTakashi Iwai 5293763f356cSTakashi Iwai if (params_rate(params) != hdspm->system_sample_rate) { 5294763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5295763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params, 5296763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_RATE); 5297763f356cSTakashi Iwai return -EBUSY; 5298763f356cSTakashi Iwai } 5299763f356cSTakashi Iwai 5300763f356cSTakashi Iwai if (params_period_size(params) != hdspm->period_bytes / 4) { 5301763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5302763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params, 5303763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 5304763f356cSTakashi Iwai return -EBUSY; 5305763f356cSTakashi Iwai } 5306763f356cSTakashi Iwai 5307763f356cSTakashi Iwai } 5308763f356cSTakashi Iwai /* We're fine. */ 5309763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5310763f356cSTakashi Iwai 5311763f356cSTakashi Iwai /* how to make sure that the rate matches an externally-set one ? */ 5312763f356cSTakashi Iwai 5313763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 5314ef5fa1a4STakashi Iwai err = hdspm_set_rate(hdspm, params_rate(params), 0); 5315ef5fa1a4STakashi Iwai if (err < 0) { 53160dca1793SAdrian Knoth snd_printk(KERN_INFO "err on hdspm_set_rate: %d\n", err); 5317763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5318763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params, 5319763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_RATE); 5320763f356cSTakashi Iwai return err; 5321763f356cSTakashi Iwai } 5322763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5323763f356cSTakashi Iwai 5324ef5fa1a4STakashi Iwai err = hdspm_set_interrupt_interval(hdspm, 5325ef5fa1a4STakashi Iwai params_period_size(params)); 5326ef5fa1a4STakashi Iwai if (err < 0) { 53270dca1793SAdrian Knoth snd_printk(KERN_INFO "err on hdspm_set_interrupt_interval: %d\n", err); 5328763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params, 5329763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 5330763f356cSTakashi Iwai return err; 5331763f356cSTakashi Iwai } 5332763f356cSTakashi Iwai 5333ef5fa1a4STakashi Iwai /* Memory allocation, takashi's method, dont know if we should 5334ef5fa1a4STakashi Iwai * spinlock 5335ef5fa1a4STakashi Iwai */ 5336763f356cSTakashi Iwai /* malloc all buffer even if not enabled to get sure */ 5337ffb2c3c0SRemy Bruno /* Update for MADI rev 204: we need to allocate for all channels, 5338ffb2c3c0SRemy Bruno * otherwise it doesn't work at 96kHz */ 53390dca1793SAdrian Knoth 5340763f356cSTakashi Iwai err = 5341ffb2c3c0SRemy Bruno snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES); 53420dca1793SAdrian Knoth if (err < 0) { 53430dca1793SAdrian Knoth snd_printk(KERN_INFO "err on snd_pcm_lib_malloc_pages: %d\n", err); 5344763f356cSTakashi Iwai return err; 53450dca1793SAdrian Knoth } 5346763f356cSTakashi Iwai 5347763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5348763f356cSTakashi Iwai 534977a23f26STakashi Iwai hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferOut, 5350763f356cSTakashi Iwai params_channels(params)); 5351763f356cSTakashi Iwai 5352763f356cSTakashi Iwai for (i = 0; i < params_channels(params); ++i) 5353763f356cSTakashi Iwai snd_hdspm_enable_out(hdspm, i, 1); 5354763f356cSTakashi Iwai 5355763f356cSTakashi Iwai hdspm->playback_buffer = 5356763f356cSTakashi Iwai (unsigned char *) substream->runtime->dma_area; 535754bf5dd9STakashi Iwai snd_printdd("Allocated sample buffer for playback at %p\n", 53583cee5a60SRemy Bruno hdspm->playback_buffer); 5359763f356cSTakashi Iwai } else { 536077a23f26STakashi Iwai hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferIn, 5361763f356cSTakashi Iwai params_channels(params)); 5362763f356cSTakashi Iwai 5363763f356cSTakashi Iwai for (i = 0; i < params_channels(params); ++i) 5364763f356cSTakashi Iwai snd_hdspm_enable_in(hdspm, i, 1); 5365763f356cSTakashi Iwai 5366763f356cSTakashi Iwai hdspm->capture_buffer = 5367763f356cSTakashi Iwai (unsigned char *) substream->runtime->dma_area; 536854bf5dd9STakashi Iwai snd_printdd("Allocated sample buffer for capture at %p\n", 53693cee5a60SRemy Bruno hdspm->capture_buffer); 5370763f356cSTakashi Iwai } 53710dca1793SAdrian Knoth 53723cee5a60SRemy Bruno /* 53733cee5a60SRemy Bruno snd_printdd("Allocated sample buffer for %s at 0x%08X\n", 53743cee5a60SRemy Bruno substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 53753cee5a60SRemy Bruno "playback" : "capture", 537677a23f26STakashi Iwai snd_pcm_sgbuf_get_addr(substream, 0)); 53773cee5a60SRemy Bruno */ 5378ffb2c3c0SRemy Bruno /* 5379ffb2c3c0SRemy Bruno snd_printdd("set_hwparams: %s %d Hz, %d channels, bs = %d\n", 5380ffb2c3c0SRemy Bruno substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 5381ffb2c3c0SRemy Bruno "playback" : "capture", 5382ffb2c3c0SRemy Bruno params_rate(params), params_channels(params), 5383ffb2c3c0SRemy Bruno params_buffer_size(params)); 5384ffb2c3c0SRemy Bruno */ 53850dca1793SAdrian Knoth 53860dca1793SAdrian Knoth 53870dca1793SAdrian Knoth /* Switch to native float format if requested */ 53880dca1793SAdrian Knoth if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) { 53890dca1793SAdrian Knoth if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT)) 53900dca1793SAdrian Knoth snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE float format.\n"); 53910dca1793SAdrian Knoth 53920dca1793SAdrian Knoth hdspm->control_register |= HDSPe_FLOAT_FORMAT; 53930dca1793SAdrian Knoth } else if (SNDRV_PCM_FORMAT_S32_LE == params_format(params)) { 53940dca1793SAdrian Knoth if (hdspm->control_register & HDSPe_FLOAT_FORMAT) 53950dca1793SAdrian Knoth snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE integer format.\n"); 53960dca1793SAdrian Knoth 53970dca1793SAdrian Knoth hdspm->control_register &= ~HDSPe_FLOAT_FORMAT; 53980dca1793SAdrian Knoth } 53990dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 54000dca1793SAdrian Knoth 5401763f356cSTakashi Iwai return 0; 5402763f356cSTakashi Iwai } 5403763f356cSTakashi Iwai 540498274f07STakashi Iwai static int snd_hdspm_hw_free(struct snd_pcm_substream *substream) 5405763f356cSTakashi Iwai { 5406763f356cSTakashi Iwai int i; 540798274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 5408763f356cSTakashi Iwai 5409763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5410763f356cSTakashi Iwai 5411763f356cSTakashi Iwai /* params_channels(params) should be enough, 5412763f356cSTakashi Iwai but to get sure in case of error */ 54130dca1793SAdrian Knoth for (i = 0; i < hdspm->max_channels_out; ++i) 5414763f356cSTakashi Iwai snd_hdspm_enable_out(hdspm, i, 0); 5415763f356cSTakashi Iwai 5416763f356cSTakashi Iwai hdspm->playback_buffer = NULL; 5417763f356cSTakashi Iwai } else { 54180dca1793SAdrian Knoth for (i = 0; i < hdspm->max_channels_in; ++i) 5419763f356cSTakashi Iwai snd_hdspm_enable_in(hdspm, i, 0); 5420763f356cSTakashi Iwai 5421763f356cSTakashi Iwai hdspm->capture_buffer = NULL; 5422763f356cSTakashi Iwai 5423763f356cSTakashi Iwai } 5424763f356cSTakashi Iwai 5425763f356cSTakashi Iwai snd_pcm_lib_free_pages(substream); 5426763f356cSTakashi Iwai 5427763f356cSTakashi Iwai return 0; 5428763f356cSTakashi Iwai } 5429763f356cSTakashi Iwai 54300dca1793SAdrian Knoth 543198274f07STakashi Iwai static int snd_hdspm_channel_info(struct snd_pcm_substream *substream, 543298274f07STakashi Iwai struct snd_pcm_channel_info *info) 5433763f356cSTakashi Iwai { 543498274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 5435763f356cSTakashi Iwai 54360dca1793SAdrian Knoth if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 54370dca1793SAdrian Knoth if (snd_BUG_ON(info->channel >= hdspm->max_channels_out)) { 54380dca1793SAdrian Knoth snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel out of range (%d)\n", info->channel); 5439da3cec35STakashi Iwai return -EINVAL; 54400dca1793SAdrian Knoth } 5441763f356cSTakashi Iwai 54420dca1793SAdrian Knoth if (hdspm->channel_map_out[info->channel] < 0) { 54430dca1793SAdrian Knoth snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel %d mapped out\n", info->channel); 5444763f356cSTakashi Iwai return -EINVAL; 54450dca1793SAdrian Knoth } 5446763f356cSTakashi Iwai 54470dca1793SAdrian Knoth info->offset = hdspm->channel_map_out[info->channel] * 54480dca1793SAdrian Knoth HDSPM_CHANNEL_BUFFER_BYTES; 54490dca1793SAdrian Knoth } else { 54500dca1793SAdrian Knoth if (snd_BUG_ON(info->channel >= hdspm->max_channels_in)) { 54510dca1793SAdrian Knoth snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel out of range (%d)\n", info->channel); 54520dca1793SAdrian Knoth return -EINVAL; 54530dca1793SAdrian Knoth } 54540dca1793SAdrian Knoth 54550dca1793SAdrian Knoth if (hdspm->channel_map_in[info->channel] < 0) { 54560dca1793SAdrian Knoth snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel %d mapped out\n", info->channel); 54570dca1793SAdrian Knoth return -EINVAL; 54580dca1793SAdrian Knoth } 54590dca1793SAdrian Knoth 54600dca1793SAdrian Knoth info->offset = hdspm->channel_map_in[info->channel] * 54610dca1793SAdrian Knoth HDSPM_CHANNEL_BUFFER_BYTES; 54620dca1793SAdrian Knoth } 54630dca1793SAdrian Knoth 5464763f356cSTakashi Iwai info->first = 0; 5465763f356cSTakashi Iwai info->step = 32; 5466763f356cSTakashi Iwai return 0; 5467763f356cSTakashi Iwai } 5468763f356cSTakashi Iwai 54690dca1793SAdrian Knoth 547098274f07STakashi Iwai static int snd_hdspm_ioctl(struct snd_pcm_substream *substream, 5471763f356cSTakashi Iwai unsigned int cmd, void *arg) 5472763f356cSTakashi Iwai { 5473763f356cSTakashi Iwai switch (cmd) { 5474763f356cSTakashi Iwai case SNDRV_PCM_IOCTL1_RESET: 5475763f356cSTakashi Iwai return snd_hdspm_reset(substream); 5476763f356cSTakashi Iwai 5477763f356cSTakashi Iwai case SNDRV_PCM_IOCTL1_CHANNEL_INFO: 5478763f356cSTakashi Iwai { 547998274f07STakashi Iwai struct snd_pcm_channel_info *info = arg; 5480763f356cSTakashi Iwai return snd_hdspm_channel_info(substream, info); 5481763f356cSTakashi Iwai } 5482763f356cSTakashi Iwai default: 5483763f356cSTakashi Iwai break; 5484763f356cSTakashi Iwai } 5485763f356cSTakashi Iwai 5486763f356cSTakashi Iwai return snd_pcm_lib_ioctl(substream, cmd, arg); 5487763f356cSTakashi Iwai } 5488763f356cSTakashi Iwai 548998274f07STakashi Iwai static int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd) 5490763f356cSTakashi Iwai { 549198274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 549298274f07STakashi Iwai struct snd_pcm_substream *other; 5493763f356cSTakashi Iwai int running; 5494763f356cSTakashi Iwai 5495763f356cSTakashi Iwai spin_lock(&hdspm->lock); 5496763f356cSTakashi Iwai running = hdspm->running; 5497763f356cSTakashi Iwai switch (cmd) { 5498763f356cSTakashi Iwai case SNDRV_PCM_TRIGGER_START: 5499763f356cSTakashi Iwai running |= 1 << substream->stream; 5500763f356cSTakashi Iwai break; 5501763f356cSTakashi Iwai case SNDRV_PCM_TRIGGER_STOP: 5502763f356cSTakashi Iwai running &= ~(1 << substream->stream); 5503763f356cSTakashi Iwai break; 5504763f356cSTakashi Iwai default: 5505763f356cSTakashi Iwai snd_BUG(); 5506763f356cSTakashi Iwai spin_unlock(&hdspm->lock); 5507763f356cSTakashi Iwai return -EINVAL; 5508763f356cSTakashi Iwai } 5509763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 5510763f356cSTakashi Iwai other = hdspm->capture_substream; 5511763f356cSTakashi Iwai else 5512763f356cSTakashi Iwai other = hdspm->playback_substream; 5513763f356cSTakashi Iwai 5514763f356cSTakashi Iwai if (other) { 551598274f07STakashi Iwai struct snd_pcm_substream *s; 5516ef991b95STakashi Iwai snd_pcm_group_for_each_entry(s, substream) { 5517763f356cSTakashi Iwai if (s == other) { 5518763f356cSTakashi Iwai snd_pcm_trigger_done(s, substream); 5519763f356cSTakashi Iwai if (cmd == SNDRV_PCM_TRIGGER_START) 5520763f356cSTakashi Iwai running |= 1 << s->stream; 5521763f356cSTakashi Iwai else 5522763f356cSTakashi Iwai running &= ~(1 << s->stream); 5523763f356cSTakashi Iwai goto _ok; 5524763f356cSTakashi Iwai } 5525763f356cSTakashi Iwai } 5526763f356cSTakashi Iwai if (cmd == SNDRV_PCM_TRIGGER_START) { 5527763f356cSTakashi Iwai if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) 5528763f356cSTakashi Iwai && substream->stream == 5529763f356cSTakashi Iwai SNDRV_PCM_STREAM_CAPTURE) 5530763f356cSTakashi Iwai hdspm_silence_playback(hdspm); 5531763f356cSTakashi Iwai } else { 5532763f356cSTakashi Iwai if (running && 5533763f356cSTakashi Iwai substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 5534763f356cSTakashi Iwai hdspm_silence_playback(hdspm); 5535763f356cSTakashi Iwai } 5536763f356cSTakashi Iwai } else { 5537763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 5538763f356cSTakashi Iwai hdspm_silence_playback(hdspm); 5539763f356cSTakashi Iwai } 5540763f356cSTakashi Iwai _ok: 5541763f356cSTakashi Iwai snd_pcm_trigger_done(substream, substream); 5542763f356cSTakashi Iwai if (!hdspm->running && running) 5543763f356cSTakashi Iwai hdspm_start_audio(hdspm); 5544763f356cSTakashi Iwai else if (hdspm->running && !running) 5545763f356cSTakashi Iwai hdspm_stop_audio(hdspm); 5546763f356cSTakashi Iwai hdspm->running = running; 5547763f356cSTakashi Iwai spin_unlock(&hdspm->lock); 5548763f356cSTakashi Iwai 5549763f356cSTakashi Iwai return 0; 5550763f356cSTakashi Iwai } 5551763f356cSTakashi Iwai 555298274f07STakashi Iwai static int snd_hdspm_prepare(struct snd_pcm_substream *substream) 5553763f356cSTakashi Iwai { 5554763f356cSTakashi Iwai return 0; 5555763f356cSTakashi Iwai } 5556763f356cSTakashi Iwai 55570dca1793SAdrian Knoth static unsigned int period_sizes_old[] = { 55580dca1793SAdrian Knoth 64, 128, 256, 512, 1024, 2048, 4096 55590dca1793SAdrian Knoth }; 55600dca1793SAdrian Knoth 55610dca1793SAdrian Knoth static unsigned int period_sizes_new[] = { 55620dca1793SAdrian Knoth 32, 64, 128, 256, 512, 1024, 2048, 4096 55630dca1793SAdrian Knoth }; 55640dca1793SAdrian Knoth 55650dca1793SAdrian Knoth /* RayDAT and AIO always have a buffer of 16384 samples per channel */ 55660dca1793SAdrian Knoth static unsigned int raydat_aio_buffer_sizes[] = { 55670dca1793SAdrian Knoth 16384 55680dca1793SAdrian Knoth }; 5569763f356cSTakashi Iwai 557098274f07STakashi Iwai static struct snd_pcm_hardware snd_hdspm_playback_subinfo = { 5571763f356cSTakashi Iwai .info = (SNDRV_PCM_INFO_MMAP | 5572763f356cSTakashi Iwai SNDRV_PCM_INFO_MMAP_VALID | 5573763f356cSTakashi Iwai SNDRV_PCM_INFO_NONINTERLEAVED | 5574763f356cSTakashi Iwai SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_DOUBLE), 5575763f356cSTakashi Iwai .formats = SNDRV_PCM_FMTBIT_S32_LE, 5576763f356cSTakashi Iwai .rates = (SNDRV_PCM_RATE_32000 | 5577763f356cSTakashi Iwai SNDRV_PCM_RATE_44100 | 5578763f356cSTakashi Iwai SNDRV_PCM_RATE_48000 | 5579763f356cSTakashi Iwai SNDRV_PCM_RATE_64000 | 55803cee5a60SRemy Bruno SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 55813cee5a60SRemy Bruno SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ), 5582763f356cSTakashi Iwai .rate_min = 32000, 55833cee5a60SRemy Bruno .rate_max = 192000, 5584763f356cSTakashi Iwai .channels_min = 1, 5585763f356cSTakashi Iwai .channels_max = HDSPM_MAX_CHANNELS, 5586763f356cSTakashi Iwai .buffer_bytes_max = 5587763f356cSTakashi Iwai HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, 5588763f356cSTakashi Iwai .period_bytes_min = (64 * 4), 55890dca1793SAdrian Knoth .period_bytes_max = (4096 * 4) * HDSPM_MAX_CHANNELS, 5590763f356cSTakashi Iwai .periods_min = 2, 55910dca1793SAdrian Knoth .periods_max = 512, 5592763f356cSTakashi Iwai .fifo_size = 0 5593763f356cSTakashi Iwai }; 5594763f356cSTakashi Iwai 559598274f07STakashi Iwai static struct snd_pcm_hardware snd_hdspm_capture_subinfo = { 5596763f356cSTakashi Iwai .info = (SNDRV_PCM_INFO_MMAP | 5597763f356cSTakashi Iwai SNDRV_PCM_INFO_MMAP_VALID | 5598763f356cSTakashi Iwai SNDRV_PCM_INFO_NONINTERLEAVED | 5599763f356cSTakashi Iwai SNDRV_PCM_INFO_SYNC_START), 5600763f356cSTakashi Iwai .formats = SNDRV_PCM_FMTBIT_S32_LE, 5601763f356cSTakashi Iwai .rates = (SNDRV_PCM_RATE_32000 | 5602763f356cSTakashi Iwai SNDRV_PCM_RATE_44100 | 5603763f356cSTakashi Iwai SNDRV_PCM_RATE_48000 | 5604763f356cSTakashi Iwai SNDRV_PCM_RATE_64000 | 56053cee5a60SRemy Bruno SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 56063cee5a60SRemy Bruno SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000), 5607763f356cSTakashi Iwai .rate_min = 32000, 56083cee5a60SRemy Bruno .rate_max = 192000, 5609763f356cSTakashi Iwai .channels_min = 1, 5610763f356cSTakashi Iwai .channels_max = HDSPM_MAX_CHANNELS, 5611763f356cSTakashi Iwai .buffer_bytes_max = 5612763f356cSTakashi Iwai HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, 5613763f356cSTakashi Iwai .period_bytes_min = (64 * 4), 56140dca1793SAdrian Knoth .period_bytes_max = (4096 * 4) * HDSPM_MAX_CHANNELS, 5615763f356cSTakashi Iwai .periods_min = 2, 56160dca1793SAdrian Knoth .periods_max = 512, 5617763f356cSTakashi Iwai .fifo_size = 0 5618763f356cSTakashi Iwai }; 5619763f356cSTakashi Iwai 56200dca1793SAdrian Knoth static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes_old = { 56210dca1793SAdrian Knoth .count = ARRAY_SIZE(period_sizes_old), 56220dca1793SAdrian Knoth .list = period_sizes_old, 5623763f356cSTakashi Iwai .mask = 0 5624763f356cSTakashi Iwai }; 5625763f356cSTakashi Iwai 56260dca1793SAdrian Knoth static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes_new = { 56270dca1793SAdrian Knoth .count = ARRAY_SIZE(period_sizes_new), 56280dca1793SAdrian Knoth .list = period_sizes_new, 56290dca1793SAdrian Knoth .mask = 0 56300dca1793SAdrian Knoth }; 5631763f356cSTakashi Iwai 56320dca1793SAdrian Knoth static struct snd_pcm_hw_constraint_list hw_constraints_raydat_io_buffer = { 56330dca1793SAdrian Knoth .count = ARRAY_SIZE(raydat_aio_buffer_sizes), 56340dca1793SAdrian Knoth .list = raydat_aio_buffer_sizes, 56350dca1793SAdrian Knoth .mask = 0 56360dca1793SAdrian Knoth }; 56370dca1793SAdrian Knoth 56380dca1793SAdrian Knoth static int snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params, 563998274f07STakashi Iwai struct snd_pcm_hw_rule *rule) 5640763f356cSTakashi Iwai { 564198274f07STakashi Iwai struct hdspm *hdspm = rule->private; 564298274f07STakashi Iwai struct snd_interval *c = 5643763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 564498274f07STakashi Iwai struct snd_interval *r = 5645763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 5646763f356cSTakashi Iwai 56470dca1793SAdrian Knoth if (r->min > 96000 && r->max <= 192000) { 564898274f07STakashi Iwai struct snd_interval t = { 56490dca1793SAdrian Knoth .min = hdspm->qs_in_channels, 56500dca1793SAdrian Knoth .max = hdspm->qs_in_channels, 56510dca1793SAdrian Knoth .integer = 1, 56520dca1793SAdrian Knoth }; 56530dca1793SAdrian Knoth return snd_interval_refine(c, &t); 56540dca1793SAdrian Knoth } else if (r->min > 48000 && r->max <= 96000) { 56550dca1793SAdrian Knoth struct snd_interval t = { 56560dca1793SAdrian Knoth .min = hdspm->ds_in_channels, 56570dca1793SAdrian Knoth .max = hdspm->ds_in_channels, 5658763f356cSTakashi Iwai .integer = 1, 5659763f356cSTakashi Iwai }; 5660763f356cSTakashi Iwai return snd_interval_refine(c, &t); 5661763f356cSTakashi Iwai } else if (r->max < 64000) { 566298274f07STakashi Iwai struct snd_interval t = { 56630dca1793SAdrian Knoth .min = hdspm->ss_in_channels, 56640dca1793SAdrian Knoth .max = hdspm->ss_in_channels, 5665763f356cSTakashi Iwai .integer = 1, 5666763f356cSTakashi Iwai }; 5667763f356cSTakashi Iwai return snd_interval_refine(c, &t); 5668763f356cSTakashi Iwai } 56690dca1793SAdrian Knoth 5670763f356cSTakashi Iwai return 0; 5671763f356cSTakashi Iwai } 5672763f356cSTakashi Iwai 56730dca1793SAdrian Knoth static int snd_hdspm_hw_rule_out_channels_rate(struct snd_pcm_hw_params *params, 567498274f07STakashi Iwai struct snd_pcm_hw_rule * rule) 5675763f356cSTakashi Iwai { 567698274f07STakashi Iwai struct hdspm *hdspm = rule->private; 567798274f07STakashi Iwai struct snd_interval *c = 5678763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 567998274f07STakashi Iwai struct snd_interval *r = 5680763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 5681763f356cSTakashi Iwai 56820dca1793SAdrian Knoth if (r->min > 96000 && r->max <= 192000) { 56830dca1793SAdrian Knoth struct snd_interval t = { 56840dca1793SAdrian Knoth .min = hdspm->qs_out_channels, 56850dca1793SAdrian Knoth .max = hdspm->qs_out_channels, 56860dca1793SAdrian Knoth .integer = 1, 56870dca1793SAdrian Knoth }; 56880dca1793SAdrian Knoth return snd_interval_refine(c, &t); 56890dca1793SAdrian Knoth } else if (r->min > 48000 && r->max <= 96000) { 56900dca1793SAdrian Knoth struct snd_interval t = { 56910dca1793SAdrian Knoth .min = hdspm->ds_out_channels, 56920dca1793SAdrian Knoth .max = hdspm->ds_out_channels, 56930dca1793SAdrian Knoth .integer = 1, 56940dca1793SAdrian Knoth }; 56950dca1793SAdrian Knoth return snd_interval_refine(c, &t); 56960dca1793SAdrian Knoth } else if (r->max < 64000) { 56970dca1793SAdrian Knoth struct snd_interval t = { 56980dca1793SAdrian Knoth .min = hdspm->ss_out_channels, 56990dca1793SAdrian Knoth .max = hdspm->ss_out_channels, 57000dca1793SAdrian Knoth .integer = 1, 57010dca1793SAdrian Knoth }; 57020dca1793SAdrian Knoth return snd_interval_refine(c, &t); 57030dca1793SAdrian Knoth } else { 57040dca1793SAdrian Knoth } 57050dca1793SAdrian Knoth return 0; 57060dca1793SAdrian Knoth } 57070dca1793SAdrian Knoth 57080dca1793SAdrian Knoth static int snd_hdspm_hw_rule_rate_in_channels(struct snd_pcm_hw_params *params, 57090dca1793SAdrian Knoth struct snd_pcm_hw_rule * rule) 57100dca1793SAdrian Knoth { 57110dca1793SAdrian Knoth struct hdspm *hdspm = rule->private; 57120dca1793SAdrian Knoth struct snd_interval *c = 57130dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 57140dca1793SAdrian Knoth struct snd_interval *r = 57150dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 57160dca1793SAdrian Knoth 57170dca1793SAdrian Knoth if (c->min >= hdspm->ss_in_channels) { 571898274f07STakashi Iwai struct snd_interval t = { 5719763f356cSTakashi Iwai .min = 32000, 5720763f356cSTakashi Iwai .max = 48000, 5721763f356cSTakashi Iwai .integer = 1, 5722763f356cSTakashi Iwai }; 5723763f356cSTakashi Iwai return snd_interval_refine(r, &t); 57240dca1793SAdrian Knoth } else if (c->max <= hdspm->qs_in_channels) { 57250dca1793SAdrian Knoth struct snd_interval t = { 57260dca1793SAdrian Knoth .min = 128000, 57270dca1793SAdrian Knoth .max = 192000, 57280dca1793SAdrian Knoth .integer = 1, 57290dca1793SAdrian Knoth }; 57300dca1793SAdrian Knoth return snd_interval_refine(r, &t); 57310dca1793SAdrian Knoth } else if (c->max <= hdspm->ds_in_channels) { 573298274f07STakashi Iwai struct snd_interval t = { 5733763f356cSTakashi Iwai .min = 64000, 5734763f356cSTakashi Iwai .max = 96000, 5735763f356cSTakashi Iwai .integer = 1, 5736763f356cSTakashi Iwai }; 5737763f356cSTakashi Iwai return snd_interval_refine(r, &t); 5738763f356cSTakashi Iwai } 57390dca1793SAdrian Knoth 57400dca1793SAdrian Knoth return 0; 57410dca1793SAdrian Knoth } 57420dca1793SAdrian Knoth static int snd_hdspm_hw_rule_rate_out_channels(struct snd_pcm_hw_params *params, 57430dca1793SAdrian Knoth struct snd_pcm_hw_rule *rule) 57440dca1793SAdrian Knoth { 57450dca1793SAdrian Knoth struct hdspm *hdspm = rule->private; 57460dca1793SAdrian Knoth struct snd_interval *c = 57470dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 57480dca1793SAdrian Knoth struct snd_interval *r = 57490dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 57500dca1793SAdrian Knoth 57510dca1793SAdrian Knoth if (c->min >= hdspm->ss_out_channels) { 57520dca1793SAdrian Knoth struct snd_interval t = { 57530dca1793SAdrian Knoth .min = 32000, 57540dca1793SAdrian Knoth .max = 48000, 57550dca1793SAdrian Knoth .integer = 1, 57560dca1793SAdrian Knoth }; 57570dca1793SAdrian Knoth return snd_interval_refine(r, &t); 57580dca1793SAdrian Knoth } else if (c->max <= hdspm->qs_out_channels) { 57590dca1793SAdrian Knoth struct snd_interval t = { 57600dca1793SAdrian Knoth .min = 128000, 57610dca1793SAdrian Knoth .max = 192000, 57620dca1793SAdrian Knoth .integer = 1, 57630dca1793SAdrian Knoth }; 57640dca1793SAdrian Knoth return snd_interval_refine(r, &t); 57650dca1793SAdrian Knoth } else if (c->max <= hdspm->ds_out_channels) { 57660dca1793SAdrian Knoth struct snd_interval t = { 57670dca1793SAdrian Knoth .min = 64000, 57680dca1793SAdrian Knoth .max = 96000, 57690dca1793SAdrian Knoth .integer = 1, 57700dca1793SAdrian Knoth }; 57710dca1793SAdrian Knoth return snd_interval_refine(r, &t); 57720dca1793SAdrian Knoth } 57730dca1793SAdrian Knoth 5774763f356cSTakashi Iwai return 0; 5775763f356cSTakashi Iwai } 5776763f356cSTakashi Iwai 57770dca1793SAdrian Knoth static int snd_hdspm_hw_rule_in_channels(struct snd_pcm_hw_params *params, 5778ffb2c3c0SRemy Bruno struct snd_pcm_hw_rule *rule) 5779ffb2c3c0SRemy Bruno { 5780ffb2c3c0SRemy Bruno unsigned int list[3]; 5781ffb2c3c0SRemy Bruno struct hdspm *hdspm = rule->private; 5782ffb2c3c0SRemy Bruno struct snd_interval *c = hw_param_interval(params, 5783ffb2c3c0SRemy Bruno SNDRV_PCM_HW_PARAM_CHANNELS); 57840dca1793SAdrian Knoth 57850dca1793SAdrian Knoth list[0] = hdspm->qs_in_channels; 57860dca1793SAdrian Knoth list[1] = hdspm->ds_in_channels; 57870dca1793SAdrian Knoth list[2] = hdspm->ss_in_channels; 5788ffb2c3c0SRemy Bruno return snd_interval_list(c, 3, list, 0); 5789ffb2c3c0SRemy Bruno } 57900dca1793SAdrian Knoth 57910dca1793SAdrian Knoth static int snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params *params, 57920dca1793SAdrian Knoth struct snd_pcm_hw_rule *rule) 57930dca1793SAdrian Knoth { 57940dca1793SAdrian Knoth unsigned int list[3]; 57950dca1793SAdrian Knoth struct hdspm *hdspm = rule->private; 57960dca1793SAdrian Knoth struct snd_interval *c = hw_param_interval(params, 57970dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_CHANNELS); 57980dca1793SAdrian Knoth 57990dca1793SAdrian Knoth list[0] = hdspm->qs_out_channels; 58000dca1793SAdrian Knoth list[1] = hdspm->ds_out_channels; 58010dca1793SAdrian Knoth list[2] = hdspm->ss_out_channels; 58020dca1793SAdrian Knoth return snd_interval_list(c, 3, list, 0); 5803ffb2c3c0SRemy Bruno } 5804ffb2c3c0SRemy Bruno 5805ffb2c3c0SRemy Bruno 5806ef5fa1a4STakashi Iwai static unsigned int hdspm_aes32_sample_rates[] = { 5807ef5fa1a4STakashi Iwai 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 5808ef5fa1a4STakashi Iwai }; 5809ffb2c3c0SRemy Bruno 5810ef5fa1a4STakashi Iwai static struct snd_pcm_hw_constraint_list 5811ef5fa1a4STakashi Iwai hdspm_hw_constraints_aes32_sample_rates = { 5812ffb2c3c0SRemy Bruno .count = ARRAY_SIZE(hdspm_aes32_sample_rates), 5813ffb2c3c0SRemy Bruno .list = hdspm_aes32_sample_rates, 5814ffb2c3c0SRemy Bruno .mask = 0 5815ffb2c3c0SRemy Bruno }; 5816ffb2c3c0SRemy Bruno 581798274f07STakashi Iwai static int snd_hdspm_playback_open(struct snd_pcm_substream *substream) 5818763f356cSTakashi Iwai { 581998274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 582098274f07STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 5821763f356cSTakashi Iwai 5822763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 5823763f356cSTakashi Iwai 5824763f356cSTakashi Iwai snd_pcm_set_sync(substream); 5825763f356cSTakashi Iwai 58260dca1793SAdrian Knoth 5827763f356cSTakashi Iwai runtime->hw = snd_hdspm_playback_subinfo; 5828763f356cSTakashi Iwai 5829763f356cSTakashi Iwai if (hdspm->capture_substream == NULL) 5830763f356cSTakashi Iwai hdspm_stop_audio(hdspm); 5831763f356cSTakashi Iwai 5832763f356cSTakashi Iwai hdspm->playback_pid = current->pid; 5833763f356cSTakashi Iwai hdspm->playback_substream = substream; 5834763f356cSTakashi Iwai 5835763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5836763f356cSTakashi Iwai 5837763f356cSTakashi Iwai snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 5838763f356cSTakashi Iwai 58390dca1793SAdrian Knoth switch (hdspm->io_type) { 58400dca1793SAdrian Knoth case AIO: 58410dca1793SAdrian Knoth case RayDAT: 5842763f356cSTakashi Iwai snd_pcm_hw_constraint_list(runtime, 0, 5843763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 58440dca1793SAdrian Knoth &hw_constraints_period_sizes_new); 58450dca1793SAdrian Knoth snd_pcm_hw_constraint_list(runtime, 0, 58460dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 58470dca1793SAdrian Knoth &hw_constraints_raydat_io_buffer); 5848763f356cSTakashi Iwai 58490dca1793SAdrian Knoth break; 58500dca1793SAdrian Knoth 58510dca1793SAdrian Knoth default: 58520dca1793SAdrian Knoth snd_pcm_hw_constraint_list(runtime, 0, 58530dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 58540dca1793SAdrian Knoth &hw_constraints_period_sizes_old); 58550dca1793SAdrian Knoth } 58560dca1793SAdrian Knoth 58570dca1793SAdrian Knoth if (AES32 == hdspm->io_type) { 5858ffb2c3c0SRemy Bruno snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 5859ffb2c3c0SRemy Bruno &hdspm_hw_constraints_aes32_sample_rates); 5860ffb2c3c0SRemy Bruno } else { 5861763f356cSTakashi Iwai snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 58620dca1793SAdrian Knoth snd_hdspm_hw_rule_rate_out_channels, hdspm, 5863763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_CHANNELS, -1); 5864ffb2c3c0SRemy Bruno } 586588fabbfcSAdrian Knoth 586688fabbfcSAdrian Knoth snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 586788fabbfcSAdrian Knoth snd_hdspm_hw_rule_out_channels, hdspm, 586888fabbfcSAdrian Knoth SNDRV_PCM_HW_PARAM_CHANNELS, -1); 586988fabbfcSAdrian Knoth 587088fabbfcSAdrian Knoth snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 587188fabbfcSAdrian Knoth snd_hdspm_hw_rule_out_channels_rate, hdspm, 587288fabbfcSAdrian Knoth SNDRV_PCM_HW_PARAM_RATE, -1); 587388fabbfcSAdrian Knoth 5874763f356cSTakashi Iwai return 0; 5875763f356cSTakashi Iwai } 5876763f356cSTakashi Iwai 587798274f07STakashi Iwai static int snd_hdspm_playback_release(struct snd_pcm_substream *substream) 5878763f356cSTakashi Iwai { 587998274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 5880763f356cSTakashi Iwai 5881763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 5882763f356cSTakashi Iwai 5883763f356cSTakashi Iwai hdspm->playback_pid = -1; 5884763f356cSTakashi Iwai hdspm->playback_substream = NULL; 5885763f356cSTakashi Iwai 5886763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5887763f356cSTakashi Iwai 5888763f356cSTakashi Iwai return 0; 5889763f356cSTakashi Iwai } 5890763f356cSTakashi Iwai 5891763f356cSTakashi Iwai 589298274f07STakashi Iwai static int snd_hdspm_capture_open(struct snd_pcm_substream *substream) 5893763f356cSTakashi Iwai { 589498274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 589598274f07STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 5896763f356cSTakashi Iwai 5897763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 5898763f356cSTakashi Iwai snd_pcm_set_sync(substream); 5899763f356cSTakashi Iwai runtime->hw = snd_hdspm_capture_subinfo; 5900763f356cSTakashi Iwai 5901763f356cSTakashi Iwai if (hdspm->playback_substream == NULL) 5902763f356cSTakashi Iwai hdspm_stop_audio(hdspm); 5903763f356cSTakashi Iwai 5904763f356cSTakashi Iwai hdspm->capture_pid = current->pid; 5905763f356cSTakashi Iwai hdspm->capture_substream = substream; 5906763f356cSTakashi Iwai 5907763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5908763f356cSTakashi Iwai 5909763f356cSTakashi Iwai snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 59100dca1793SAdrian Knoth switch (hdspm->io_type) { 59110dca1793SAdrian Knoth case AIO: 59120dca1793SAdrian Knoth case RayDAT: 5913763f356cSTakashi Iwai snd_pcm_hw_constraint_list(runtime, 0, 5914763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 59150dca1793SAdrian Knoth &hw_constraints_period_sizes_new); 59160dca1793SAdrian Knoth snd_pcm_hw_constraint_list(runtime, 0, 59170dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 59180dca1793SAdrian Knoth &hw_constraints_raydat_io_buffer); 59190dca1793SAdrian Knoth break; 59200dca1793SAdrian Knoth 59210dca1793SAdrian Knoth default: 59220dca1793SAdrian Knoth snd_pcm_hw_constraint_list(runtime, 0, 59230dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 59240dca1793SAdrian Knoth &hw_constraints_period_sizes_old); 59250dca1793SAdrian Knoth } 59260dca1793SAdrian Knoth 59270dca1793SAdrian Knoth if (AES32 == hdspm->io_type) { 5928ffb2c3c0SRemy Bruno snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 5929ffb2c3c0SRemy Bruno &hdspm_hw_constraints_aes32_sample_rates); 5930ffb2c3c0SRemy Bruno } else { 5931763f356cSTakashi Iwai snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 59320dca1793SAdrian Knoth snd_hdspm_hw_rule_rate_in_channels, hdspm, 5933763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_CHANNELS, -1); 5934ffb2c3c0SRemy Bruno } 593588fabbfcSAdrian Knoth 593688fabbfcSAdrian Knoth snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 593788fabbfcSAdrian Knoth snd_hdspm_hw_rule_in_channels, hdspm, 593888fabbfcSAdrian Knoth SNDRV_PCM_HW_PARAM_CHANNELS, -1); 593988fabbfcSAdrian Knoth 594088fabbfcSAdrian Knoth snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 594188fabbfcSAdrian Knoth snd_hdspm_hw_rule_in_channels_rate, hdspm, 594288fabbfcSAdrian Knoth SNDRV_PCM_HW_PARAM_RATE, -1); 594388fabbfcSAdrian Knoth 5944763f356cSTakashi Iwai return 0; 5945763f356cSTakashi Iwai } 5946763f356cSTakashi Iwai 594798274f07STakashi Iwai static int snd_hdspm_capture_release(struct snd_pcm_substream *substream) 5948763f356cSTakashi Iwai { 594998274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream); 5950763f356cSTakashi Iwai 5951763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 5952763f356cSTakashi Iwai 5953763f356cSTakashi Iwai hdspm->capture_pid = -1; 5954763f356cSTakashi Iwai hdspm->capture_substream = NULL; 5955763f356cSTakashi Iwai 5956763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 5957763f356cSTakashi Iwai return 0; 5958763f356cSTakashi Iwai } 5959763f356cSTakashi Iwai 59600dca1793SAdrian Knoth static int snd_hdspm_hwdep_dummy_op(struct snd_hwdep *hw, struct file *file) 5961763f356cSTakashi Iwai { 59620dca1793SAdrian Knoth /* we have nothing to initialize but the call is required */ 59630dca1793SAdrian Knoth return 0; 59640dca1793SAdrian Knoth } 59650dca1793SAdrian Knoth 59660dca1793SAdrian Knoth static inline int copy_u32_le(void __user *dest, void __iomem *src) 59670dca1793SAdrian Knoth { 59680dca1793SAdrian Knoth u32 val = readl(src); 59690dca1793SAdrian Knoth return copy_to_user(dest, &val, 4); 59700dca1793SAdrian Knoth } 59710dca1793SAdrian Knoth 59720dca1793SAdrian Knoth static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, 59730dca1793SAdrian Knoth unsigned int cmd, unsigned long __user arg) 59740dca1793SAdrian Knoth { 59750dca1793SAdrian Knoth void __user *argp = (void __user *)arg; 5976ef5fa1a4STakashi Iwai struct hdspm *hdspm = hw->private_data; 597798274f07STakashi Iwai struct hdspm_mixer_ioctl mixer; 59780dca1793SAdrian Knoth struct hdspm_config info; 59790dca1793SAdrian Knoth struct hdspm_status status; 598098274f07STakashi Iwai struct hdspm_version hdspm_version; 5981730a5865SJaroslav Kysela struct hdspm_peak_rms *levels; 59820dca1793SAdrian Knoth struct hdspm_ltc ltc; 59830dca1793SAdrian Knoth unsigned int statusregister; 59840dca1793SAdrian Knoth long unsigned int s; 59850dca1793SAdrian Knoth int i = 0; 5986763f356cSTakashi Iwai 5987763f356cSTakashi Iwai switch (cmd) { 5988763f356cSTakashi Iwai 5989763f356cSTakashi Iwai case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS: 5990730a5865SJaroslav Kysela levels = &hdspm->peak_rms; 59910dca1793SAdrian Knoth for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { 5992730a5865SJaroslav Kysela levels->input_peaks[i] = 59930dca1793SAdrian Knoth readl(hdspm->iobase + 59940dca1793SAdrian Knoth HDSPM_MADI_INPUT_PEAK + i*4); 5995730a5865SJaroslav Kysela levels->playback_peaks[i] = 59960dca1793SAdrian Knoth readl(hdspm->iobase + 59970dca1793SAdrian Knoth HDSPM_MADI_PLAYBACK_PEAK + i*4); 5998730a5865SJaroslav Kysela levels->output_peaks[i] = 59990dca1793SAdrian Knoth readl(hdspm->iobase + 60000dca1793SAdrian Knoth HDSPM_MADI_OUTPUT_PEAK + i*4); 60010dca1793SAdrian Knoth 6002730a5865SJaroslav Kysela levels->input_rms[i] = 60030dca1793SAdrian Knoth ((uint64_t) readl(hdspm->iobase + 60040dca1793SAdrian Knoth HDSPM_MADI_INPUT_RMS_H + i*4) << 32) | 60050dca1793SAdrian Knoth (uint64_t) readl(hdspm->iobase + 60060dca1793SAdrian Knoth HDSPM_MADI_INPUT_RMS_L + i*4); 6007730a5865SJaroslav Kysela levels->playback_rms[i] = 60080dca1793SAdrian Knoth ((uint64_t)readl(hdspm->iobase + 60090dca1793SAdrian Knoth HDSPM_MADI_PLAYBACK_RMS_H+i*4) << 32) | 60100dca1793SAdrian Knoth (uint64_t)readl(hdspm->iobase + 60110dca1793SAdrian Knoth HDSPM_MADI_PLAYBACK_RMS_L + i*4); 6012730a5865SJaroslav Kysela levels->output_rms[i] = 60130dca1793SAdrian Knoth ((uint64_t)readl(hdspm->iobase + 60140dca1793SAdrian Knoth HDSPM_MADI_OUTPUT_RMS_H + i*4) << 32) | 60150dca1793SAdrian Knoth (uint64_t)readl(hdspm->iobase + 60160dca1793SAdrian Knoth HDSPM_MADI_OUTPUT_RMS_L + i*4); 60170dca1793SAdrian Knoth } 60180dca1793SAdrian Knoth 60190dca1793SAdrian Knoth if (hdspm->system_sample_rate > 96000) { 6020730a5865SJaroslav Kysela levels->speed = qs; 60210dca1793SAdrian Knoth } else if (hdspm->system_sample_rate > 48000) { 6022730a5865SJaroslav Kysela levels->speed = ds; 60230dca1793SAdrian Knoth } else { 6024730a5865SJaroslav Kysela levels->speed = ss; 60250dca1793SAdrian Knoth } 6026730a5865SJaroslav Kysela levels->status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 60270dca1793SAdrian Knoth 6028730a5865SJaroslav Kysela s = copy_to_user(argp, levels, sizeof(struct hdspm_peak_rms)); 60290dca1793SAdrian Knoth if (0 != s) { 60300dca1793SAdrian Knoth /* snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu 60310dca1793SAdrian Knoth [Levels]\n", sizeof(struct hdspm_peak_rms), s); 6032ef5fa1a4STakashi Iwai */ 6033763f356cSTakashi Iwai return -EFAULT; 60340dca1793SAdrian Knoth } 60350dca1793SAdrian Knoth break; 60360dca1793SAdrian Knoth 60370dca1793SAdrian Knoth case SNDRV_HDSPM_IOCTL_GET_LTC: 60380dca1793SAdrian Knoth ltc.ltc = hdspm_read(hdspm, HDSPM_RD_TCO); 60390dca1793SAdrian Knoth i = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 60400dca1793SAdrian Knoth if (i & HDSPM_TCO1_LTC_Input_valid) { 60410dca1793SAdrian Knoth switch (i & (HDSPM_TCO1_LTC_Format_LSB | 60420dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB)) { 60430dca1793SAdrian Knoth case 0: 60440dca1793SAdrian Knoth ltc.format = fps_24; 60450dca1793SAdrian Knoth break; 60460dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_LSB: 60470dca1793SAdrian Knoth ltc.format = fps_25; 60480dca1793SAdrian Knoth break; 60490dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_MSB: 60500dca1793SAdrian Knoth ltc.format = fps_2997; 60510dca1793SAdrian Knoth break; 60520dca1793SAdrian Knoth default: 60530dca1793SAdrian Knoth ltc.format = 30; 60540dca1793SAdrian Knoth break; 60550dca1793SAdrian Knoth } 60560dca1793SAdrian Knoth if (i & HDSPM_TCO1_set_drop_frame_flag) { 60570dca1793SAdrian Knoth ltc.frame = drop_frame; 60580dca1793SAdrian Knoth } else { 60590dca1793SAdrian Knoth ltc.frame = full_frame; 60600dca1793SAdrian Knoth } 60610dca1793SAdrian Knoth } else { 60620dca1793SAdrian Knoth ltc.format = format_invalid; 60630dca1793SAdrian Knoth ltc.frame = frame_invalid; 60640dca1793SAdrian Knoth } 60650dca1793SAdrian Knoth if (i & HDSPM_TCO1_Video_Input_Format_NTSC) { 60660dca1793SAdrian Knoth ltc.input_format = ntsc; 60670dca1793SAdrian Knoth } else if (i & HDSPM_TCO1_Video_Input_Format_PAL) { 60680dca1793SAdrian Knoth ltc.input_format = pal; 60690dca1793SAdrian Knoth } else { 60700dca1793SAdrian Knoth ltc.input_format = no_video; 60710dca1793SAdrian Knoth } 60720dca1793SAdrian Knoth 60730dca1793SAdrian Knoth s = copy_to_user(argp, <c, sizeof(struct hdspm_ltc)); 60740dca1793SAdrian Knoth if (0 != s) { 60750dca1793SAdrian Knoth /* 60760dca1793SAdrian Knoth snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */ 60770dca1793SAdrian Knoth return -EFAULT; 60780dca1793SAdrian Knoth } 6079763f356cSTakashi Iwai 6080763f356cSTakashi Iwai break; 6081763f356cSTakashi Iwai 60820dca1793SAdrian Knoth case SNDRV_HDSPM_IOCTL_GET_CONFIG: 6083763f356cSTakashi Iwai 6084*4ab69a2bSAdrian Knoth memset(&info, 0, sizeof(info)); 6085763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock); 6086ef5fa1a4STakashi Iwai info.pref_sync_ref = hdspm_pref_sync_ref(hdspm); 6087ef5fa1a4STakashi Iwai info.wordclock_sync_check = hdspm_wc_sync_check(hdspm); 6088763f356cSTakashi Iwai 6089763f356cSTakashi Iwai info.system_sample_rate = hdspm->system_sample_rate; 6090763f356cSTakashi Iwai info.autosync_sample_rate = 6091763f356cSTakashi Iwai hdspm_external_sample_rate(hdspm); 6092ef5fa1a4STakashi Iwai info.system_clock_mode = hdspm_system_clock_mode(hdspm); 6093ef5fa1a4STakashi Iwai info.clock_source = hdspm_clock_source(hdspm); 6094ef5fa1a4STakashi Iwai info.autosync_ref = hdspm_autosync_ref(hdspm); 6095ef5fa1a4STakashi Iwai info.line_out = hdspm_line_out(hdspm); 6096763f356cSTakashi Iwai info.passthru = 0; 6097763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock); 6098763f356cSTakashi Iwai if (copy_to_user((void __user *) arg, &info, sizeof(info))) 6099763f356cSTakashi Iwai return -EFAULT; 6100763f356cSTakashi Iwai break; 6101763f356cSTakashi Iwai 61020dca1793SAdrian Knoth case SNDRV_HDSPM_IOCTL_GET_STATUS: 61030dca1793SAdrian Knoth status.card_type = hdspm->io_type; 61040dca1793SAdrian Knoth 61050dca1793SAdrian Knoth status.autosync_source = hdspm_autosync_ref(hdspm); 61060dca1793SAdrian Knoth 61070dca1793SAdrian Knoth status.card_clock = 110069313433624ULL; 61080dca1793SAdrian Knoth status.master_period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 61090dca1793SAdrian Knoth 61100dca1793SAdrian Knoth switch (hdspm->io_type) { 61110dca1793SAdrian Knoth case MADI: 61120dca1793SAdrian Knoth case MADIface: 61130dca1793SAdrian Knoth status.card_specific.madi.sync_wc = 61140dca1793SAdrian Knoth hdspm_wc_sync_check(hdspm); 61150dca1793SAdrian Knoth status.card_specific.madi.sync_madi = 61160dca1793SAdrian Knoth hdspm_madi_sync_check(hdspm); 61170dca1793SAdrian Knoth status.card_specific.madi.sync_tco = 61180dca1793SAdrian Knoth hdspm_tco_sync_check(hdspm); 61190dca1793SAdrian Knoth status.card_specific.madi.sync_in = 61200dca1793SAdrian Knoth hdspm_sync_in_sync_check(hdspm); 61210dca1793SAdrian Knoth 61220dca1793SAdrian Knoth statusregister = 61230dca1793SAdrian Knoth hdspm_read(hdspm, HDSPM_statusRegister); 61240dca1793SAdrian Knoth status.card_specific.madi.madi_input = 61250dca1793SAdrian Knoth (statusregister & HDSPM_AB_int) ? 1 : 0; 61260dca1793SAdrian Knoth status.card_specific.madi.channel_format = 61270dca1793SAdrian Knoth (statusregister & HDSPM_TX_64ch) ? 1 : 0; 61280dca1793SAdrian Knoth /* TODO: Mac driver sets it when f_s>48kHz */ 61290dca1793SAdrian Knoth status.card_specific.madi.frame_format = 0; 61300dca1793SAdrian Knoth 61310dca1793SAdrian Knoth default: 61320dca1793SAdrian Knoth break; 61330dca1793SAdrian Knoth } 61340dca1793SAdrian Knoth 61350dca1793SAdrian Knoth if (copy_to_user((void __user *) arg, &status, sizeof(status))) 61360dca1793SAdrian Knoth return -EFAULT; 61370dca1793SAdrian Knoth 61380dca1793SAdrian Knoth 61390dca1793SAdrian Knoth break; 61400dca1793SAdrian Knoth 6141763f356cSTakashi Iwai case SNDRV_HDSPM_IOCTL_GET_VERSION: 61420dca1793SAdrian Knoth hdspm_version.card_type = hdspm->io_type; 61430dca1793SAdrian Knoth strncpy(hdspm_version.cardname, hdspm->card_name, 61440dca1793SAdrian Knoth sizeof(hdspm_version.cardname)); 61450dca1793SAdrian Knoth hdspm_version.serial = (hdspm_read(hdspm, 61460dca1793SAdrian Knoth HDSPM_midiStatusIn0)>>8) & 0xFFFFFF; 6147763f356cSTakashi Iwai hdspm_version.firmware_rev = hdspm->firmware_rev; 61480dca1793SAdrian Knoth hdspm_version.addons = 0; 61490dca1793SAdrian Knoth if (hdspm->tco) 61500dca1793SAdrian Knoth hdspm_version.addons |= HDSPM_ADDON_TCO; 61510dca1793SAdrian Knoth 6152763f356cSTakashi Iwai if (copy_to_user((void __user *) arg, &hdspm_version, 6153763f356cSTakashi Iwai sizeof(hdspm_version))) 6154763f356cSTakashi Iwai return -EFAULT; 6155763f356cSTakashi Iwai break; 6156763f356cSTakashi Iwai 6157763f356cSTakashi Iwai case SNDRV_HDSPM_IOCTL_GET_MIXER: 6158763f356cSTakashi Iwai if (copy_from_user(&mixer, (void __user *)arg, sizeof(mixer))) 6159763f356cSTakashi Iwai return -EFAULT; 6160ef5fa1a4STakashi Iwai if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer, 6161ef5fa1a4STakashi Iwai sizeof(struct hdspm_mixer))) 6162763f356cSTakashi Iwai return -EFAULT; 6163763f356cSTakashi Iwai break; 6164763f356cSTakashi Iwai 6165763f356cSTakashi Iwai default: 6166763f356cSTakashi Iwai return -EINVAL; 6167763f356cSTakashi Iwai } 6168763f356cSTakashi Iwai return 0; 6169763f356cSTakashi Iwai } 6170763f356cSTakashi Iwai 617198274f07STakashi Iwai static struct snd_pcm_ops snd_hdspm_playback_ops = { 6172763f356cSTakashi Iwai .open = snd_hdspm_playback_open, 6173763f356cSTakashi Iwai .close = snd_hdspm_playback_release, 6174763f356cSTakashi Iwai .ioctl = snd_hdspm_ioctl, 6175763f356cSTakashi Iwai .hw_params = snd_hdspm_hw_params, 6176763f356cSTakashi Iwai .hw_free = snd_hdspm_hw_free, 6177763f356cSTakashi Iwai .prepare = snd_hdspm_prepare, 6178763f356cSTakashi Iwai .trigger = snd_hdspm_trigger, 6179763f356cSTakashi Iwai .pointer = snd_hdspm_hw_pointer, 6180763f356cSTakashi Iwai .page = snd_pcm_sgbuf_ops_page, 6181763f356cSTakashi Iwai }; 6182763f356cSTakashi Iwai 618398274f07STakashi Iwai static struct snd_pcm_ops snd_hdspm_capture_ops = { 6184763f356cSTakashi Iwai .open = snd_hdspm_capture_open, 6185763f356cSTakashi Iwai .close = snd_hdspm_capture_release, 6186763f356cSTakashi Iwai .ioctl = snd_hdspm_ioctl, 6187763f356cSTakashi Iwai .hw_params = snd_hdspm_hw_params, 6188763f356cSTakashi Iwai .hw_free = snd_hdspm_hw_free, 6189763f356cSTakashi Iwai .prepare = snd_hdspm_prepare, 6190763f356cSTakashi Iwai .trigger = snd_hdspm_trigger, 6191763f356cSTakashi Iwai .pointer = snd_hdspm_hw_pointer, 6192763f356cSTakashi Iwai .page = snd_pcm_sgbuf_ops_page, 6193763f356cSTakashi Iwai }; 6194763f356cSTakashi Iwai 619598274f07STakashi Iwai static int __devinit snd_hdspm_create_hwdep(struct snd_card *card, 619698274f07STakashi Iwai struct hdspm * hdspm) 6197763f356cSTakashi Iwai { 619898274f07STakashi Iwai struct snd_hwdep *hw; 6199763f356cSTakashi Iwai int err; 6200763f356cSTakashi Iwai 6201ef5fa1a4STakashi Iwai err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw); 6202ef5fa1a4STakashi Iwai if (err < 0) 6203763f356cSTakashi Iwai return err; 6204763f356cSTakashi Iwai 6205763f356cSTakashi Iwai hdspm->hwdep = hw; 6206763f356cSTakashi Iwai hw->private_data = hdspm; 6207763f356cSTakashi Iwai strcpy(hw->name, "HDSPM hwdep interface"); 6208763f356cSTakashi Iwai 62090dca1793SAdrian Knoth hw->ops.open = snd_hdspm_hwdep_dummy_op; 6210763f356cSTakashi Iwai hw->ops.ioctl = snd_hdspm_hwdep_ioctl; 62110dca1793SAdrian Knoth hw->ops.release = snd_hdspm_hwdep_dummy_op; 6212763f356cSTakashi Iwai 6213763f356cSTakashi Iwai return 0; 6214763f356cSTakashi Iwai } 6215763f356cSTakashi Iwai 6216763f356cSTakashi Iwai 6217763f356cSTakashi Iwai /*------------------------------------------------------------ 6218763f356cSTakashi Iwai memory interface 6219763f356cSTakashi Iwai ------------------------------------------------------------*/ 622098274f07STakashi Iwai static int __devinit snd_hdspm_preallocate_memory(struct hdspm *hdspm) 6221763f356cSTakashi Iwai { 6222763f356cSTakashi Iwai int err; 622398274f07STakashi Iwai struct snd_pcm *pcm; 6224763f356cSTakashi Iwai size_t wanted; 6225763f356cSTakashi Iwai 6226763f356cSTakashi Iwai pcm = hdspm->pcm; 6227763f356cSTakashi Iwai 62283cee5a60SRemy Bruno wanted = HDSPM_DMA_AREA_BYTES; 6229763f356cSTakashi Iwai 6230ef5fa1a4STakashi Iwai err = 6231763f356cSTakashi Iwai snd_pcm_lib_preallocate_pages_for_all(pcm, 6232763f356cSTakashi Iwai SNDRV_DMA_TYPE_DEV_SG, 6233763f356cSTakashi Iwai snd_dma_pci_data(hdspm->pci), 6234763f356cSTakashi Iwai wanted, 6235ef5fa1a4STakashi Iwai wanted); 6236ef5fa1a4STakashi Iwai if (err < 0) { 6237e2eba3e7SAndrew Morton snd_printdd("Could not preallocate %zd Bytes\n", wanted); 6238763f356cSTakashi Iwai 6239763f356cSTakashi Iwai return err; 6240763f356cSTakashi Iwai } else 6241e2eba3e7SAndrew Morton snd_printdd(" Preallocated %zd Bytes\n", wanted); 6242763f356cSTakashi Iwai 6243763f356cSTakashi Iwai return 0; 6244763f356cSTakashi Iwai } 6245763f356cSTakashi Iwai 62460dca1793SAdrian Knoth 624777a23f26STakashi Iwai static void hdspm_set_sgbuf(struct hdspm *hdspm, 624877a23f26STakashi Iwai struct snd_pcm_substream *substream, 6249763f356cSTakashi Iwai unsigned int reg, int channels) 6250763f356cSTakashi Iwai { 6251763f356cSTakashi Iwai int i; 62520dca1793SAdrian Knoth 62530dca1793SAdrian Knoth /* continuous memory segment */ 6254763f356cSTakashi Iwai for (i = 0; i < (channels * 16); i++) 6255763f356cSTakashi Iwai hdspm_write(hdspm, reg + 4 * i, 625677a23f26STakashi Iwai snd_pcm_sgbuf_get_addr(substream, 4096 * i)); 6257763f356cSTakashi Iwai } 6258763f356cSTakashi Iwai 62590dca1793SAdrian Knoth 6260763f356cSTakashi Iwai /* ------------- ALSA Devices ---------------------------- */ 626198274f07STakashi Iwai static int __devinit snd_hdspm_create_pcm(struct snd_card *card, 626298274f07STakashi Iwai struct hdspm *hdspm) 6263763f356cSTakashi Iwai { 626498274f07STakashi Iwai struct snd_pcm *pcm; 6265763f356cSTakashi Iwai int err; 6266763f356cSTakashi Iwai 6267ef5fa1a4STakashi Iwai err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm); 6268ef5fa1a4STakashi Iwai if (err < 0) 6269763f356cSTakashi Iwai return err; 6270763f356cSTakashi Iwai 6271763f356cSTakashi Iwai hdspm->pcm = pcm; 6272763f356cSTakashi Iwai pcm->private_data = hdspm; 6273763f356cSTakashi Iwai strcpy(pcm->name, hdspm->card_name); 6274763f356cSTakashi Iwai 6275763f356cSTakashi Iwai snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 6276763f356cSTakashi Iwai &snd_hdspm_playback_ops); 6277763f356cSTakashi Iwai snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 6278763f356cSTakashi Iwai &snd_hdspm_capture_ops); 6279763f356cSTakashi Iwai 6280763f356cSTakashi Iwai pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; 6281763f356cSTakashi Iwai 6282ef5fa1a4STakashi Iwai err = snd_hdspm_preallocate_memory(hdspm); 6283ef5fa1a4STakashi Iwai if (err < 0) 6284763f356cSTakashi Iwai return err; 6285763f356cSTakashi Iwai 6286763f356cSTakashi Iwai return 0; 6287763f356cSTakashi Iwai } 6288763f356cSTakashi Iwai 628998274f07STakashi Iwai static inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm) 6290763f356cSTakashi Iwai { 6291763f356cSTakashi Iwai snd_hdspm_flush_midi_input(hdspm, 0); 6292763f356cSTakashi Iwai snd_hdspm_flush_midi_input(hdspm, 1); 6293763f356cSTakashi Iwai } 6294763f356cSTakashi Iwai 629598274f07STakashi Iwai static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, 629698274f07STakashi Iwai struct hdspm * hdspm) 6297763f356cSTakashi Iwai { 62980dca1793SAdrian Knoth int err, i; 6299763f356cSTakashi Iwai 6300763f356cSTakashi Iwai snd_printdd("Create card...\n"); 6301ef5fa1a4STakashi Iwai err = snd_hdspm_create_pcm(card, hdspm); 6302ef5fa1a4STakashi Iwai if (err < 0) 6303763f356cSTakashi Iwai return err; 6304763f356cSTakashi Iwai 63050dca1793SAdrian Knoth i = 0; 63060dca1793SAdrian Knoth while (i < hdspm->midiPorts) { 63070dca1793SAdrian Knoth err = snd_hdspm_create_midi(card, hdspm, i); 63080dca1793SAdrian Knoth if (err < 0) { 6309763f356cSTakashi Iwai return err; 63100dca1793SAdrian Knoth } 63110dca1793SAdrian Knoth i++; 63120dca1793SAdrian Knoth } 6313763f356cSTakashi Iwai 6314ef5fa1a4STakashi Iwai err = snd_hdspm_create_controls(card, hdspm); 6315ef5fa1a4STakashi Iwai if (err < 0) 6316763f356cSTakashi Iwai return err; 6317763f356cSTakashi Iwai 6318ef5fa1a4STakashi Iwai err = snd_hdspm_create_hwdep(card, hdspm); 6319ef5fa1a4STakashi Iwai if (err < 0) 6320763f356cSTakashi Iwai return err; 6321763f356cSTakashi Iwai 6322763f356cSTakashi Iwai snd_printdd("proc init...\n"); 6323763f356cSTakashi Iwai snd_hdspm_proc_init(hdspm); 6324763f356cSTakashi Iwai 6325763f356cSTakashi Iwai hdspm->system_sample_rate = -1; 6326763f356cSTakashi Iwai hdspm->last_external_sample_rate = -1; 6327763f356cSTakashi Iwai hdspm->last_internal_sample_rate = -1; 6328763f356cSTakashi Iwai hdspm->playback_pid = -1; 6329763f356cSTakashi Iwai hdspm->capture_pid = -1; 6330763f356cSTakashi Iwai hdspm->capture_substream = NULL; 6331763f356cSTakashi Iwai hdspm->playback_substream = NULL; 6332763f356cSTakashi Iwai 6333763f356cSTakashi Iwai snd_printdd("Set defaults...\n"); 6334ef5fa1a4STakashi Iwai err = snd_hdspm_set_defaults(hdspm); 6335ef5fa1a4STakashi Iwai if (err < 0) 6336763f356cSTakashi Iwai return err; 6337763f356cSTakashi Iwai 6338763f356cSTakashi Iwai snd_printdd("Update mixer controls...\n"); 6339763f356cSTakashi Iwai hdspm_update_simple_mixer_controls(hdspm); 6340763f356cSTakashi Iwai 6341763f356cSTakashi Iwai snd_printdd("Initializeing complete ???\n"); 6342763f356cSTakashi Iwai 6343ef5fa1a4STakashi Iwai err = snd_card_register(card); 6344ef5fa1a4STakashi Iwai if (err < 0) { 6345763f356cSTakashi Iwai snd_printk(KERN_ERR "HDSPM: error registering card\n"); 6346763f356cSTakashi Iwai return err; 6347763f356cSTakashi Iwai } 6348763f356cSTakashi Iwai 6349763f356cSTakashi Iwai snd_printdd("... yes now\n"); 6350763f356cSTakashi Iwai 6351763f356cSTakashi Iwai return 0; 6352763f356cSTakashi Iwai } 6353763f356cSTakashi Iwai 6354ef5fa1a4STakashi Iwai static int __devinit snd_hdspm_create(struct snd_card *card, 63550dca1793SAdrian Knoth struct hdspm *hdspm) { 63560dca1793SAdrian Knoth 6357763f356cSTakashi Iwai struct pci_dev *pci = hdspm->pci; 6358763f356cSTakashi Iwai int err; 6359763f356cSTakashi Iwai unsigned long io_extent; 6360763f356cSTakashi Iwai 6361763f356cSTakashi Iwai hdspm->irq = -1; 6362763f356cSTakashi Iwai hdspm->card = card; 6363763f356cSTakashi Iwai 6364763f356cSTakashi Iwai spin_lock_init(&hdspm->lock); 6365763f356cSTakashi Iwai 6366763f356cSTakashi Iwai pci_read_config_word(hdspm->pci, 6367763f356cSTakashi Iwai PCI_CLASS_REVISION, &hdspm->firmware_rev); 6368763f356cSTakashi Iwai 6369763f356cSTakashi Iwai strcpy(card->mixername, "Xilinx FPGA"); 63703cee5a60SRemy Bruno strcpy(card->driver, "HDSPM"); 63710dca1793SAdrian Knoth 63720dca1793SAdrian Knoth switch (hdspm->firmware_rev) { 63730dca1793SAdrian Knoth case HDSPM_MADI_REV: 63740dca1793SAdrian Knoth hdspm->io_type = MADI; 63750dca1793SAdrian Knoth hdspm->card_name = "RME MADI"; 63760dca1793SAdrian Knoth hdspm->midiPorts = 3; 63770dca1793SAdrian Knoth break; 63780dca1793SAdrian Knoth case HDSPM_RAYDAT_REV: 63790dca1793SAdrian Knoth hdspm->io_type = RayDAT; 63800dca1793SAdrian Knoth hdspm->card_name = "RME RayDAT"; 63810dca1793SAdrian Knoth hdspm->midiPorts = 2; 63820dca1793SAdrian Knoth break; 63830dca1793SAdrian Knoth case HDSPM_AIO_REV: 63840dca1793SAdrian Knoth hdspm->io_type = AIO; 63850dca1793SAdrian Knoth hdspm->card_name = "RME AIO"; 63860dca1793SAdrian Knoth hdspm->midiPorts = 1; 63870dca1793SAdrian Knoth break; 63880dca1793SAdrian Knoth case HDSPM_MADIFACE_REV: 63890dca1793SAdrian Knoth hdspm->io_type = MADIface; 63900dca1793SAdrian Knoth hdspm->card_name = "RME MADIface"; 63910dca1793SAdrian Knoth hdspm->midiPorts = 1; 63920dca1793SAdrian Knoth break; 63930dca1793SAdrian Knoth case HDSPM_AES_REV: 63940dca1793SAdrian Knoth hdspm->io_type = AES32; 63950dca1793SAdrian Knoth hdspm->card_name = "RME AES32"; 63960dca1793SAdrian Knoth hdspm->midiPorts = 2; 63970dca1793SAdrian Knoth break; 63983cee5a60SRemy Bruno } 6399763f356cSTakashi Iwai 6400ef5fa1a4STakashi Iwai err = pci_enable_device(pci); 6401ef5fa1a4STakashi Iwai if (err < 0) 6402763f356cSTakashi Iwai return err; 6403763f356cSTakashi Iwai 6404763f356cSTakashi Iwai pci_set_master(hdspm->pci); 6405763f356cSTakashi Iwai 6406ef5fa1a4STakashi Iwai err = pci_request_regions(pci, "hdspm"); 6407ef5fa1a4STakashi Iwai if (err < 0) 6408763f356cSTakashi Iwai return err; 6409763f356cSTakashi Iwai 6410763f356cSTakashi Iwai hdspm->port = pci_resource_start(pci, 0); 6411763f356cSTakashi Iwai io_extent = pci_resource_len(pci, 0); 6412763f356cSTakashi Iwai 6413763f356cSTakashi Iwai snd_printdd("grabbed memory region 0x%lx-0x%lx\n", 6414763f356cSTakashi Iwai hdspm->port, hdspm->port + io_extent - 1); 6415763f356cSTakashi Iwai 6416ef5fa1a4STakashi Iwai hdspm->iobase = ioremap_nocache(hdspm->port, io_extent); 6417ef5fa1a4STakashi Iwai if (!hdspm->iobase) { 6418ef5fa1a4STakashi Iwai snd_printk(KERN_ERR "HDSPM: " 6419ef5fa1a4STakashi Iwai "unable to remap region 0x%lx-0x%lx\n", 6420763f356cSTakashi Iwai hdspm->port, hdspm->port + io_extent - 1); 6421763f356cSTakashi Iwai return -EBUSY; 6422763f356cSTakashi Iwai } 6423763f356cSTakashi Iwai snd_printdd("remapped region (0x%lx) 0x%lx-0x%lx\n", 6424763f356cSTakashi Iwai (unsigned long)hdspm->iobase, hdspm->port, 6425763f356cSTakashi Iwai hdspm->port + io_extent - 1); 6426763f356cSTakashi Iwai 6427763f356cSTakashi Iwai if (request_irq(pci->irq, snd_hdspm_interrupt, 6428437a5a46STakashi Iwai IRQF_SHARED, "hdspm", hdspm)) { 6429763f356cSTakashi Iwai snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq); 6430763f356cSTakashi Iwai return -EBUSY; 6431763f356cSTakashi Iwai } 6432763f356cSTakashi Iwai 6433763f356cSTakashi Iwai snd_printdd("use IRQ %d\n", pci->irq); 6434763f356cSTakashi Iwai 6435763f356cSTakashi Iwai hdspm->irq = pci->irq; 6436763f356cSTakashi Iwai 6437e2eba3e7SAndrew Morton snd_printdd("kmalloc Mixer memory of %zd Bytes\n", 643898274f07STakashi Iwai sizeof(struct hdspm_mixer)); 6439ef5fa1a4STakashi Iwai hdspm->mixer = kzalloc(sizeof(struct hdspm_mixer), GFP_KERNEL); 6440ef5fa1a4STakashi Iwai if (!hdspm->mixer) { 6441ef5fa1a4STakashi Iwai snd_printk(KERN_ERR "HDSPM: " 6442ef5fa1a4STakashi Iwai "unable to kmalloc Mixer memory of %d Bytes\n", 644398274f07STakashi Iwai (int)sizeof(struct hdspm_mixer)); 6444763f356cSTakashi Iwai return err; 6445763f356cSTakashi Iwai } 6446763f356cSTakashi Iwai 64470dca1793SAdrian Knoth hdspm->port_names_in = NULL; 64480dca1793SAdrian Knoth hdspm->port_names_out = NULL; 64490dca1793SAdrian Knoth 64500dca1793SAdrian Knoth switch (hdspm->io_type) { 64510dca1793SAdrian Knoth case AES32: 6452432d2500SAdrian Knoth hdspm->ss_in_channels = hdspm->ss_out_channels = 16; 6453432d2500SAdrian Knoth hdspm->ds_in_channels = hdspm->ds_out_channels = 16; 6454432d2500SAdrian Knoth hdspm->qs_in_channels = hdspm->qs_out_channels = 16; 6455432d2500SAdrian Knoth 6456432d2500SAdrian Knoth hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 6457432d2500SAdrian Knoth channel_map_aes32; 6458432d2500SAdrian Knoth hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 6459432d2500SAdrian Knoth channel_map_aes32; 6460432d2500SAdrian Knoth hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 6461432d2500SAdrian Knoth channel_map_aes32; 6462432d2500SAdrian Knoth hdspm->port_names_in_ss = hdspm->port_names_out_ss = 6463432d2500SAdrian Knoth texts_ports_aes32; 6464432d2500SAdrian Knoth hdspm->port_names_in_ds = hdspm->port_names_out_ds = 6465432d2500SAdrian Knoth texts_ports_aes32; 6466432d2500SAdrian Knoth hdspm->port_names_in_qs = hdspm->port_names_out_qs = 6467432d2500SAdrian Knoth texts_ports_aes32; 6468432d2500SAdrian Knoth 6469432d2500SAdrian Knoth hdspm->max_channels_out = hdspm->max_channels_in = 16; 6470432d2500SAdrian Knoth hdspm->port_names_in = hdspm->port_names_out = 6471432d2500SAdrian Knoth texts_ports_aes32; 6472432d2500SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_out = 6473432d2500SAdrian Knoth channel_map_aes32; 6474432d2500SAdrian Knoth 64750dca1793SAdrian Knoth break; 64760dca1793SAdrian Knoth 64770dca1793SAdrian Knoth case MADI: 64780dca1793SAdrian Knoth case MADIface: 64790dca1793SAdrian Knoth hdspm->ss_in_channels = hdspm->ss_out_channels = 64800dca1793SAdrian Knoth MADI_SS_CHANNELS; 64810dca1793SAdrian Knoth hdspm->ds_in_channels = hdspm->ds_out_channels = 64820dca1793SAdrian Knoth MADI_DS_CHANNELS; 64830dca1793SAdrian Knoth hdspm->qs_in_channels = hdspm->qs_out_channels = 64840dca1793SAdrian Knoth MADI_QS_CHANNELS; 64850dca1793SAdrian Knoth 64860dca1793SAdrian Knoth hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 64870dca1793SAdrian Knoth channel_map_unity_ss; 648801e96078SAdrian Knoth hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 64890dca1793SAdrian Knoth channel_map_unity_ss; 649001e96078SAdrian Knoth hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 64910dca1793SAdrian Knoth channel_map_unity_ss; 64920dca1793SAdrian Knoth 64930dca1793SAdrian Knoth hdspm->port_names_in_ss = hdspm->port_names_out_ss = 64940dca1793SAdrian Knoth texts_ports_madi; 64950dca1793SAdrian Knoth hdspm->port_names_in_ds = hdspm->port_names_out_ds = 64960dca1793SAdrian Knoth texts_ports_madi; 64970dca1793SAdrian Knoth hdspm->port_names_in_qs = hdspm->port_names_out_qs = 64980dca1793SAdrian Knoth texts_ports_madi; 64990dca1793SAdrian Knoth break; 65000dca1793SAdrian Knoth 65010dca1793SAdrian Knoth case AIO: 65020dca1793SAdrian Knoth if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { 65030dca1793SAdrian Knoth snd_printk(KERN_INFO "HDSPM: AEB input board found, but not supported\n"); 65040dca1793SAdrian Knoth } 65050dca1793SAdrian Knoth 65060dca1793SAdrian Knoth hdspm->ss_in_channels = AIO_IN_SS_CHANNELS; 65070dca1793SAdrian Knoth hdspm->ds_in_channels = AIO_IN_DS_CHANNELS; 65080dca1793SAdrian Knoth hdspm->qs_in_channels = AIO_IN_QS_CHANNELS; 65090dca1793SAdrian Knoth hdspm->ss_out_channels = AIO_OUT_SS_CHANNELS; 65100dca1793SAdrian Knoth hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS; 65110dca1793SAdrian Knoth hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS; 65120dca1793SAdrian Knoth 65130dca1793SAdrian Knoth hdspm->channel_map_out_ss = channel_map_aio_out_ss; 65140dca1793SAdrian Knoth hdspm->channel_map_out_ds = channel_map_aio_out_ds; 65150dca1793SAdrian Knoth hdspm->channel_map_out_qs = channel_map_aio_out_qs; 65160dca1793SAdrian Knoth 65170dca1793SAdrian Knoth hdspm->channel_map_in_ss = channel_map_aio_in_ss; 65180dca1793SAdrian Knoth hdspm->channel_map_in_ds = channel_map_aio_in_ds; 65190dca1793SAdrian Knoth hdspm->channel_map_in_qs = channel_map_aio_in_qs; 65200dca1793SAdrian Knoth 65210dca1793SAdrian Knoth hdspm->port_names_in_ss = texts_ports_aio_in_ss; 65220dca1793SAdrian Knoth hdspm->port_names_out_ss = texts_ports_aio_out_ss; 65230dca1793SAdrian Knoth hdspm->port_names_in_ds = texts_ports_aio_in_ds; 65240dca1793SAdrian Knoth hdspm->port_names_out_ds = texts_ports_aio_out_ds; 65250dca1793SAdrian Knoth hdspm->port_names_in_qs = texts_ports_aio_in_qs; 65260dca1793SAdrian Knoth hdspm->port_names_out_qs = texts_ports_aio_out_qs; 65270dca1793SAdrian Knoth 65280dca1793SAdrian Knoth break; 65290dca1793SAdrian Knoth 65300dca1793SAdrian Knoth case RayDAT: 65310dca1793SAdrian Knoth hdspm->ss_in_channels = hdspm->ss_out_channels = 65320dca1793SAdrian Knoth RAYDAT_SS_CHANNELS; 65330dca1793SAdrian Knoth hdspm->ds_in_channels = hdspm->ds_out_channels = 65340dca1793SAdrian Knoth RAYDAT_DS_CHANNELS; 65350dca1793SAdrian Knoth hdspm->qs_in_channels = hdspm->qs_out_channels = 65360dca1793SAdrian Knoth RAYDAT_QS_CHANNELS; 65370dca1793SAdrian Knoth 65380dca1793SAdrian Knoth hdspm->max_channels_in = RAYDAT_SS_CHANNELS; 65390dca1793SAdrian Knoth hdspm->max_channels_out = RAYDAT_SS_CHANNELS; 65400dca1793SAdrian Knoth 65410dca1793SAdrian Knoth hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 65420dca1793SAdrian Knoth channel_map_raydat_ss; 65430dca1793SAdrian Knoth hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 65440dca1793SAdrian Knoth channel_map_raydat_ds; 65450dca1793SAdrian Knoth hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 65460dca1793SAdrian Knoth channel_map_raydat_qs; 65470dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_out = 65480dca1793SAdrian Knoth channel_map_raydat_ss; 65490dca1793SAdrian Knoth 65500dca1793SAdrian Knoth hdspm->port_names_in_ss = hdspm->port_names_out_ss = 65510dca1793SAdrian Knoth texts_ports_raydat_ss; 65520dca1793SAdrian Knoth hdspm->port_names_in_ds = hdspm->port_names_out_ds = 65530dca1793SAdrian Knoth texts_ports_raydat_ds; 65540dca1793SAdrian Knoth hdspm->port_names_in_qs = hdspm->port_names_out_qs = 65550dca1793SAdrian Knoth texts_ports_raydat_qs; 65560dca1793SAdrian Knoth 65570dca1793SAdrian Knoth 65580dca1793SAdrian Knoth break; 65590dca1793SAdrian Knoth 65600dca1793SAdrian Knoth } 65610dca1793SAdrian Knoth 65620dca1793SAdrian Knoth /* TCO detection */ 65630dca1793SAdrian Knoth switch (hdspm->io_type) { 65640dca1793SAdrian Knoth case AIO: 65650dca1793SAdrian Knoth case RayDAT: 65660dca1793SAdrian Knoth if (hdspm_read(hdspm, HDSPM_statusRegister2) & 65670dca1793SAdrian Knoth HDSPM_s2_tco_detect) { 65680dca1793SAdrian Knoth hdspm->midiPorts++; 65690dca1793SAdrian Knoth hdspm->tco = kzalloc(sizeof(struct hdspm_tco), 65700dca1793SAdrian Knoth GFP_KERNEL); 65710dca1793SAdrian Knoth if (NULL != hdspm->tco) { 65720dca1793SAdrian Knoth hdspm_tco_write(hdspm); 65730dca1793SAdrian Knoth } 65740dca1793SAdrian Knoth snd_printk(KERN_INFO "HDSPM: AIO/RayDAT TCO module found\n"); 65750dca1793SAdrian Knoth } else { 65760dca1793SAdrian Knoth hdspm->tco = NULL; 65770dca1793SAdrian Knoth } 65780dca1793SAdrian Knoth break; 65790dca1793SAdrian Knoth 65800dca1793SAdrian Knoth case MADI: 65810dca1793SAdrian Knoth if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) { 65820dca1793SAdrian Knoth hdspm->midiPorts++; 65830dca1793SAdrian Knoth hdspm->tco = kzalloc(sizeof(struct hdspm_tco), 65840dca1793SAdrian Knoth GFP_KERNEL); 65850dca1793SAdrian Knoth if (NULL != hdspm->tco) { 65860dca1793SAdrian Knoth hdspm_tco_write(hdspm); 65870dca1793SAdrian Knoth } 65880dca1793SAdrian Knoth snd_printk(KERN_INFO "HDSPM: MADI TCO module found\n"); 65890dca1793SAdrian Knoth } else { 65900dca1793SAdrian Knoth hdspm->tco = NULL; 65910dca1793SAdrian Knoth } 65920dca1793SAdrian Knoth break; 65930dca1793SAdrian Knoth 65940dca1793SAdrian Knoth default: 65950dca1793SAdrian Knoth hdspm->tco = NULL; 65960dca1793SAdrian Knoth } 65970dca1793SAdrian Knoth 65980dca1793SAdrian Knoth /* texts */ 65990dca1793SAdrian Knoth switch (hdspm->io_type) { 66000dca1793SAdrian Knoth case AES32: 66010dca1793SAdrian Knoth if (hdspm->tco) { 66020dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aes_tco; 66030dca1793SAdrian Knoth hdspm->texts_autosync_items = 10; 66040dca1793SAdrian Knoth } else { 66050dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aes; 66060dca1793SAdrian Knoth hdspm->texts_autosync_items = 9; 66070dca1793SAdrian Knoth } 66080dca1793SAdrian Knoth break; 66090dca1793SAdrian Knoth 66100dca1793SAdrian Knoth case MADI: 66110dca1793SAdrian Knoth if (hdspm->tco) { 66120dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_madi_tco; 66130dca1793SAdrian Knoth hdspm->texts_autosync_items = 4; 66140dca1793SAdrian Knoth } else { 66150dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_madi; 66160dca1793SAdrian Knoth hdspm->texts_autosync_items = 3; 66170dca1793SAdrian Knoth } 66180dca1793SAdrian Knoth break; 66190dca1793SAdrian Knoth 66200dca1793SAdrian Knoth case MADIface: 66210dca1793SAdrian Knoth 66220dca1793SAdrian Knoth break; 66230dca1793SAdrian Knoth 66240dca1793SAdrian Knoth case RayDAT: 66250dca1793SAdrian Knoth if (hdspm->tco) { 66260dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_raydat_tco; 66270dca1793SAdrian Knoth hdspm->texts_autosync_items = 9; 66280dca1793SAdrian Knoth } else { 66290dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_raydat; 66300dca1793SAdrian Knoth hdspm->texts_autosync_items = 8; 66310dca1793SAdrian Knoth } 66320dca1793SAdrian Knoth break; 66330dca1793SAdrian Knoth 66340dca1793SAdrian Knoth case AIO: 66350dca1793SAdrian Knoth if (hdspm->tco) { 66360dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aio_tco; 66370dca1793SAdrian Knoth hdspm->texts_autosync_items = 6; 66380dca1793SAdrian Knoth } else { 66390dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aio; 66400dca1793SAdrian Knoth hdspm->texts_autosync_items = 5; 66410dca1793SAdrian Knoth } 66420dca1793SAdrian Knoth break; 66430dca1793SAdrian Knoth 66440dca1793SAdrian Knoth } 66450dca1793SAdrian Knoth 66460dca1793SAdrian Knoth tasklet_init(&hdspm->midi_tasklet, 66470dca1793SAdrian Knoth hdspm_midi_tasklet, (unsigned long) hdspm); 6648763f356cSTakashi Iwai 6649763f356cSTakashi Iwai snd_printdd("create alsa devices.\n"); 6650ef5fa1a4STakashi Iwai err = snd_hdspm_create_alsa_devices(card, hdspm); 6651ef5fa1a4STakashi Iwai if (err < 0) 6652763f356cSTakashi Iwai return err; 6653763f356cSTakashi Iwai 6654763f356cSTakashi Iwai snd_hdspm_initialize_midi_flush(hdspm); 6655763f356cSTakashi Iwai 6656763f356cSTakashi Iwai return 0; 6657763f356cSTakashi Iwai } 6658763f356cSTakashi Iwai 66590dca1793SAdrian Knoth 666098274f07STakashi Iwai static int snd_hdspm_free(struct hdspm * hdspm) 6661763f356cSTakashi Iwai { 6662763f356cSTakashi Iwai 6663763f356cSTakashi Iwai if (hdspm->port) { 6664763f356cSTakashi Iwai 6665763f356cSTakashi Iwai /* stop th audio, and cancel all interrupts */ 6666763f356cSTakashi Iwai hdspm->control_register &= 6667ef5fa1a4STakashi Iwai ~(HDSPM_Start | HDSPM_AudioInterruptEnable | 66680dca1793SAdrian Knoth HDSPM_Midi0InterruptEnable | HDSPM_Midi1InterruptEnable | 66690dca1793SAdrian Knoth HDSPM_Midi2InterruptEnable | HDSPM_Midi3InterruptEnable); 6670763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, 6671763f356cSTakashi Iwai hdspm->control_register); 6672763f356cSTakashi Iwai } 6673763f356cSTakashi Iwai 6674763f356cSTakashi Iwai if (hdspm->irq >= 0) 6675763f356cSTakashi Iwai free_irq(hdspm->irq, (void *) hdspm); 6676763f356cSTakashi Iwai 6677763f356cSTakashi Iwai kfree(hdspm->mixer); 6678763f356cSTakashi Iwai 6679763f356cSTakashi Iwai if (hdspm->iobase) 6680763f356cSTakashi Iwai iounmap(hdspm->iobase); 6681763f356cSTakashi Iwai 6682763f356cSTakashi Iwai if (hdspm->port) 6683763f356cSTakashi Iwai pci_release_regions(hdspm->pci); 6684763f356cSTakashi Iwai 6685763f356cSTakashi Iwai pci_disable_device(hdspm->pci); 6686763f356cSTakashi Iwai return 0; 6687763f356cSTakashi Iwai } 6688763f356cSTakashi Iwai 66890dca1793SAdrian Knoth 669098274f07STakashi Iwai static void snd_hdspm_card_free(struct snd_card *card) 6691763f356cSTakashi Iwai { 6692ef5fa1a4STakashi Iwai struct hdspm *hdspm = card->private_data; 6693763f356cSTakashi Iwai 6694763f356cSTakashi Iwai if (hdspm) 6695763f356cSTakashi Iwai snd_hdspm_free(hdspm); 6696763f356cSTakashi Iwai } 6697763f356cSTakashi Iwai 66980dca1793SAdrian Knoth 6699763f356cSTakashi Iwai static int __devinit snd_hdspm_probe(struct pci_dev *pci, 6700763f356cSTakashi Iwai const struct pci_device_id *pci_id) 6701763f356cSTakashi Iwai { 6702763f356cSTakashi Iwai static int dev; 670398274f07STakashi Iwai struct hdspm *hdspm; 670498274f07STakashi Iwai struct snd_card *card; 6705763f356cSTakashi Iwai int err; 6706763f356cSTakashi Iwai 6707763f356cSTakashi Iwai if (dev >= SNDRV_CARDS) 6708763f356cSTakashi Iwai return -ENODEV; 6709763f356cSTakashi Iwai if (!enable[dev]) { 6710763f356cSTakashi Iwai dev++; 6711763f356cSTakashi Iwai return -ENOENT; 6712763f356cSTakashi Iwai } 6713763f356cSTakashi Iwai 6714e58de7baSTakashi Iwai err = snd_card_create(index[dev], id[dev], 6715e58de7baSTakashi Iwai THIS_MODULE, sizeof(struct hdspm), &card); 6716e58de7baSTakashi Iwai if (err < 0) 6717e58de7baSTakashi Iwai return err; 6718763f356cSTakashi Iwai 6719ef5fa1a4STakashi Iwai hdspm = card->private_data; 6720763f356cSTakashi Iwai card->private_free = snd_hdspm_card_free; 6721763f356cSTakashi Iwai hdspm->dev = dev; 6722763f356cSTakashi Iwai hdspm->pci = pci; 6723763f356cSTakashi Iwai 6724c187c041STakashi Iwai snd_card_set_dev(card, &pci->dev); 6725c187c041STakashi Iwai 67260dca1793SAdrian Knoth err = snd_hdspm_create(card, hdspm); 6727ef5fa1a4STakashi Iwai if (err < 0) { 6728763f356cSTakashi Iwai snd_card_free(card); 6729763f356cSTakashi Iwai return err; 6730763f356cSTakashi Iwai } 6731763f356cSTakashi Iwai 67320dca1793SAdrian Knoth if (hdspm->io_type != MADIface) { 67330dca1793SAdrian Knoth sprintf(card->shortname, "%s_%x", 67340dca1793SAdrian Knoth hdspm->card_name, 67350dca1793SAdrian Knoth (hdspm_read(hdspm, HDSPM_midiStatusIn0)>>8) & 0xFFFFFF); 67360dca1793SAdrian Knoth sprintf(card->longname, "%s S/N 0x%x at 0x%lx, irq %d", 67370dca1793SAdrian Knoth hdspm->card_name, 67380dca1793SAdrian Knoth (hdspm_read(hdspm, HDSPM_midiStatusIn0)>>8) & 0xFFFFFF, 6739763f356cSTakashi Iwai hdspm->port, hdspm->irq); 67400dca1793SAdrian Knoth } else { 67410dca1793SAdrian Knoth sprintf(card->shortname, "%s", hdspm->card_name); 67420dca1793SAdrian Knoth sprintf(card->longname, "%s at 0x%lx, irq %d", 67430dca1793SAdrian Knoth hdspm->card_name, hdspm->port, hdspm->irq); 67440dca1793SAdrian Knoth } 6745763f356cSTakashi Iwai 6746ef5fa1a4STakashi Iwai err = snd_card_register(card); 6747ef5fa1a4STakashi Iwai if (err < 0) { 6748763f356cSTakashi Iwai snd_card_free(card); 6749763f356cSTakashi Iwai return err; 6750763f356cSTakashi Iwai } 6751763f356cSTakashi Iwai 6752763f356cSTakashi Iwai pci_set_drvdata(pci, card); 6753763f356cSTakashi Iwai 6754763f356cSTakashi Iwai dev++; 6755763f356cSTakashi Iwai return 0; 6756763f356cSTakashi Iwai } 6757763f356cSTakashi Iwai 6758763f356cSTakashi Iwai static void __devexit snd_hdspm_remove(struct pci_dev *pci) 6759763f356cSTakashi Iwai { 6760763f356cSTakashi Iwai snd_card_free(pci_get_drvdata(pci)); 6761763f356cSTakashi Iwai pci_set_drvdata(pci, NULL); 6762763f356cSTakashi Iwai } 6763763f356cSTakashi Iwai 6764763f356cSTakashi Iwai static struct pci_driver driver = { 6765763f356cSTakashi Iwai .name = "RME Hammerfall DSP MADI", 6766763f356cSTakashi Iwai .id_table = snd_hdspm_ids, 6767763f356cSTakashi Iwai .probe = snd_hdspm_probe, 6768763f356cSTakashi Iwai .remove = __devexit_p(snd_hdspm_remove), 6769763f356cSTakashi Iwai }; 6770763f356cSTakashi Iwai 6771763f356cSTakashi Iwai 6772763f356cSTakashi Iwai static int __init alsa_card_hdspm_init(void) 6773763f356cSTakashi Iwai { 6774763f356cSTakashi Iwai return pci_register_driver(&driver); 6775763f356cSTakashi Iwai } 6776763f356cSTakashi Iwai 6777763f356cSTakashi Iwai static void __exit alsa_card_hdspm_exit(void) 6778763f356cSTakashi Iwai { 6779763f356cSTakashi Iwai pci_unregister_driver(&driver); 6780763f356cSTakashi Iwai } 6781763f356cSTakashi Iwai 6782763f356cSTakashi Iwai module_init(alsa_card_hdspm_init) 6783763f356cSTakashi Iwai module_exit(alsa_card_hdspm_exit) 6784