xref: /OK3568_Linux_fs/kernel/sound/pci/rme9652/hdspm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *   ALSA driver for RME Hammerfall DSP MADI audio interface(s)
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *      Copyright (c) 2003 Winfried Ritsch (IEM)
6*4882a593Smuzhiyun  *      code based on hdsp.c   Paul Davis
7*4882a593Smuzhiyun  *                             Marcus Andersson
8*4882a593Smuzhiyun  *                             Thomas Charbonnel
9*4882a593Smuzhiyun  *      Modified 2006-06-01 for AES32 support by Remy Bruno
10*4882a593Smuzhiyun  *                                               <remy.bruno@trinnov.com>
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  *      Modified 2009-04-13 for proper metering by Florian Faber
13*4882a593Smuzhiyun  *                                               <faber@faberman.de>
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  *      Modified 2009-04-14 for native float support by Florian Faber
16*4882a593Smuzhiyun  *                                               <faber@faberman.de>
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  *      Modified 2009-04-26 fixed bug in rms metering by Florian Faber
19*4882a593Smuzhiyun  *                                               <faber@faberman.de>
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  *      Modified 2009-04-30 added hw serial number support by Florian Faber
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  *      Modified 2011-01-14 added S/PDIF input on RayDATs by Adrian Knoth
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  *	Modified 2011-01-25 variable period sizes on RayDAT/AIO by Adrian Knoth
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  *      Modified 2019-05-23 fix AIO single speed ADAT capture and playback
28*4882a593Smuzhiyun  *      by Philippe.Bekaert@uhasselt.be
29*4882a593Smuzhiyun  */
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* *************    Register Documentation   *******************************************************
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  * Work in progress! Documentation is based on the code in this file.
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  * --------- HDSPM_controlRegister ---------
36*4882a593Smuzhiyun  * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
37*4882a593Smuzhiyun  * :||||.||||:||||.||||:||||.||||:||||.||||:
38*4882a593Smuzhiyun  * :3322.2222:2222.1111:1111.1100:0000.0000: bit number
39*4882a593Smuzhiyun  * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
40*4882a593Smuzhiyun  * :||||.||||:||||.||||:||||.||||:||||.||||:
41*4882a593Smuzhiyun  * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
42*4882a593Smuzhiyun  * :    .    :    .    :    .    :  x .    :  HDSPM_AudioInterruptEnable \_ setting both bits
43*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .   x:  HDSPM_Start                /  enables audio IO
44*4882a593Smuzhiyun  * :    .    :    .    :    .    :   x.    :  HDSPM_ClockModeMaster - 1: Master, 0: Slave
45*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .210 :  HDSPM_LatencyMask - 3 Bit value for latency
46*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .    :      0:64, 1:128, 2:256, 3:512,
47*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .    :      4:1024, 5:2048, 6:4096, 7:8192
48*4882a593Smuzhiyun  * :x   .    :    .    :    .   x:xx  .    :  HDSPM_FrequencyMask
49*4882a593Smuzhiyun  * :    .    :    .    :    .    :10  .    :  HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=??
50*4882a593Smuzhiyun  * :    .    :    .    :    .   x:    .    :  <MADI> HDSPM_DoubleSpeed
51*4882a593Smuzhiyun  * :x   .    :    .    :    .    :    .    :  <MADI> HDSPM_QuadSpeed
52*4882a593Smuzhiyun  * :    .  3 :    .  10:  2 .    :    .    :  HDSPM_SyncRefMask :
53*4882a593Smuzhiyun  * :    .    :    .   x:    .    :    .    :  HDSPM_SyncRef0
54*4882a593Smuzhiyun  * :    .    :    .  x :    .    :    .    :  HDSPM_SyncRef1
55*4882a593Smuzhiyun  * :    .    :    .    :  x .    :    .    :  <AES32> HDSPM_SyncRef2
56*4882a593Smuzhiyun  * :    .  x :    .    :    .    :    .    :  <AES32> HDSPM_SyncRef3
57*4882a593Smuzhiyun  * :    .    :    .  10:    .    :    .    :  <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn
58*4882a593Smuzhiyun  * :    .  3 :    .  10:  2 .    :    .    :  <AES32>  0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn?
59*4882a593Smuzhiyun  * :    .  x :    .    :    .    :    .    :  <MADIe> HDSPe_FLOAT_FORMAT
60*4882a593Smuzhiyun  * :    .    :    .    : x  .    :    .    :  <MADI> HDSPM_InputSelect0 : 0=optical,1=coax
61*4882a593Smuzhiyun  * :    .    :    .    :x   .    :    .    :  <MADI> HDSPM_InputSelect1
62*4882a593Smuzhiyun  * :    .    :    .x   :    .    :    .    :  <MADI> HDSPM_clr_tms
63*4882a593Smuzhiyun  * :    .    :    .    :    . x  :    .    :  <MADI> HDSPM_TX_64ch
64*4882a593Smuzhiyun  * :    .    :    .    :    . x  :    .    :  <AES32> HDSPM_Emphasis
65*4882a593Smuzhiyun  * :    .    :    .    :    .x   :    .    :  <MADI> HDSPM_AutoInp
66*4882a593Smuzhiyun  * :    .    :    . x  :    .    :    .    :  <MADI> HDSPM_SMUX
67*4882a593Smuzhiyun  * :    .    :    .x   :    .    :    .    :  <MADI> HDSPM_clr_tms
68*4882a593Smuzhiyun  * :    .    :   x.    :    .    :    .    :  <MADI> HDSPM_taxi_reset
69*4882a593Smuzhiyun  * :    .   x:    .    :    .    :    .    :  <MADI> HDSPM_LineOut
70*4882a593Smuzhiyun  * :    .   x:    .    :    .    :    .    :  <AES32> ??????????????????
71*4882a593Smuzhiyun  * :    .    :   x.    :    .    :    .    :  <AES32> HDSPM_WCK48
72*4882a593Smuzhiyun  * :    .    :    .    :    .x   :    .    :  <AES32> HDSPM_Dolby
73*4882a593Smuzhiyun  * :    .    : x  .    :    .    :    .    :  HDSPM_Midi0InterruptEnable
74*4882a593Smuzhiyun  * :    .    :x   .    :    .    :    .    :  HDSPM_Midi1InterruptEnable
75*4882a593Smuzhiyun  * :    .    :  x .    :    .    :    .    :  HDSPM_Midi2InterruptEnable
76*4882a593Smuzhiyun  * :    . x  :    .    :    .    :    .    :  <MADI> HDSPM_Midi3InterruptEnable
77*4882a593Smuzhiyun  * :    . x  :    .    :    .    :    .    :  <AES32> HDSPM_DS_DoubleWire
78*4882a593Smuzhiyun  * :    .x   :    .    :    .    :    .    :  <AES32> HDSPM_QS_DoubleWire
79*4882a593Smuzhiyun  * :   x.    :    .    :    .    :    .    :  <AES32> HDSPM_QS_QuadWire
80*4882a593Smuzhiyun  * :    .    :    .    :    .  x :    .    :  <AES32> HDSPM_Professional
81*4882a593Smuzhiyun  * : x  .    :    .    :    .    :    .    :  HDSPM_wclk_sel
82*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .    :
83*4882a593Smuzhiyun  * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
84*4882a593Smuzhiyun  * :||||.||||:||||.||||:||||.||||:||||.||||:
85*4882a593Smuzhiyun  * :3322.2222:2222.1111:1111.1100:0000.0000: bit number
86*4882a593Smuzhiyun  * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
87*4882a593Smuzhiyun  * :||||.||||:||||.||||:||||.||||:||||.||||:
88*4882a593Smuzhiyun  * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit
89*4882a593Smuzhiyun  *
90*4882a593Smuzhiyun  *
91*4882a593Smuzhiyun  *
92*4882a593Smuzhiyun  * AIO / RayDAT only
93*4882a593Smuzhiyun  *
94*4882a593Smuzhiyun  * ------------ HDSPM_WR_SETTINGS ----------
95*4882a593Smuzhiyun  * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
96*4882a593Smuzhiyun  * :1098.7654:3210.9876:5432.1098:7654.3210:
97*4882a593Smuzhiyun  * :||||.||||:||||.||||:||||.||||:||||.||||: bit number
98*4882a593Smuzhiyun  * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
99*4882a593Smuzhiyun  * :||||.||||:||||.||||:||||.||||:||||.||||:
100*4882a593Smuzhiyun  * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
101*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .   x: HDSPM_c0Master 1: Master, 0: Slave
102*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .  x : HDSPM_c0_SyncRef0
103*4882a593Smuzhiyun  * :    .    :    .    :    .    :    . x  : HDSPM_c0_SyncRef1
104*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .x   : HDSPM_c0_SyncRef2
105*4882a593Smuzhiyun  * :    .    :    .    :    .    :   x.    : HDSPM_c0_SyncRef3
106*4882a593Smuzhiyun  * :    .    :    .    :    .    :   3.210 : HDSPM_c0_SyncRefMask:
107*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .    :  RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4,
108*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .    :          9:TCO, 10:SyncIn
109*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .    :  AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT,
110*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .    :          9:TCO, 10:SyncIn
111*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .    :
112*4882a593Smuzhiyun  * :    .    :    .    :    .    :    .    :
113*4882a593Smuzhiyun  * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
114*4882a593Smuzhiyun  * :1098.7654:3210.9876:5432.1098:7654.3210:
115*4882a593Smuzhiyun  * :||||.||||:||||.||||:||||.||||:||||.||||: bit number
116*4882a593Smuzhiyun  * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
117*4882a593Smuzhiyun  * :||||.||||:||||.||||:||||.||||:||||.||||:
118*4882a593Smuzhiyun  * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
119*4882a593Smuzhiyun  *
120*4882a593Smuzhiyun  */
121*4882a593Smuzhiyun #include <linux/init.h>
122*4882a593Smuzhiyun #include <linux/delay.h>
123*4882a593Smuzhiyun #include <linux/interrupt.h>
124*4882a593Smuzhiyun #include <linux/module.h>
125*4882a593Smuzhiyun #include <linux/slab.h>
126*4882a593Smuzhiyun #include <linux/pci.h>
127*4882a593Smuzhiyun #include <linux/math64.h>
128*4882a593Smuzhiyun #include <linux/io.h>
129*4882a593Smuzhiyun #include <linux/nospec.h>
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun #include <sound/core.h>
132*4882a593Smuzhiyun #include <sound/control.h>
133*4882a593Smuzhiyun #include <sound/pcm.h>
134*4882a593Smuzhiyun #include <sound/pcm_params.h>
135*4882a593Smuzhiyun #include <sound/info.h>
136*4882a593Smuzhiyun #include <sound/asoundef.h>
137*4882a593Smuzhiyun #include <sound/rawmidi.h>
138*4882a593Smuzhiyun #include <sound/hwdep.h>
139*4882a593Smuzhiyun #include <sound/initval.h>
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun #include <sound/hdspm.h>
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	  /* Index 0-MAX */
144*4882a593Smuzhiyun static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	  /* ID for this card */
145*4882a593Smuzhiyun static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun module_param_array(index, int, NULL, 0444);
148*4882a593Smuzhiyun MODULE_PARM_DESC(index, "Index value for RME HDSPM interface.");
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun module_param_array(id, charp, NULL, 0444);
151*4882a593Smuzhiyun MODULE_PARM_DESC(id, "ID string for RME HDSPM interface.");
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun module_param_array(enable, bool, NULL, 0444);
154*4882a593Smuzhiyun MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards.");
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun MODULE_AUTHOR
158*4882a593Smuzhiyun (
159*4882a593Smuzhiyun 	"Winfried Ritsch <ritsch_AT_iem.at>, "
160*4882a593Smuzhiyun 	"Paul Davis <paul@linuxaudiosystems.com>, "
161*4882a593Smuzhiyun 	"Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, "
162*4882a593Smuzhiyun 	"Remy Bruno <remy.bruno@trinnov.com>, "
163*4882a593Smuzhiyun 	"Florian Faber <faberman@linuxproaudio.org>, "
164*4882a593Smuzhiyun 	"Adrian Knoth <adi@drcomp.erfurt.thur.de>"
165*4882a593Smuzhiyun );
166*4882a593Smuzhiyun MODULE_DESCRIPTION("RME HDSPM");
167*4882a593Smuzhiyun MODULE_LICENSE("GPL");
168*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun /* --- Write registers. ---
171*4882a593Smuzhiyun   These are defined as byte-offsets from the iobase value.  */
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun #define HDSPM_WR_SETTINGS             0
174*4882a593Smuzhiyun #define HDSPM_outputBufferAddress    32
175*4882a593Smuzhiyun #define HDSPM_inputBufferAddress     36
176*4882a593Smuzhiyun #define HDSPM_controlRegister	     64
177*4882a593Smuzhiyun #define HDSPM_interruptConfirmation  96
178*4882a593Smuzhiyun #define HDSPM_control2Reg	     256  /* not in specs ???????? */
179*4882a593Smuzhiyun #define HDSPM_freqReg                256  /* for setting arbitrary clock values (DDS feature) */
180*4882a593Smuzhiyun #define HDSPM_midiDataOut0	     352  /* just believe in old code */
181*4882a593Smuzhiyun #define HDSPM_midiDataOut1	     356
182*4882a593Smuzhiyun #define HDSPM_eeprom_wr		     384  /* for AES32 */
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun /* DMA enable for 64 channels, only Bit 0 is relevant */
185*4882a593Smuzhiyun #define HDSPM_outputEnableBase       512  /* 512-767  input  DMA */
186*4882a593Smuzhiyun #define HDSPM_inputEnableBase        768  /* 768-1023 output DMA */
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun /* 16 page addresses for each of the 64 channels DMA buffer in and out
189*4882a593Smuzhiyun    (each 64k=16*4k) Buffer must be 4k aligned (which is default i386 ????) */
190*4882a593Smuzhiyun #define HDSPM_pageAddressBufferOut       8192
191*4882a593Smuzhiyun #define HDSPM_pageAddressBufferIn        (HDSPM_pageAddressBufferOut+64*16*4)
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun #define HDSPM_MADI_mixerBase    32768	/* 32768-65535 for 2x64x64 Fader */
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun #define HDSPM_MATRIX_MIXER_SIZE  8192	/* = 2*64*64 * 4 Byte => 32kB */
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun /* --- Read registers. ---
198*4882a593Smuzhiyun    These are defined as byte-offsets from the iobase value */
199*4882a593Smuzhiyun #define HDSPM_statusRegister    0
200*4882a593Smuzhiyun /*#define HDSPM_statusRegister2  96 */
201*4882a593Smuzhiyun /* after RME Windows driver sources, status2 is 4-byte word # 48 = word at
202*4882a593Smuzhiyun  * offset 192, for AES32 *and* MADI
203*4882a593Smuzhiyun  * => need to check that offset 192 is working on MADI */
204*4882a593Smuzhiyun #define HDSPM_statusRegister2  192
205*4882a593Smuzhiyun #define HDSPM_timecodeRegister 128
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun /* AIO, RayDAT */
208*4882a593Smuzhiyun #define HDSPM_RD_STATUS_0 0
209*4882a593Smuzhiyun #define HDSPM_RD_STATUS_1 64
210*4882a593Smuzhiyun #define HDSPM_RD_STATUS_2 128
211*4882a593Smuzhiyun #define HDSPM_RD_STATUS_3 192
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun #define HDSPM_RD_TCO           256
214*4882a593Smuzhiyun #define HDSPM_RD_PLL_FREQ      512
215*4882a593Smuzhiyun #define HDSPM_WR_TCO           128
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun #define HDSPM_TCO1_TCO_lock			0x00000001
218*4882a593Smuzhiyun #define HDSPM_TCO1_WCK_Input_Range_LSB		0x00000002
219*4882a593Smuzhiyun #define HDSPM_TCO1_WCK_Input_Range_MSB		0x00000004
220*4882a593Smuzhiyun #define HDSPM_TCO1_LTC_Input_valid		0x00000008
221*4882a593Smuzhiyun #define HDSPM_TCO1_WCK_Input_valid		0x00000010
222*4882a593Smuzhiyun #define HDSPM_TCO1_Video_Input_Format_NTSC	0x00000020
223*4882a593Smuzhiyun #define HDSPM_TCO1_Video_Input_Format_PAL	0x00000040
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun #define HDSPM_TCO1_set_TC			0x00000100
226*4882a593Smuzhiyun #define HDSPM_TCO1_set_drop_frame_flag		0x00000200
227*4882a593Smuzhiyun #define HDSPM_TCO1_LTC_Format_LSB		0x00000400
228*4882a593Smuzhiyun #define HDSPM_TCO1_LTC_Format_MSB		0x00000800
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun #define HDSPM_TCO2_TC_run			0x00010000
231*4882a593Smuzhiyun #define HDSPM_TCO2_WCK_IO_ratio_LSB		0x00020000
232*4882a593Smuzhiyun #define HDSPM_TCO2_WCK_IO_ratio_MSB		0x00040000
233*4882a593Smuzhiyun #define HDSPM_TCO2_set_num_drop_frames_LSB	0x00080000
234*4882a593Smuzhiyun #define HDSPM_TCO2_set_num_drop_frames_MSB	0x00100000
235*4882a593Smuzhiyun #define HDSPM_TCO2_set_jam_sync			0x00200000
236*4882a593Smuzhiyun #define HDSPM_TCO2_set_flywheel			0x00400000
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun #define HDSPM_TCO2_set_01_4			0x01000000
239*4882a593Smuzhiyun #define HDSPM_TCO2_set_pull_down		0x02000000
240*4882a593Smuzhiyun #define HDSPM_TCO2_set_pull_up			0x04000000
241*4882a593Smuzhiyun #define HDSPM_TCO2_set_freq			0x08000000
242*4882a593Smuzhiyun #define HDSPM_TCO2_set_term_75R			0x10000000
243*4882a593Smuzhiyun #define HDSPM_TCO2_set_input_LSB		0x20000000
244*4882a593Smuzhiyun #define HDSPM_TCO2_set_input_MSB		0x40000000
245*4882a593Smuzhiyun #define HDSPM_TCO2_set_freq_from_app		0x80000000
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun #define HDSPM_midiDataOut0    352
249*4882a593Smuzhiyun #define HDSPM_midiDataOut1    356
250*4882a593Smuzhiyun #define HDSPM_midiDataOut2    368
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun #define HDSPM_midiDataIn0     360
253*4882a593Smuzhiyun #define HDSPM_midiDataIn1     364
254*4882a593Smuzhiyun #define HDSPM_midiDataIn2     372
255*4882a593Smuzhiyun #define HDSPM_midiDataIn3     376
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun /* status is data bytes in MIDI-FIFO (0-128) */
258*4882a593Smuzhiyun #define HDSPM_midiStatusOut0  384
259*4882a593Smuzhiyun #define HDSPM_midiStatusOut1  388
260*4882a593Smuzhiyun #define HDSPM_midiStatusOut2  400
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun #define HDSPM_midiStatusIn0   392
263*4882a593Smuzhiyun #define HDSPM_midiStatusIn1   396
264*4882a593Smuzhiyun #define HDSPM_midiStatusIn2   404
265*4882a593Smuzhiyun #define HDSPM_midiStatusIn3   408
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun /* the meters are regular i/o-mapped registers, but offset
269*4882a593Smuzhiyun    considerably from the rest. the peak registers are reset
270*4882a593Smuzhiyun    when read; the least-significant 4 bits are full-scale counters;
271*4882a593Smuzhiyun    the actual peak value is in the most-significant 24 bits.
272*4882a593Smuzhiyun */
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun #define HDSPM_MADI_INPUT_PEAK		4096
275*4882a593Smuzhiyun #define HDSPM_MADI_PLAYBACK_PEAK	4352
276*4882a593Smuzhiyun #define HDSPM_MADI_OUTPUT_PEAK		4608
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun #define HDSPM_MADI_INPUT_RMS_L		6144
279*4882a593Smuzhiyun #define HDSPM_MADI_PLAYBACK_RMS_L	6400
280*4882a593Smuzhiyun #define HDSPM_MADI_OUTPUT_RMS_L		6656
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun #define HDSPM_MADI_INPUT_RMS_H		7168
283*4882a593Smuzhiyun #define HDSPM_MADI_PLAYBACK_RMS_H	7424
284*4882a593Smuzhiyun #define HDSPM_MADI_OUTPUT_RMS_H		7680
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun /* --- Control Register bits --------- */
287*4882a593Smuzhiyun #define HDSPM_Start                (1<<0) /* start engine */
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun #define HDSPM_Latency0             (1<<1) /* buffer size = 2^n */
290*4882a593Smuzhiyun #define HDSPM_Latency1             (1<<2) /* where n is defined */
291*4882a593Smuzhiyun #define HDSPM_Latency2             (1<<3) /* by Latency{2,1,0} */
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun #define HDSPM_ClockModeMaster      (1<<4) /* 1=Master, 0=Autosync */
294*4882a593Smuzhiyun #define HDSPM_c0Master		0x1    /* Master clock bit in settings
295*4882a593Smuzhiyun 					  register [RayDAT, AIO] */
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun #define HDSPM_AudioInterruptEnable (1<<5) /* what do you think ? */
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun #define HDSPM_Frequency0  (1<<6)  /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */
300*4882a593Smuzhiyun #define HDSPM_Frequency1  (1<<7)  /* 0=32kHz/64kHz */
301*4882a593Smuzhiyun #define HDSPM_DoubleSpeed (1<<8)  /* 0=normal speed, 1=double speed */
302*4882a593Smuzhiyun #define HDSPM_QuadSpeed   (1<<31) /* quad speed bit */
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun #define HDSPM_Professional (1<<9) /* Professional */ /* AES32 ONLY */
305*4882a593Smuzhiyun #define HDSPM_TX_64ch     (1<<10) /* Output 64channel MODE=1,
306*4882a593Smuzhiyun 				     56channelMODE=0 */ /* MADI ONLY*/
307*4882a593Smuzhiyun #define HDSPM_Emphasis    (1<<10) /* Emphasis */ /* AES32 ONLY */
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun #define HDSPM_AutoInp     (1<<11) /* Auto Input (takeover) == Safe Mode,
310*4882a593Smuzhiyun                                      0=off, 1=on  */ /* MADI ONLY */
311*4882a593Smuzhiyun #define HDSPM_Dolby       (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun #define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax
314*4882a593Smuzhiyun 				    * -- MADI ONLY
315*4882a593Smuzhiyun 				    */
316*4882a593Smuzhiyun #define HDSPM_InputSelect1 (1<<15) /* should be 0 */
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun #define HDSPM_SyncRef2     (1<<13)
319*4882a593Smuzhiyun #define HDSPM_SyncRef3     (1<<25)
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun #define HDSPM_SMUX         (1<<18) /* Frame ??? */ /* MADI ONY */
322*4882a593Smuzhiyun #define HDSPM_clr_tms      (1<<19) /* clear track marker, do not use
323*4882a593Smuzhiyun                                       AES additional bits in
324*4882a593Smuzhiyun 				      lower 5 Audiodatabits ??? */
325*4882a593Smuzhiyun #define HDSPM_taxi_reset   (1<<20) /* ??? */ /* MADI ONLY ? */
326*4882a593Smuzhiyun #define HDSPM_WCK48        (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun #define HDSPM_Midi0InterruptEnable 0x0400000
329*4882a593Smuzhiyun #define HDSPM_Midi1InterruptEnable 0x0800000
330*4882a593Smuzhiyun #define HDSPM_Midi2InterruptEnable 0x0200000
331*4882a593Smuzhiyun #define HDSPM_Midi3InterruptEnable 0x4000000
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun #define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */
334*4882a593Smuzhiyun #define HDSPe_FLOAT_FORMAT         0x2000000
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun #define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */
337*4882a593Smuzhiyun #define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */
338*4882a593Smuzhiyun #define HDSPM_QS_QuadWire   (1<<28) /* AES32 ONLY */
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun #define HDSPM_wclk_sel (1<<30)
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun /* additional control register bits for AIO*/
343*4882a593Smuzhiyun #define HDSPM_c0_Wck48				0x20 /* also RayDAT */
344*4882a593Smuzhiyun #define HDSPM_c0_Input0				0x1000
345*4882a593Smuzhiyun #define HDSPM_c0_Input1				0x2000
346*4882a593Smuzhiyun #define HDSPM_c0_Spdif_Opt			0x4000
347*4882a593Smuzhiyun #define HDSPM_c0_Pro				0x8000
348*4882a593Smuzhiyun #define HDSPM_c0_clr_tms			0x10000
349*4882a593Smuzhiyun #define HDSPM_c0_AEB1				0x20000
350*4882a593Smuzhiyun #define HDSPM_c0_AEB2				0x40000
351*4882a593Smuzhiyun #define HDSPM_c0_LineOut			0x80000
352*4882a593Smuzhiyun #define HDSPM_c0_AD_GAIN0			0x100000
353*4882a593Smuzhiyun #define HDSPM_c0_AD_GAIN1			0x200000
354*4882a593Smuzhiyun #define HDSPM_c0_DA_GAIN0			0x400000
355*4882a593Smuzhiyun #define HDSPM_c0_DA_GAIN1			0x800000
356*4882a593Smuzhiyun #define HDSPM_c0_PH_GAIN0			0x1000000
357*4882a593Smuzhiyun #define HDSPM_c0_PH_GAIN1			0x2000000
358*4882a593Smuzhiyun #define HDSPM_c0_Sym6db				0x4000000
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun /* --- bit helper defines */
362*4882a593Smuzhiyun #define HDSPM_LatencyMask    (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2)
363*4882a593Smuzhiyun #define HDSPM_FrequencyMask  (HDSPM_Frequency0|HDSPM_Frequency1|\
364*4882a593Smuzhiyun 			      HDSPM_DoubleSpeed|HDSPM_QuadSpeed)
365*4882a593Smuzhiyun #define HDSPM_InputMask      (HDSPM_InputSelect0|HDSPM_InputSelect1)
366*4882a593Smuzhiyun #define HDSPM_InputOptical   0
367*4882a593Smuzhiyun #define HDSPM_InputCoaxial   (HDSPM_InputSelect0)
368*4882a593Smuzhiyun #define HDSPM_SyncRefMask    (HDSPM_SyncRef0|HDSPM_SyncRef1|\
369*4882a593Smuzhiyun 			      HDSPM_SyncRef2|HDSPM_SyncRef3)
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun #define HDSPM_c0_SyncRef0      0x2
372*4882a593Smuzhiyun #define HDSPM_c0_SyncRef1      0x4
373*4882a593Smuzhiyun #define HDSPM_c0_SyncRef2      0x8
374*4882a593Smuzhiyun #define HDSPM_c0_SyncRef3      0x10
375*4882a593Smuzhiyun #define HDSPM_c0_SyncRefMask   (HDSPM_c0_SyncRef0 | HDSPM_c0_SyncRef1 |\
376*4882a593Smuzhiyun 				HDSPM_c0_SyncRef2 | HDSPM_c0_SyncRef3)
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun #define HDSPM_SYNC_FROM_WORD    0	/* Preferred sync reference */
379*4882a593Smuzhiyun #define HDSPM_SYNC_FROM_MADI    1	/* choices - used by "pref_sync_ref" */
380*4882a593Smuzhiyun #define HDSPM_SYNC_FROM_TCO     2
381*4882a593Smuzhiyun #define HDSPM_SYNC_FROM_SYNC_IN 3
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun #define HDSPM_Frequency32KHz    HDSPM_Frequency0
384*4882a593Smuzhiyun #define HDSPM_Frequency44_1KHz  HDSPM_Frequency1
385*4882a593Smuzhiyun #define HDSPM_Frequency48KHz   (HDSPM_Frequency1|HDSPM_Frequency0)
386*4882a593Smuzhiyun #define HDSPM_Frequency64KHz   (HDSPM_DoubleSpeed|HDSPM_Frequency0)
387*4882a593Smuzhiyun #define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1)
388*4882a593Smuzhiyun #define HDSPM_Frequency96KHz   (HDSPM_DoubleSpeed|HDSPM_Frequency1|\
389*4882a593Smuzhiyun 				HDSPM_Frequency0)
390*4882a593Smuzhiyun #define HDSPM_Frequency128KHz   (HDSPM_QuadSpeed|HDSPM_Frequency0)
391*4882a593Smuzhiyun #define HDSPM_Frequency176_4KHz   (HDSPM_QuadSpeed|HDSPM_Frequency1)
392*4882a593Smuzhiyun #define HDSPM_Frequency192KHz   (HDSPM_QuadSpeed|HDSPM_Frequency1|\
393*4882a593Smuzhiyun 				 HDSPM_Frequency0)
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun /* Synccheck Status */
397*4882a593Smuzhiyun #define HDSPM_SYNC_CHECK_NO_LOCK 0
398*4882a593Smuzhiyun #define HDSPM_SYNC_CHECK_LOCK    1
399*4882a593Smuzhiyun #define HDSPM_SYNC_CHECK_SYNC	 2
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun /* AutoSync References - used by "autosync_ref" control switch */
402*4882a593Smuzhiyun #define HDSPM_AUTOSYNC_FROM_WORD      0
403*4882a593Smuzhiyun #define HDSPM_AUTOSYNC_FROM_MADI      1
404*4882a593Smuzhiyun #define HDSPM_AUTOSYNC_FROM_TCO       2
405*4882a593Smuzhiyun #define HDSPM_AUTOSYNC_FROM_SYNC_IN   3
406*4882a593Smuzhiyun #define HDSPM_AUTOSYNC_FROM_NONE      4
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun /* Possible sources of MADI input */
409*4882a593Smuzhiyun #define HDSPM_OPTICAL 0		/* optical   */
410*4882a593Smuzhiyun #define HDSPM_COAXIAL 1		/* BNC */
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun #define hdspm_encode_latency(x)       (((x)<<1) & HDSPM_LatencyMask)
413*4882a593Smuzhiyun #define hdspm_decode_latency(x)       ((((x) & HDSPM_LatencyMask)>>1))
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun #define hdspm_encode_in(x) (((x)&0x3)<<14)
416*4882a593Smuzhiyun #define hdspm_decode_in(x) (((x)>>14)&0x3)
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun /* --- control2 register bits --- */
419*4882a593Smuzhiyun #define HDSPM_TMS             (1<<0)
420*4882a593Smuzhiyun #define HDSPM_TCK             (1<<1)
421*4882a593Smuzhiyun #define HDSPM_TDI             (1<<2)
422*4882a593Smuzhiyun #define HDSPM_JTAG            (1<<3)
423*4882a593Smuzhiyun #define HDSPM_PWDN            (1<<4)
424*4882a593Smuzhiyun #define HDSPM_PROGRAM	      (1<<5)
425*4882a593Smuzhiyun #define HDSPM_CONFIG_MODE_0   (1<<6)
426*4882a593Smuzhiyun #define HDSPM_CONFIG_MODE_1   (1<<7)
427*4882a593Smuzhiyun /*#define HDSPM_VERSION_BIT     (1<<8) not defined any more*/
428*4882a593Smuzhiyun #define HDSPM_BIGENDIAN_MODE  (1<<9)
429*4882a593Smuzhiyun #define HDSPM_RD_MULTIPLE     (1<<10)
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun /* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and
432*4882a593Smuzhiyun      that do not conflict with specific bits for AES32 seem to be valid also
433*4882a593Smuzhiyun      for the AES32
434*4882a593Smuzhiyun  */
435*4882a593Smuzhiyun #define HDSPM_audioIRQPending    (1<<0)	/* IRQ is high and pending */
436*4882a593Smuzhiyun #define HDSPM_RX_64ch            (1<<1)	/* Input 64chan. MODE=1, 56chn MODE=0 */
437*4882a593Smuzhiyun #define HDSPM_AB_int             (1<<2)	/* InputChannel Opt=0, Coax=1
438*4882a593Smuzhiyun 					 * (like inp0)
439*4882a593Smuzhiyun 					 */
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun #define HDSPM_madiLock           (1<<3)	/* MADI Locked =1, no=0 */
442*4882a593Smuzhiyun #define HDSPM_madiSync          (1<<18) /* MADI is in sync */
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun #define HDSPM_tcoLockMadi    0x00000020 /* Optional TCO locked status for HDSPe MADI*/
445*4882a593Smuzhiyun #define HDSPM_tcoSync    0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun #define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */
448*4882a593Smuzhiyun #define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */
451*4882a593Smuzhiyun 			/* since 64byte accurate, last 6 bits are not used */
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun #define HDSPM_DoubleSpeedStatus (1<<19) /* (input) card in double speed */
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun #define HDSPM_madiFreq0         (1<<22)	/* system freq 0=error */
458*4882a593Smuzhiyun #define HDSPM_madiFreq1         (1<<23)	/* 1=32, 2=44.1 3=48 */
459*4882a593Smuzhiyun #define HDSPM_madiFreq2         (1<<24)	/* 4=64, 5=88.2 6=96 */
460*4882a593Smuzhiyun #define HDSPM_madiFreq3         (1<<25)	/* 7=128, 8=176.4 9=192 */
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun #define HDSPM_BufferID          (1<<26)	/* (Double)Buffer ID toggles with
463*4882a593Smuzhiyun 					 * Interrupt
464*4882a593Smuzhiyun 					 */
465*4882a593Smuzhiyun #define HDSPM_tco_detect         0x08000000
466*4882a593Smuzhiyun #define HDSPM_tcoLockAes         0x20000000 /* Optional TCO locked status for HDSPe AES */
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun #define HDSPM_s2_tco_detect      0x00000040
469*4882a593Smuzhiyun #define HDSPM_s2_AEBO_D          0x00000080
470*4882a593Smuzhiyun #define HDSPM_s2_AEBI_D          0x00000100
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun #define HDSPM_midi0IRQPending    0x40000000
474*4882a593Smuzhiyun #define HDSPM_midi1IRQPending    0x80000000
475*4882a593Smuzhiyun #define HDSPM_midi2IRQPending    0x20000000
476*4882a593Smuzhiyun #define HDSPM_midi2IRQPendingAES 0x00000020
477*4882a593Smuzhiyun #define HDSPM_midi3IRQPending    0x00200000
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun /* --- status bit helpers */
480*4882a593Smuzhiyun #define HDSPM_madiFreqMask  (HDSPM_madiFreq0|HDSPM_madiFreq1|\
481*4882a593Smuzhiyun 			     HDSPM_madiFreq2|HDSPM_madiFreq3)
482*4882a593Smuzhiyun #define HDSPM_madiFreq32    (HDSPM_madiFreq0)
483*4882a593Smuzhiyun #define HDSPM_madiFreq44_1  (HDSPM_madiFreq1)
484*4882a593Smuzhiyun #define HDSPM_madiFreq48    (HDSPM_madiFreq0|HDSPM_madiFreq1)
485*4882a593Smuzhiyun #define HDSPM_madiFreq64    (HDSPM_madiFreq2)
486*4882a593Smuzhiyun #define HDSPM_madiFreq88_2  (HDSPM_madiFreq0|HDSPM_madiFreq2)
487*4882a593Smuzhiyun #define HDSPM_madiFreq96    (HDSPM_madiFreq1|HDSPM_madiFreq2)
488*4882a593Smuzhiyun #define HDSPM_madiFreq128   (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2)
489*4882a593Smuzhiyun #define HDSPM_madiFreq176_4 (HDSPM_madiFreq3)
490*4882a593Smuzhiyun #define HDSPM_madiFreq192   (HDSPM_madiFreq3|HDSPM_madiFreq0)
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun /* Status2 Register bits */ /* MADI ONLY */
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun #define HDSPM_version0 (1<<0)	/* not really defined but I guess */
495*4882a593Smuzhiyun #define HDSPM_version1 (1<<1)	/* in former cards it was ??? */
496*4882a593Smuzhiyun #define HDSPM_version2 (1<<2)
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun #define HDSPM_wcLock (1<<3)	/* Wordclock is detected and locked */
499*4882a593Smuzhiyun #define HDSPM_wcSync (1<<4)	/* Wordclock is in sync with systemclock */
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun #define HDSPM_wc_freq0 (1<<5)	/* input freq detected via autosync  */
502*4882a593Smuzhiyun #define HDSPM_wc_freq1 (1<<6)	/* 001=32, 010==44.1, 011=48, */
503*4882a593Smuzhiyun #define HDSPM_wc_freq2 (1<<7)	/* 100=64, 101=88.2, 110=96, 111=128 */
504*4882a593Smuzhiyun #define HDSPM_wc_freq3 0x800	/* 1000=176.4, 1001=192 */
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun #define HDSPM_SyncRef0 0x10000  /* Sync Reference */
507*4882a593Smuzhiyun #define HDSPM_SyncRef1 0x20000
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun #define HDSPM_SelSyncRef0 (1<<8)	/* AutoSync Source */
510*4882a593Smuzhiyun #define HDSPM_SelSyncRef1 (1<<9)	/* 000=word, 001=MADI, */
511*4882a593Smuzhiyun #define HDSPM_SelSyncRef2 (1<<10)	/* 111=no valid signal */
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun #define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync)
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun #define HDSPM_wcFreqMask  (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2|\
516*4882a593Smuzhiyun 			    HDSPM_wc_freq3)
517*4882a593Smuzhiyun #define HDSPM_wcFreq32    (HDSPM_wc_freq0)
518*4882a593Smuzhiyun #define HDSPM_wcFreq44_1  (HDSPM_wc_freq1)
519*4882a593Smuzhiyun #define HDSPM_wcFreq48    (HDSPM_wc_freq0|HDSPM_wc_freq1)
520*4882a593Smuzhiyun #define HDSPM_wcFreq64    (HDSPM_wc_freq2)
521*4882a593Smuzhiyun #define HDSPM_wcFreq88_2  (HDSPM_wc_freq0|HDSPM_wc_freq2)
522*4882a593Smuzhiyun #define HDSPM_wcFreq96    (HDSPM_wc_freq1|HDSPM_wc_freq2)
523*4882a593Smuzhiyun #define HDSPM_wcFreq128   (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2)
524*4882a593Smuzhiyun #define HDSPM_wcFreq176_4 (HDSPM_wc_freq3)
525*4882a593Smuzhiyun #define HDSPM_wcFreq192   (HDSPM_wc_freq0|HDSPM_wc_freq3)
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun #define HDSPM_status1_F_0 0x0400000
528*4882a593Smuzhiyun #define HDSPM_status1_F_1 0x0800000
529*4882a593Smuzhiyun #define HDSPM_status1_F_2 0x1000000
530*4882a593Smuzhiyun #define HDSPM_status1_F_3 0x2000000
531*4882a593Smuzhiyun #define HDSPM_status1_freqMask (HDSPM_status1_F_0|HDSPM_status1_F_1|HDSPM_status1_F_2|HDSPM_status1_F_3)
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun #define HDSPM_SelSyncRefMask       (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\
535*4882a593Smuzhiyun 				    HDSPM_SelSyncRef2)
536*4882a593Smuzhiyun #define HDSPM_SelSyncRef_WORD      0
537*4882a593Smuzhiyun #define HDSPM_SelSyncRef_MADI      (HDSPM_SelSyncRef0)
538*4882a593Smuzhiyun #define HDSPM_SelSyncRef_TCO       (HDSPM_SelSyncRef1)
539*4882a593Smuzhiyun #define HDSPM_SelSyncRef_SyncIn    (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1)
540*4882a593Smuzhiyun #define HDSPM_SelSyncRef_NVALID    (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\
541*4882a593Smuzhiyun 				    HDSPM_SelSyncRef2)
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun /*
544*4882a593Smuzhiyun    For AES32, bits for status, status2 and timecode are different
545*4882a593Smuzhiyun */
546*4882a593Smuzhiyun /* status */
547*4882a593Smuzhiyun #define HDSPM_AES32_wcLock	0x0200000
548*4882a593Smuzhiyun #define HDSPM_AES32_wcSync	0x0100000
549*4882a593Smuzhiyun #define HDSPM_AES32_wcFreq_bit  22
550*4882a593Smuzhiyun /* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function
551*4882a593Smuzhiyun   HDSPM_bit2freq */
552*4882a593Smuzhiyun #define HDSPM_AES32_syncref_bit  16
553*4882a593Smuzhiyun /* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_WORD 0
556*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_AES1 1
557*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_AES2 2
558*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_AES3 3
559*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_AES4 4
560*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_AES5 5
561*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6
562*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7
563*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8
564*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_TCO 9
565*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10
566*4882a593Smuzhiyun #define HDSPM_AES32_AUTOSYNC_FROM_NONE 11
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun /*  status2 */
569*4882a593Smuzhiyun /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */
570*4882a593Smuzhiyun #define HDSPM_LockAES   0x80
571*4882a593Smuzhiyun #define HDSPM_LockAES1  0x80
572*4882a593Smuzhiyun #define HDSPM_LockAES2  0x40
573*4882a593Smuzhiyun #define HDSPM_LockAES3  0x20
574*4882a593Smuzhiyun #define HDSPM_LockAES4  0x10
575*4882a593Smuzhiyun #define HDSPM_LockAES5  0x8
576*4882a593Smuzhiyun #define HDSPM_LockAES6  0x4
577*4882a593Smuzhiyun #define HDSPM_LockAES7  0x2
578*4882a593Smuzhiyun #define HDSPM_LockAES8  0x1
579*4882a593Smuzhiyun /*
580*4882a593Smuzhiyun    Timecode
581*4882a593Smuzhiyun    After windows driver sources, bits 4*i to 4*i+3 give the input frequency on
582*4882a593Smuzhiyun    AES i+1
583*4882a593Smuzhiyun  bits 3210
584*4882a593Smuzhiyun       0001  32kHz
585*4882a593Smuzhiyun       0010  44.1kHz
586*4882a593Smuzhiyun       0011  48kHz
587*4882a593Smuzhiyun       0100  64kHz
588*4882a593Smuzhiyun       0101  88.2kHz
589*4882a593Smuzhiyun       0110  96kHz
590*4882a593Smuzhiyun       0111  128kHz
591*4882a593Smuzhiyun       1000  176.4kHz
592*4882a593Smuzhiyun       1001  192kHz
593*4882a593Smuzhiyun   NB: Timecode register doesn't seem to work on AES32 card revision 230
594*4882a593Smuzhiyun */
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun /* Mixer Values */
597*4882a593Smuzhiyun #define UNITY_GAIN          32768	/* = 65536/2 */
598*4882a593Smuzhiyun #define MINUS_INFINITY_GAIN 0
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun /* Number of channels for different Speed Modes */
601*4882a593Smuzhiyun #define MADI_SS_CHANNELS       64
602*4882a593Smuzhiyun #define MADI_DS_CHANNELS       32
603*4882a593Smuzhiyun #define MADI_QS_CHANNELS       16
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun #define RAYDAT_SS_CHANNELS     36
606*4882a593Smuzhiyun #define RAYDAT_DS_CHANNELS     20
607*4882a593Smuzhiyun #define RAYDAT_QS_CHANNELS     12
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun #define AIO_IN_SS_CHANNELS        14
610*4882a593Smuzhiyun #define AIO_IN_DS_CHANNELS        10
611*4882a593Smuzhiyun #define AIO_IN_QS_CHANNELS        8
612*4882a593Smuzhiyun #define AIO_OUT_SS_CHANNELS        16
613*4882a593Smuzhiyun #define AIO_OUT_DS_CHANNELS        12
614*4882a593Smuzhiyun #define AIO_OUT_QS_CHANNELS        10
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun #define AES32_CHANNELS		16
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun /* the size of a substream (1 mono data stream) */
619*4882a593Smuzhiyun #define HDSPM_CHANNEL_BUFFER_SAMPLES  (16*1024)
620*4882a593Smuzhiyun #define HDSPM_CHANNEL_BUFFER_BYTES    (4*HDSPM_CHANNEL_BUFFER_SAMPLES)
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun /* the size of the area we need to allocate for DMA transfers. the
623*4882a593Smuzhiyun    size is the same regardless of the number of channels, and
624*4882a593Smuzhiyun    also the latency to use.
625*4882a593Smuzhiyun    for one direction !!!
626*4882a593Smuzhiyun */
627*4882a593Smuzhiyun #define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
628*4882a593Smuzhiyun #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024)
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun #define HDSPM_RAYDAT_REV	211
631*4882a593Smuzhiyun #define HDSPM_AIO_REV		212
632*4882a593Smuzhiyun #define HDSPM_MADIFACE_REV	213
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun /* speed factor modes */
635*4882a593Smuzhiyun #define HDSPM_SPEED_SINGLE 0
636*4882a593Smuzhiyun #define HDSPM_SPEED_DOUBLE 1
637*4882a593Smuzhiyun #define HDSPM_SPEED_QUAD   2
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun /* names for speed modes */
640*4882a593Smuzhiyun static const char * const hdspm_speed_names[] = { "single", "double", "quad" };
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun static const char *const texts_autosync_aes_tco[] = { "Word Clock",
643*4882a593Smuzhiyun 					  "AES1", "AES2", "AES3", "AES4",
644*4882a593Smuzhiyun 					  "AES5", "AES6", "AES7", "AES8",
645*4882a593Smuzhiyun 					  "TCO", "Sync In"
646*4882a593Smuzhiyun };
647*4882a593Smuzhiyun static const char *const texts_autosync_aes[] = { "Word Clock",
648*4882a593Smuzhiyun 				      "AES1", "AES2", "AES3", "AES4",
649*4882a593Smuzhiyun 				      "AES5", "AES6", "AES7", "AES8",
650*4882a593Smuzhiyun 				      "Sync In"
651*4882a593Smuzhiyun };
652*4882a593Smuzhiyun static const char *const texts_autosync_madi_tco[] = { "Word Clock",
653*4882a593Smuzhiyun 					   "MADI", "TCO", "Sync In" };
654*4882a593Smuzhiyun static const char *const texts_autosync_madi[] = { "Word Clock",
655*4882a593Smuzhiyun 				       "MADI", "Sync In" };
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun static const char *const texts_autosync_raydat_tco[] = {
658*4882a593Smuzhiyun 	"Word Clock",
659*4882a593Smuzhiyun 	"ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
660*4882a593Smuzhiyun 	"AES", "SPDIF", "TCO", "Sync In"
661*4882a593Smuzhiyun };
662*4882a593Smuzhiyun static const char *const texts_autosync_raydat[] = {
663*4882a593Smuzhiyun 	"Word Clock",
664*4882a593Smuzhiyun 	"ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
665*4882a593Smuzhiyun 	"AES", "SPDIF", "Sync In"
666*4882a593Smuzhiyun };
667*4882a593Smuzhiyun static const char *const texts_autosync_aio_tco[] = {
668*4882a593Smuzhiyun 	"Word Clock",
669*4882a593Smuzhiyun 	"ADAT", "AES", "SPDIF", "TCO", "Sync In"
670*4882a593Smuzhiyun };
671*4882a593Smuzhiyun static const char *const texts_autosync_aio[] = { "Word Clock",
672*4882a593Smuzhiyun 				      "ADAT", "AES", "SPDIF", "Sync In" };
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun static const char *const texts_freq[] = {
675*4882a593Smuzhiyun 	"No Lock",
676*4882a593Smuzhiyun 	"32 kHz",
677*4882a593Smuzhiyun 	"44.1 kHz",
678*4882a593Smuzhiyun 	"48 kHz",
679*4882a593Smuzhiyun 	"64 kHz",
680*4882a593Smuzhiyun 	"88.2 kHz",
681*4882a593Smuzhiyun 	"96 kHz",
682*4882a593Smuzhiyun 	"128 kHz",
683*4882a593Smuzhiyun 	"176.4 kHz",
684*4882a593Smuzhiyun 	"192 kHz"
685*4882a593Smuzhiyun };
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun static const char * const texts_ports_madi[] = {
688*4882a593Smuzhiyun 	"MADI.1", "MADI.2", "MADI.3", "MADI.4", "MADI.5", "MADI.6",
689*4882a593Smuzhiyun 	"MADI.7", "MADI.8", "MADI.9", "MADI.10", "MADI.11", "MADI.12",
690*4882a593Smuzhiyun 	"MADI.13", "MADI.14", "MADI.15", "MADI.16", "MADI.17", "MADI.18",
691*4882a593Smuzhiyun 	"MADI.19", "MADI.20", "MADI.21", "MADI.22", "MADI.23", "MADI.24",
692*4882a593Smuzhiyun 	"MADI.25", "MADI.26", "MADI.27", "MADI.28", "MADI.29", "MADI.30",
693*4882a593Smuzhiyun 	"MADI.31", "MADI.32", "MADI.33", "MADI.34", "MADI.35", "MADI.36",
694*4882a593Smuzhiyun 	"MADI.37", "MADI.38", "MADI.39", "MADI.40", "MADI.41", "MADI.42",
695*4882a593Smuzhiyun 	"MADI.43", "MADI.44", "MADI.45", "MADI.46", "MADI.47", "MADI.48",
696*4882a593Smuzhiyun 	"MADI.49", "MADI.50", "MADI.51", "MADI.52", "MADI.53", "MADI.54",
697*4882a593Smuzhiyun 	"MADI.55", "MADI.56", "MADI.57", "MADI.58", "MADI.59", "MADI.60",
698*4882a593Smuzhiyun 	"MADI.61", "MADI.62", "MADI.63", "MADI.64",
699*4882a593Smuzhiyun };
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun static const char * const texts_ports_raydat_ss[] = {
703*4882a593Smuzhiyun 	"ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4", "ADAT1.5", "ADAT1.6",
704*4882a593Smuzhiyun 	"ADAT1.7", "ADAT1.8", "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4",
705*4882a593Smuzhiyun 	"ADAT2.5", "ADAT2.6", "ADAT2.7", "ADAT2.8", "ADAT3.1", "ADAT3.2",
706*4882a593Smuzhiyun 	"ADAT3.3", "ADAT3.4", "ADAT3.5", "ADAT3.6", "ADAT3.7", "ADAT3.8",
707*4882a593Smuzhiyun 	"ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4", "ADAT4.5", "ADAT4.6",
708*4882a593Smuzhiyun 	"ADAT4.7", "ADAT4.8",
709*4882a593Smuzhiyun 	"AES.L", "AES.R",
710*4882a593Smuzhiyun 	"SPDIF.L", "SPDIF.R"
711*4882a593Smuzhiyun };
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun static const char * const texts_ports_raydat_ds[] = {
714*4882a593Smuzhiyun 	"ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4",
715*4882a593Smuzhiyun 	"ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4",
716*4882a593Smuzhiyun 	"ADAT3.1", "ADAT3.2", "ADAT3.3", "ADAT3.4",
717*4882a593Smuzhiyun 	"ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4",
718*4882a593Smuzhiyun 	"AES.L", "AES.R",
719*4882a593Smuzhiyun 	"SPDIF.L", "SPDIF.R"
720*4882a593Smuzhiyun };
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun static const char * const texts_ports_raydat_qs[] = {
723*4882a593Smuzhiyun 	"ADAT1.1", "ADAT1.2",
724*4882a593Smuzhiyun 	"ADAT2.1", "ADAT2.2",
725*4882a593Smuzhiyun 	"ADAT3.1", "ADAT3.2",
726*4882a593Smuzhiyun 	"ADAT4.1", "ADAT4.2",
727*4882a593Smuzhiyun 	"AES.L", "AES.R",
728*4882a593Smuzhiyun 	"SPDIF.L", "SPDIF.R"
729*4882a593Smuzhiyun };
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun static const char * const texts_ports_aio_in_ss[] = {
733*4882a593Smuzhiyun 	"Analogue.L", "Analogue.R",
734*4882a593Smuzhiyun 	"AES.L", "AES.R",
735*4882a593Smuzhiyun 	"SPDIF.L", "SPDIF.R",
736*4882a593Smuzhiyun 	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
737*4882a593Smuzhiyun 	"ADAT.7", "ADAT.8",
738*4882a593Smuzhiyun 	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
739*4882a593Smuzhiyun };
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun static const char * const texts_ports_aio_out_ss[] = {
742*4882a593Smuzhiyun 	"Analogue.L", "Analogue.R",
743*4882a593Smuzhiyun 	"AES.L", "AES.R",
744*4882a593Smuzhiyun 	"SPDIF.L", "SPDIF.R",
745*4882a593Smuzhiyun 	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
746*4882a593Smuzhiyun 	"ADAT.7", "ADAT.8",
747*4882a593Smuzhiyun 	"Phone.L", "Phone.R",
748*4882a593Smuzhiyun 	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
749*4882a593Smuzhiyun };
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun static const char * const texts_ports_aio_in_ds[] = {
752*4882a593Smuzhiyun 	"Analogue.L", "Analogue.R",
753*4882a593Smuzhiyun 	"AES.L", "AES.R",
754*4882a593Smuzhiyun 	"SPDIF.L", "SPDIF.R",
755*4882a593Smuzhiyun 	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
756*4882a593Smuzhiyun 	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
757*4882a593Smuzhiyun };
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun static const char * const texts_ports_aio_out_ds[] = {
760*4882a593Smuzhiyun 	"Analogue.L", "Analogue.R",
761*4882a593Smuzhiyun 	"AES.L", "AES.R",
762*4882a593Smuzhiyun 	"SPDIF.L", "SPDIF.R",
763*4882a593Smuzhiyun 	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
764*4882a593Smuzhiyun 	"Phone.L", "Phone.R",
765*4882a593Smuzhiyun 	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
766*4882a593Smuzhiyun };
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun static const char * const texts_ports_aio_in_qs[] = {
769*4882a593Smuzhiyun 	"Analogue.L", "Analogue.R",
770*4882a593Smuzhiyun 	"AES.L", "AES.R",
771*4882a593Smuzhiyun 	"SPDIF.L", "SPDIF.R",
772*4882a593Smuzhiyun 	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
773*4882a593Smuzhiyun 	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
774*4882a593Smuzhiyun };
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun static const char * const texts_ports_aio_out_qs[] = {
777*4882a593Smuzhiyun 	"Analogue.L", "Analogue.R",
778*4882a593Smuzhiyun 	"AES.L", "AES.R",
779*4882a593Smuzhiyun 	"SPDIF.L", "SPDIF.R",
780*4882a593Smuzhiyun 	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
781*4882a593Smuzhiyun 	"Phone.L", "Phone.R",
782*4882a593Smuzhiyun 	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
783*4882a593Smuzhiyun };
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun static const char * const texts_ports_aes32[] = {
786*4882a593Smuzhiyun 	"AES.1", "AES.2", "AES.3", "AES.4", "AES.5", "AES.6", "AES.7",
787*4882a593Smuzhiyun 	"AES.8", "AES.9.", "AES.10", "AES.11", "AES.12", "AES.13", "AES.14",
788*4882a593Smuzhiyun 	"AES.15", "AES.16"
789*4882a593Smuzhiyun };
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun /* These tables map the ALSA channels 1..N to the channels that we
792*4882a593Smuzhiyun    need to use in order to find the relevant channel buffer. RME
793*4882a593Smuzhiyun    refers to this kind of mapping as between "the ADAT channel and
794*4882a593Smuzhiyun    the DMA channel." We index it using the logical audio channel,
795*4882a593Smuzhiyun    and the value is the DMA channel (i.e. channel buffer number)
796*4882a593Smuzhiyun    where the data for that channel can be read/written from/to.
797*4882a593Smuzhiyun */
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun static const char channel_map_unity_ss[HDSPM_MAX_CHANNELS] = {
800*4882a593Smuzhiyun 	0, 1, 2, 3, 4, 5, 6, 7,
801*4882a593Smuzhiyun 	8, 9, 10, 11, 12, 13, 14, 15,
802*4882a593Smuzhiyun 	16, 17, 18, 19, 20, 21, 22, 23,
803*4882a593Smuzhiyun 	24, 25, 26, 27, 28, 29, 30, 31,
804*4882a593Smuzhiyun 	32, 33, 34, 35, 36, 37, 38, 39,
805*4882a593Smuzhiyun 	40, 41, 42, 43, 44, 45, 46, 47,
806*4882a593Smuzhiyun 	48, 49, 50, 51, 52, 53, 54, 55,
807*4882a593Smuzhiyun 	56, 57, 58, 59, 60, 61, 62, 63
808*4882a593Smuzhiyun };
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun static const char channel_map_raydat_ss[HDSPM_MAX_CHANNELS] = {
811*4882a593Smuzhiyun 	4, 5, 6, 7, 8, 9, 10, 11,	/* ADAT 1 */
812*4882a593Smuzhiyun 	12, 13, 14, 15, 16, 17, 18, 19,	/* ADAT 2 */
813*4882a593Smuzhiyun 	20, 21, 22, 23, 24, 25, 26, 27,	/* ADAT 3 */
814*4882a593Smuzhiyun 	28, 29, 30, 31, 32, 33, 34, 35,	/* ADAT 4 */
815*4882a593Smuzhiyun 	0, 1,			/* AES */
816*4882a593Smuzhiyun 	2, 3,			/* SPDIF */
817*4882a593Smuzhiyun 	-1, -1, -1, -1,
818*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
819*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
820*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
821*4882a593Smuzhiyun };
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun static const char channel_map_raydat_ds[HDSPM_MAX_CHANNELS] = {
824*4882a593Smuzhiyun 	4, 5, 6, 7,		/* ADAT 1 */
825*4882a593Smuzhiyun 	8, 9, 10, 11,		/* ADAT 2 */
826*4882a593Smuzhiyun 	12, 13, 14, 15,		/* ADAT 3 */
827*4882a593Smuzhiyun 	16, 17, 18, 19,		/* ADAT 4 */
828*4882a593Smuzhiyun 	0, 1,			/* AES */
829*4882a593Smuzhiyun 	2, 3,			/* SPDIF */
830*4882a593Smuzhiyun 	-1, -1, -1, -1,
831*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
832*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
833*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
834*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
835*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
836*4882a593Smuzhiyun };
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun static const char channel_map_raydat_qs[HDSPM_MAX_CHANNELS] = {
839*4882a593Smuzhiyun 	4, 5,			/* ADAT 1 */
840*4882a593Smuzhiyun 	6, 7,			/* ADAT 2 */
841*4882a593Smuzhiyun 	8, 9,			/* ADAT 3 */
842*4882a593Smuzhiyun 	10, 11,			/* ADAT 4 */
843*4882a593Smuzhiyun 	0, 1,			/* AES */
844*4882a593Smuzhiyun 	2, 3,			/* SPDIF */
845*4882a593Smuzhiyun 	-1, -1, -1, -1,
846*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
847*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
848*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
849*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
850*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
851*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
852*4882a593Smuzhiyun };
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun static const char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = {
855*4882a593Smuzhiyun 	0, 1,			/* line in */
856*4882a593Smuzhiyun 	8, 9,			/* aes in, */
857*4882a593Smuzhiyun 	10, 11,			/* spdif in */
858*4882a593Smuzhiyun 	12, 13, 14, 15, 16, 17, 18, 19,	/* ADAT in */
859*4882a593Smuzhiyun 	2, 3, 4, 5,		/* AEB */
860*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1,
861*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
862*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
863*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
864*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
865*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
866*4882a593Smuzhiyun };
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun static const char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = {
869*4882a593Smuzhiyun 	0, 1,			/* line out */
870*4882a593Smuzhiyun 	8, 9,			/* aes out */
871*4882a593Smuzhiyun 	10, 11,			/* spdif out */
872*4882a593Smuzhiyun 	12, 13, 14, 15, 16, 17, 18, 19,	/* ADAT out */
873*4882a593Smuzhiyun 	6, 7,			/* phone out */
874*4882a593Smuzhiyun 	2, 3, 4, 5,		/* AEB */
875*4882a593Smuzhiyun 	-1, -1, -1, -1,
876*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
877*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
878*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
879*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
880*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
881*4882a593Smuzhiyun };
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun static const char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = {
884*4882a593Smuzhiyun 	0, 1,			/* line in */
885*4882a593Smuzhiyun 	8, 9,			/* aes in */
886*4882a593Smuzhiyun 	10, 11,			/* spdif in */
887*4882a593Smuzhiyun 	12, 14, 16, 18,		/* adat in */
888*4882a593Smuzhiyun 	2, 3, 4, 5,		/* AEB */
889*4882a593Smuzhiyun 	-1, -1,
890*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
891*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
892*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
893*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
894*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
895*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1
896*4882a593Smuzhiyun };
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun static const char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = {
899*4882a593Smuzhiyun 	0, 1,			/* line out */
900*4882a593Smuzhiyun 	8, 9,			/* aes out */
901*4882a593Smuzhiyun 	10, 11,			/* spdif out */
902*4882a593Smuzhiyun 	12, 14, 16, 18,		/* adat out */
903*4882a593Smuzhiyun 	6, 7,			/* phone out */
904*4882a593Smuzhiyun 	2, 3, 4, 5,		/* AEB */
905*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
906*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
907*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
908*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
909*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
910*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1
911*4882a593Smuzhiyun };
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun static const char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = {
914*4882a593Smuzhiyun 	0, 1,			/* line in */
915*4882a593Smuzhiyun 	8, 9,			/* aes in */
916*4882a593Smuzhiyun 	10, 11,			/* spdif in */
917*4882a593Smuzhiyun 	12, 16,			/* adat in */
918*4882a593Smuzhiyun 	2, 3, 4, 5,		/* AEB */
919*4882a593Smuzhiyun 	-1, -1, -1, -1,
920*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
921*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
922*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
923*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
924*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
925*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1
926*4882a593Smuzhiyun };
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun static const char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = {
929*4882a593Smuzhiyun 	0, 1,			/* line out */
930*4882a593Smuzhiyun 	8, 9,			/* aes out */
931*4882a593Smuzhiyun 	10, 11,			/* spdif out */
932*4882a593Smuzhiyun 	12, 16,			/* adat out */
933*4882a593Smuzhiyun 	6, 7,			/* phone out */
934*4882a593Smuzhiyun 	2, 3, 4, 5,		/* AEB */
935*4882a593Smuzhiyun 	-1, -1,
936*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
937*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
938*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
939*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
940*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
941*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1
942*4882a593Smuzhiyun };
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun static const char channel_map_aes32[HDSPM_MAX_CHANNELS] = {
945*4882a593Smuzhiyun 	0, 1, 2, 3, 4, 5, 6, 7,
946*4882a593Smuzhiyun 	8, 9, 10, 11, 12, 13, 14, 15,
947*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
948*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
949*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
950*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
951*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1,
952*4882a593Smuzhiyun 	-1, -1, -1, -1, -1, -1, -1, -1
953*4882a593Smuzhiyun };
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun struct hdspm_midi {
956*4882a593Smuzhiyun 	struct hdspm *hdspm;
957*4882a593Smuzhiyun 	int id;
958*4882a593Smuzhiyun 	struct snd_rawmidi *rmidi;
959*4882a593Smuzhiyun 	struct snd_rawmidi_substream *input;
960*4882a593Smuzhiyun 	struct snd_rawmidi_substream *output;
961*4882a593Smuzhiyun 	char istimer;		/* timer in use */
962*4882a593Smuzhiyun 	struct timer_list timer;
963*4882a593Smuzhiyun 	spinlock_t lock;
964*4882a593Smuzhiyun 	int pending;
965*4882a593Smuzhiyun 	int dataIn;
966*4882a593Smuzhiyun 	int statusIn;
967*4882a593Smuzhiyun 	int dataOut;
968*4882a593Smuzhiyun 	int statusOut;
969*4882a593Smuzhiyun 	int ie;
970*4882a593Smuzhiyun 	int irq;
971*4882a593Smuzhiyun };
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun struct hdspm_tco {
974*4882a593Smuzhiyun 	int input; /* 0: LTC, 1:Video, 2: WC*/
975*4882a593Smuzhiyun 	int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */
976*4882a593Smuzhiyun 	int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */
977*4882a593Smuzhiyun 	int samplerate; /* 0=44.1, 1=48, 2= freq from app */
978*4882a593Smuzhiyun 	int pull; /*   0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/
979*4882a593Smuzhiyun 	int term; /* 0 = off, 1 = on */
980*4882a593Smuzhiyun };
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun struct hdspm {
983*4882a593Smuzhiyun         spinlock_t lock;
984*4882a593Smuzhiyun 	/* only one playback and/or capture stream */
985*4882a593Smuzhiyun         struct snd_pcm_substream *capture_substream;
986*4882a593Smuzhiyun         struct snd_pcm_substream *playback_substream;
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 	char *card_name;	     /* for procinfo */
989*4882a593Smuzhiyun 	unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun 	uint8_t io_type;
992*4882a593Smuzhiyun 
993*4882a593Smuzhiyun 	int monitor_outs;	/* set up monitoring outs init flag */
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 	u32 control_register;	/* cached value */
996*4882a593Smuzhiyun 	u32 control2_register;	/* cached value */
997*4882a593Smuzhiyun 	u32 settings_register;  /* cached value for AIO / RayDat (sync reference, master/slave) */
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	struct hdspm_midi midi[4];
1000*4882a593Smuzhiyun 	struct work_struct midi_work;
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	size_t period_bytes;
1003*4882a593Smuzhiyun 	unsigned char ss_in_channels;
1004*4882a593Smuzhiyun 	unsigned char ds_in_channels;
1005*4882a593Smuzhiyun 	unsigned char qs_in_channels;
1006*4882a593Smuzhiyun 	unsigned char ss_out_channels;
1007*4882a593Smuzhiyun 	unsigned char ds_out_channels;
1008*4882a593Smuzhiyun 	unsigned char qs_out_channels;
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	unsigned char max_channels_in;
1011*4882a593Smuzhiyun 	unsigned char max_channels_out;
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun 	const signed char *channel_map_in;
1014*4882a593Smuzhiyun 	const signed char *channel_map_out;
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	const signed char *channel_map_in_ss, *channel_map_in_ds, *channel_map_in_qs;
1017*4882a593Smuzhiyun 	const signed char *channel_map_out_ss, *channel_map_out_ds, *channel_map_out_qs;
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun 	const char * const *port_names_in;
1020*4882a593Smuzhiyun 	const char * const *port_names_out;
1021*4882a593Smuzhiyun 
1022*4882a593Smuzhiyun 	const char * const *port_names_in_ss;
1023*4882a593Smuzhiyun 	const char * const *port_names_in_ds;
1024*4882a593Smuzhiyun 	const char * const *port_names_in_qs;
1025*4882a593Smuzhiyun 	const char * const *port_names_out_ss;
1026*4882a593Smuzhiyun 	const char * const *port_names_out_ds;
1027*4882a593Smuzhiyun 	const char * const *port_names_out_qs;
1028*4882a593Smuzhiyun 
1029*4882a593Smuzhiyun 	unsigned char *playback_buffer;	/* suitably aligned address */
1030*4882a593Smuzhiyun 	unsigned char *capture_buffer;	/* suitably aligned address */
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 	pid_t capture_pid;	/* process id which uses capture */
1033*4882a593Smuzhiyun 	pid_t playback_pid;	/* process id which uses capture */
1034*4882a593Smuzhiyun 	int running;		/* running status */
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	int last_external_sample_rate;	/* samplerate mystic ... */
1037*4882a593Smuzhiyun 	int last_internal_sample_rate;
1038*4882a593Smuzhiyun 	int system_sample_rate;
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun 	int dev;		/* Hardware vars... */
1041*4882a593Smuzhiyun 	int irq;
1042*4882a593Smuzhiyun 	unsigned long port;
1043*4882a593Smuzhiyun 	void __iomem *iobase;
1044*4882a593Smuzhiyun 
1045*4882a593Smuzhiyun 	int irq_count;		/* for debug */
1046*4882a593Smuzhiyun 	int midiPorts;
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	struct snd_card *card;	/* one card */
1049*4882a593Smuzhiyun 	struct snd_pcm *pcm;		/* has one pcm */
1050*4882a593Smuzhiyun 	struct snd_hwdep *hwdep;	/* and a hwdep for additional ioctl */
1051*4882a593Smuzhiyun 	struct pci_dev *pci;	/* and an pci info */
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun 	/* Mixer vars */
1054*4882a593Smuzhiyun 	/* fast alsa mixer */
1055*4882a593Smuzhiyun 	struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS];
1056*4882a593Smuzhiyun 	/* but input to much, so not used */
1057*4882a593Smuzhiyun 	struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS];
1058*4882a593Smuzhiyun 	/* full mixer accessible over mixer ioctl or hwdep-device */
1059*4882a593Smuzhiyun 	struct hdspm_mixer *mixer;
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun 	struct hdspm_tco *tco;  /* NULL if no TCO detected */
1062*4882a593Smuzhiyun 
1063*4882a593Smuzhiyun 	const char *const *texts_autosync;
1064*4882a593Smuzhiyun 	int texts_autosync_items;
1065*4882a593Smuzhiyun 
1066*4882a593Smuzhiyun 	cycles_t last_interrupt;
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	unsigned int serial;
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	struct hdspm_peak_rms peak_rms;
1071*4882a593Smuzhiyun };
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun static const struct pci_device_id snd_hdspm_ids[] = {
1075*4882a593Smuzhiyun 	{
1076*4882a593Smuzhiyun 	 .vendor = PCI_VENDOR_ID_XILINX,
1077*4882a593Smuzhiyun 	 .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI,
1078*4882a593Smuzhiyun 	 .subvendor = PCI_ANY_ID,
1079*4882a593Smuzhiyun 	 .subdevice = PCI_ANY_ID,
1080*4882a593Smuzhiyun 	 .class = 0,
1081*4882a593Smuzhiyun 	 .class_mask = 0,
1082*4882a593Smuzhiyun 	 .driver_data = 0},
1083*4882a593Smuzhiyun 	{0,}
1084*4882a593Smuzhiyun };
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, snd_hdspm_ids);
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun /* prototypes */
1089*4882a593Smuzhiyun static int snd_hdspm_create_alsa_devices(struct snd_card *card,
1090*4882a593Smuzhiyun 					 struct hdspm *hdspm);
1091*4882a593Smuzhiyun static int snd_hdspm_create_pcm(struct snd_card *card,
1092*4882a593Smuzhiyun 				struct hdspm *hdspm);
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm);
1095*4882a593Smuzhiyun static inline int hdspm_get_pll_freq(struct hdspm *hdspm);
1096*4882a593Smuzhiyun static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm);
1097*4882a593Smuzhiyun static int hdspm_autosync_ref(struct hdspm *hdspm);
1098*4882a593Smuzhiyun static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out);
1099*4882a593Smuzhiyun static int snd_hdspm_set_defaults(struct hdspm *hdspm);
1100*4882a593Smuzhiyun static int hdspm_system_clock_mode(struct hdspm *hdspm);
1101*4882a593Smuzhiyun static void hdspm_set_channel_dma_addr(struct hdspm *hdspm,
1102*4882a593Smuzhiyun 				       struct snd_pcm_substream *substream,
1103*4882a593Smuzhiyun 				       unsigned int reg, int channels);
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx);
1106*4882a593Smuzhiyun static int hdspm_wc_sync_check(struct hdspm *hdspm);
1107*4882a593Smuzhiyun static int hdspm_tco_sync_check(struct hdspm *hdspm);
1108*4882a593Smuzhiyun static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index);
1111*4882a593Smuzhiyun static int hdspm_get_tco_sample_rate(struct hdspm *hdspm);
1112*4882a593Smuzhiyun static int hdspm_get_wc_sample_rate(struct hdspm *hdspm);
1113*4882a593Smuzhiyun 
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 
HDSPM_bit2freq(int n)1116*4882a593Smuzhiyun static inline int HDSPM_bit2freq(int n)
1117*4882a593Smuzhiyun {
1118*4882a593Smuzhiyun 	static const int bit2freq_tab[] = {
1119*4882a593Smuzhiyun 		0, 32000, 44100, 48000, 64000, 88200,
1120*4882a593Smuzhiyun 		96000, 128000, 176400, 192000 };
1121*4882a593Smuzhiyun 	if (n < 1 || n > 9)
1122*4882a593Smuzhiyun 		return 0;
1123*4882a593Smuzhiyun 	return bit2freq_tab[n];
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun 
hdspm_is_raydat_or_aio(struct hdspm * hdspm)1126*4882a593Smuzhiyun static bool hdspm_is_raydat_or_aio(struct hdspm *hdspm)
1127*4882a593Smuzhiyun {
1128*4882a593Smuzhiyun 	return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type));
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun /* Write/read to/from HDSPM with Adresses in Bytes
1133*4882a593Smuzhiyun    not words but only 32Bit writes are allowed */
1134*4882a593Smuzhiyun 
hdspm_write(struct hdspm * hdspm,unsigned int reg,unsigned int val)1135*4882a593Smuzhiyun static inline void hdspm_write(struct hdspm * hdspm, unsigned int reg,
1136*4882a593Smuzhiyun 			       unsigned int val)
1137*4882a593Smuzhiyun {
1138*4882a593Smuzhiyun 	writel(val, hdspm->iobase + reg);
1139*4882a593Smuzhiyun }
1140*4882a593Smuzhiyun 
hdspm_read(struct hdspm * hdspm,unsigned int reg)1141*4882a593Smuzhiyun static inline unsigned int hdspm_read(struct hdspm * hdspm, unsigned int reg)
1142*4882a593Smuzhiyun {
1143*4882a593Smuzhiyun 	return readl(hdspm->iobase + reg);
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun 
1146*4882a593Smuzhiyun /* for each output channel (chan) I have an Input (in) and Playback (pb) Fader
1147*4882a593Smuzhiyun    mixer is write only on hardware so we have to cache him for read
1148*4882a593Smuzhiyun    each fader is a u32, but uses only the first 16 bit */
1149*4882a593Smuzhiyun 
hdspm_read_in_gain(struct hdspm * hdspm,unsigned int chan,unsigned int in)1150*4882a593Smuzhiyun static inline int hdspm_read_in_gain(struct hdspm * hdspm, unsigned int chan,
1151*4882a593Smuzhiyun 				     unsigned int in)
1152*4882a593Smuzhiyun {
1153*4882a593Smuzhiyun 	if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS)
1154*4882a593Smuzhiyun 		return 0;
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	return hdspm->mixer->ch[chan].in[in];
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun 
hdspm_read_pb_gain(struct hdspm * hdspm,unsigned int chan,unsigned int pb)1159*4882a593Smuzhiyun static inline int hdspm_read_pb_gain(struct hdspm * hdspm, unsigned int chan,
1160*4882a593Smuzhiyun 				     unsigned int pb)
1161*4882a593Smuzhiyun {
1162*4882a593Smuzhiyun 	if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS)
1163*4882a593Smuzhiyun 		return 0;
1164*4882a593Smuzhiyun 	return hdspm->mixer->ch[chan].pb[pb];
1165*4882a593Smuzhiyun }
1166*4882a593Smuzhiyun 
hdspm_write_in_gain(struct hdspm * hdspm,unsigned int chan,unsigned int in,unsigned short data)1167*4882a593Smuzhiyun static int hdspm_write_in_gain(struct hdspm *hdspm, unsigned int chan,
1168*4882a593Smuzhiyun 				      unsigned int in, unsigned short data)
1169*4882a593Smuzhiyun {
1170*4882a593Smuzhiyun 	if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS)
1171*4882a593Smuzhiyun 		return -1;
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 	hdspm_write(hdspm,
1174*4882a593Smuzhiyun 		    HDSPM_MADI_mixerBase +
1175*4882a593Smuzhiyun 		    ((in + 128 * chan) * sizeof(u32)),
1176*4882a593Smuzhiyun 		    (hdspm->mixer->ch[chan].in[in] = data & 0xFFFF));
1177*4882a593Smuzhiyun 	return 0;
1178*4882a593Smuzhiyun }
1179*4882a593Smuzhiyun 
hdspm_write_pb_gain(struct hdspm * hdspm,unsigned int chan,unsigned int pb,unsigned short data)1180*4882a593Smuzhiyun static int hdspm_write_pb_gain(struct hdspm *hdspm, unsigned int chan,
1181*4882a593Smuzhiyun 				      unsigned int pb, unsigned short data)
1182*4882a593Smuzhiyun {
1183*4882a593Smuzhiyun 	if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS)
1184*4882a593Smuzhiyun 		return -1;
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 	hdspm_write(hdspm,
1187*4882a593Smuzhiyun 		    HDSPM_MADI_mixerBase +
1188*4882a593Smuzhiyun 		    ((64 + pb + 128 * chan) * sizeof(u32)),
1189*4882a593Smuzhiyun 		    (hdspm->mixer->ch[chan].pb[pb] = data & 0xFFFF));
1190*4882a593Smuzhiyun 	return 0;
1191*4882a593Smuzhiyun }
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 
1194*4882a593Smuzhiyun /* enable DMA for specific channels, now available for DSP-MADI */
snd_hdspm_enable_in(struct hdspm * hdspm,int i,int v)1195*4882a593Smuzhiyun static inline void snd_hdspm_enable_in(struct hdspm * hdspm, int i, int v)
1196*4882a593Smuzhiyun {
1197*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_inputEnableBase + (4 * i), v);
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun 
snd_hdspm_enable_out(struct hdspm * hdspm,int i,int v)1200*4882a593Smuzhiyun static inline void snd_hdspm_enable_out(struct hdspm * hdspm, int i, int v)
1201*4882a593Smuzhiyun {
1202*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_outputEnableBase + (4 * i), v);
1203*4882a593Smuzhiyun }
1204*4882a593Smuzhiyun 
1205*4882a593Smuzhiyun /* check if same process is writing and reading */
snd_hdspm_use_is_exclusive(struct hdspm * hdspm)1206*4882a593Smuzhiyun static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm)
1207*4882a593Smuzhiyun {
1208*4882a593Smuzhiyun 	unsigned long flags;
1209*4882a593Smuzhiyun 	int ret = 1;
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 	spin_lock_irqsave(&hdspm->lock, flags);
1212*4882a593Smuzhiyun 	if ((hdspm->playback_pid != hdspm->capture_pid) &&
1213*4882a593Smuzhiyun 	    (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) {
1214*4882a593Smuzhiyun 		ret = 0;
1215*4882a593Smuzhiyun 	}
1216*4882a593Smuzhiyun 	spin_unlock_irqrestore(&hdspm->lock, flags);
1217*4882a593Smuzhiyun 	return ret;
1218*4882a593Smuzhiyun }
1219*4882a593Smuzhiyun 
1220*4882a593Smuzhiyun /* round arbitrary sample rates to commonly known rates */
hdspm_round_frequency(int rate)1221*4882a593Smuzhiyun static int hdspm_round_frequency(int rate)
1222*4882a593Smuzhiyun {
1223*4882a593Smuzhiyun 	if (rate < 38050)
1224*4882a593Smuzhiyun 		return 32000;
1225*4882a593Smuzhiyun 	if (rate < 46008)
1226*4882a593Smuzhiyun 		return 44100;
1227*4882a593Smuzhiyun 	else
1228*4882a593Smuzhiyun 		return 48000;
1229*4882a593Smuzhiyun }
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun /* QS and DS rates normally can not be detected
1232*4882a593Smuzhiyun  * automatically by the card. Only exception is MADI
1233*4882a593Smuzhiyun  * in 96k frame mode.
1234*4882a593Smuzhiyun  *
1235*4882a593Smuzhiyun  * So if we read SS values (32 .. 48k), check for
1236*4882a593Smuzhiyun  * user-provided DS/QS bits in the control register
1237*4882a593Smuzhiyun  * and multiply the base frequency accordingly.
1238*4882a593Smuzhiyun  */
hdspm_rate_multiplier(struct hdspm * hdspm,int rate)1239*4882a593Smuzhiyun static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate)
1240*4882a593Smuzhiyun {
1241*4882a593Smuzhiyun 	if (rate <= 48000) {
1242*4882a593Smuzhiyun 		if (hdspm->control_register & HDSPM_QuadSpeed)
1243*4882a593Smuzhiyun 			return rate * 4;
1244*4882a593Smuzhiyun 		else if (hdspm->control_register &
1245*4882a593Smuzhiyun 				HDSPM_DoubleSpeed)
1246*4882a593Smuzhiyun 			return rate * 2;
1247*4882a593Smuzhiyun 	}
1248*4882a593Smuzhiyun 	return rate;
1249*4882a593Smuzhiyun }
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun /* check for external sample rate, returns the sample rate in Hz*/
hdspm_external_sample_rate(struct hdspm * hdspm)1252*4882a593Smuzhiyun static int hdspm_external_sample_rate(struct hdspm *hdspm)
1253*4882a593Smuzhiyun {
1254*4882a593Smuzhiyun 	unsigned int status, status2;
1255*4882a593Smuzhiyun 	int syncref, rate = 0, rate_bits;
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	switch (hdspm->io_type) {
1258*4882a593Smuzhiyun 	case AES32:
1259*4882a593Smuzhiyun 		status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
1260*4882a593Smuzhiyun 		status = hdspm_read(hdspm, HDSPM_statusRegister);
1261*4882a593Smuzhiyun 
1262*4882a593Smuzhiyun 		syncref = hdspm_autosync_ref(hdspm);
1263*4882a593Smuzhiyun 		switch (syncref) {
1264*4882a593Smuzhiyun 		case HDSPM_AES32_AUTOSYNC_FROM_WORD:
1265*4882a593Smuzhiyun 		/* Check WC sync and get sample rate */
1266*4882a593Smuzhiyun 			if (hdspm_wc_sync_check(hdspm))
1267*4882a593Smuzhiyun 				return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm));
1268*4882a593Smuzhiyun 			break;
1269*4882a593Smuzhiyun 
1270*4882a593Smuzhiyun 		case HDSPM_AES32_AUTOSYNC_FROM_AES1:
1271*4882a593Smuzhiyun 		case HDSPM_AES32_AUTOSYNC_FROM_AES2:
1272*4882a593Smuzhiyun 		case HDSPM_AES32_AUTOSYNC_FROM_AES3:
1273*4882a593Smuzhiyun 		case HDSPM_AES32_AUTOSYNC_FROM_AES4:
1274*4882a593Smuzhiyun 		case HDSPM_AES32_AUTOSYNC_FROM_AES5:
1275*4882a593Smuzhiyun 		case HDSPM_AES32_AUTOSYNC_FROM_AES6:
1276*4882a593Smuzhiyun 		case HDSPM_AES32_AUTOSYNC_FROM_AES7:
1277*4882a593Smuzhiyun 		case HDSPM_AES32_AUTOSYNC_FROM_AES8:
1278*4882a593Smuzhiyun 		/* Check AES sync and get sample rate */
1279*4882a593Smuzhiyun 			if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))
1280*4882a593Smuzhiyun 				return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm,
1281*4882a593Smuzhiyun 							syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1));
1282*4882a593Smuzhiyun 			break;
1283*4882a593Smuzhiyun 
1284*4882a593Smuzhiyun 
1285*4882a593Smuzhiyun 		case HDSPM_AES32_AUTOSYNC_FROM_TCO:
1286*4882a593Smuzhiyun 		/* Check TCO sync and get sample rate */
1287*4882a593Smuzhiyun 			if (hdspm_tco_sync_check(hdspm))
1288*4882a593Smuzhiyun 				return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm));
1289*4882a593Smuzhiyun 			break;
1290*4882a593Smuzhiyun 		default:
1291*4882a593Smuzhiyun 			return 0;
1292*4882a593Smuzhiyun 		} /* end switch(syncref) */
1293*4882a593Smuzhiyun 		break;
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 	case MADIface:
1296*4882a593Smuzhiyun 		status = hdspm_read(hdspm, HDSPM_statusRegister);
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 		if (!(status & HDSPM_madiLock)) {
1299*4882a593Smuzhiyun 			rate = 0;  /* no lock */
1300*4882a593Smuzhiyun 		} else {
1301*4882a593Smuzhiyun 			switch (status & (HDSPM_status1_freqMask)) {
1302*4882a593Smuzhiyun 			case HDSPM_status1_F_0*1:
1303*4882a593Smuzhiyun 				rate = 32000; break;
1304*4882a593Smuzhiyun 			case HDSPM_status1_F_0*2:
1305*4882a593Smuzhiyun 				rate = 44100; break;
1306*4882a593Smuzhiyun 			case HDSPM_status1_F_0*3:
1307*4882a593Smuzhiyun 				rate = 48000; break;
1308*4882a593Smuzhiyun 			case HDSPM_status1_F_0*4:
1309*4882a593Smuzhiyun 				rate = 64000; break;
1310*4882a593Smuzhiyun 			case HDSPM_status1_F_0*5:
1311*4882a593Smuzhiyun 				rate = 88200; break;
1312*4882a593Smuzhiyun 			case HDSPM_status1_F_0*6:
1313*4882a593Smuzhiyun 				rate = 96000; break;
1314*4882a593Smuzhiyun 			case HDSPM_status1_F_0*7:
1315*4882a593Smuzhiyun 				rate = 128000; break;
1316*4882a593Smuzhiyun 			case HDSPM_status1_F_0*8:
1317*4882a593Smuzhiyun 				rate = 176400; break;
1318*4882a593Smuzhiyun 			case HDSPM_status1_F_0*9:
1319*4882a593Smuzhiyun 				rate = 192000; break;
1320*4882a593Smuzhiyun 			default:
1321*4882a593Smuzhiyun 				rate = 0; break;
1322*4882a593Smuzhiyun 			}
1323*4882a593Smuzhiyun 		}
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 		break;
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun 	case MADI:
1328*4882a593Smuzhiyun 	case AIO:
1329*4882a593Smuzhiyun 	case RayDAT:
1330*4882a593Smuzhiyun 		status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
1331*4882a593Smuzhiyun 		status = hdspm_read(hdspm, HDSPM_statusRegister);
1332*4882a593Smuzhiyun 		rate = 0;
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 		/* if wordclock has synced freq and wordclock is valid */
1335*4882a593Smuzhiyun 		if ((status2 & HDSPM_wcLock) != 0 &&
1336*4882a593Smuzhiyun 				(status2 & HDSPM_SelSyncRef0) == 0) {
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun 			rate_bits = status2 & HDSPM_wcFreqMask;
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun 
1341*4882a593Smuzhiyun 			switch (rate_bits) {
1342*4882a593Smuzhiyun 			case HDSPM_wcFreq32:
1343*4882a593Smuzhiyun 				rate = 32000;
1344*4882a593Smuzhiyun 				break;
1345*4882a593Smuzhiyun 			case HDSPM_wcFreq44_1:
1346*4882a593Smuzhiyun 				rate = 44100;
1347*4882a593Smuzhiyun 				break;
1348*4882a593Smuzhiyun 			case HDSPM_wcFreq48:
1349*4882a593Smuzhiyun 				rate = 48000;
1350*4882a593Smuzhiyun 				break;
1351*4882a593Smuzhiyun 			case HDSPM_wcFreq64:
1352*4882a593Smuzhiyun 				rate = 64000;
1353*4882a593Smuzhiyun 				break;
1354*4882a593Smuzhiyun 			case HDSPM_wcFreq88_2:
1355*4882a593Smuzhiyun 				rate = 88200;
1356*4882a593Smuzhiyun 				break;
1357*4882a593Smuzhiyun 			case HDSPM_wcFreq96:
1358*4882a593Smuzhiyun 				rate = 96000;
1359*4882a593Smuzhiyun 				break;
1360*4882a593Smuzhiyun 			case HDSPM_wcFreq128:
1361*4882a593Smuzhiyun 				rate = 128000;
1362*4882a593Smuzhiyun 				break;
1363*4882a593Smuzhiyun 			case HDSPM_wcFreq176_4:
1364*4882a593Smuzhiyun 				rate = 176400;
1365*4882a593Smuzhiyun 				break;
1366*4882a593Smuzhiyun 			case HDSPM_wcFreq192:
1367*4882a593Smuzhiyun 				rate = 192000;
1368*4882a593Smuzhiyun 				break;
1369*4882a593Smuzhiyun 			default:
1370*4882a593Smuzhiyun 				rate = 0;
1371*4882a593Smuzhiyun 				break;
1372*4882a593Smuzhiyun 			}
1373*4882a593Smuzhiyun 		}
1374*4882a593Smuzhiyun 
1375*4882a593Smuzhiyun 		/* if rate detected and Syncref is Word than have it,
1376*4882a593Smuzhiyun 		 * word has priority to MADI
1377*4882a593Smuzhiyun 		 */
1378*4882a593Smuzhiyun 		if (rate != 0 &&
1379*4882a593Smuzhiyun 		(status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
1380*4882a593Smuzhiyun 			return hdspm_rate_multiplier(hdspm, rate);
1381*4882a593Smuzhiyun 
1382*4882a593Smuzhiyun 		/* maybe a madi input (which is taken if sel sync is madi) */
1383*4882a593Smuzhiyun 		if (status & HDSPM_madiLock) {
1384*4882a593Smuzhiyun 			rate_bits = status & HDSPM_madiFreqMask;
1385*4882a593Smuzhiyun 
1386*4882a593Smuzhiyun 			switch (rate_bits) {
1387*4882a593Smuzhiyun 			case HDSPM_madiFreq32:
1388*4882a593Smuzhiyun 				rate = 32000;
1389*4882a593Smuzhiyun 				break;
1390*4882a593Smuzhiyun 			case HDSPM_madiFreq44_1:
1391*4882a593Smuzhiyun 				rate = 44100;
1392*4882a593Smuzhiyun 				break;
1393*4882a593Smuzhiyun 			case HDSPM_madiFreq48:
1394*4882a593Smuzhiyun 				rate = 48000;
1395*4882a593Smuzhiyun 				break;
1396*4882a593Smuzhiyun 			case HDSPM_madiFreq64:
1397*4882a593Smuzhiyun 				rate = 64000;
1398*4882a593Smuzhiyun 				break;
1399*4882a593Smuzhiyun 			case HDSPM_madiFreq88_2:
1400*4882a593Smuzhiyun 				rate = 88200;
1401*4882a593Smuzhiyun 				break;
1402*4882a593Smuzhiyun 			case HDSPM_madiFreq96:
1403*4882a593Smuzhiyun 				rate = 96000;
1404*4882a593Smuzhiyun 				break;
1405*4882a593Smuzhiyun 			case HDSPM_madiFreq128:
1406*4882a593Smuzhiyun 				rate = 128000;
1407*4882a593Smuzhiyun 				break;
1408*4882a593Smuzhiyun 			case HDSPM_madiFreq176_4:
1409*4882a593Smuzhiyun 				rate = 176400;
1410*4882a593Smuzhiyun 				break;
1411*4882a593Smuzhiyun 			case HDSPM_madiFreq192:
1412*4882a593Smuzhiyun 				rate = 192000;
1413*4882a593Smuzhiyun 				break;
1414*4882a593Smuzhiyun 			default:
1415*4882a593Smuzhiyun 				rate = 0;
1416*4882a593Smuzhiyun 				break;
1417*4882a593Smuzhiyun 			}
1418*4882a593Smuzhiyun 
1419*4882a593Smuzhiyun 		} /* endif HDSPM_madiLock */
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 		/* check sample rate from TCO or SYNC_IN */
1422*4882a593Smuzhiyun 		{
1423*4882a593Smuzhiyun 			bool is_valid_input = 0;
1424*4882a593Smuzhiyun 			bool has_sync = 0;
1425*4882a593Smuzhiyun 
1426*4882a593Smuzhiyun 			syncref = hdspm_autosync_ref(hdspm);
1427*4882a593Smuzhiyun 			if (HDSPM_AUTOSYNC_FROM_TCO == syncref) {
1428*4882a593Smuzhiyun 				is_valid_input = 1;
1429*4882a593Smuzhiyun 				has_sync = (HDSPM_SYNC_CHECK_SYNC ==
1430*4882a593Smuzhiyun 					hdspm_tco_sync_check(hdspm));
1431*4882a593Smuzhiyun 			} else if (HDSPM_AUTOSYNC_FROM_SYNC_IN == syncref) {
1432*4882a593Smuzhiyun 				is_valid_input = 1;
1433*4882a593Smuzhiyun 				has_sync = (HDSPM_SYNC_CHECK_SYNC ==
1434*4882a593Smuzhiyun 					hdspm_sync_in_sync_check(hdspm));
1435*4882a593Smuzhiyun 			}
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 			if (is_valid_input && has_sync) {
1438*4882a593Smuzhiyun 				rate = hdspm_round_frequency(
1439*4882a593Smuzhiyun 					hdspm_get_pll_freq(hdspm));
1440*4882a593Smuzhiyun 			}
1441*4882a593Smuzhiyun 		}
1442*4882a593Smuzhiyun 
1443*4882a593Smuzhiyun 		rate = hdspm_rate_multiplier(hdspm, rate);
1444*4882a593Smuzhiyun 
1445*4882a593Smuzhiyun 		break;
1446*4882a593Smuzhiyun 	}
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 	return rate;
1449*4882a593Smuzhiyun }
1450*4882a593Smuzhiyun 
1451*4882a593Smuzhiyun /* return latency in samples per period */
hdspm_get_latency(struct hdspm * hdspm)1452*4882a593Smuzhiyun static int hdspm_get_latency(struct hdspm *hdspm)
1453*4882a593Smuzhiyun {
1454*4882a593Smuzhiyun 	int n;
1455*4882a593Smuzhiyun 
1456*4882a593Smuzhiyun 	n = hdspm_decode_latency(hdspm->control_register);
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 	/* Special case for new RME cards with 32 samples period size.
1459*4882a593Smuzhiyun 	 * The three latency bits in the control register
1460*4882a593Smuzhiyun 	 * (HDSP_LatencyMask) encode latency values of 64 samples as
1461*4882a593Smuzhiyun 	 * 0, 128 samples as 1 ... 4096 samples as 6. For old cards, 7
1462*4882a593Smuzhiyun 	 * denotes 8192 samples, but on new cards like RayDAT or AIO,
1463*4882a593Smuzhiyun 	 * it corresponds to 32 samples.
1464*4882a593Smuzhiyun 	 */
1465*4882a593Smuzhiyun 	if ((7 == n) && (RayDAT == hdspm->io_type || AIO == hdspm->io_type))
1466*4882a593Smuzhiyun 		n = -1;
1467*4882a593Smuzhiyun 
1468*4882a593Smuzhiyun 	return 1 << (n + 6);
1469*4882a593Smuzhiyun }
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun /* Latency function */
hdspm_compute_period_size(struct hdspm * hdspm)1472*4882a593Smuzhiyun static inline void hdspm_compute_period_size(struct hdspm *hdspm)
1473*4882a593Smuzhiyun {
1474*4882a593Smuzhiyun 	hdspm->period_bytes = 4 * hdspm_get_latency(hdspm);
1475*4882a593Smuzhiyun }
1476*4882a593Smuzhiyun 
1477*4882a593Smuzhiyun 
hdspm_hw_pointer(struct hdspm * hdspm)1478*4882a593Smuzhiyun static snd_pcm_uframes_t hdspm_hw_pointer(struct hdspm *hdspm)
1479*4882a593Smuzhiyun {
1480*4882a593Smuzhiyun 	int position;
1481*4882a593Smuzhiyun 
1482*4882a593Smuzhiyun 	position = hdspm_read(hdspm, HDSPM_statusRegister);
1483*4882a593Smuzhiyun 
1484*4882a593Smuzhiyun 	switch (hdspm->io_type) {
1485*4882a593Smuzhiyun 	case RayDAT:
1486*4882a593Smuzhiyun 	case AIO:
1487*4882a593Smuzhiyun 		position &= HDSPM_BufferPositionMask;
1488*4882a593Smuzhiyun 		position /= 4; /* Bytes per sample */
1489*4882a593Smuzhiyun 		break;
1490*4882a593Smuzhiyun 	default:
1491*4882a593Smuzhiyun 		position = (position & HDSPM_BufferID) ?
1492*4882a593Smuzhiyun 			(hdspm->period_bytes / 4) : 0;
1493*4882a593Smuzhiyun 	}
1494*4882a593Smuzhiyun 
1495*4882a593Smuzhiyun 	return position;
1496*4882a593Smuzhiyun }
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun 
hdspm_start_audio(struct hdspm * s)1499*4882a593Smuzhiyun static inline void hdspm_start_audio(struct hdspm * s)
1500*4882a593Smuzhiyun {
1501*4882a593Smuzhiyun 	s->control_register |= (HDSPM_AudioInterruptEnable | HDSPM_Start);
1502*4882a593Smuzhiyun 	hdspm_write(s, HDSPM_controlRegister, s->control_register);
1503*4882a593Smuzhiyun }
1504*4882a593Smuzhiyun 
hdspm_stop_audio(struct hdspm * s)1505*4882a593Smuzhiyun static inline void hdspm_stop_audio(struct hdspm * s)
1506*4882a593Smuzhiyun {
1507*4882a593Smuzhiyun 	s->control_register &= ~(HDSPM_Start | HDSPM_AudioInterruptEnable);
1508*4882a593Smuzhiyun 	hdspm_write(s, HDSPM_controlRegister, s->control_register);
1509*4882a593Smuzhiyun }
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun /* should I silence all or only opened ones ? doit all for first even is 4MB*/
hdspm_silence_playback(struct hdspm * hdspm)1512*4882a593Smuzhiyun static void hdspm_silence_playback(struct hdspm *hdspm)
1513*4882a593Smuzhiyun {
1514*4882a593Smuzhiyun 	int i;
1515*4882a593Smuzhiyun 	int n = hdspm->period_bytes;
1516*4882a593Smuzhiyun 	void *buf = hdspm->playback_buffer;
1517*4882a593Smuzhiyun 
1518*4882a593Smuzhiyun 	if (!buf)
1519*4882a593Smuzhiyun 		return;
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 	for (i = 0; i < HDSPM_MAX_CHANNELS; i++) {
1522*4882a593Smuzhiyun 		memset(buf, 0, n);
1523*4882a593Smuzhiyun 		buf += HDSPM_CHANNEL_BUFFER_BYTES;
1524*4882a593Smuzhiyun 	}
1525*4882a593Smuzhiyun }
1526*4882a593Smuzhiyun 
hdspm_set_interrupt_interval(struct hdspm * s,unsigned int frames)1527*4882a593Smuzhiyun static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames)
1528*4882a593Smuzhiyun {
1529*4882a593Smuzhiyun 	int n;
1530*4882a593Smuzhiyun 
1531*4882a593Smuzhiyun 	spin_lock_irq(&s->lock);
1532*4882a593Smuzhiyun 
1533*4882a593Smuzhiyun 	if (32 == frames) {
1534*4882a593Smuzhiyun 		/* Special case for new RME cards like RayDAT/AIO which
1535*4882a593Smuzhiyun 		 * support period sizes of 32 samples. Since latency is
1536*4882a593Smuzhiyun 		 * encoded in the three bits of HDSP_LatencyMask, we can only
1537*4882a593Smuzhiyun 		 * have values from 0 .. 7. While 0 still means 64 samples and
1538*4882a593Smuzhiyun 		 * 6 represents 4096 samples on all cards, 7 represents 8192
1539*4882a593Smuzhiyun 		 * on older cards and 32 samples on new cards.
1540*4882a593Smuzhiyun 		 *
1541*4882a593Smuzhiyun 		 * In other words, period size in samples is calculated by
1542*4882a593Smuzhiyun 		 * 2^(n+6) with n ranging from 0 .. 7.
1543*4882a593Smuzhiyun 		 */
1544*4882a593Smuzhiyun 		n = 7;
1545*4882a593Smuzhiyun 	} else {
1546*4882a593Smuzhiyun 		frames >>= 7;
1547*4882a593Smuzhiyun 		n = 0;
1548*4882a593Smuzhiyun 		while (frames) {
1549*4882a593Smuzhiyun 			n++;
1550*4882a593Smuzhiyun 			frames >>= 1;
1551*4882a593Smuzhiyun 		}
1552*4882a593Smuzhiyun 	}
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun 	s->control_register &= ~HDSPM_LatencyMask;
1555*4882a593Smuzhiyun 	s->control_register |= hdspm_encode_latency(n);
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun 	hdspm_write(s, HDSPM_controlRegister, s->control_register);
1558*4882a593Smuzhiyun 
1559*4882a593Smuzhiyun 	hdspm_compute_period_size(s);
1560*4882a593Smuzhiyun 
1561*4882a593Smuzhiyun 	spin_unlock_irq(&s->lock);
1562*4882a593Smuzhiyun 
1563*4882a593Smuzhiyun 	return 0;
1564*4882a593Smuzhiyun }
1565*4882a593Smuzhiyun 
hdspm_calc_dds_value(struct hdspm * hdspm,u64 period)1566*4882a593Smuzhiyun static u64 hdspm_calc_dds_value(struct hdspm *hdspm, u64 period)
1567*4882a593Smuzhiyun {
1568*4882a593Smuzhiyun 	u64 freq_const;
1569*4882a593Smuzhiyun 
1570*4882a593Smuzhiyun 	if (period == 0)
1571*4882a593Smuzhiyun 		return 0;
1572*4882a593Smuzhiyun 
1573*4882a593Smuzhiyun 	switch (hdspm->io_type) {
1574*4882a593Smuzhiyun 	case MADI:
1575*4882a593Smuzhiyun 	case AES32:
1576*4882a593Smuzhiyun 		freq_const = 110069313433624ULL;
1577*4882a593Smuzhiyun 		break;
1578*4882a593Smuzhiyun 	case RayDAT:
1579*4882a593Smuzhiyun 	case AIO:
1580*4882a593Smuzhiyun 		freq_const = 104857600000000ULL;
1581*4882a593Smuzhiyun 		break;
1582*4882a593Smuzhiyun 	case MADIface:
1583*4882a593Smuzhiyun 		freq_const = 131072000000000ULL;
1584*4882a593Smuzhiyun 		break;
1585*4882a593Smuzhiyun 	default:
1586*4882a593Smuzhiyun 		snd_BUG();
1587*4882a593Smuzhiyun 		return 0;
1588*4882a593Smuzhiyun 	}
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun 	return div_u64(freq_const, period);
1591*4882a593Smuzhiyun }
1592*4882a593Smuzhiyun 
1593*4882a593Smuzhiyun 
hdspm_set_dds_value(struct hdspm * hdspm,int rate)1594*4882a593Smuzhiyun static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
1595*4882a593Smuzhiyun {
1596*4882a593Smuzhiyun 	u64 n;
1597*4882a593Smuzhiyun 
1598*4882a593Smuzhiyun 	if (snd_BUG_ON(rate <= 0))
1599*4882a593Smuzhiyun 		return;
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun 	if (rate >= 112000)
1602*4882a593Smuzhiyun 		rate /= 4;
1603*4882a593Smuzhiyun 	else if (rate >= 56000)
1604*4882a593Smuzhiyun 		rate /= 2;
1605*4882a593Smuzhiyun 
1606*4882a593Smuzhiyun 	switch (hdspm->io_type) {
1607*4882a593Smuzhiyun 	case MADIface:
1608*4882a593Smuzhiyun 		n = 131072000000000ULL;  /* 125 MHz */
1609*4882a593Smuzhiyun 		break;
1610*4882a593Smuzhiyun 	case MADI:
1611*4882a593Smuzhiyun 	case AES32:
1612*4882a593Smuzhiyun 		n = 110069313433624ULL;  /* 105 MHz */
1613*4882a593Smuzhiyun 		break;
1614*4882a593Smuzhiyun 	case RayDAT:
1615*4882a593Smuzhiyun 	case AIO:
1616*4882a593Smuzhiyun 		n = 104857600000000ULL;  /* 100 MHz */
1617*4882a593Smuzhiyun 		break;
1618*4882a593Smuzhiyun 	default:
1619*4882a593Smuzhiyun 		snd_BUG();
1620*4882a593Smuzhiyun 		return;
1621*4882a593Smuzhiyun 	}
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun 	n = div_u64(n, rate);
1624*4882a593Smuzhiyun 	/* n should be less than 2^32 for being written to FREQ register */
1625*4882a593Smuzhiyun 	snd_BUG_ON(n >> 32);
1626*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_freqReg, (u32)n);
1627*4882a593Smuzhiyun }
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun /* dummy set rate lets see what happens */
hdspm_set_rate(struct hdspm * hdspm,int rate,int called_internally)1630*4882a593Smuzhiyun static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
1631*4882a593Smuzhiyun {
1632*4882a593Smuzhiyun 	int current_rate;
1633*4882a593Smuzhiyun 	int rate_bits;
1634*4882a593Smuzhiyun 	int not_set = 0;
1635*4882a593Smuzhiyun 	int current_speed, target_speed;
1636*4882a593Smuzhiyun 
1637*4882a593Smuzhiyun 	/* ASSUMPTION: hdspm->lock is either set, or there is no need for
1638*4882a593Smuzhiyun 	   it (e.g. during module initialization).
1639*4882a593Smuzhiyun 	 */
1640*4882a593Smuzhiyun 
1641*4882a593Smuzhiyun 	if (!(hdspm->control_register & HDSPM_ClockModeMaster)) {
1642*4882a593Smuzhiyun 
1643*4882a593Smuzhiyun 		/* SLAVE --- */
1644*4882a593Smuzhiyun 		if (called_internally) {
1645*4882a593Smuzhiyun 
1646*4882a593Smuzhiyun 			/* request from ctl or card initialization
1647*4882a593Smuzhiyun 			   just make a warning an remember setting
1648*4882a593Smuzhiyun 			   for future master mode switching */
1649*4882a593Smuzhiyun 
1650*4882a593Smuzhiyun 			dev_warn(hdspm->card->dev,
1651*4882a593Smuzhiyun 				 "Warning: device is not running as a clock master.\n");
1652*4882a593Smuzhiyun 			not_set = 1;
1653*4882a593Smuzhiyun 		} else {
1654*4882a593Smuzhiyun 
1655*4882a593Smuzhiyun 			/* hw_param request while in AutoSync mode */
1656*4882a593Smuzhiyun 			int external_freq =
1657*4882a593Smuzhiyun 			    hdspm_external_sample_rate(hdspm);
1658*4882a593Smuzhiyun 
1659*4882a593Smuzhiyun 			if (hdspm_autosync_ref(hdspm) ==
1660*4882a593Smuzhiyun 			    HDSPM_AUTOSYNC_FROM_NONE) {
1661*4882a593Smuzhiyun 
1662*4882a593Smuzhiyun 				dev_warn(hdspm->card->dev,
1663*4882a593Smuzhiyun 					 "Detected no External Sync\n");
1664*4882a593Smuzhiyun 				not_set = 1;
1665*4882a593Smuzhiyun 
1666*4882a593Smuzhiyun 			} else if (rate != external_freq) {
1667*4882a593Smuzhiyun 
1668*4882a593Smuzhiyun 				dev_warn(hdspm->card->dev,
1669*4882a593Smuzhiyun 					 "Warning: No AutoSync source for requested rate\n");
1670*4882a593Smuzhiyun 				not_set = 1;
1671*4882a593Smuzhiyun 			}
1672*4882a593Smuzhiyun 		}
1673*4882a593Smuzhiyun 	}
1674*4882a593Smuzhiyun 
1675*4882a593Smuzhiyun 	current_rate = hdspm->system_sample_rate;
1676*4882a593Smuzhiyun 
1677*4882a593Smuzhiyun 	/* Changing between Singe, Double and Quad speed is not
1678*4882a593Smuzhiyun 	   allowed if any substreams are open. This is because such a change
1679*4882a593Smuzhiyun 	   causes a shift in the location of the DMA buffers and a reduction
1680*4882a593Smuzhiyun 	   in the number of available buffers.
1681*4882a593Smuzhiyun 
1682*4882a593Smuzhiyun 	   Note that a similar but essentially insoluble problem exists for
1683*4882a593Smuzhiyun 	   externally-driven rate changes. All we can do is to flag rate
1684*4882a593Smuzhiyun 	   changes in the read/write routines.
1685*4882a593Smuzhiyun 	 */
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun 	if (current_rate <= 48000)
1688*4882a593Smuzhiyun 		current_speed = HDSPM_SPEED_SINGLE;
1689*4882a593Smuzhiyun 	else if (current_rate <= 96000)
1690*4882a593Smuzhiyun 		current_speed = HDSPM_SPEED_DOUBLE;
1691*4882a593Smuzhiyun 	else
1692*4882a593Smuzhiyun 		current_speed = HDSPM_SPEED_QUAD;
1693*4882a593Smuzhiyun 
1694*4882a593Smuzhiyun 	if (rate <= 48000)
1695*4882a593Smuzhiyun 		target_speed = HDSPM_SPEED_SINGLE;
1696*4882a593Smuzhiyun 	else if (rate <= 96000)
1697*4882a593Smuzhiyun 		target_speed = HDSPM_SPEED_DOUBLE;
1698*4882a593Smuzhiyun 	else
1699*4882a593Smuzhiyun 		target_speed = HDSPM_SPEED_QUAD;
1700*4882a593Smuzhiyun 
1701*4882a593Smuzhiyun 	switch (rate) {
1702*4882a593Smuzhiyun 	case 32000:
1703*4882a593Smuzhiyun 		rate_bits = HDSPM_Frequency32KHz;
1704*4882a593Smuzhiyun 		break;
1705*4882a593Smuzhiyun 	case 44100:
1706*4882a593Smuzhiyun 		rate_bits = HDSPM_Frequency44_1KHz;
1707*4882a593Smuzhiyun 		break;
1708*4882a593Smuzhiyun 	case 48000:
1709*4882a593Smuzhiyun 		rate_bits = HDSPM_Frequency48KHz;
1710*4882a593Smuzhiyun 		break;
1711*4882a593Smuzhiyun 	case 64000:
1712*4882a593Smuzhiyun 		rate_bits = HDSPM_Frequency64KHz;
1713*4882a593Smuzhiyun 		break;
1714*4882a593Smuzhiyun 	case 88200:
1715*4882a593Smuzhiyun 		rate_bits = HDSPM_Frequency88_2KHz;
1716*4882a593Smuzhiyun 		break;
1717*4882a593Smuzhiyun 	case 96000:
1718*4882a593Smuzhiyun 		rate_bits = HDSPM_Frequency96KHz;
1719*4882a593Smuzhiyun 		break;
1720*4882a593Smuzhiyun 	case 128000:
1721*4882a593Smuzhiyun 		rate_bits = HDSPM_Frequency128KHz;
1722*4882a593Smuzhiyun 		break;
1723*4882a593Smuzhiyun 	case 176400:
1724*4882a593Smuzhiyun 		rate_bits = HDSPM_Frequency176_4KHz;
1725*4882a593Smuzhiyun 		break;
1726*4882a593Smuzhiyun 	case 192000:
1727*4882a593Smuzhiyun 		rate_bits = HDSPM_Frequency192KHz;
1728*4882a593Smuzhiyun 		break;
1729*4882a593Smuzhiyun 	default:
1730*4882a593Smuzhiyun 		return -EINVAL;
1731*4882a593Smuzhiyun 	}
1732*4882a593Smuzhiyun 
1733*4882a593Smuzhiyun 	if (current_speed != target_speed
1734*4882a593Smuzhiyun 	    && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) {
1735*4882a593Smuzhiyun 		dev_err(hdspm->card->dev,
1736*4882a593Smuzhiyun 			"cannot change from %s speed to %s speed mode (capture PID = %d, playback PID = %d)\n",
1737*4882a593Smuzhiyun 			hdspm_speed_names[current_speed],
1738*4882a593Smuzhiyun 			hdspm_speed_names[target_speed],
1739*4882a593Smuzhiyun 			hdspm->capture_pid, hdspm->playback_pid);
1740*4882a593Smuzhiyun 		return -EBUSY;
1741*4882a593Smuzhiyun 	}
1742*4882a593Smuzhiyun 
1743*4882a593Smuzhiyun 	hdspm->control_register &= ~HDSPM_FrequencyMask;
1744*4882a593Smuzhiyun 	hdspm->control_register |= rate_bits;
1745*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
1746*4882a593Smuzhiyun 
1747*4882a593Smuzhiyun 	/* For AES32, need to set DDS value in FREQ register
1748*4882a593Smuzhiyun 	   For MADI, also apparently */
1749*4882a593Smuzhiyun 	hdspm_set_dds_value(hdspm, rate);
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun 	if (AES32 == hdspm->io_type && rate != current_rate)
1752*4882a593Smuzhiyun 		hdspm_write(hdspm, HDSPM_eeprom_wr, 0);
1753*4882a593Smuzhiyun 
1754*4882a593Smuzhiyun 	hdspm->system_sample_rate = rate;
1755*4882a593Smuzhiyun 
1756*4882a593Smuzhiyun 	if (rate <= 48000) {
1757*4882a593Smuzhiyun 		hdspm->channel_map_in = hdspm->channel_map_in_ss;
1758*4882a593Smuzhiyun 		hdspm->channel_map_out = hdspm->channel_map_out_ss;
1759*4882a593Smuzhiyun 		hdspm->max_channels_in = hdspm->ss_in_channels;
1760*4882a593Smuzhiyun 		hdspm->max_channels_out = hdspm->ss_out_channels;
1761*4882a593Smuzhiyun 		hdspm->port_names_in = hdspm->port_names_in_ss;
1762*4882a593Smuzhiyun 		hdspm->port_names_out = hdspm->port_names_out_ss;
1763*4882a593Smuzhiyun 	} else if (rate <= 96000) {
1764*4882a593Smuzhiyun 		hdspm->channel_map_in = hdspm->channel_map_in_ds;
1765*4882a593Smuzhiyun 		hdspm->channel_map_out = hdspm->channel_map_out_ds;
1766*4882a593Smuzhiyun 		hdspm->max_channels_in = hdspm->ds_in_channels;
1767*4882a593Smuzhiyun 		hdspm->max_channels_out = hdspm->ds_out_channels;
1768*4882a593Smuzhiyun 		hdspm->port_names_in = hdspm->port_names_in_ds;
1769*4882a593Smuzhiyun 		hdspm->port_names_out = hdspm->port_names_out_ds;
1770*4882a593Smuzhiyun 	} else {
1771*4882a593Smuzhiyun 		hdspm->channel_map_in = hdspm->channel_map_in_qs;
1772*4882a593Smuzhiyun 		hdspm->channel_map_out = hdspm->channel_map_out_qs;
1773*4882a593Smuzhiyun 		hdspm->max_channels_in = hdspm->qs_in_channels;
1774*4882a593Smuzhiyun 		hdspm->max_channels_out = hdspm->qs_out_channels;
1775*4882a593Smuzhiyun 		hdspm->port_names_in = hdspm->port_names_in_qs;
1776*4882a593Smuzhiyun 		hdspm->port_names_out = hdspm->port_names_out_qs;
1777*4882a593Smuzhiyun 	}
1778*4882a593Smuzhiyun 
1779*4882a593Smuzhiyun 	if (not_set != 0)
1780*4882a593Smuzhiyun 		return -1;
1781*4882a593Smuzhiyun 
1782*4882a593Smuzhiyun 	return 0;
1783*4882a593Smuzhiyun }
1784*4882a593Smuzhiyun 
1785*4882a593Smuzhiyun /* mainly for init to 0 on load */
all_in_all_mixer(struct hdspm * hdspm,int sgain)1786*4882a593Smuzhiyun static void all_in_all_mixer(struct hdspm * hdspm, int sgain)
1787*4882a593Smuzhiyun {
1788*4882a593Smuzhiyun 	int i, j;
1789*4882a593Smuzhiyun 	unsigned int gain;
1790*4882a593Smuzhiyun 
1791*4882a593Smuzhiyun 	if (sgain > UNITY_GAIN)
1792*4882a593Smuzhiyun 		gain = UNITY_GAIN;
1793*4882a593Smuzhiyun 	else if (sgain < 0)
1794*4882a593Smuzhiyun 		gain = 0;
1795*4882a593Smuzhiyun 	else
1796*4882a593Smuzhiyun 		gain = sgain;
1797*4882a593Smuzhiyun 
1798*4882a593Smuzhiyun 	for (i = 0; i < HDSPM_MIXER_CHANNELS; i++)
1799*4882a593Smuzhiyun 		for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) {
1800*4882a593Smuzhiyun 			hdspm_write_in_gain(hdspm, i, j, gain);
1801*4882a593Smuzhiyun 			hdspm_write_pb_gain(hdspm, i, j, gain);
1802*4882a593Smuzhiyun 		}
1803*4882a593Smuzhiyun }
1804*4882a593Smuzhiyun 
1805*4882a593Smuzhiyun /*----------------------------------------------------------------------------
1806*4882a593Smuzhiyun    MIDI
1807*4882a593Smuzhiyun   ----------------------------------------------------------------------------*/
1808*4882a593Smuzhiyun 
snd_hdspm_midi_read_byte(struct hdspm * hdspm,int id)1809*4882a593Smuzhiyun static inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm,
1810*4882a593Smuzhiyun 						      int id)
1811*4882a593Smuzhiyun {
1812*4882a593Smuzhiyun 	/* the hardware already does the relevant bit-mask with 0xff */
1813*4882a593Smuzhiyun 	return hdspm_read(hdspm, hdspm->midi[id].dataIn);
1814*4882a593Smuzhiyun }
1815*4882a593Smuzhiyun 
snd_hdspm_midi_write_byte(struct hdspm * hdspm,int id,int val)1816*4882a593Smuzhiyun static inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id,
1817*4882a593Smuzhiyun 					      int val)
1818*4882a593Smuzhiyun {
1819*4882a593Smuzhiyun 	/* the hardware already does the relevant bit-mask with 0xff */
1820*4882a593Smuzhiyun 	return hdspm_write(hdspm, hdspm->midi[id].dataOut, val);
1821*4882a593Smuzhiyun }
1822*4882a593Smuzhiyun 
snd_hdspm_midi_input_available(struct hdspm * hdspm,int id)1823*4882a593Smuzhiyun static inline int snd_hdspm_midi_input_available (struct hdspm *hdspm, int id)
1824*4882a593Smuzhiyun {
1825*4882a593Smuzhiyun 	return hdspm_read(hdspm, hdspm->midi[id].statusIn) & 0xFF;
1826*4882a593Smuzhiyun }
1827*4882a593Smuzhiyun 
snd_hdspm_midi_output_possible(struct hdspm * hdspm,int id)1828*4882a593Smuzhiyun static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id)
1829*4882a593Smuzhiyun {
1830*4882a593Smuzhiyun 	int fifo_bytes_used;
1831*4882a593Smuzhiyun 
1832*4882a593Smuzhiyun 	fifo_bytes_used = hdspm_read(hdspm, hdspm->midi[id].statusOut) & 0xFF;
1833*4882a593Smuzhiyun 
1834*4882a593Smuzhiyun 	if (fifo_bytes_used < 128)
1835*4882a593Smuzhiyun 		return  128 - fifo_bytes_used;
1836*4882a593Smuzhiyun 	else
1837*4882a593Smuzhiyun 		return 0;
1838*4882a593Smuzhiyun }
1839*4882a593Smuzhiyun 
snd_hdspm_flush_midi_input(struct hdspm * hdspm,int id)1840*4882a593Smuzhiyun static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id)
1841*4882a593Smuzhiyun {
1842*4882a593Smuzhiyun 	while (snd_hdspm_midi_input_available (hdspm, id))
1843*4882a593Smuzhiyun 		snd_hdspm_midi_read_byte (hdspm, id);
1844*4882a593Smuzhiyun }
1845*4882a593Smuzhiyun 
snd_hdspm_midi_output_write(struct hdspm_midi * hmidi)1846*4882a593Smuzhiyun static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi)
1847*4882a593Smuzhiyun {
1848*4882a593Smuzhiyun 	unsigned long flags;
1849*4882a593Smuzhiyun 	int n_pending;
1850*4882a593Smuzhiyun 	int to_write;
1851*4882a593Smuzhiyun 	int i;
1852*4882a593Smuzhiyun 	unsigned char buf[128];
1853*4882a593Smuzhiyun 
1854*4882a593Smuzhiyun 	/* Output is not interrupt driven */
1855*4882a593Smuzhiyun 
1856*4882a593Smuzhiyun 	spin_lock_irqsave (&hmidi->lock, flags);
1857*4882a593Smuzhiyun 	if (hmidi->output &&
1858*4882a593Smuzhiyun 	    !snd_rawmidi_transmit_empty (hmidi->output)) {
1859*4882a593Smuzhiyun 		n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm,
1860*4882a593Smuzhiyun 							    hmidi->id);
1861*4882a593Smuzhiyun 		if (n_pending > 0) {
1862*4882a593Smuzhiyun 			if (n_pending > (int)sizeof (buf))
1863*4882a593Smuzhiyun 				n_pending = sizeof (buf);
1864*4882a593Smuzhiyun 
1865*4882a593Smuzhiyun 			to_write = snd_rawmidi_transmit (hmidi->output, buf,
1866*4882a593Smuzhiyun 							 n_pending);
1867*4882a593Smuzhiyun 			if (to_write > 0) {
1868*4882a593Smuzhiyun 				for (i = 0; i < to_write; ++i)
1869*4882a593Smuzhiyun 					snd_hdspm_midi_write_byte (hmidi->hdspm,
1870*4882a593Smuzhiyun 								   hmidi->id,
1871*4882a593Smuzhiyun 								   buf[i]);
1872*4882a593Smuzhiyun 			}
1873*4882a593Smuzhiyun 		}
1874*4882a593Smuzhiyun 	}
1875*4882a593Smuzhiyun 	spin_unlock_irqrestore (&hmidi->lock, flags);
1876*4882a593Smuzhiyun 	return 0;
1877*4882a593Smuzhiyun }
1878*4882a593Smuzhiyun 
snd_hdspm_midi_input_read(struct hdspm_midi * hmidi)1879*4882a593Smuzhiyun static int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi)
1880*4882a593Smuzhiyun {
1881*4882a593Smuzhiyun 	unsigned char buf[128]; /* this buffer is designed to match the MIDI
1882*4882a593Smuzhiyun 				 * input FIFO size
1883*4882a593Smuzhiyun 				 */
1884*4882a593Smuzhiyun 	unsigned long flags;
1885*4882a593Smuzhiyun 	int n_pending;
1886*4882a593Smuzhiyun 	int i;
1887*4882a593Smuzhiyun 
1888*4882a593Smuzhiyun 	spin_lock_irqsave (&hmidi->lock, flags);
1889*4882a593Smuzhiyun 	n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id);
1890*4882a593Smuzhiyun 	if (n_pending > 0) {
1891*4882a593Smuzhiyun 		if (hmidi->input) {
1892*4882a593Smuzhiyun 			if (n_pending > (int)sizeof (buf))
1893*4882a593Smuzhiyun 				n_pending = sizeof (buf);
1894*4882a593Smuzhiyun 			for (i = 0; i < n_pending; ++i)
1895*4882a593Smuzhiyun 				buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm,
1896*4882a593Smuzhiyun 								   hmidi->id);
1897*4882a593Smuzhiyun 			if (n_pending)
1898*4882a593Smuzhiyun 				snd_rawmidi_receive (hmidi->input, buf,
1899*4882a593Smuzhiyun 						     n_pending);
1900*4882a593Smuzhiyun 		} else {
1901*4882a593Smuzhiyun 			/* flush the MIDI input FIFO */
1902*4882a593Smuzhiyun 			while (n_pending--)
1903*4882a593Smuzhiyun 				snd_hdspm_midi_read_byte (hmidi->hdspm,
1904*4882a593Smuzhiyun 							  hmidi->id);
1905*4882a593Smuzhiyun 		}
1906*4882a593Smuzhiyun 	}
1907*4882a593Smuzhiyun 	hmidi->pending = 0;
1908*4882a593Smuzhiyun 	spin_unlock_irqrestore(&hmidi->lock, flags);
1909*4882a593Smuzhiyun 
1910*4882a593Smuzhiyun 	spin_lock_irqsave(&hmidi->hdspm->lock, flags);
1911*4882a593Smuzhiyun 	hmidi->hdspm->control_register |= hmidi->ie;
1912*4882a593Smuzhiyun 	hdspm_write(hmidi->hdspm, HDSPM_controlRegister,
1913*4882a593Smuzhiyun 		    hmidi->hdspm->control_register);
1914*4882a593Smuzhiyun 	spin_unlock_irqrestore(&hmidi->hdspm->lock, flags);
1915*4882a593Smuzhiyun 
1916*4882a593Smuzhiyun 	return snd_hdspm_midi_output_write (hmidi);
1917*4882a593Smuzhiyun }
1918*4882a593Smuzhiyun 
1919*4882a593Smuzhiyun static void
snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream * substream,int up)1920*4882a593Smuzhiyun snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
1921*4882a593Smuzhiyun {
1922*4882a593Smuzhiyun 	struct hdspm *hdspm;
1923*4882a593Smuzhiyun 	struct hdspm_midi *hmidi;
1924*4882a593Smuzhiyun 	unsigned long flags;
1925*4882a593Smuzhiyun 
1926*4882a593Smuzhiyun 	hmidi = substream->rmidi->private_data;
1927*4882a593Smuzhiyun 	hdspm = hmidi->hdspm;
1928*4882a593Smuzhiyun 
1929*4882a593Smuzhiyun 	spin_lock_irqsave (&hdspm->lock, flags);
1930*4882a593Smuzhiyun 	if (up) {
1931*4882a593Smuzhiyun 		if (!(hdspm->control_register & hmidi->ie)) {
1932*4882a593Smuzhiyun 			snd_hdspm_flush_midi_input (hdspm, hmidi->id);
1933*4882a593Smuzhiyun 			hdspm->control_register |= hmidi->ie;
1934*4882a593Smuzhiyun 		}
1935*4882a593Smuzhiyun 	} else {
1936*4882a593Smuzhiyun 		hdspm->control_register &= ~hmidi->ie;
1937*4882a593Smuzhiyun 	}
1938*4882a593Smuzhiyun 
1939*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
1940*4882a593Smuzhiyun 	spin_unlock_irqrestore (&hdspm->lock, flags);
1941*4882a593Smuzhiyun }
1942*4882a593Smuzhiyun 
snd_hdspm_midi_output_timer(struct timer_list * t)1943*4882a593Smuzhiyun static void snd_hdspm_midi_output_timer(struct timer_list *t)
1944*4882a593Smuzhiyun {
1945*4882a593Smuzhiyun 	struct hdspm_midi *hmidi = from_timer(hmidi, t, timer);
1946*4882a593Smuzhiyun 	unsigned long flags;
1947*4882a593Smuzhiyun 
1948*4882a593Smuzhiyun 	snd_hdspm_midi_output_write(hmidi);
1949*4882a593Smuzhiyun 	spin_lock_irqsave (&hmidi->lock, flags);
1950*4882a593Smuzhiyun 
1951*4882a593Smuzhiyun 	/* this does not bump hmidi->istimer, because the
1952*4882a593Smuzhiyun 	   kernel automatically removed the timer when it
1953*4882a593Smuzhiyun 	   expired, and we are now adding it back, thus
1954*4882a593Smuzhiyun 	   leaving istimer wherever it was set before.
1955*4882a593Smuzhiyun 	*/
1956*4882a593Smuzhiyun 
1957*4882a593Smuzhiyun 	if (hmidi->istimer)
1958*4882a593Smuzhiyun 		mod_timer(&hmidi->timer, 1 + jiffies);
1959*4882a593Smuzhiyun 
1960*4882a593Smuzhiyun 	spin_unlock_irqrestore (&hmidi->lock, flags);
1961*4882a593Smuzhiyun }
1962*4882a593Smuzhiyun 
1963*4882a593Smuzhiyun static void
snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream * substream,int up)1964*4882a593Smuzhiyun snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
1965*4882a593Smuzhiyun {
1966*4882a593Smuzhiyun 	struct hdspm_midi *hmidi;
1967*4882a593Smuzhiyun 	unsigned long flags;
1968*4882a593Smuzhiyun 
1969*4882a593Smuzhiyun 	hmidi = substream->rmidi->private_data;
1970*4882a593Smuzhiyun 	spin_lock_irqsave (&hmidi->lock, flags);
1971*4882a593Smuzhiyun 	if (up) {
1972*4882a593Smuzhiyun 		if (!hmidi->istimer) {
1973*4882a593Smuzhiyun 			timer_setup(&hmidi->timer,
1974*4882a593Smuzhiyun 				    snd_hdspm_midi_output_timer, 0);
1975*4882a593Smuzhiyun 			mod_timer(&hmidi->timer, 1 + jiffies);
1976*4882a593Smuzhiyun 			hmidi->istimer++;
1977*4882a593Smuzhiyun 		}
1978*4882a593Smuzhiyun 	} else {
1979*4882a593Smuzhiyun 		if (hmidi->istimer && --hmidi->istimer <= 0)
1980*4882a593Smuzhiyun 			del_timer (&hmidi->timer);
1981*4882a593Smuzhiyun 	}
1982*4882a593Smuzhiyun 	spin_unlock_irqrestore (&hmidi->lock, flags);
1983*4882a593Smuzhiyun 	if (up)
1984*4882a593Smuzhiyun 		snd_hdspm_midi_output_write(hmidi);
1985*4882a593Smuzhiyun }
1986*4882a593Smuzhiyun 
snd_hdspm_midi_input_open(struct snd_rawmidi_substream * substream)1987*4882a593Smuzhiyun static int snd_hdspm_midi_input_open(struct snd_rawmidi_substream *substream)
1988*4882a593Smuzhiyun {
1989*4882a593Smuzhiyun 	struct hdspm_midi *hmidi;
1990*4882a593Smuzhiyun 
1991*4882a593Smuzhiyun 	hmidi = substream->rmidi->private_data;
1992*4882a593Smuzhiyun 	spin_lock_irq (&hmidi->lock);
1993*4882a593Smuzhiyun 	snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id);
1994*4882a593Smuzhiyun 	hmidi->input = substream;
1995*4882a593Smuzhiyun 	spin_unlock_irq (&hmidi->lock);
1996*4882a593Smuzhiyun 
1997*4882a593Smuzhiyun 	return 0;
1998*4882a593Smuzhiyun }
1999*4882a593Smuzhiyun 
snd_hdspm_midi_output_open(struct snd_rawmidi_substream * substream)2000*4882a593Smuzhiyun static int snd_hdspm_midi_output_open(struct snd_rawmidi_substream *substream)
2001*4882a593Smuzhiyun {
2002*4882a593Smuzhiyun 	struct hdspm_midi *hmidi;
2003*4882a593Smuzhiyun 
2004*4882a593Smuzhiyun 	hmidi = substream->rmidi->private_data;
2005*4882a593Smuzhiyun 	spin_lock_irq (&hmidi->lock);
2006*4882a593Smuzhiyun 	hmidi->output = substream;
2007*4882a593Smuzhiyun 	spin_unlock_irq (&hmidi->lock);
2008*4882a593Smuzhiyun 
2009*4882a593Smuzhiyun 	return 0;
2010*4882a593Smuzhiyun }
2011*4882a593Smuzhiyun 
snd_hdspm_midi_input_close(struct snd_rawmidi_substream * substream)2012*4882a593Smuzhiyun static int snd_hdspm_midi_input_close(struct snd_rawmidi_substream *substream)
2013*4882a593Smuzhiyun {
2014*4882a593Smuzhiyun 	struct hdspm_midi *hmidi;
2015*4882a593Smuzhiyun 
2016*4882a593Smuzhiyun 	snd_hdspm_midi_input_trigger (substream, 0);
2017*4882a593Smuzhiyun 
2018*4882a593Smuzhiyun 	hmidi = substream->rmidi->private_data;
2019*4882a593Smuzhiyun 	spin_lock_irq (&hmidi->lock);
2020*4882a593Smuzhiyun 	hmidi->input = NULL;
2021*4882a593Smuzhiyun 	spin_unlock_irq (&hmidi->lock);
2022*4882a593Smuzhiyun 
2023*4882a593Smuzhiyun 	return 0;
2024*4882a593Smuzhiyun }
2025*4882a593Smuzhiyun 
snd_hdspm_midi_output_close(struct snd_rawmidi_substream * substream)2026*4882a593Smuzhiyun static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream)
2027*4882a593Smuzhiyun {
2028*4882a593Smuzhiyun 	struct hdspm_midi *hmidi;
2029*4882a593Smuzhiyun 
2030*4882a593Smuzhiyun 	snd_hdspm_midi_output_trigger (substream, 0);
2031*4882a593Smuzhiyun 
2032*4882a593Smuzhiyun 	hmidi = substream->rmidi->private_data;
2033*4882a593Smuzhiyun 	spin_lock_irq (&hmidi->lock);
2034*4882a593Smuzhiyun 	hmidi->output = NULL;
2035*4882a593Smuzhiyun 	spin_unlock_irq (&hmidi->lock);
2036*4882a593Smuzhiyun 
2037*4882a593Smuzhiyun 	return 0;
2038*4882a593Smuzhiyun }
2039*4882a593Smuzhiyun 
2040*4882a593Smuzhiyun static const struct snd_rawmidi_ops snd_hdspm_midi_output =
2041*4882a593Smuzhiyun {
2042*4882a593Smuzhiyun 	.open =		snd_hdspm_midi_output_open,
2043*4882a593Smuzhiyun 	.close =	snd_hdspm_midi_output_close,
2044*4882a593Smuzhiyun 	.trigger =	snd_hdspm_midi_output_trigger,
2045*4882a593Smuzhiyun };
2046*4882a593Smuzhiyun 
2047*4882a593Smuzhiyun static const struct snd_rawmidi_ops snd_hdspm_midi_input =
2048*4882a593Smuzhiyun {
2049*4882a593Smuzhiyun 	.open =		snd_hdspm_midi_input_open,
2050*4882a593Smuzhiyun 	.close =	snd_hdspm_midi_input_close,
2051*4882a593Smuzhiyun 	.trigger =	snd_hdspm_midi_input_trigger,
2052*4882a593Smuzhiyun };
2053*4882a593Smuzhiyun 
snd_hdspm_create_midi(struct snd_card * card,struct hdspm * hdspm,int id)2054*4882a593Smuzhiyun static int snd_hdspm_create_midi(struct snd_card *card,
2055*4882a593Smuzhiyun 				 struct hdspm *hdspm, int id)
2056*4882a593Smuzhiyun {
2057*4882a593Smuzhiyun 	int err;
2058*4882a593Smuzhiyun 	char buf[64];
2059*4882a593Smuzhiyun 
2060*4882a593Smuzhiyun 	hdspm->midi[id].id = id;
2061*4882a593Smuzhiyun 	hdspm->midi[id].hdspm = hdspm;
2062*4882a593Smuzhiyun 	spin_lock_init (&hdspm->midi[id].lock);
2063*4882a593Smuzhiyun 
2064*4882a593Smuzhiyun 	if (0 == id) {
2065*4882a593Smuzhiyun 		if (MADIface == hdspm->io_type) {
2066*4882a593Smuzhiyun 			/* MIDI-over-MADI on HDSPe MADIface */
2067*4882a593Smuzhiyun 			hdspm->midi[0].dataIn = HDSPM_midiDataIn2;
2068*4882a593Smuzhiyun 			hdspm->midi[0].statusIn = HDSPM_midiStatusIn2;
2069*4882a593Smuzhiyun 			hdspm->midi[0].dataOut = HDSPM_midiDataOut2;
2070*4882a593Smuzhiyun 			hdspm->midi[0].statusOut = HDSPM_midiStatusOut2;
2071*4882a593Smuzhiyun 			hdspm->midi[0].ie = HDSPM_Midi2InterruptEnable;
2072*4882a593Smuzhiyun 			hdspm->midi[0].irq = HDSPM_midi2IRQPending;
2073*4882a593Smuzhiyun 		} else {
2074*4882a593Smuzhiyun 			hdspm->midi[0].dataIn = HDSPM_midiDataIn0;
2075*4882a593Smuzhiyun 			hdspm->midi[0].statusIn = HDSPM_midiStatusIn0;
2076*4882a593Smuzhiyun 			hdspm->midi[0].dataOut = HDSPM_midiDataOut0;
2077*4882a593Smuzhiyun 			hdspm->midi[0].statusOut = HDSPM_midiStatusOut0;
2078*4882a593Smuzhiyun 			hdspm->midi[0].ie = HDSPM_Midi0InterruptEnable;
2079*4882a593Smuzhiyun 			hdspm->midi[0].irq = HDSPM_midi0IRQPending;
2080*4882a593Smuzhiyun 		}
2081*4882a593Smuzhiyun 	} else if (1 == id) {
2082*4882a593Smuzhiyun 		hdspm->midi[1].dataIn = HDSPM_midiDataIn1;
2083*4882a593Smuzhiyun 		hdspm->midi[1].statusIn = HDSPM_midiStatusIn1;
2084*4882a593Smuzhiyun 		hdspm->midi[1].dataOut = HDSPM_midiDataOut1;
2085*4882a593Smuzhiyun 		hdspm->midi[1].statusOut = HDSPM_midiStatusOut1;
2086*4882a593Smuzhiyun 		hdspm->midi[1].ie = HDSPM_Midi1InterruptEnable;
2087*4882a593Smuzhiyun 		hdspm->midi[1].irq = HDSPM_midi1IRQPending;
2088*4882a593Smuzhiyun 	} else if ((2 == id) && (MADI == hdspm->io_type)) {
2089*4882a593Smuzhiyun 		/* MIDI-over-MADI on HDSPe MADI */
2090*4882a593Smuzhiyun 		hdspm->midi[2].dataIn = HDSPM_midiDataIn2;
2091*4882a593Smuzhiyun 		hdspm->midi[2].statusIn = HDSPM_midiStatusIn2;
2092*4882a593Smuzhiyun 		hdspm->midi[2].dataOut = HDSPM_midiDataOut2;
2093*4882a593Smuzhiyun 		hdspm->midi[2].statusOut = HDSPM_midiStatusOut2;
2094*4882a593Smuzhiyun 		hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable;
2095*4882a593Smuzhiyun 		hdspm->midi[2].irq = HDSPM_midi2IRQPending;
2096*4882a593Smuzhiyun 	} else if (2 == id) {
2097*4882a593Smuzhiyun 		/* TCO MTC, read only */
2098*4882a593Smuzhiyun 		hdspm->midi[2].dataIn = HDSPM_midiDataIn2;
2099*4882a593Smuzhiyun 		hdspm->midi[2].statusIn = HDSPM_midiStatusIn2;
2100*4882a593Smuzhiyun 		hdspm->midi[2].dataOut = -1;
2101*4882a593Smuzhiyun 		hdspm->midi[2].statusOut = -1;
2102*4882a593Smuzhiyun 		hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable;
2103*4882a593Smuzhiyun 		hdspm->midi[2].irq = HDSPM_midi2IRQPendingAES;
2104*4882a593Smuzhiyun 	} else if (3 == id) {
2105*4882a593Smuzhiyun 		/* TCO MTC on HDSPe MADI */
2106*4882a593Smuzhiyun 		hdspm->midi[3].dataIn = HDSPM_midiDataIn3;
2107*4882a593Smuzhiyun 		hdspm->midi[3].statusIn = HDSPM_midiStatusIn3;
2108*4882a593Smuzhiyun 		hdspm->midi[3].dataOut = -1;
2109*4882a593Smuzhiyun 		hdspm->midi[3].statusOut = -1;
2110*4882a593Smuzhiyun 		hdspm->midi[3].ie = HDSPM_Midi3InterruptEnable;
2111*4882a593Smuzhiyun 		hdspm->midi[3].irq = HDSPM_midi3IRQPending;
2112*4882a593Smuzhiyun 	}
2113*4882a593Smuzhiyun 
2114*4882a593Smuzhiyun 	if ((id < 2) || ((2 == id) && ((MADI == hdspm->io_type) ||
2115*4882a593Smuzhiyun 					(MADIface == hdspm->io_type)))) {
2116*4882a593Smuzhiyun 		if ((id == 0) && (MADIface == hdspm->io_type)) {
2117*4882a593Smuzhiyun 			snprintf(buf, sizeof(buf), "%s MIDIoverMADI",
2118*4882a593Smuzhiyun 				 card->shortname);
2119*4882a593Smuzhiyun 		} else if ((id == 2) && (MADI == hdspm->io_type)) {
2120*4882a593Smuzhiyun 			snprintf(buf, sizeof(buf), "%s MIDIoverMADI",
2121*4882a593Smuzhiyun 				 card->shortname);
2122*4882a593Smuzhiyun 		} else {
2123*4882a593Smuzhiyun 			snprintf(buf, sizeof(buf), "%s MIDI %d",
2124*4882a593Smuzhiyun 				 card->shortname, id+1);
2125*4882a593Smuzhiyun 		}
2126*4882a593Smuzhiyun 		err = snd_rawmidi_new(card, buf, id, 1, 1,
2127*4882a593Smuzhiyun 				&hdspm->midi[id].rmidi);
2128*4882a593Smuzhiyun 		if (err < 0)
2129*4882a593Smuzhiyun 			return err;
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun 		snprintf(hdspm->midi[id].rmidi->name,
2132*4882a593Smuzhiyun 			 sizeof(hdspm->midi[id].rmidi->name),
2133*4882a593Smuzhiyun 			 "%s MIDI %d", card->id, id+1);
2134*4882a593Smuzhiyun 		hdspm->midi[id].rmidi->private_data = &hdspm->midi[id];
2135*4882a593Smuzhiyun 
2136*4882a593Smuzhiyun 		snd_rawmidi_set_ops(hdspm->midi[id].rmidi,
2137*4882a593Smuzhiyun 				SNDRV_RAWMIDI_STREAM_OUTPUT,
2138*4882a593Smuzhiyun 				&snd_hdspm_midi_output);
2139*4882a593Smuzhiyun 		snd_rawmidi_set_ops(hdspm->midi[id].rmidi,
2140*4882a593Smuzhiyun 				SNDRV_RAWMIDI_STREAM_INPUT,
2141*4882a593Smuzhiyun 				&snd_hdspm_midi_input);
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun 		hdspm->midi[id].rmidi->info_flags |=
2144*4882a593Smuzhiyun 			SNDRV_RAWMIDI_INFO_OUTPUT |
2145*4882a593Smuzhiyun 			SNDRV_RAWMIDI_INFO_INPUT |
2146*4882a593Smuzhiyun 			SNDRV_RAWMIDI_INFO_DUPLEX;
2147*4882a593Smuzhiyun 	} else {
2148*4882a593Smuzhiyun 		/* TCO MTC, read only */
2149*4882a593Smuzhiyun 		snprintf(buf, sizeof(buf), "%s MTC %d",
2150*4882a593Smuzhiyun 			 card->shortname, id+1);
2151*4882a593Smuzhiyun 		err = snd_rawmidi_new(card, buf, id, 1, 1,
2152*4882a593Smuzhiyun 				&hdspm->midi[id].rmidi);
2153*4882a593Smuzhiyun 		if (err < 0)
2154*4882a593Smuzhiyun 			return err;
2155*4882a593Smuzhiyun 
2156*4882a593Smuzhiyun 		snprintf(hdspm->midi[id].rmidi->name,
2157*4882a593Smuzhiyun 			 sizeof(hdspm->midi[id].rmidi->name),
2158*4882a593Smuzhiyun 			 "%s MTC %d", card->id, id+1);
2159*4882a593Smuzhiyun 		hdspm->midi[id].rmidi->private_data = &hdspm->midi[id];
2160*4882a593Smuzhiyun 
2161*4882a593Smuzhiyun 		snd_rawmidi_set_ops(hdspm->midi[id].rmidi,
2162*4882a593Smuzhiyun 				SNDRV_RAWMIDI_STREAM_INPUT,
2163*4882a593Smuzhiyun 				&snd_hdspm_midi_input);
2164*4882a593Smuzhiyun 
2165*4882a593Smuzhiyun 		hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
2166*4882a593Smuzhiyun 	}
2167*4882a593Smuzhiyun 
2168*4882a593Smuzhiyun 	return 0;
2169*4882a593Smuzhiyun }
2170*4882a593Smuzhiyun 
2171*4882a593Smuzhiyun 
hdspm_midi_work(struct work_struct * work)2172*4882a593Smuzhiyun static void hdspm_midi_work(struct work_struct *work)
2173*4882a593Smuzhiyun {
2174*4882a593Smuzhiyun 	struct hdspm *hdspm = container_of(work, struct hdspm, midi_work);
2175*4882a593Smuzhiyun 	int i = 0;
2176*4882a593Smuzhiyun 
2177*4882a593Smuzhiyun 	while (i < hdspm->midiPorts) {
2178*4882a593Smuzhiyun 		if (hdspm->midi[i].pending)
2179*4882a593Smuzhiyun 			snd_hdspm_midi_input_read(&hdspm->midi[i]);
2180*4882a593Smuzhiyun 
2181*4882a593Smuzhiyun 		i++;
2182*4882a593Smuzhiyun 	}
2183*4882a593Smuzhiyun }
2184*4882a593Smuzhiyun 
2185*4882a593Smuzhiyun 
2186*4882a593Smuzhiyun /*-----------------------------------------------------------------------------
2187*4882a593Smuzhiyun   Status Interface
2188*4882a593Smuzhiyun   ----------------------------------------------------------------------------*/
2189*4882a593Smuzhiyun 
2190*4882a593Smuzhiyun /* get the system sample rate which is set */
2191*4882a593Smuzhiyun 
2192*4882a593Smuzhiyun 
hdspm_get_pll_freq(struct hdspm * hdspm)2193*4882a593Smuzhiyun static inline int hdspm_get_pll_freq(struct hdspm *hdspm)
2194*4882a593Smuzhiyun {
2195*4882a593Smuzhiyun 	unsigned int period, rate;
2196*4882a593Smuzhiyun 
2197*4882a593Smuzhiyun 	period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
2198*4882a593Smuzhiyun 	rate = hdspm_calc_dds_value(hdspm, period);
2199*4882a593Smuzhiyun 
2200*4882a593Smuzhiyun 	return rate;
2201*4882a593Smuzhiyun }
2202*4882a593Smuzhiyun 
2203*4882a593Smuzhiyun /*
2204*4882a593Smuzhiyun  * Calculate the real sample rate from the
2205*4882a593Smuzhiyun  * current DDS value.
2206*4882a593Smuzhiyun  */
hdspm_get_system_sample_rate(struct hdspm * hdspm)2207*4882a593Smuzhiyun static int hdspm_get_system_sample_rate(struct hdspm *hdspm)
2208*4882a593Smuzhiyun {
2209*4882a593Smuzhiyun 	unsigned int rate;
2210*4882a593Smuzhiyun 
2211*4882a593Smuzhiyun 	rate = hdspm_get_pll_freq(hdspm);
2212*4882a593Smuzhiyun 
2213*4882a593Smuzhiyun 	if (rate > 207000) {
2214*4882a593Smuzhiyun 		/* Unreasonable high sample rate as seen on PCI MADI cards. */
2215*4882a593Smuzhiyun 		if (0 == hdspm_system_clock_mode(hdspm)) {
2216*4882a593Smuzhiyun 			/* master mode, return internal sample rate */
2217*4882a593Smuzhiyun 			rate = hdspm->system_sample_rate;
2218*4882a593Smuzhiyun 		} else {
2219*4882a593Smuzhiyun 			/* slave mode, return external sample rate */
2220*4882a593Smuzhiyun 			rate = hdspm_external_sample_rate(hdspm);
2221*4882a593Smuzhiyun 			if (!rate)
2222*4882a593Smuzhiyun 				rate = hdspm->system_sample_rate;
2223*4882a593Smuzhiyun 		}
2224*4882a593Smuzhiyun 	}
2225*4882a593Smuzhiyun 
2226*4882a593Smuzhiyun 	return rate;
2227*4882a593Smuzhiyun }
2228*4882a593Smuzhiyun 
2229*4882a593Smuzhiyun 
2230*4882a593Smuzhiyun #define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \
2231*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2232*4882a593Smuzhiyun 	.name = xname, \
2233*4882a593Smuzhiyun 	.index = xindex, \
2234*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
2235*4882a593Smuzhiyun 		SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
2236*4882a593Smuzhiyun 	.info = snd_hdspm_info_system_sample_rate, \
2237*4882a593Smuzhiyun 	.put = snd_hdspm_put_system_sample_rate, \
2238*4882a593Smuzhiyun 	.get = snd_hdspm_get_system_sample_rate \
2239*4882a593Smuzhiyun }
2240*4882a593Smuzhiyun 
snd_hdspm_info_system_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2241*4882a593Smuzhiyun static int snd_hdspm_info_system_sample_rate(struct snd_kcontrol *kcontrol,
2242*4882a593Smuzhiyun 					     struct snd_ctl_elem_info *uinfo)
2243*4882a593Smuzhiyun {
2244*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2245*4882a593Smuzhiyun 	uinfo->count = 1;
2246*4882a593Smuzhiyun 	uinfo->value.integer.min = 27000;
2247*4882a593Smuzhiyun 	uinfo->value.integer.max = 207000;
2248*4882a593Smuzhiyun 	uinfo->value.integer.step = 1;
2249*4882a593Smuzhiyun 	return 0;
2250*4882a593Smuzhiyun }
2251*4882a593Smuzhiyun 
2252*4882a593Smuzhiyun 
snd_hdspm_get_system_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2253*4882a593Smuzhiyun static int snd_hdspm_get_system_sample_rate(struct snd_kcontrol *kcontrol,
2254*4882a593Smuzhiyun 					    struct snd_ctl_elem_value *
2255*4882a593Smuzhiyun 					    ucontrol)
2256*4882a593Smuzhiyun {
2257*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2258*4882a593Smuzhiyun 
2259*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = hdspm_get_system_sample_rate(hdspm);
2260*4882a593Smuzhiyun 	return 0;
2261*4882a593Smuzhiyun }
2262*4882a593Smuzhiyun 
snd_hdspm_put_system_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2263*4882a593Smuzhiyun static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol,
2264*4882a593Smuzhiyun 					    struct snd_ctl_elem_value *
2265*4882a593Smuzhiyun 					    ucontrol)
2266*4882a593Smuzhiyun {
2267*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2268*4882a593Smuzhiyun 	int rate = ucontrol->value.integer.value[0];
2269*4882a593Smuzhiyun 
2270*4882a593Smuzhiyun 	if (rate < 27000 || rate > 207000)
2271*4882a593Smuzhiyun 		return -EINVAL;
2272*4882a593Smuzhiyun 	hdspm_set_dds_value(hdspm, ucontrol->value.integer.value[0]);
2273*4882a593Smuzhiyun 	return 0;
2274*4882a593Smuzhiyun }
2275*4882a593Smuzhiyun 
2276*4882a593Smuzhiyun 
2277*4882a593Smuzhiyun /*
2278*4882a593Smuzhiyun  * Returns the WordClock sample rate class for the given card.
2279*4882a593Smuzhiyun  */
hdspm_get_wc_sample_rate(struct hdspm * hdspm)2280*4882a593Smuzhiyun static int hdspm_get_wc_sample_rate(struct hdspm *hdspm)
2281*4882a593Smuzhiyun {
2282*4882a593Smuzhiyun 	int status;
2283*4882a593Smuzhiyun 
2284*4882a593Smuzhiyun 	switch (hdspm->io_type) {
2285*4882a593Smuzhiyun 	case RayDAT:
2286*4882a593Smuzhiyun 	case AIO:
2287*4882a593Smuzhiyun 		status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
2288*4882a593Smuzhiyun 		return (status >> 16) & 0xF;
2289*4882a593Smuzhiyun 		break;
2290*4882a593Smuzhiyun 	case AES32:
2291*4882a593Smuzhiyun 		status = hdspm_read(hdspm, HDSPM_statusRegister);
2292*4882a593Smuzhiyun 		return (status >> HDSPM_AES32_wcFreq_bit) & 0xF;
2293*4882a593Smuzhiyun 	default:
2294*4882a593Smuzhiyun 		break;
2295*4882a593Smuzhiyun 	}
2296*4882a593Smuzhiyun 
2297*4882a593Smuzhiyun 
2298*4882a593Smuzhiyun 	return 0;
2299*4882a593Smuzhiyun }
2300*4882a593Smuzhiyun 
2301*4882a593Smuzhiyun 
2302*4882a593Smuzhiyun /*
2303*4882a593Smuzhiyun  * Returns the TCO sample rate class for the given card.
2304*4882a593Smuzhiyun  */
hdspm_get_tco_sample_rate(struct hdspm * hdspm)2305*4882a593Smuzhiyun static int hdspm_get_tco_sample_rate(struct hdspm *hdspm)
2306*4882a593Smuzhiyun {
2307*4882a593Smuzhiyun 	int status;
2308*4882a593Smuzhiyun 
2309*4882a593Smuzhiyun 	if (hdspm->tco) {
2310*4882a593Smuzhiyun 		switch (hdspm->io_type) {
2311*4882a593Smuzhiyun 		case RayDAT:
2312*4882a593Smuzhiyun 		case AIO:
2313*4882a593Smuzhiyun 			status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
2314*4882a593Smuzhiyun 			return (status >> 20) & 0xF;
2315*4882a593Smuzhiyun 			break;
2316*4882a593Smuzhiyun 		case AES32:
2317*4882a593Smuzhiyun 			status = hdspm_read(hdspm, HDSPM_statusRegister);
2318*4882a593Smuzhiyun 			return (status >> 1) & 0xF;
2319*4882a593Smuzhiyun 		default:
2320*4882a593Smuzhiyun 			break;
2321*4882a593Smuzhiyun 		}
2322*4882a593Smuzhiyun 	}
2323*4882a593Smuzhiyun 
2324*4882a593Smuzhiyun 	return 0;
2325*4882a593Smuzhiyun }
2326*4882a593Smuzhiyun 
2327*4882a593Smuzhiyun 
2328*4882a593Smuzhiyun /*
2329*4882a593Smuzhiyun  * Returns the SYNC_IN sample rate class for the given card.
2330*4882a593Smuzhiyun  */
hdspm_get_sync_in_sample_rate(struct hdspm * hdspm)2331*4882a593Smuzhiyun static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm)
2332*4882a593Smuzhiyun {
2333*4882a593Smuzhiyun 	int status;
2334*4882a593Smuzhiyun 
2335*4882a593Smuzhiyun 	if (hdspm->tco) {
2336*4882a593Smuzhiyun 		switch (hdspm->io_type) {
2337*4882a593Smuzhiyun 		case RayDAT:
2338*4882a593Smuzhiyun 		case AIO:
2339*4882a593Smuzhiyun 			status = hdspm_read(hdspm, HDSPM_RD_STATUS_2);
2340*4882a593Smuzhiyun 			return (status >> 12) & 0xF;
2341*4882a593Smuzhiyun 			break;
2342*4882a593Smuzhiyun 		default:
2343*4882a593Smuzhiyun 			break;
2344*4882a593Smuzhiyun 		}
2345*4882a593Smuzhiyun 	}
2346*4882a593Smuzhiyun 
2347*4882a593Smuzhiyun 	return 0;
2348*4882a593Smuzhiyun }
2349*4882a593Smuzhiyun 
2350*4882a593Smuzhiyun /*
2351*4882a593Smuzhiyun  * Returns the AES sample rate class for the given card.
2352*4882a593Smuzhiyun  */
hdspm_get_aes_sample_rate(struct hdspm * hdspm,int index)2353*4882a593Smuzhiyun static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index)
2354*4882a593Smuzhiyun {
2355*4882a593Smuzhiyun 	int timecode;
2356*4882a593Smuzhiyun 
2357*4882a593Smuzhiyun 	switch (hdspm->io_type) {
2358*4882a593Smuzhiyun 	case AES32:
2359*4882a593Smuzhiyun 		timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
2360*4882a593Smuzhiyun 		return (timecode >> (4*index)) & 0xF;
2361*4882a593Smuzhiyun 		break;
2362*4882a593Smuzhiyun 	default:
2363*4882a593Smuzhiyun 		break;
2364*4882a593Smuzhiyun 	}
2365*4882a593Smuzhiyun 	return 0;
2366*4882a593Smuzhiyun }
2367*4882a593Smuzhiyun 
2368*4882a593Smuzhiyun /*
2369*4882a593Smuzhiyun  * Returns the sample rate class for input source <idx> for
2370*4882a593Smuzhiyun  * 'new style' cards like the AIO and RayDAT.
2371*4882a593Smuzhiyun  */
hdspm_get_s1_sample_rate(struct hdspm * hdspm,unsigned int idx)2372*4882a593Smuzhiyun static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
2373*4882a593Smuzhiyun {
2374*4882a593Smuzhiyun 	int status = hdspm_read(hdspm, HDSPM_RD_STATUS_2);
2375*4882a593Smuzhiyun 
2376*4882a593Smuzhiyun 	return (status >> (idx*4)) & 0xF;
2377*4882a593Smuzhiyun }
2378*4882a593Smuzhiyun 
2379*4882a593Smuzhiyun #define ENUMERATED_CTL_INFO(info, texts) \
2380*4882a593Smuzhiyun 	snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts)
2381*4882a593Smuzhiyun 
2382*4882a593Smuzhiyun 
2383*4882a593Smuzhiyun /* Helper function to query the external sample rate and return the
2384*4882a593Smuzhiyun  * corresponding enum to be returned to userspace.
2385*4882a593Smuzhiyun  */
hdspm_external_rate_to_enum(struct hdspm * hdspm)2386*4882a593Smuzhiyun static int hdspm_external_rate_to_enum(struct hdspm *hdspm)
2387*4882a593Smuzhiyun {
2388*4882a593Smuzhiyun 	int rate = hdspm_external_sample_rate(hdspm);
2389*4882a593Smuzhiyun 	int i, selected_rate = 0;
2390*4882a593Smuzhiyun 	for (i = 1; i < 10; i++)
2391*4882a593Smuzhiyun 		if (HDSPM_bit2freq(i) == rate) {
2392*4882a593Smuzhiyun 			selected_rate = i;
2393*4882a593Smuzhiyun 			break;
2394*4882a593Smuzhiyun 		}
2395*4882a593Smuzhiyun 	return selected_rate;
2396*4882a593Smuzhiyun }
2397*4882a593Smuzhiyun 
2398*4882a593Smuzhiyun 
2399*4882a593Smuzhiyun #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
2400*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2401*4882a593Smuzhiyun 	.name = xname, \
2402*4882a593Smuzhiyun 	.private_value = xindex, \
2403*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READ, \
2404*4882a593Smuzhiyun 	.info = snd_hdspm_info_autosync_sample_rate, \
2405*4882a593Smuzhiyun 	.get = snd_hdspm_get_autosync_sample_rate \
2406*4882a593Smuzhiyun }
2407*4882a593Smuzhiyun 
2408*4882a593Smuzhiyun 
snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2409*4882a593Smuzhiyun static int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol,
2410*4882a593Smuzhiyun 					       struct snd_ctl_elem_info *uinfo)
2411*4882a593Smuzhiyun {
2412*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts_freq);
2413*4882a593Smuzhiyun 	return 0;
2414*4882a593Smuzhiyun }
2415*4882a593Smuzhiyun 
2416*4882a593Smuzhiyun 
snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2417*4882a593Smuzhiyun static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
2418*4882a593Smuzhiyun 					      struct snd_ctl_elem_value *
2419*4882a593Smuzhiyun 					      ucontrol)
2420*4882a593Smuzhiyun {
2421*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2422*4882a593Smuzhiyun 
2423*4882a593Smuzhiyun 	switch (hdspm->io_type) {
2424*4882a593Smuzhiyun 	case RayDAT:
2425*4882a593Smuzhiyun 		switch (kcontrol->private_value) {
2426*4882a593Smuzhiyun 		case 0:
2427*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2428*4882a593Smuzhiyun 				hdspm_get_wc_sample_rate(hdspm);
2429*4882a593Smuzhiyun 			break;
2430*4882a593Smuzhiyun 		case 7:
2431*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2432*4882a593Smuzhiyun 				hdspm_get_tco_sample_rate(hdspm);
2433*4882a593Smuzhiyun 			break;
2434*4882a593Smuzhiyun 		case 8:
2435*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2436*4882a593Smuzhiyun 				hdspm_get_sync_in_sample_rate(hdspm);
2437*4882a593Smuzhiyun 			break;
2438*4882a593Smuzhiyun 		default:
2439*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2440*4882a593Smuzhiyun 				hdspm_get_s1_sample_rate(hdspm,
2441*4882a593Smuzhiyun 						kcontrol->private_value-1);
2442*4882a593Smuzhiyun 		}
2443*4882a593Smuzhiyun 		break;
2444*4882a593Smuzhiyun 
2445*4882a593Smuzhiyun 	case AIO:
2446*4882a593Smuzhiyun 		switch (kcontrol->private_value) {
2447*4882a593Smuzhiyun 		case 0: /* WC */
2448*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2449*4882a593Smuzhiyun 				hdspm_get_wc_sample_rate(hdspm);
2450*4882a593Smuzhiyun 			break;
2451*4882a593Smuzhiyun 		case 4: /* TCO */
2452*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2453*4882a593Smuzhiyun 				hdspm_get_tco_sample_rate(hdspm);
2454*4882a593Smuzhiyun 			break;
2455*4882a593Smuzhiyun 		case 5: /* SYNC_IN */
2456*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2457*4882a593Smuzhiyun 				hdspm_get_sync_in_sample_rate(hdspm);
2458*4882a593Smuzhiyun 			break;
2459*4882a593Smuzhiyun 		default:
2460*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2461*4882a593Smuzhiyun 				hdspm_get_s1_sample_rate(hdspm,
2462*4882a593Smuzhiyun 						kcontrol->private_value-1);
2463*4882a593Smuzhiyun 		}
2464*4882a593Smuzhiyun 		break;
2465*4882a593Smuzhiyun 
2466*4882a593Smuzhiyun 	case AES32:
2467*4882a593Smuzhiyun 
2468*4882a593Smuzhiyun 		switch (kcontrol->private_value) {
2469*4882a593Smuzhiyun 		case 0: /* WC */
2470*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2471*4882a593Smuzhiyun 				hdspm_get_wc_sample_rate(hdspm);
2472*4882a593Smuzhiyun 			break;
2473*4882a593Smuzhiyun 		case 9: /* TCO */
2474*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2475*4882a593Smuzhiyun 				hdspm_get_tco_sample_rate(hdspm);
2476*4882a593Smuzhiyun 			break;
2477*4882a593Smuzhiyun 		case 10: /* SYNC_IN */
2478*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2479*4882a593Smuzhiyun 				hdspm_get_sync_in_sample_rate(hdspm);
2480*4882a593Smuzhiyun 			break;
2481*4882a593Smuzhiyun 		case 11: /* External Rate */
2482*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2483*4882a593Smuzhiyun 				hdspm_external_rate_to_enum(hdspm);
2484*4882a593Smuzhiyun 			break;
2485*4882a593Smuzhiyun 		default: /* AES1 to AES8 */
2486*4882a593Smuzhiyun 			ucontrol->value.enumerated.item[0] =
2487*4882a593Smuzhiyun 				hdspm_get_aes_sample_rate(hdspm,
2488*4882a593Smuzhiyun 						kcontrol->private_value -
2489*4882a593Smuzhiyun 						HDSPM_AES32_AUTOSYNC_FROM_AES1);
2490*4882a593Smuzhiyun 			break;
2491*4882a593Smuzhiyun 		}
2492*4882a593Smuzhiyun 		break;
2493*4882a593Smuzhiyun 
2494*4882a593Smuzhiyun 	case MADI:
2495*4882a593Smuzhiyun 	case MADIface:
2496*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] =
2497*4882a593Smuzhiyun 			hdspm_external_rate_to_enum(hdspm);
2498*4882a593Smuzhiyun 		break;
2499*4882a593Smuzhiyun 	default:
2500*4882a593Smuzhiyun 		break;
2501*4882a593Smuzhiyun 	}
2502*4882a593Smuzhiyun 
2503*4882a593Smuzhiyun 	return 0;
2504*4882a593Smuzhiyun }
2505*4882a593Smuzhiyun 
2506*4882a593Smuzhiyun 
2507*4882a593Smuzhiyun #define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \
2508*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2509*4882a593Smuzhiyun 	.name = xname, \
2510*4882a593Smuzhiyun 	.index = xindex, \
2511*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
2512*4882a593Smuzhiyun 		SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
2513*4882a593Smuzhiyun 	.info = snd_hdspm_info_system_clock_mode, \
2514*4882a593Smuzhiyun 	.get = snd_hdspm_get_system_clock_mode, \
2515*4882a593Smuzhiyun 	.put = snd_hdspm_put_system_clock_mode, \
2516*4882a593Smuzhiyun }
2517*4882a593Smuzhiyun 
2518*4882a593Smuzhiyun 
2519*4882a593Smuzhiyun /*
2520*4882a593Smuzhiyun  * Returns the system clock mode for the given card.
2521*4882a593Smuzhiyun  * @returns 0 - master, 1 - slave
2522*4882a593Smuzhiyun  */
hdspm_system_clock_mode(struct hdspm * hdspm)2523*4882a593Smuzhiyun static int hdspm_system_clock_mode(struct hdspm *hdspm)
2524*4882a593Smuzhiyun {
2525*4882a593Smuzhiyun 	switch (hdspm->io_type) {
2526*4882a593Smuzhiyun 	case AIO:
2527*4882a593Smuzhiyun 	case RayDAT:
2528*4882a593Smuzhiyun 		if (hdspm->settings_register & HDSPM_c0Master)
2529*4882a593Smuzhiyun 			return 0;
2530*4882a593Smuzhiyun 		break;
2531*4882a593Smuzhiyun 
2532*4882a593Smuzhiyun 	default:
2533*4882a593Smuzhiyun 		if (hdspm->control_register & HDSPM_ClockModeMaster)
2534*4882a593Smuzhiyun 			return 0;
2535*4882a593Smuzhiyun 	}
2536*4882a593Smuzhiyun 
2537*4882a593Smuzhiyun 	return 1;
2538*4882a593Smuzhiyun }
2539*4882a593Smuzhiyun 
2540*4882a593Smuzhiyun 
2541*4882a593Smuzhiyun /*
2542*4882a593Smuzhiyun  * Sets the system clock mode.
2543*4882a593Smuzhiyun  * @param mode 0 - master, 1 - slave
2544*4882a593Smuzhiyun  */
hdspm_set_system_clock_mode(struct hdspm * hdspm,int mode)2545*4882a593Smuzhiyun static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode)
2546*4882a593Smuzhiyun {
2547*4882a593Smuzhiyun 	hdspm_set_toggle_setting(hdspm,
2548*4882a593Smuzhiyun 			(hdspm_is_raydat_or_aio(hdspm)) ?
2549*4882a593Smuzhiyun 			HDSPM_c0Master : HDSPM_ClockModeMaster,
2550*4882a593Smuzhiyun 			(0 == mode));
2551*4882a593Smuzhiyun }
2552*4882a593Smuzhiyun 
2553*4882a593Smuzhiyun 
snd_hdspm_info_system_clock_mode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2554*4882a593Smuzhiyun static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol,
2555*4882a593Smuzhiyun 					    struct snd_ctl_elem_info *uinfo)
2556*4882a593Smuzhiyun {
2557*4882a593Smuzhiyun 	static const char *const texts[] = { "Master", "AutoSync" };
2558*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
2559*4882a593Smuzhiyun 	return 0;
2560*4882a593Smuzhiyun }
2561*4882a593Smuzhiyun 
snd_hdspm_get_system_clock_mode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2562*4882a593Smuzhiyun static int snd_hdspm_get_system_clock_mode(struct snd_kcontrol *kcontrol,
2563*4882a593Smuzhiyun 					   struct snd_ctl_elem_value *ucontrol)
2564*4882a593Smuzhiyun {
2565*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2566*4882a593Smuzhiyun 
2567*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm_system_clock_mode(hdspm);
2568*4882a593Smuzhiyun 	return 0;
2569*4882a593Smuzhiyun }
2570*4882a593Smuzhiyun 
snd_hdspm_put_system_clock_mode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2571*4882a593Smuzhiyun static int snd_hdspm_put_system_clock_mode(struct snd_kcontrol *kcontrol,
2572*4882a593Smuzhiyun 					   struct snd_ctl_elem_value *ucontrol)
2573*4882a593Smuzhiyun {
2574*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2575*4882a593Smuzhiyun 	int val;
2576*4882a593Smuzhiyun 
2577*4882a593Smuzhiyun 	if (!snd_hdspm_use_is_exclusive(hdspm))
2578*4882a593Smuzhiyun 		return -EBUSY;
2579*4882a593Smuzhiyun 
2580*4882a593Smuzhiyun 	val = ucontrol->value.enumerated.item[0];
2581*4882a593Smuzhiyun 	if (val < 0)
2582*4882a593Smuzhiyun 		val = 0;
2583*4882a593Smuzhiyun 	else if (val > 1)
2584*4882a593Smuzhiyun 		val = 1;
2585*4882a593Smuzhiyun 
2586*4882a593Smuzhiyun 	hdspm_set_system_clock_mode(hdspm, val);
2587*4882a593Smuzhiyun 
2588*4882a593Smuzhiyun 	return 0;
2589*4882a593Smuzhiyun }
2590*4882a593Smuzhiyun 
2591*4882a593Smuzhiyun 
2592*4882a593Smuzhiyun #define HDSPM_INTERNAL_CLOCK(xname, xindex) \
2593*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2594*4882a593Smuzhiyun 	.name = xname, \
2595*4882a593Smuzhiyun 	.index = xindex, \
2596*4882a593Smuzhiyun 	.info = snd_hdspm_info_clock_source, \
2597*4882a593Smuzhiyun 	.get = snd_hdspm_get_clock_source, \
2598*4882a593Smuzhiyun 	.put = snd_hdspm_put_clock_source \
2599*4882a593Smuzhiyun }
2600*4882a593Smuzhiyun 
2601*4882a593Smuzhiyun 
hdspm_clock_source(struct hdspm * hdspm)2602*4882a593Smuzhiyun static int hdspm_clock_source(struct hdspm * hdspm)
2603*4882a593Smuzhiyun {
2604*4882a593Smuzhiyun 	switch (hdspm->system_sample_rate) {
2605*4882a593Smuzhiyun 	case 32000: return 0;
2606*4882a593Smuzhiyun 	case 44100: return 1;
2607*4882a593Smuzhiyun 	case 48000: return 2;
2608*4882a593Smuzhiyun 	case 64000: return 3;
2609*4882a593Smuzhiyun 	case 88200: return 4;
2610*4882a593Smuzhiyun 	case 96000: return 5;
2611*4882a593Smuzhiyun 	case 128000: return 6;
2612*4882a593Smuzhiyun 	case 176400: return 7;
2613*4882a593Smuzhiyun 	case 192000: return 8;
2614*4882a593Smuzhiyun 	}
2615*4882a593Smuzhiyun 
2616*4882a593Smuzhiyun 	return -1;
2617*4882a593Smuzhiyun }
2618*4882a593Smuzhiyun 
hdspm_set_clock_source(struct hdspm * hdspm,int mode)2619*4882a593Smuzhiyun static int hdspm_set_clock_source(struct hdspm * hdspm, int mode)
2620*4882a593Smuzhiyun {
2621*4882a593Smuzhiyun 	int rate;
2622*4882a593Smuzhiyun 	switch (mode) {
2623*4882a593Smuzhiyun 	case 0:
2624*4882a593Smuzhiyun 		rate = 32000; break;
2625*4882a593Smuzhiyun 	case 1:
2626*4882a593Smuzhiyun 		rate = 44100; break;
2627*4882a593Smuzhiyun 	case 2:
2628*4882a593Smuzhiyun 		rate = 48000; break;
2629*4882a593Smuzhiyun 	case 3:
2630*4882a593Smuzhiyun 		rate = 64000; break;
2631*4882a593Smuzhiyun 	case 4:
2632*4882a593Smuzhiyun 		rate = 88200; break;
2633*4882a593Smuzhiyun 	case 5:
2634*4882a593Smuzhiyun 		rate = 96000; break;
2635*4882a593Smuzhiyun 	case 6:
2636*4882a593Smuzhiyun 		rate = 128000; break;
2637*4882a593Smuzhiyun 	case 7:
2638*4882a593Smuzhiyun 		rate = 176400; break;
2639*4882a593Smuzhiyun 	case 8:
2640*4882a593Smuzhiyun 		rate = 192000; break;
2641*4882a593Smuzhiyun 	default:
2642*4882a593Smuzhiyun 		rate = 48000;
2643*4882a593Smuzhiyun 	}
2644*4882a593Smuzhiyun 	hdspm_set_rate(hdspm, rate, 1);
2645*4882a593Smuzhiyun 	return 0;
2646*4882a593Smuzhiyun }
2647*4882a593Smuzhiyun 
snd_hdspm_info_clock_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2648*4882a593Smuzhiyun static int snd_hdspm_info_clock_source(struct snd_kcontrol *kcontrol,
2649*4882a593Smuzhiyun 				       struct snd_ctl_elem_info *uinfo)
2650*4882a593Smuzhiyun {
2651*4882a593Smuzhiyun 	return snd_ctl_enum_info(uinfo, 1, 9, texts_freq + 1);
2652*4882a593Smuzhiyun }
2653*4882a593Smuzhiyun 
snd_hdspm_get_clock_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2654*4882a593Smuzhiyun static int snd_hdspm_get_clock_source(struct snd_kcontrol *kcontrol,
2655*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
2656*4882a593Smuzhiyun {
2657*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2658*4882a593Smuzhiyun 
2659*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm_clock_source(hdspm);
2660*4882a593Smuzhiyun 	return 0;
2661*4882a593Smuzhiyun }
2662*4882a593Smuzhiyun 
snd_hdspm_put_clock_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2663*4882a593Smuzhiyun static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol,
2664*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
2665*4882a593Smuzhiyun {
2666*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2667*4882a593Smuzhiyun 	int change;
2668*4882a593Smuzhiyun 	int val;
2669*4882a593Smuzhiyun 
2670*4882a593Smuzhiyun 	if (!snd_hdspm_use_is_exclusive(hdspm))
2671*4882a593Smuzhiyun 		return -EBUSY;
2672*4882a593Smuzhiyun 	val = ucontrol->value.enumerated.item[0];
2673*4882a593Smuzhiyun 	if (val < 0)
2674*4882a593Smuzhiyun 		val = 0;
2675*4882a593Smuzhiyun 	if (val > 9)
2676*4882a593Smuzhiyun 		val = 9;
2677*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
2678*4882a593Smuzhiyun 	if (val != hdspm_clock_source(hdspm))
2679*4882a593Smuzhiyun 		change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0;
2680*4882a593Smuzhiyun 	else
2681*4882a593Smuzhiyun 		change = 0;
2682*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
2683*4882a593Smuzhiyun 	return change;
2684*4882a593Smuzhiyun }
2685*4882a593Smuzhiyun 
2686*4882a593Smuzhiyun 
2687*4882a593Smuzhiyun #define HDSPM_PREF_SYNC_REF(xname, xindex) \
2688*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2689*4882a593Smuzhiyun 	.name = xname, \
2690*4882a593Smuzhiyun 	.index = xindex, \
2691*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
2692*4882a593Smuzhiyun 			SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
2693*4882a593Smuzhiyun 	.info = snd_hdspm_info_pref_sync_ref, \
2694*4882a593Smuzhiyun 	.get = snd_hdspm_get_pref_sync_ref, \
2695*4882a593Smuzhiyun 	.put = snd_hdspm_put_pref_sync_ref \
2696*4882a593Smuzhiyun }
2697*4882a593Smuzhiyun 
2698*4882a593Smuzhiyun 
2699*4882a593Smuzhiyun /*
2700*4882a593Smuzhiyun  * Returns the current preferred sync reference setting.
2701*4882a593Smuzhiyun  * The semantics of the return value are depending on the
2702*4882a593Smuzhiyun  * card, please see the comments for clarification.
2703*4882a593Smuzhiyun  */
hdspm_pref_sync_ref(struct hdspm * hdspm)2704*4882a593Smuzhiyun static int hdspm_pref_sync_ref(struct hdspm * hdspm)
2705*4882a593Smuzhiyun {
2706*4882a593Smuzhiyun 	switch (hdspm->io_type) {
2707*4882a593Smuzhiyun 	case AES32:
2708*4882a593Smuzhiyun 		switch (hdspm->control_register & HDSPM_SyncRefMask) {
2709*4882a593Smuzhiyun 		case 0: return 0;  /* WC */
2710*4882a593Smuzhiyun 		case HDSPM_SyncRef0: return 1; /* AES 1 */
2711*4882a593Smuzhiyun 		case HDSPM_SyncRef1: return 2; /* AES 2 */
2712*4882a593Smuzhiyun 		case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3; /* AES 3 */
2713*4882a593Smuzhiyun 		case HDSPM_SyncRef2: return 4; /* AES 4 */
2714*4882a593Smuzhiyun 		case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5; /* AES 5 */
2715*4882a593Smuzhiyun 		case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6; /* AES 6 */
2716*4882a593Smuzhiyun 		case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0:
2717*4882a593Smuzhiyun 						    return 7; /* AES 7 */
2718*4882a593Smuzhiyun 		case HDSPM_SyncRef3: return 8; /* AES 8 */
2719*4882a593Smuzhiyun 		case HDSPM_SyncRef3+HDSPM_SyncRef0: return 9; /* TCO */
2720*4882a593Smuzhiyun 		}
2721*4882a593Smuzhiyun 		break;
2722*4882a593Smuzhiyun 
2723*4882a593Smuzhiyun 	case MADI:
2724*4882a593Smuzhiyun 	case MADIface:
2725*4882a593Smuzhiyun 		if (hdspm->tco) {
2726*4882a593Smuzhiyun 			switch (hdspm->control_register & HDSPM_SyncRefMask) {
2727*4882a593Smuzhiyun 			case 0: return 0;  /* WC */
2728*4882a593Smuzhiyun 			case HDSPM_SyncRef0: return 1;  /* MADI */
2729*4882a593Smuzhiyun 			case HDSPM_SyncRef1: return 2;  /* TCO */
2730*4882a593Smuzhiyun 			case HDSPM_SyncRef1+HDSPM_SyncRef0:
2731*4882a593Smuzhiyun 					     return 3;  /* SYNC_IN */
2732*4882a593Smuzhiyun 			}
2733*4882a593Smuzhiyun 		} else {
2734*4882a593Smuzhiyun 			switch (hdspm->control_register & HDSPM_SyncRefMask) {
2735*4882a593Smuzhiyun 			case 0: return 0;  /* WC */
2736*4882a593Smuzhiyun 			case HDSPM_SyncRef0: return 1;  /* MADI */
2737*4882a593Smuzhiyun 			case HDSPM_SyncRef1+HDSPM_SyncRef0:
2738*4882a593Smuzhiyun 					     return 2;  /* SYNC_IN */
2739*4882a593Smuzhiyun 			}
2740*4882a593Smuzhiyun 		}
2741*4882a593Smuzhiyun 		break;
2742*4882a593Smuzhiyun 
2743*4882a593Smuzhiyun 	case RayDAT:
2744*4882a593Smuzhiyun 		if (hdspm->tco) {
2745*4882a593Smuzhiyun 			switch ((hdspm->settings_register &
2746*4882a593Smuzhiyun 				HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
2747*4882a593Smuzhiyun 			case 0: return 0;  /* WC */
2748*4882a593Smuzhiyun 			case 3: return 1;  /* ADAT 1 */
2749*4882a593Smuzhiyun 			case 4: return 2;  /* ADAT 2 */
2750*4882a593Smuzhiyun 			case 5: return 3;  /* ADAT 3 */
2751*4882a593Smuzhiyun 			case 6: return 4;  /* ADAT 4 */
2752*4882a593Smuzhiyun 			case 1: return 5;  /* AES */
2753*4882a593Smuzhiyun 			case 2: return 6;  /* SPDIF */
2754*4882a593Smuzhiyun 			case 9: return 7;  /* TCO */
2755*4882a593Smuzhiyun 			case 10: return 8; /* SYNC_IN */
2756*4882a593Smuzhiyun 			}
2757*4882a593Smuzhiyun 		} else {
2758*4882a593Smuzhiyun 			switch ((hdspm->settings_register &
2759*4882a593Smuzhiyun 				HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
2760*4882a593Smuzhiyun 			case 0: return 0;  /* WC */
2761*4882a593Smuzhiyun 			case 3: return 1;  /* ADAT 1 */
2762*4882a593Smuzhiyun 			case 4: return 2;  /* ADAT 2 */
2763*4882a593Smuzhiyun 			case 5: return 3;  /* ADAT 3 */
2764*4882a593Smuzhiyun 			case 6: return 4;  /* ADAT 4 */
2765*4882a593Smuzhiyun 			case 1: return 5;  /* AES */
2766*4882a593Smuzhiyun 			case 2: return 6;  /* SPDIF */
2767*4882a593Smuzhiyun 			case 10: return 7; /* SYNC_IN */
2768*4882a593Smuzhiyun 			}
2769*4882a593Smuzhiyun 		}
2770*4882a593Smuzhiyun 
2771*4882a593Smuzhiyun 		break;
2772*4882a593Smuzhiyun 
2773*4882a593Smuzhiyun 	case AIO:
2774*4882a593Smuzhiyun 		if (hdspm->tco) {
2775*4882a593Smuzhiyun 			switch ((hdspm->settings_register &
2776*4882a593Smuzhiyun 				HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
2777*4882a593Smuzhiyun 			case 0: return 0;  /* WC */
2778*4882a593Smuzhiyun 			case 3: return 1;  /* ADAT */
2779*4882a593Smuzhiyun 			case 1: return 2;  /* AES */
2780*4882a593Smuzhiyun 			case 2: return 3;  /* SPDIF */
2781*4882a593Smuzhiyun 			case 9: return 4;  /* TCO */
2782*4882a593Smuzhiyun 			case 10: return 5; /* SYNC_IN */
2783*4882a593Smuzhiyun 			}
2784*4882a593Smuzhiyun 		} else {
2785*4882a593Smuzhiyun 			switch ((hdspm->settings_register &
2786*4882a593Smuzhiyun 				HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
2787*4882a593Smuzhiyun 			case 0: return 0;  /* WC */
2788*4882a593Smuzhiyun 			case 3: return 1;  /* ADAT */
2789*4882a593Smuzhiyun 			case 1: return 2;  /* AES */
2790*4882a593Smuzhiyun 			case 2: return 3;  /* SPDIF */
2791*4882a593Smuzhiyun 			case 10: return 4; /* SYNC_IN */
2792*4882a593Smuzhiyun 			}
2793*4882a593Smuzhiyun 		}
2794*4882a593Smuzhiyun 
2795*4882a593Smuzhiyun 		break;
2796*4882a593Smuzhiyun 	}
2797*4882a593Smuzhiyun 
2798*4882a593Smuzhiyun 	return -1;
2799*4882a593Smuzhiyun }
2800*4882a593Smuzhiyun 
2801*4882a593Smuzhiyun 
2802*4882a593Smuzhiyun /*
2803*4882a593Smuzhiyun  * Set the preferred sync reference to <pref>. The semantics
2804*4882a593Smuzhiyun  * of <pref> are depending on the card type, see the comments
2805*4882a593Smuzhiyun  * for clarification.
2806*4882a593Smuzhiyun  */
hdspm_set_pref_sync_ref(struct hdspm * hdspm,int pref)2807*4882a593Smuzhiyun static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref)
2808*4882a593Smuzhiyun {
2809*4882a593Smuzhiyun 	int p = 0;
2810*4882a593Smuzhiyun 
2811*4882a593Smuzhiyun 	switch (hdspm->io_type) {
2812*4882a593Smuzhiyun 	case AES32:
2813*4882a593Smuzhiyun 		hdspm->control_register &= ~HDSPM_SyncRefMask;
2814*4882a593Smuzhiyun 		switch (pref) {
2815*4882a593Smuzhiyun 		case 0: /* WC  */
2816*4882a593Smuzhiyun 			break;
2817*4882a593Smuzhiyun 		case 1: /* AES 1 */
2818*4882a593Smuzhiyun 			hdspm->control_register |= HDSPM_SyncRef0;
2819*4882a593Smuzhiyun 			break;
2820*4882a593Smuzhiyun 		case 2: /* AES 2 */
2821*4882a593Smuzhiyun 			hdspm->control_register |= HDSPM_SyncRef1;
2822*4882a593Smuzhiyun 			break;
2823*4882a593Smuzhiyun 		case 3: /* AES 3 */
2824*4882a593Smuzhiyun 			hdspm->control_register |=
2825*4882a593Smuzhiyun 				HDSPM_SyncRef1+HDSPM_SyncRef0;
2826*4882a593Smuzhiyun 			break;
2827*4882a593Smuzhiyun 		case 4: /* AES 4 */
2828*4882a593Smuzhiyun 			hdspm->control_register |= HDSPM_SyncRef2;
2829*4882a593Smuzhiyun 			break;
2830*4882a593Smuzhiyun 		case 5: /* AES 5 */
2831*4882a593Smuzhiyun 			hdspm->control_register |=
2832*4882a593Smuzhiyun 				HDSPM_SyncRef2+HDSPM_SyncRef0;
2833*4882a593Smuzhiyun 			break;
2834*4882a593Smuzhiyun 		case 6: /* AES 6 */
2835*4882a593Smuzhiyun 			hdspm->control_register |=
2836*4882a593Smuzhiyun 				HDSPM_SyncRef2+HDSPM_SyncRef1;
2837*4882a593Smuzhiyun 			break;
2838*4882a593Smuzhiyun 		case 7: /* AES 7 */
2839*4882a593Smuzhiyun 			hdspm->control_register |=
2840*4882a593Smuzhiyun 				HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0;
2841*4882a593Smuzhiyun 			break;
2842*4882a593Smuzhiyun 		case 8: /* AES 8 */
2843*4882a593Smuzhiyun 			hdspm->control_register |= HDSPM_SyncRef3;
2844*4882a593Smuzhiyun 			break;
2845*4882a593Smuzhiyun 		case 9: /* TCO */
2846*4882a593Smuzhiyun 			hdspm->control_register |=
2847*4882a593Smuzhiyun 				HDSPM_SyncRef3+HDSPM_SyncRef0;
2848*4882a593Smuzhiyun 			break;
2849*4882a593Smuzhiyun 		default:
2850*4882a593Smuzhiyun 			return -1;
2851*4882a593Smuzhiyun 		}
2852*4882a593Smuzhiyun 
2853*4882a593Smuzhiyun 		break;
2854*4882a593Smuzhiyun 
2855*4882a593Smuzhiyun 	case MADI:
2856*4882a593Smuzhiyun 	case MADIface:
2857*4882a593Smuzhiyun 		hdspm->control_register &= ~HDSPM_SyncRefMask;
2858*4882a593Smuzhiyun 		if (hdspm->tco) {
2859*4882a593Smuzhiyun 			switch (pref) {
2860*4882a593Smuzhiyun 			case 0: /* WC */
2861*4882a593Smuzhiyun 				break;
2862*4882a593Smuzhiyun 			case 1: /* MADI */
2863*4882a593Smuzhiyun 				hdspm->control_register |= HDSPM_SyncRef0;
2864*4882a593Smuzhiyun 				break;
2865*4882a593Smuzhiyun 			case 2: /* TCO */
2866*4882a593Smuzhiyun 				hdspm->control_register |= HDSPM_SyncRef1;
2867*4882a593Smuzhiyun 				break;
2868*4882a593Smuzhiyun 			case 3: /* SYNC_IN */
2869*4882a593Smuzhiyun 				hdspm->control_register |=
2870*4882a593Smuzhiyun 					HDSPM_SyncRef0+HDSPM_SyncRef1;
2871*4882a593Smuzhiyun 				break;
2872*4882a593Smuzhiyun 			default:
2873*4882a593Smuzhiyun 				return -1;
2874*4882a593Smuzhiyun 			}
2875*4882a593Smuzhiyun 		} else {
2876*4882a593Smuzhiyun 			switch (pref) {
2877*4882a593Smuzhiyun 			case 0: /* WC */
2878*4882a593Smuzhiyun 				break;
2879*4882a593Smuzhiyun 			case 1: /* MADI */
2880*4882a593Smuzhiyun 				hdspm->control_register |= HDSPM_SyncRef0;
2881*4882a593Smuzhiyun 				break;
2882*4882a593Smuzhiyun 			case 2: /* SYNC_IN */
2883*4882a593Smuzhiyun 				hdspm->control_register |=
2884*4882a593Smuzhiyun 					HDSPM_SyncRef0+HDSPM_SyncRef1;
2885*4882a593Smuzhiyun 				break;
2886*4882a593Smuzhiyun 			default:
2887*4882a593Smuzhiyun 				return -1;
2888*4882a593Smuzhiyun 			}
2889*4882a593Smuzhiyun 		}
2890*4882a593Smuzhiyun 
2891*4882a593Smuzhiyun 		break;
2892*4882a593Smuzhiyun 
2893*4882a593Smuzhiyun 	case RayDAT:
2894*4882a593Smuzhiyun 		if (hdspm->tco) {
2895*4882a593Smuzhiyun 			switch (pref) {
2896*4882a593Smuzhiyun 			case 0: p = 0; break;  /* WC */
2897*4882a593Smuzhiyun 			case 1: p = 3; break;  /* ADAT 1 */
2898*4882a593Smuzhiyun 			case 2: p = 4; break;  /* ADAT 2 */
2899*4882a593Smuzhiyun 			case 3: p = 5; break;  /* ADAT 3 */
2900*4882a593Smuzhiyun 			case 4: p = 6; break;  /* ADAT 4 */
2901*4882a593Smuzhiyun 			case 5: p = 1; break;  /* AES */
2902*4882a593Smuzhiyun 			case 6: p = 2; break;  /* SPDIF */
2903*4882a593Smuzhiyun 			case 7: p = 9; break;  /* TCO */
2904*4882a593Smuzhiyun 			case 8: p = 10; break; /* SYNC_IN */
2905*4882a593Smuzhiyun 			default: return -1;
2906*4882a593Smuzhiyun 			}
2907*4882a593Smuzhiyun 		} else {
2908*4882a593Smuzhiyun 			switch (pref) {
2909*4882a593Smuzhiyun 			case 0: p = 0; break;  /* WC */
2910*4882a593Smuzhiyun 			case 1: p = 3; break;  /* ADAT 1 */
2911*4882a593Smuzhiyun 			case 2: p = 4; break;  /* ADAT 2 */
2912*4882a593Smuzhiyun 			case 3: p = 5; break;  /* ADAT 3 */
2913*4882a593Smuzhiyun 			case 4: p = 6; break;  /* ADAT 4 */
2914*4882a593Smuzhiyun 			case 5: p = 1; break;  /* AES */
2915*4882a593Smuzhiyun 			case 6: p = 2; break;  /* SPDIF */
2916*4882a593Smuzhiyun 			case 7: p = 10; break; /* SYNC_IN */
2917*4882a593Smuzhiyun 			default: return -1;
2918*4882a593Smuzhiyun 			}
2919*4882a593Smuzhiyun 		}
2920*4882a593Smuzhiyun 		break;
2921*4882a593Smuzhiyun 
2922*4882a593Smuzhiyun 	case AIO:
2923*4882a593Smuzhiyun 		if (hdspm->tco) {
2924*4882a593Smuzhiyun 			switch (pref) {
2925*4882a593Smuzhiyun 			case 0: p = 0; break;  /* WC */
2926*4882a593Smuzhiyun 			case 1: p = 3; break;  /* ADAT */
2927*4882a593Smuzhiyun 			case 2: p = 1; break;  /* AES */
2928*4882a593Smuzhiyun 			case 3: p = 2; break;  /* SPDIF */
2929*4882a593Smuzhiyun 			case 4: p = 9; break;  /* TCO */
2930*4882a593Smuzhiyun 			case 5: p = 10; break; /* SYNC_IN */
2931*4882a593Smuzhiyun 			default: return -1;
2932*4882a593Smuzhiyun 			}
2933*4882a593Smuzhiyun 		} else {
2934*4882a593Smuzhiyun 			switch (pref) {
2935*4882a593Smuzhiyun 			case 0: p = 0; break;  /* WC */
2936*4882a593Smuzhiyun 			case 1: p = 3; break;  /* ADAT */
2937*4882a593Smuzhiyun 			case 2: p = 1; break;  /* AES */
2938*4882a593Smuzhiyun 			case 3: p = 2; break;  /* SPDIF */
2939*4882a593Smuzhiyun 			case 4: p = 10; break; /* SYNC_IN */
2940*4882a593Smuzhiyun 			default: return -1;
2941*4882a593Smuzhiyun 			}
2942*4882a593Smuzhiyun 		}
2943*4882a593Smuzhiyun 		break;
2944*4882a593Smuzhiyun 	}
2945*4882a593Smuzhiyun 
2946*4882a593Smuzhiyun 	switch (hdspm->io_type) {
2947*4882a593Smuzhiyun 	case RayDAT:
2948*4882a593Smuzhiyun 	case AIO:
2949*4882a593Smuzhiyun 		hdspm->settings_register &= ~HDSPM_c0_SyncRefMask;
2950*4882a593Smuzhiyun 		hdspm->settings_register |= HDSPM_c0_SyncRef0 * p;
2951*4882a593Smuzhiyun 		hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
2952*4882a593Smuzhiyun 		break;
2953*4882a593Smuzhiyun 
2954*4882a593Smuzhiyun 	case MADI:
2955*4882a593Smuzhiyun 	case MADIface:
2956*4882a593Smuzhiyun 	case AES32:
2957*4882a593Smuzhiyun 		hdspm_write(hdspm, HDSPM_controlRegister,
2958*4882a593Smuzhiyun 				hdspm->control_register);
2959*4882a593Smuzhiyun 	}
2960*4882a593Smuzhiyun 
2961*4882a593Smuzhiyun 	return 0;
2962*4882a593Smuzhiyun }
2963*4882a593Smuzhiyun 
2964*4882a593Smuzhiyun 
snd_hdspm_info_pref_sync_ref(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2965*4882a593Smuzhiyun static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol,
2966*4882a593Smuzhiyun 					struct snd_ctl_elem_info *uinfo)
2967*4882a593Smuzhiyun {
2968*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2969*4882a593Smuzhiyun 
2970*4882a593Smuzhiyun 	snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync);
2971*4882a593Smuzhiyun 
2972*4882a593Smuzhiyun 	return 0;
2973*4882a593Smuzhiyun }
2974*4882a593Smuzhiyun 
snd_hdspm_get_pref_sync_ref(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2975*4882a593Smuzhiyun static int snd_hdspm_get_pref_sync_ref(struct snd_kcontrol *kcontrol,
2976*4882a593Smuzhiyun 				       struct snd_ctl_elem_value *ucontrol)
2977*4882a593Smuzhiyun {
2978*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2979*4882a593Smuzhiyun 	int psf = hdspm_pref_sync_ref(hdspm);
2980*4882a593Smuzhiyun 
2981*4882a593Smuzhiyun 	if (psf >= 0) {
2982*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = psf;
2983*4882a593Smuzhiyun 		return 0;
2984*4882a593Smuzhiyun 	}
2985*4882a593Smuzhiyun 
2986*4882a593Smuzhiyun 	return -1;
2987*4882a593Smuzhiyun }
2988*4882a593Smuzhiyun 
snd_hdspm_put_pref_sync_ref(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2989*4882a593Smuzhiyun static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
2990*4882a593Smuzhiyun 				       struct snd_ctl_elem_value *ucontrol)
2991*4882a593Smuzhiyun {
2992*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2993*4882a593Smuzhiyun 	int val, change = 0;
2994*4882a593Smuzhiyun 
2995*4882a593Smuzhiyun 	if (!snd_hdspm_use_is_exclusive(hdspm))
2996*4882a593Smuzhiyun 		return -EBUSY;
2997*4882a593Smuzhiyun 
2998*4882a593Smuzhiyun 	val = ucontrol->value.enumerated.item[0];
2999*4882a593Smuzhiyun 
3000*4882a593Smuzhiyun 	if (val < 0)
3001*4882a593Smuzhiyun 		val = 0;
3002*4882a593Smuzhiyun 	else if (val >= hdspm->texts_autosync_items)
3003*4882a593Smuzhiyun 		val = hdspm->texts_autosync_items-1;
3004*4882a593Smuzhiyun 
3005*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3006*4882a593Smuzhiyun 	if (val != hdspm_pref_sync_ref(hdspm))
3007*4882a593Smuzhiyun 		change = (0 == hdspm_set_pref_sync_ref(hdspm, val)) ? 1 : 0;
3008*4882a593Smuzhiyun 
3009*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3010*4882a593Smuzhiyun 	return change;
3011*4882a593Smuzhiyun }
3012*4882a593Smuzhiyun 
3013*4882a593Smuzhiyun 
3014*4882a593Smuzhiyun #define HDSPM_AUTOSYNC_REF(xname, xindex) \
3015*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3016*4882a593Smuzhiyun 	.name = xname, \
3017*4882a593Smuzhiyun 	.index = xindex, \
3018*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READ, \
3019*4882a593Smuzhiyun 	.info = snd_hdspm_info_autosync_ref, \
3020*4882a593Smuzhiyun 	.get = snd_hdspm_get_autosync_ref, \
3021*4882a593Smuzhiyun }
3022*4882a593Smuzhiyun 
hdspm_autosync_ref(struct hdspm * hdspm)3023*4882a593Smuzhiyun static int hdspm_autosync_ref(struct hdspm *hdspm)
3024*4882a593Smuzhiyun {
3025*4882a593Smuzhiyun 	/* This looks at the autosync selected sync reference */
3026*4882a593Smuzhiyun 	if (AES32 == hdspm->io_type) {
3027*4882a593Smuzhiyun 
3028*4882a593Smuzhiyun 		unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
3029*4882a593Smuzhiyun 		unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF;
3030*4882a593Smuzhiyun 		/* syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD is always true */
3031*4882a593Smuzhiyun 		if (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN) {
3032*4882a593Smuzhiyun 			return syncref;
3033*4882a593Smuzhiyun 		}
3034*4882a593Smuzhiyun 		return HDSPM_AES32_AUTOSYNC_FROM_NONE;
3035*4882a593Smuzhiyun 
3036*4882a593Smuzhiyun 	} else if (MADI == hdspm->io_type) {
3037*4882a593Smuzhiyun 
3038*4882a593Smuzhiyun 		unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
3039*4882a593Smuzhiyun 		switch (status2 & HDSPM_SelSyncRefMask) {
3040*4882a593Smuzhiyun 		case HDSPM_SelSyncRef_WORD:
3041*4882a593Smuzhiyun 			return HDSPM_AUTOSYNC_FROM_WORD;
3042*4882a593Smuzhiyun 		case HDSPM_SelSyncRef_MADI:
3043*4882a593Smuzhiyun 			return HDSPM_AUTOSYNC_FROM_MADI;
3044*4882a593Smuzhiyun 		case HDSPM_SelSyncRef_TCO:
3045*4882a593Smuzhiyun 			return HDSPM_AUTOSYNC_FROM_TCO;
3046*4882a593Smuzhiyun 		case HDSPM_SelSyncRef_SyncIn:
3047*4882a593Smuzhiyun 			return HDSPM_AUTOSYNC_FROM_SYNC_IN;
3048*4882a593Smuzhiyun 		case HDSPM_SelSyncRef_NVALID:
3049*4882a593Smuzhiyun 			return HDSPM_AUTOSYNC_FROM_NONE;
3050*4882a593Smuzhiyun 		default:
3051*4882a593Smuzhiyun 			return HDSPM_AUTOSYNC_FROM_NONE;
3052*4882a593Smuzhiyun 		}
3053*4882a593Smuzhiyun 
3054*4882a593Smuzhiyun 	}
3055*4882a593Smuzhiyun 	return 0;
3056*4882a593Smuzhiyun }
3057*4882a593Smuzhiyun 
3058*4882a593Smuzhiyun 
snd_hdspm_info_autosync_ref(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3059*4882a593Smuzhiyun static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol,
3060*4882a593Smuzhiyun 				       struct snd_ctl_elem_info *uinfo)
3061*4882a593Smuzhiyun {
3062*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3063*4882a593Smuzhiyun 
3064*4882a593Smuzhiyun 	if (AES32 == hdspm->io_type) {
3065*4882a593Smuzhiyun 		static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3",
3066*4882a593Smuzhiyun 			"AES4",	"AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"};
3067*4882a593Smuzhiyun 
3068*4882a593Smuzhiyun 		ENUMERATED_CTL_INFO(uinfo, texts);
3069*4882a593Smuzhiyun 	} else if (MADI == hdspm->io_type) {
3070*4882a593Smuzhiyun 		static const char *const texts[] = {"Word Clock", "MADI", "TCO",
3071*4882a593Smuzhiyun 			"Sync In", "None" };
3072*4882a593Smuzhiyun 
3073*4882a593Smuzhiyun 		ENUMERATED_CTL_INFO(uinfo, texts);
3074*4882a593Smuzhiyun 	}
3075*4882a593Smuzhiyun 	return 0;
3076*4882a593Smuzhiyun }
3077*4882a593Smuzhiyun 
snd_hdspm_get_autosync_ref(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3078*4882a593Smuzhiyun static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol,
3079*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
3080*4882a593Smuzhiyun {
3081*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3082*4882a593Smuzhiyun 
3083*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm_autosync_ref(hdspm);
3084*4882a593Smuzhiyun 	return 0;
3085*4882a593Smuzhiyun }
3086*4882a593Smuzhiyun 
3087*4882a593Smuzhiyun 
3088*4882a593Smuzhiyun 
3089*4882a593Smuzhiyun #define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname, xindex) \
3090*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3091*4882a593Smuzhiyun 	.name = xname, \
3092*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READ |\
3093*4882a593Smuzhiyun 		SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3094*4882a593Smuzhiyun 	.info = snd_hdspm_info_tco_video_input_format, \
3095*4882a593Smuzhiyun 	.get = snd_hdspm_get_tco_video_input_format, \
3096*4882a593Smuzhiyun }
3097*4882a593Smuzhiyun 
snd_hdspm_info_tco_video_input_format(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3098*4882a593Smuzhiyun static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol,
3099*4882a593Smuzhiyun 				       struct snd_ctl_elem_info *uinfo)
3100*4882a593Smuzhiyun {
3101*4882a593Smuzhiyun 	static const char *const texts[] = {"No video", "NTSC", "PAL"};
3102*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
3103*4882a593Smuzhiyun 	return 0;
3104*4882a593Smuzhiyun }
3105*4882a593Smuzhiyun 
snd_hdspm_get_tco_video_input_format(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3106*4882a593Smuzhiyun static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol,
3107*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
3108*4882a593Smuzhiyun {
3109*4882a593Smuzhiyun 	u32 status;
3110*4882a593Smuzhiyun 	int ret = 0;
3111*4882a593Smuzhiyun 
3112*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3113*4882a593Smuzhiyun 	status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
3114*4882a593Smuzhiyun 	switch (status & (HDSPM_TCO1_Video_Input_Format_NTSC |
3115*4882a593Smuzhiyun 			HDSPM_TCO1_Video_Input_Format_PAL)) {
3116*4882a593Smuzhiyun 	case HDSPM_TCO1_Video_Input_Format_NTSC:
3117*4882a593Smuzhiyun 		/* ntsc */
3118*4882a593Smuzhiyun 		ret = 1;
3119*4882a593Smuzhiyun 		break;
3120*4882a593Smuzhiyun 	case HDSPM_TCO1_Video_Input_Format_PAL:
3121*4882a593Smuzhiyun 		/* pal */
3122*4882a593Smuzhiyun 		ret = 2;
3123*4882a593Smuzhiyun 		break;
3124*4882a593Smuzhiyun 	default:
3125*4882a593Smuzhiyun 		/* no video */
3126*4882a593Smuzhiyun 		ret = 0;
3127*4882a593Smuzhiyun 		break;
3128*4882a593Smuzhiyun 	}
3129*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = ret;
3130*4882a593Smuzhiyun 	return 0;
3131*4882a593Smuzhiyun }
3132*4882a593Smuzhiyun 
3133*4882a593Smuzhiyun 
3134*4882a593Smuzhiyun 
3135*4882a593Smuzhiyun #define HDSPM_TCO_LTC_FRAMES(xname, xindex) \
3136*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3137*4882a593Smuzhiyun 	.name = xname, \
3138*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READ |\
3139*4882a593Smuzhiyun 		SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3140*4882a593Smuzhiyun 	.info = snd_hdspm_info_tco_ltc_frames, \
3141*4882a593Smuzhiyun 	.get = snd_hdspm_get_tco_ltc_frames, \
3142*4882a593Smuzhiyun }
3143*4882a593Smuzhiyun 
snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3144*4882a593Smuzhiyun static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol,
3145*4882a593Smuzhiyun 				       struct snd_ctl_elem_info *uinfo)
3146*4882a593Smuzhiyun {
3147*4882a593Smuzhiyun 	static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps",
3148*4882a593Smuzhiyun 				"30 fps"};
3149*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
3150*4882a593Smuzhiyun 	return 0;
3151*4882a593Smuzhiyun }
3152*4882a593Smuzhiyun 
hdspm_tco_ltc_frames(struct hdspm * hdspm)3153*4882a593Smuzhiyun static int hdspm_tco_ltc_frames(struct hdspm *hdspm)
3154*4882a593Smuzhiyun {
3155*4882a593Smuzhiyun 	u32 status;
3156*4882a593Smuzhiyun 	int ret = 0;
3157*4882a593Smuzhiyun 
3158*4882a593Smuzhiyun 	status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
3159*4882a593Smuzhiyun 	if (status & HDSPM_TCO1_LTC_Input_valid) {
3160*4882a593Smuzhiyun 		switch (status & (HDSPM_TCO1_LTC_Format_LSB |
3161*4882a593Smuzhiyun 					HDSPM_TCO1_LTC_Format_MSB)) {
3162*4882a593Smuzhiyun 		case 0:
3163*4882a593Smuzhiyun 			/* 24 fps */
3164*4882a593Smuzhiyun 			ret = fps_24;
3165*4882a593Smuzhiyun 			break;
3166*4882a593Smuzhiyun 		case HDSPM_TCO1_LTC_Format_LSB:
3167*4882a593Smuzhiyun 			/* 25 fps */
3168*4882a593Smuzhiyun 			ret = fps_25;
3169*4882a593Smuzhiyun 			break;
3170*4882a593Smuzhiyun 		case HDSPM_TCO1_LTC_Format_MSB:
3171*4882a593Smuzhiyun 			/* 29.97 fps */
3172*4882a593Smuzhiyun 			ret = fps_2997;
3173*4882a593Smuzhiyun 			break;
3174*4882a593Smuzhiyun 		default:
3175*4882a593Smuzhiyun 			/* 30 fps */
3176*4882a593Smuzhiyun 			ret = fps_30;
3177*4882a593Smuzhiyun 			break;
3178*4882a593Smuzhiyun 		}
3179*4882a593Smuzhiyun 	}
3180*4882a593Smuzhiyun 
3181*4882a593Smuzhiyun 	return ret;
3182*4882a593Smuzhiyun }
3183*4882a593Smuzhiyun 
snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3184*4882a593Smuzhiyun static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol,
3185*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
3186*4882a593Smuzhiyun {
3187*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3188*4882a593Smuzhiyun 
3189*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm_tco_ltc_frames(hdspm);
3190*4882a593Smuzhiyun 	return 0;
3191*4882a593Smuzhiyun }
3192*4882a593Smuzhiyun 
3193*4882a593Smuzhiyun #define HDSPM_TOGGLE_SETTING(xname, xindex) \
3194*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3195*4882a593Smuzhiyun 	.name = xname, \
3196*4882a593Smuzhiyun 	.private_value = xindex, \
3197*4882a593Smuzhiyun 	.info = snd_hdspm_info_toggle_setting, \
3198*4882a593Smuzhiyun 	.get = snd_hdspm_get_toggle_setting, \
3199*4882a593Smuzhiyun 	.put = snd_hdspm_put_toggle_setting \
3200*4882a593Smuzhiyun }
3201*4882a593Smuzhiyun 
hdspm_toggle_setting(struct hdspm * hdspm,u32 regmask)3202*4882a593Smuzhiyun static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask)
3203*4882a593Smuzhiyun {
3204*4882a593Smuzhiyun 	u32 reg;
3205*4882a593Smuzhiyun 
3206*4882a593Smuzhiyun 	if (hdspm_is_raydat_or_aio(hdspm))
3207*4882a593Smuzhiyun 		reg = hdspm->settings_register;
3208*4882a593Smuzhiyun 	else
3209*4882a593Smuzhiyun 		reg = hdspm->control_register;
3210*4882a593Smuzhiyun 
3211*4882a593Smuzhiyun 	return (reg & regmask) ? 1 : 0;
3212*4882a593Smuzhiyun }
3213*4882a593Smuzhiyun 
hdspm_set_toggle_setting(struct hdspm * hdspm,u32 regmask,int out)3214*4882a593Smuzhiyun static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out)
3215*4882a593Smuzhiyun {
3216*4882a593Smuzhiyun 	u32 *reg;
3217*4882a593Smuzhiyun 	u32 target_reg;
3218*4882a593Smuzhiyun 
3219*4882a593Smuzhiyun 	if (hdspm_is_raydat_or_aio(hdspm)) {
3220*4882a593Smuzhiyun 		reg = &(hdspm->settings_register);
3221*4882a593Smuzhiyun 		target_reg = HDSPM_WR_SETTINGS;
3222*4882a593Smuzhiyun 	} else {
3223*4882a593Smuzhiyun 		reg = &(hdspm->control_register);
3224*4882a593Smuzhiyun 		target_reg = HDSPM_controlRegister;
3225*4882a593Smuzhiyun 	}
3226*4882a593Smuzhiyun 
3227*4882a593Smuzhiyun 	if (out)
3228*4882a593Smuzhiyun 		*reg |= regmask;
3229*4882a593Smuzhiyun 	else
3230*4882a593Smuzhiyun 		*reg &= ~regmask;
3231*4882a593Smuzhiyun 
3232*4882a593Smuzhiyun 	hdspm_write(hdspm, target_reg, *reg);
3233*4882a593Smuzhiyun 
3234*4882a593Smuzhiyun 	return 0;
3235*4882a593Smuzhiyun }
3236*4882a593Smuzhiyun 
3237*4882a593Smuzhiyun #define snd_hdspm_info_toggle_setting		snd_ctl_boolean_mono_info
3238*4882a593Smuzhiyun 
snd_hdspm_get_toggle_setting(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3239*4882a593Smuzhiyun static int snd_hdspm_get_toggle_setting(struct snd_kcontrol *kcontrol,
3240*4882a593Smuzhiyun 			       struct snd_ctl_elem_value *ucontrol)
3241*4882a593Smuzhiyun {
3242*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3243*4882a593Smuzhiyun 	u32 regmask = kcontrol->private_value;
3244*4882a593Smuzhiyun 
3245*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3246*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = hdspm_toggle_setting(hdspm, regmask);
3247*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3248*4882a593Smuzhiyun 	return 0;
3249*4882a593Smuzhiyun }
3250*4882a593Smuzhiyun 
snd_hdspm_put_toggle_setting(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3251*4882a593Smuzhiyun static int snd_hdspm_put_toggle_setting(struct snd_kcontrol *kcontrol,
3252*4882a593Smuzhiyun 			       struct snd_ctl_elem_value *ucontrol)
3253*4882a593Smuzhiyun {
3254*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3255*4882a593Smuzhiyun 	u32 regmask = kcontrol->private_value;
3256*4882a593Smuzhiyun 	int change;
3257*4882a593Smuzhiyun 	unsigned int val;
3258*4882a593Smuzhiyun 
3259*4882a593Smuzhiyun 	if (!snd_hdspm_use_is_exclusive(hdspm))
3260*4882a593Smuzhiyun 		return -EBUSY;
3261*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0] & 1;
3262*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3263*4882a593Smuzhiyun 	change = (int) val != hdspm_toggle_setting(hdspm, regmask);
3264*4882a593Smuzhiyun 	hdspm_set_toggle_setting(hdspm, regmask, val);
3265*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3266*4882a593Smuzhiyun 	return change;
3267*4882a593Smuzhiyun }
3268*4882a593Smuzhiyun 
3269*4882a593Smuzhiyun #define HDSPM_INPUT_SELECT(xname, xindex) \
3270*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3271*4882a593Smuzhiyun 	.name = xname, \
3272*4882a593Smuzhiyun 	.index = xindex, \
3273*4882a593Smuzhiyun 	.info = snd_hdspm_info_input_select, \
3274*4882a593Smuzhiyun 	.get = snd_hdspm_get_input_select, \
3275*4882a593Smuzhiyun 	.put = snd_hdspm_put_input_select \
3276*4882a593Smuzhiyun }
3277*4882a593Smuzhiyun 
hdspm_input_select(struct hdspm * hdspm)3278*4882a593Smuzhiyun static int hdspm_input_select(struct hdspm * hdspm)
3279*4882a593Smuzhiyun {
3280*4882a593Smuzhiyun 	return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0;
3281*4882a593Smuzhiyun }
3282*4882a593Smuzhiyun 
hdspm_set_input_select(struct hdspm * hdspm,int out)3283*4882a593Smuzhiyun static int hdspm_set_input_select(struct hdspm * hdspm, int out)
3284*4882a593Smuzhiyun {
3285*4882a593Smuzhiyun 	if (out)
3286*4882a593Smuzhiyun 		hdspm->control_register |= HDSPM_InputSelect0;
3287*4882a593Smuzhiyun 	else
3288*4882a593Smuzhiyun 		hdspm->control_register &= ~HDSPM_InputSelect0;
3289*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
3290*4882a593Smuzhiyun 
3291*4882a593Smuzhiyun 	return 0;
3292*4882a593Smuzhiyun }
3293*4882a593Smuzhiyun 
snd_hdspm_info_input_select(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3294*4882a593Smuzhiyun static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol,
3295*4882a593Smuzhiyun 				       struct snd_ctl_elem_info *uinfo)
3296*4882a593Smuzhiyun {
3297*4882a593Smuzhiyun 	static const char *const texts[] = { "optical", "coaxial" };
3298*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
3299*4882a593Smuzhiyun 	return 0;
3300*4882a593Smuzhiyun }
3301*4882a593Smuzhiyun 
snd_hdspm_get_input_select(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3302*4882a593Smuzhiyun static int snd_hdspm_get_input_select(struct snd_kcontrol *kcontrol,
3303*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
3304*4882a593Smuzhiyun {
3305*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3306*4882a593Smuzhiyun 
3307*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3308*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm);
3309*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3310*4882a593Smuzhiyun 	return 0;
3311*4882a593Smuzhiyun }
3312*4882a593Smuzhiyun 
snd_hdspm_put_input_select(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3313*4882a593Smuzhiyun static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol,
3314*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
3315*4882a593Smuzhiyun {
3316*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3317*4882a593Smuzhiyun 	int change;
3318*4882a593Smuzhiyun 	unsigned int val;
3319*4882a593Smuzhiyun 
3320*4882a593Smuzhiyun 	if (!snd_hdspm_use_is_exclusive(hdspm))
3321*4882a593Smuzhiyun 		return -EBUSY;
3322*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0] & 1;
3323*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3324*4882a593Smuzhiyun 	change = (int) val != hdspm_input_select(hdspm);
3325*4882a593Smuzhiyun 	hdspm_set_input_select(hdspm, val);
3326*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3327*4882a593Smuzhiyun 	return change;
3328*4882a593Smuzhiyun }
3329*4882a593Smuzhiyun 
3330*4882a593Smuzhiyun 
3331*4882a593Smuzhiyun #define HDSPM_DS_WIRE(xname, xindex) \
3332*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3333*4882a593Smuzhiyun 	.name = xname, \
3334*4882a593Smuzhiyun 	.index = xindex, \
3335*4882a593Smuzhiyun 	.info = snd_hdspm_info_ds_wire, \
3336*4882a593Smuzhiyun 	.get = snd_hdspm_get_ds_wire, \
3337*4882a593Smuzhiyun 	.put = snd_hdspm_put_ds_wire \
3338*4882a593Smuzhiyun }
3339*4882a593Smuzhiyun 
hdspm_ds_wire(struct hdspm * hdspm)3340*4882a593Smuzhiyun static int hdspm_ds_wire(struct hdspm * hdspm)
3341*4882a593Smuzhiyun {
3342*4882a593Smuzhiyun 	return (hdspm->control_register & HDSPM_DS_DoubleWire) ? 1 : 0;
3343*4882a593Smuzhiyun }
3344*4882a593Smuzhiyun 
hdspm_set_ds_wire(struct hdspm * hdspm,int ds)3345*4882a593Smuzhiyun static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds)
3346*4882a593Smuzhiyun {
3347*4882a593Smuzhiyun 	if (ds)
3348*4882a593Smuzhiyun 		hdspm->control_register |= HDSPM_DS_DoubleWire;
3349*4882a593Smuzhiyun 	else
3350*4882a593Smuzhiyun 		hdspm->control_register &= ~HDSPM_DS_DoubleWire;
3351*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
3352*4882a593Smuzhiyun 
3353*4882a593Smuzhiyun 	return 0;
3354*4882a593Smuzhiyun }
3355*4882a593Smuzhiyun 
snd_hdspm_info_ds_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3356*4882a593Smuzhiyun static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol,
3357*4882a593Smuzhiyun 				  struct snd_ctl_elem_info *uinfo)
3358*4882a593Smuzhiyun {
3359*4882a593Smuzhiyun 	static const char *const texts[] = { "Single", "Double" };
3360*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
3361*4882a593Smuzhiyun 	return 0;
3362*4882a593Smuzhiyun }
3363*4882a593Smuzhiyun 
snd_hdspm_get_ds_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3364*4882a593Smuzhiyun static int snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol,
3365*4882a593Smuzhiyun 				 struct snd_ctl_elem_value *ucontrol)
3366*4882a593Smuzhiyun {
3367*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3368*4882a593Smuzhiyun 
3369*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3370*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm);
3371*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3372*4882a593Smuzhiyun 	return 0;
3373*4882a593Smuzhiyun }
3374*4882a593Smuzhiyun 
snd_hdspm_put_ds_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3375*4882a593Smuzhiyun static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol,
3376*4882a593Smuzhiyun 				 struct snd_ctl_elem_value *ucontrol)
3377*4882a593Smuzhiyun {
3378*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3379*4882a593Smuzhiyun 	int change;
3380*4882a593Smuzhiyun 	unsigned int val;
3381*4882a593Smuzhiyun 
3382*4882a593Smuzhiyun 	if (!snd_hdspm_use_is_exclusive(hdspm))
3383*4882a593Smuzhiyun 		return -EBUSY;
3384*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0] & 1;
3385*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3386*4882a593Smuzhiyun 	change = (int) val != hdspm_ds_wire(hdspm);
3387*4882a593Smuzhiyun 	hdspm_set_ds_wire(hdspm, val);
3388*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3389*4882a593Smuzhiyun 	return change;
3390*4882a593Smuzhiyun }
3391*4882a593Smuzhiyun 
3392*4882a593Smuzhiyun 
3393*4882a593Smuzhiyun #define HDSPM_QS_WIRE(xname, xindex) \
3394*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3395*4882a593Smuzhiyun 	.name = xname, \
3396*4882a593Smuzhiyun 	.index = xindex, \
3397*4882a593Smuzhiyun 	.info = snd_hdspm_info_qs_wire, \
3398*4882a593Smuzhiyun 	.get = snd_hdspm_get_qs_wire, \
3399*4882a593Smuzhiyun 	.put = snd_hdspm_put_qs_wire \
3400*4882a593Smuzhiyun }
3401*4882a593Smuzhiyun 
hdspm_qs_wire(struct hdspm * hdspm)3402*4882a593Smuzhiyun static int hdspm_qs_wire(struct hdspm * hdspm)
3403*4882a593Smuzhiyun {
3404*4882a593Smuzhiyun 	if (hdspm->control_register & HDSPM_QS_DoubleWire)
3405*4882a593Smuzhiyun 		return 1;
3406*4882a593Smuzhiyun 	if (hdspm->control_register & HDSPM_QS_QuadWire)
3407*4882a593Smuzhiyun 		return 2;
3408*4882a593Smuzhiyun 	return 0;
3409*4882a593Smuzhiyun }
3410*4882a593Smuzhiyun 
hdspm_set_qs_wire(struct hdspm * hdspm,int mode)3411*4882a593Smuzhiyun static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode)
3412*4882a593Smuzhiyun {
3413*4882a593Smuzhiyun 	hdspm->control_register &= ~(HDSPM_QS_DoubleWire | HDSPM_QS_QuadWire);
3414*4882a593Smuzhiyun 	switch (mode) {
3415*4882a593Smuzhiyun 	case 0:
3416*4882a593Smuzhiyun 		break;
3417*4882a593Smuzhiyun 	case 1:
3418*4882a593Smuzhiyun 		hdspm->control_register |= HDSPM_QS_DoubleWire;
3419*4882a593Smuzhiyun 		break;
3420*4882a593Smuzhiyun 	case 2:
3421*4882a593Smuzhiyun 		hdspm->control_register |= HDSPM_QS_QuadWire;
3422*4882a593Smuzhiyun 		break;
3423*4882a593Smuzhiyun 	}
3424*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
3425*4882a593Smuzhiyun 
3426*4882a593Smuzhiyun 	return 0;
3427*4882a593Smuzhiyun }
3428*4882a593Smuzhiyun 
snd_hdspm_info_qs_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3429*4882a593Smuzhiyun static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol,
3430*4882a593Smuzhiyun 				       struct snd_ctl_elem_info *uinfo)
3431*4882a593Smuzhiyun {
3432*4882a593Smuzhiyun 	static const char *const texts[] = { "Single", "Double", "Quad" };
3433*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
3434*4882a593Smuzhiyun 	return 0;
3435*4882a593Smuzhiyun }
3436*4882a593Smuzhiyun 
snd_hdspm_get_qs_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3437*4882a593Smuzhiyun static int snd_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol,
3438*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
3439*4882a593Smuzhiyun {
3440*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3441*4882a593Smuzhiyun 
3442*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3443*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm);
3444*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3445*4882a593Smuzhiyun 	return 0;
3446*4882a593Smuzhiyun }
3447*4882a593Smuzhiyun 
snd_hdspm_put_qs_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3448*4882a593Smuzhiyun static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
3449*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
3450*4882a593Smuzhiyun {
3451*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3452*4882a593Smuzhiyun 	int change;
3453*4882a593Smuzhiyun 	int val;
3454*4882a593Smuzhiyun 
3455*4882a593Smuzhiyun 	if (!snd_hdspm_use_is_exclusive(hdspm))
3456*4882a593Smuzhiyun 		return -EBUSY;
3457*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0];
3458*4882a593Smuzhiyun 	if (val < 0)
3459*4882a593Smuzhiyun 		val = 0;
3460*4882a593Smuzhiyun 	if (val > 2)
3461*4882a593Smuzhiyun 		val = 2;
3462*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3463*4882a593Smuzhiyun 	change = val != hdspm_qs_wire(hdspm);
3464*4882a593Smuzhiyun 	hdspm_set_qs_wire(hdspm, val);
3465*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3466*4882a593Smuzhiyun 	return change;
3467*4882a593Smuzhiyun }
3468*4882a593Smuzhiyun 
3469*4882a593Smuzhiyun #define HDSPM_CONTROL_TRISTATE(xname, xindex) \
3470*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3471*4882a593Smuzhiyun 	.name = xname, \
3472*4882a593Smuzhiyun 	.private_value = xindex, \
3473*4882a593Smuzhiyun 	.info = snd_hdspm_info_tristate, \
3474*4882a593Smuzhiyun 	.get = snd_hdspm_get_tristate, \
3475*4882a593Smuzhiyun 	.put = snd_hdspm_put_tristate \
3476*4882a593Smuzhiyun }
3477*4882a593Smuzhiyun 
hdspm_tristate(struct hdspm * hdspm,u32 regmask)3478*4882a593Smuzhiyun static int hdspm_tristate(struct hdspm *hdspm, u32 regmask)
3479*4882a593Smuzhiyun {
3480*4882a593Smuzhiyun 	u32 reg = hdspm->settings_register & (regmask * 3);
3481*4882a593Smuzhiyun 	return reg / regmask;
3482*4882a593Smuzhiyun }
3483*4882a593Smuzhiyun 
hdspm_set_tristate(struct hdspm * hdspm,int mode,u32 regmask)3484*4882a593Smuzhiyun static int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask)
3485*4882a593Smuzhiyun {
3486*4882a593Smuzhiyun 	hdspm->settings_register &= ~(regmask * 3);
3487*4882a593Smuzhiyun 	hdspm->settings_register |= (regmask * mode);
3488*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
3489*4882a593Smuzhiyun 
3490*4882a593Smuzhiyun 	return 0;
3491*4882a593Smuzhiyun }
3492*4882a593Smuzhiyun 
snd_hdspm_info_tristate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3493*4882a593Smuzhiyun static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol,
3494*4882a593Smuzhiyun 				       struct snd_ctl_elem_info *uinfo)
3495*4882a593Smuzhiyun {
3496*4882a593Smuzhiyun 	u32 regmask = kcontrol->private_value;
3497*4882a593Smuzhiyun 
3498*4882a593Smuzhiyun 	static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" };
3499*4882a593Smuzhiyun 	static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" };
3500*4882a593Smuzhiyun 
3501*4882a593Smuzhiyun 	switch (regmask) {
3502*4882a593Smuzhiyun 	case HDSPM_c0_Input0:
3503*4882a593Smuzhiyun 		ENUMERATED_CTL_INFO(uinfo, texts_spdif);
3504*4882a593Smuzhiyun 		break;
3505*4882a593Smuzhiyun 	default:
3506*4882a593Smuzhiyun 		ENUMERATED_CTL_INFO(uinfo, texts_levels);
3507*4882a593Smuzhiyun 		break;
3508*4882a593Smuzhiyun 	}
3509*4882a593Smuzhiyun 	return 0;
3510*4882a593Smuzhiyun }
3511*4882a593Smuzhiyun 
snd_hdspm_get_tristate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3512*4882a593Smuzhiyun static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol,
3513*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
3514*4882a593Smuzhiyun {
3515*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3516*4882a593Smuzhiyun 	u32 regmask = kcontrol->private_value;
3517*4882a593Smuzhiyun 
3518*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3519*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask);
3520*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3521*4882a593Smuzhiyun 	return 0;
3522*4882a593Smuzhiyun }
3523*4882a593Smuzhiyun 
snd_hdspm_put_tristate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3524*4882a593Smuzhiyun static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol,
3525*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
3526*4882a593Smuzhiyun {
3527*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3528*4882a593Smuzhiyun 	u32 regmask = kcontrol->private_value;
3529*4882a593Smuzhiyun 	int change;
3530*4882a593Smuzhiyun 	int val;
3531*4882a593Smuzhiyun 
3532*4882a593Smuzhiyun 	if (!snd_hdspm_use_is_exclusive(hdspm))
3533*4882a593Smuzhiyun 		return -EBUSY;
3534*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0];
3535*4882a593Smuzhiyun 	if (val < 0)
3536*4882a593Smuzhiyun 		val = 0;
3537*4882a593Smuzhiyun 	if (val > 2)
3538*4882a593Smuzhiyun 		val = 2;
3539*4882a593Smuzhiyun 
3540*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3541*4882a593Smuzhiyun 	change = val != hdspm_tristate(hdspm, regmask);
3542*4882a593Smuzhiyun 	hdspm_set_tristate(hdspm, val, regmask);
3543*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3544*4882a593Smuzhiyun 	return change;
3545*4882a593Smuzhiyun }
3546*4882a593Smuzhiyun 
3547*4882a593Smuzhiyun #define HDSPM_MADI_SPEEDMODE(xname, xindex) \
3548*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3549*4882a593Smuzhiyun 	.name = xname, \
3550*4882a593Smuzhiyun 	.index = xindex, \
3551*4882a593Smuzhiyun 	.info = snd_hdspm_info_madi_speedmode, \
3552*4882a593Smuzhiyun 	.get = snd_hdspm_get_madi_speedmode, \
3553*4882a593Smuzhiyun 	.put = snd_hdspm_put_madi_speedmode \
3554*4882a593Smuzhiyun }
3555*4882a593Smuzhiyun 
hdspm_madi_speedmode(struct hdspm * hdspm)3556*4882a593Smuzhiyun static int hdspm_madi_speedmode(struct hdspm *hdspm)
3557*4882a593Smuzhiyun {
3558*4882a593Smuzhiyun 	if (hdspm->control_register & HDSPM_QuadSpeed)
3559*4882a593Smuzhiyun 		return 2;
3560*4882a593Smuzhiyun 	if (hdspm->control_register & HDSPM_DoubleSpeed)
3561*4882a593Smuzhiyun 		return 1;
3562*4882a593Smuzhiyun 	return 0;
3563*4882a593Smuzhiyun }
3564*4882a593Smuzhiyun 
hdspm_set_madi_speedmode(struct hdspm * hdspm,int mode)3565*4882a593Smuzhiyun static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode)
3566*4882a593Smuzhiyun {
3567*4882a593Smuzhiyun 	hdspm->control_register &= ~(HDSPM_DoubleSpeed | HDSPM_QuadSpeed);
3568*4882a593Smuzhiyun 	switch (mode) {
3569*4882a593Smuzhiyun 	case 0:
3570*4882a593Smuzhiyun 		break;
3571*4882a593Smuzhiyun 	case 1:
3572*4882a593Smuzhiyun 		hdspm->control_register |= HDSPM_DoubleSpeed;
3573*4882a593Smuzhiyun 		break;
3574*4882a593Smuzhiyun 	case 2:
3575*4882a593Smuzhiyun 		hdspm->control_register |= HDSPM_QuadSpeed;
3576*4882a593Smuzhiyun 		break;
3577*4882a593Smuzhiyun 	}
3578*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
3579*4882a593Smuzhiyun 
3580*4882a593Smuzhiyun 	return 0;
3581*4882a593Smuzhiyun }
3582*4882a593Smuzhiyun 
snd_hdspm_info_madi_speedmode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3583*4882a593Smuzhiyun static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol,
3584*4882a593Smuzhiyun 				       struct snd_ctl_elem_info *uinfo)
3585*4882a593Smuzhiyun {
3586*4882a593Smuzhiyun 	static const char *const texts[] = { "Single", "Double", "Quad" };
3587*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
3588*4882a593Smuzhiyun 	return 0;
3589*4882a593Smuzhiyun }
3590*4882a593Smuzhiyun 
snd_hdspm_get_madi_speedmode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3591*4882a593Smuzhiyun static int snd_hdspm_get_madi_speedmode(struct snd_kcontrol *kcontrol,
3592*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
3593*4882a593Smuzhiyun {
3594*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3595*4882a593Smuzhiyun 
3596*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3597*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm_madi_speedmode(hdspm);
3598*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3599*4882a593Smuzhiyun 	return 0;
3600*4882a593Smuzhiyun }
3601*4882a593Smuzhiyun 
snd_hdspm_put_madi_speedmode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3602*4882a593Smuzhiyun static int snd_hdspm_put_madi_speedmode(struct snd_kcontrol *kcontrol,
3603*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
3604*4882a593Smuzhiyun {
3605*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3606*4882a593Smuzhiyun 	int change;
3607*4882a593Smuzhiyun 	int val;
3608*4882a593Smuzhiyun 
3609*4882a593Smuzhiyun 	if (!snd_hdspm_use_is_exclusive(hdspm))
3610*4882a593Smuzhiyun 		return -EBUSY;
3611*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0];
3612*4882a593Smuzhiyun 	if (val < 0)
3613*4882a593Smuzhiyun 		val = 0;
3614*4882a593Smuzhiyun 	if (val > 2)
3615*4882a593Smuzhiyun 		val = 2;
3616*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3617*4882a593Smuzhiyun 	change = val != hdspm_madi_speedmode(hdspm);
3618*4882a593Smuzhiyun 	hdspm_set_madi_speedmode(hdspm, val);
3619*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3620*4882a593Smuzhiyun 	return change;
3621*4882a593Smuzhiyun }
3622*4882a593Smuzhiyun 
3623*4882a593Smuzhiyun #define HDSPM_MIXER(xname, xindex) \
3624*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
3625*4882a593Smuzhiyun 	.name = xname, \
3626*4882a593Smuzhiyun 	.index = xindex, \
3627*4882a593Smuzhiyun 	.device = 0, \
3628*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
3629*4882a593Smuzhiyun 		SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3630*4882a593Smuzhiyun 	.info = snd_hdspm_info_mixer, \
3631*4882a593Smuzhiyun 	.get = snd_hdspm_get_mixer, \
3632*4882a593Smuzhiyun 	.put = snd_hdspm_put_mixer \
3633*4882a593Smuzhiyun }
3634*4882a593Smuzhiyun 
snd_hdspm_info_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3635*4882a593Smuzhiyun static int snd_hdspm_info_mixer(struct snd_kcontrol *kcontrol,
3636*4882a593Smuzhiyun 				struct snd_ctl_elem_info *uinfo)
3637*4882a593Smuzhiyun {
3638*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3639*4882a593Smuzhiyun 	uinfo->count = 3;
3640*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
3641*4882a593Smuzhiyun 	uinfo->value.integer.max = 65535;
3642*4882a593Smuzhiyun 	uinfo->value.integer.step = 1;
3643*4882a593Smuzhiyun 	return 0;
3644*4882a593Smuzhiyun }
3645*4882a593Smuzhiyun 
snd_hdspm_get_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3646*4882a593Smuzhiyun static int snd_hdspm_get_mixer(struct snd_kcontrol *kcontrol,
3647*4882a593Smuzhiyun 			       struct snd_ctl_elem_value *ucontrol)
3648*4882a593Smuzhiyun {
3649*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3650*4882a593Smuzhiyun 	int source;
3651*4882a593Smuzhiyun 	int destination;
3652*4882a593Smuzhiyun 
3653*4882a593Smuzhiyun 	source = ucontrol->value.integer.value[0];
3654*4882a593Smuzhiyun 	if (source < 0)
3655*4882a593Smuzhiyun 		source = 0;
3656*4882a593Smuzhiyun 	else if (source >= 2 * HDSPM_MAX_CHANNELS)
3657*4882a593Smuzhiyun 		source = 2 * HDSPM_MAX_CHANNELS - 1;
3658*4882a593Smuzhiyun 
3659*4882a593Smuzhiyun 	destination = ucontrol->value.integer.value[1];
3660*4882a593Smuzhiyun 	if (destination < 0)
3661*4882a593Smuzhiyun 		destination = 0;
3662*4882a593Smuzhiyun 	else if (destination >= HDSPM_MAX_CHANNELS)
3663*4882a593Smuzhiyun 		destination = HDSPM_MAX_CHANNELS - 1;
3664*4882a593Smuzhiyun 
3665*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3666*4882a593Smuzhiyun 	if (source >= HDSPM_MAX_CHANNELS)
3667*4882a593Smuzhiyun 		ucontrol->value.integer.value[2] =
3668*4882a593Smuzhiyun 		    hdspm_read_pb_gain(hdspm, destination,
3669*4882a593Smuzhiyun 				       source - HDSPM_MAX_CHANNELS);
3670*4882a593Smuzhiyun 	else
3671*4882a593Smuzhiyun 		ucontrol->value.integer.value[2] =
3672*4882a593Smuzhiyun 		    hdspm_read_in_gain(hdspm, destination, source);
3673*4882a593Smuzhiyun 
3674*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3675*4882a593Smuzhiyun 
3676*4882a593Smuzhiyun 	return 0;
3677*4882a593Smuzhiyun }
3678*4882a593Smuzhiyun 
snd_hdspm_put_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3679*4882a593Smuzhiyun static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol,
3680*4882a593Smuzhiyun 			       struct snd_ctl_elem_value *ucontrol)
3681*4882a593Smuzhiyun {
3682*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3683*4882a593Smuzhiyun 	int change;
3684*4882a593Smuzhiyun 	int source;
3685*4882a593Smuzhiyun 	int destination;
3686*4882a593Smuzhiyun 	int gain;
3687*4882a593Smuzhiyun 
3688*4882a593Smuzhiyun 	if (!snd_hdspm_use_is_exclusive(hdspm))
3689*4882a593Smuzhiyun 		return -EBUSY;
3690*4882a593Smuzhiyun 
3691*4882a593Smuzhiyun 	source = ucontrol->value.integer.value[0];
3692*4882a593Smuzhiyun 	destination = ucontrol->value.integer.value[1];
3693*4882a593Smuzhiyun 
3694*4882a593Smuzhiyun 	if (source < 0 || source >= 2 * HDSPM_MAX_CHANNELS)
3695*4882a593Smuzhiyun 		return -1;
3696*4882a593Smuzhiyun 	if (destination < 0 || destination >= HDSPM_MAX_CHANNELS)
3697*4882a593Smuzhiyun 		return -1;
3698*4882a593Smuzhiyun 
3699*4882a593Smuzhiyun 	gain = ucontrol->value.integer.value[2];
3700*4882a593Smuzhiyun 
3701*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3702*4882a593Smuzhiyun 
3703*4882a593Smuzhiyun 	if (source >= HDSPM_MAX_CHANNELS)
3704*4882a593Smuzhiyun 		change = gain != hdspm_read_pb_gain(hdspm, destination,
3705*4882a593Smuzhiyun 						    source -
3706*4882a593Smuzhiyun 						    HDSPM_MAX_CHANNELS);
3707*4882a593Smuzhiyun 	else
3708*4882a593Smuzhiyun 		change = gain != hdspm_read_in_gain(hdspm, destination,
3709*4882a593Smuzhiyun 						    source);
3710*4882a593Smuzhiyun 
3711*4882a593Smuzhiyun 	if (change) {
3712*4882a593Smuzhiyun 		if (source >= HDSPM_MAX_CHANNELS)
3713*4882a593Smuzhiyun 			hdspm_write_pb_gain(hdspm, destination,
3714*4882a593Smuzhiyun 					    source - HDSPM_MAX_CHANNELS,
3715*4882a593Smuzhiyun 					    gain);
3716*4882a593Smuzhiyun 		else
3717*4882a593Smuzhiyun 			hdspm_write_in_gain(hdspm, destination, source,
3718*4882a593Smuzhiyun 					    gain);
3719*4882a593Smuzhiyun 	}
3720*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3721*4882a593Smuzhiyun 
3722*4882a593Smuzhiyun 	return change;
3723*4882a593Smuzhiyun }
3724*4882a593Smuzhiyun 
3725*4882a593Smuzhiyun /* The simple mixer control(s) provide gain control for the
3726*4882a593Smuzhiyun    basic 1:1 mappings of playback streams to output
3727*4882a593Smuzhiyun    streams.
3728*4882a593Smuzhiyun */
3729*4882a593Smuzhiyun 
3730*4882a593Smuzhiyun #define HDSPM_PLAYBACK_MIXER \
3731*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3732*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \
3733*4882a593Smuzhiyun 		SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3734*4882a593Smuzhiyun 	.info = snd_hdspm_info_playback_mixer, \
3735*4882a593Smuzhiyun 	.get = snd_hdspm_get_playback_mixer, \
3736*4882a593Smuzhiyun 	.put = snd_hdspm_put_playback_mixer \
3737*4882a593Smuzhiyun }
3738*4882a593Smuzhiyun 
snd_hdspm_info_playback_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3739*4882a593Smuzhiyun static int snd_hdspm_info_playback_mixer(struct snd_kcontrol *kcontrol,
3740*4882a593Smuzhiyun 					 struct snd_ctl_elem_info *uinfo)
3741*4882a593Smuzhiyun {
3742*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3743*4882a593Smuzhiyun 	uinfo->count = 1;
3744*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
3745*4882a593Smuzhiyun 	uinfo->value.integer.max = 64;
3746*4882a593Smuzhiyun 	uinfo->value.integer.step = 1;
3747*4882a593Smuzhiyun 	return 0;
3748*4882a593Smuzhiyun }
3749*4882a593Smuzhiyun 
snd_hdspm_get_playback_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3750*4882a593Smuzhiyun static int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol,
3751*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
3752*4882a593Smuzhiyun {
3753*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3754*4882a593Smuzhiyun 	int channel;
3755*4882a593Smuzhiyun 
3756*4882a593Smuzhiyun 	channel = ucontrol->id.index - 1;
3757*4882a593Smuzhiyun 
3758*4882a593Smuzhiyun 	if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
3759*4882a593Smuzhiyun 		return -EINVAL;
3760*4882a593Smuzhiyun 
3761*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3762*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] =
3763*4882a593Smuzhiyun 	  (hdspm_read_pb_gain(hdspm, channel, channel)*64)/UNITY_GAIN;
3764*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3765*4882a593Smuzhiyun 
3766*4882a593Smuzhiyun 	return 0;
3767*4882a593Smuzhiyun }
3768*4882a593Smuzhiyun 
snd_hdspm_put_playback_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3769*4882a593Smuzhiyun static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
3770*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
3771*4882a593Smuzhiyun {
3772*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3773*4882a593Smuzhiyun 	int change;
3774*4882a593Smuzhiyun 	int channel;
3775*4882a593Smuzhiyun 	int gain;
3776*4882a593Smuzhiyun 
3777*4882a593Smuzhiyun 	if (!snd_hdspm_use_is_exclusive(hdspm))
3778*4882a593Smuzhiyun 		return -EBUSY;
3779*4882a593Smuzhiyun 
3780*4882a593Smuzhiyun 	channel = ucontrol->id.index - 1;
3781*4882a593Smuzhiyun 
3782*4882a593Smuzhiyun 	if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
3783*4882a593Smuzhiyun 		return -EINVAL;
3784*4882a593Smuzhiyun 
3785*4882a593Smuzhiyun 	gain = ucontrol->value.integer.value[0]*UNITY_GAIN/64;
3786*4882a593Smuzhiyun 
3787*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
3788*4882a593Smuzhiyun 	change =
3789*4882a593Smuzhiyun 	    gain != hdspm_read_pb_gain(hdspm, channel,
3790*4882a593Smuzhiyun 				       channel);
3791*4882a593Smuzhiyun 	if (change)
3792*4882a593Smuzhiyun 		hdspm_write_pb_gain(hdspm, channel, channel,
3793*4882a593Smuzhiyun 				    gain);
3794*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
3795*4882a593Smuzhiyun 	return change;
3796*4882a593Smuzhiyun }
3797*4882a593Smuzhiyun 
3798*4882a593Smuzhiyun #define HDSPM_SYNC_CHECK(xname, xindex) \
3799*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3800*4882a593Smuzhiyun 	.name = xname, \
3801*4882a593Smuzhiyun 	.private_value = xindex, \
3802*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3803*4882a593Smuzhiyun 	.info = snd_hdspm_info_sync_check, \
3804*4882a593Smuzhiyun 	.get = snd_hdspm_get_sync_check \
3805*4882a593Smuzhiyun }
3806*4882a593Smuzhiyun 
3807*4882a593Smuzhiyun #define HDSPM_TCO_LOCK_CHECK(xname, xindex) \
3808*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3809*4882a593Smuzhiyun 	.name = xname, \
3810*4882a593Smuzhiyun 	.private_value = xindex, \
3811*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3812*4882a593Smuzhiyun 	.info = snd_hdspm_tco_info_lock_check, \
3813*4882a593Smuzhiyun 	.get = snd_hdspm_get_sync_check \
3814*4882a593Smuzhiyun }
3815*4882a593Smuzhiyun 
3816*4882a593Smuzhiyun 
3817*4882a593Smuzhiyun 
snd_hdspm_info_sync_check(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3818*4882a593Smuzhiyun static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
3819*4882a593Smuzhiyun 				     struct snd_ctl_elem_info *uinfo)
3820*4882a593Smuzhiyun {
3821*4882a593Smuzhiyun 	static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" };
3822*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
3823*4882a593Smuzhiyun 	return 0;
3824*4882a593Smuzhiyun }
3825*4882a593Smuzhiyun 
snd_hdspm_tco_info_lock_check(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3826*4882a593Smuzhiyun static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol,
3827*4882a593Smuzhiyun 				     struct snd_ctl_elem_info *uinfo)
3828*4882a593Smuzhiyun {
3829*4882a593Smuzhiyun 	static const char *const texts[] = { "No Lock", "Lock" };
3830*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
3831*4882a593Smuzhiyun 	return 0;
3832*4882a593Smuzhiyun }
3833*4882a593Smuzhiyun 
hdspm_wc_sync_check(struct hdspm * hdspm)3834*4882a593Smuzhiyun static int hdspm_wc_sync_check(struct hdspm *hdspm)
3835*4882a593Smuzhiyun {
3836*4882a593Smuzhiyun 	int status, status2;
3837*4882a593Smuzhiyun 
3838*4882a593Smuzhiyun 	switch (hdspm->io_type) {
3839*4882a593Smuzhiyun 	case AES32:
3840*4882a593Smuzhiyun 		status = hdspm_read(hdspm, HDSPM_statusRegister);
3841*4882a593Smuzhiyun 		if (status & HDSPM_AES32_wcLock) {
3842*4882a593Smuzhiyun 			if (status & HDSPM_AES32_wcSync)
3843*4882a593Smuzhiyun 				return 2;
3844*4882a593Smuzhiyun 			else
3845*4882a593Smuzhiyun 				return 1;
3846*4882a593Smuzhiyun 		}
3847*4882a593Smuzhiyun 		return 0;
3848*4882a593Smuzhiyun 		break;
3849*4882a593Smuzhiyun 
3850*4882a593Smuzhiyun 	case MADI:
3851*4882a593Smuzhiyun 		status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
3852*4882a593Smuzhiyun 		if (status2 & HDSPM_wcLock) {
3853*4882a593Smuzhiyun 			if (status2 & HDSPM_wcSync)
3854*4882a593Smuzhiyun 				return 2;
3855*4882a593Smuzhiyun 			else
3856*4882a593Smuzhiyun 				return 1;
3857*4882a593Smuzhiyun 		}
3858*4882a593Smuzhiyun 		return 0;
3859*4882a593Smuzhiyun 		break;
3860*4882a593Smuzhiyun 
3861*4882a593Smuzhiyun 	case RayDAT:
3862*4882a593Smuzhiyun 	case AIO:
3863*4882a593Smuzhiyun 		status = hdspm_read(hdspm, HDSPM_statusRegister);
3864*4882a593Smuzhiyun 
3865*4882a593Smuzhiyun 		if (status & 0x2000000)
3866*4882a593Smuzhiyun 			return 2;
3867*4882a593Smuzhiyun 		else if (status & 0x1000000)
3868*4882a593Smuzhiyun 			return 1;
3869*4882a593Smuzhiyun 		return 0;
3870*4882a593Smuzhiyun 
3871*4882a593Smuzhiyun 		break;
3872*4882a593Smuzhiyun 
3873*4882a593Smuzhiyun 	case MADIface:
3874*4882a593Smuzhiyun 		break;
3875*4882a593Smuzhiyun 	}
3876*4882a593Smuzhiyun 
3877*4882a593Smuzhiyun 
3878*4882a593Smuzhiyun 	return 3;
3879*4882a593Smuzhiyun }
3880*4882a593Smuzhiyun 
3881*4882a593Smuzhiyun 
hdspm_madi_sync_check(struct hdspm * hdspm)3882*4882a593Smuzhiyun static int hdspm_madi_sync_check(struct hdspm *hdspm)
3883*4882a593Smuzhiyun {
3884*4882a593Smuzhiyun 	int status = hdspm_read(hdspm, HDSPM_statusRegister);
3885*4882a593Smuzhiyun 	if (status & HDSPM_madiLock) {
3886*4882a593Smuzhiyun 		if (status & HDSPM_madiSync)
3887*4882a593Smuzhiyun 			return 2;
3888*4882a593Smuzhiyun 		else
3889*4882a593Smuzhiyun 			return 1;
3890*4882a593Smuzhiyun 	}
3891*4882a593Smuzhiyun 	return 0;
3892*4882a593Smuzhiyun }
3893*4882a593Smuzhiyun 
3894*4882a593Smuzhiyun 
hdspm_s1_sync_check(struct hdspm * hdspm,int idx)3895*4882a593Smuzhiyun static int hdspm_s1_sync_check(struct hdspm *hdspm, int idx)
3896*4882a593Smuzhiyun {
3897*4882a593Smuzhiyun 	int status, lock, sync;
3898*4882a593Smuzhiyun 
3899*4882a593Smuzhiyun 	status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
3900*4882a593Smuzhiyun 
3901*4882a593Smuzhiyun 	lock = (status & (0x1<<idx)) ? 1 : 0;
3902*4882a593Smuzhiyun 	sync = (status & (0x100<<idx)) ? 1 : 0;
3903*4882a593Smuzhiyun 
3904*4882a593Smuzhiyun 	if (lock && sync)
3905*4882a593Smuzhiyun 		return 2;
3906*4882a593Smuzhiyun 	else if (lock)
3907*4882a593Smuzhiyun 		return 1;
3908*4882a593Smuzhiyun 	return 0;
3909*4882a593Smuzhiyun }
3910*4882a593Smuzhiyun 
3911*4882a593Smuzhiyun 
hdspm_sync_in_sync_check(struct hdspm * hdspm)3912*4882a593Smuzhiyun static int hdspm_sync_in_sync_check(struct hdspm *hdspm)
3913*4882a593Smuzhiyun {
3914*4882a593Smuzhiyun 	int status, lock = 0, sync = 0;
3915*4882a593Smuzhiyun 
3916*4882a593Smuzhiyun 	switch (hdspm->io_type) {
3917*4882a593Smuzhiyun 	case RayDAT:
3918*4882a593Smuzhiyun 	case AIO:
3919*4882a593Smuzhiyun 		status = hdspm_read(hdspm, HDSPM_RD_STATUS_3);
3920*4882a593Smuzhiyun 		lock = (status & 0x400) ? 1 : 0;
3921*4882a593Smuzhiyun 		sync = (status & 0x800) ? 1 : 0;
3922*4882a593Smuzhiyun 		break;
3923*4882a593Smuzhiyun 
3924*4882a593Smuzhiyun 	case MADI:
3925*4882a593Smuzhiyun 		status = hdspm_read(hdspm, HDSPM_statusRegister);
3926*4882a593Smuzhiyun 		lock = (status & HDSPM_syncInLock) ? 1 : 0;
3927*4882a593Smuzhiyun 		sync = (status & HDSPM_syncInSync) ? 1 : 0;
3928*4882a593Smuzhiyun 		break;
3929*4882a593Smuzhiyun 
3930*4882a593Smuzhiyun 	case AES32:
3931*4882a593Smuzhiyun 		status = hdspm_read(hdspm, HDSPM_statusRegister2);
3932*4882a593Smuzhiyun 		lock = (status & 0x100000) ? 1 : 0;
3933*4882a593Smuzhiyun 		sync = (status & 0x200000) ? 1 : 0;
3934*4882a593Smuzhiyun 		break;
3935*4882a593Smuzhiyun 
3936*4882a593Smuzhiyun 	case MADIface:
3937*4882a593Smuzhiyun 		break;
3938*4882a593Smuzhiyun 	}
3939*4882a593Smuzhiyun 
3940*4882a593Smuzhiyun 	if (lock && sync)
3941*4882a593Smuzhiyun 		return 2;
3942*4882a593Smuzhiyun 	else if (lock)
3943*4882a593Smuzhiyun 		return 1;
3944*4882a593Smuzhiyun 
3945*4882a593Smuzhiyun 	return 0;
3946*4882a593Smuzhiyun }
3947*4882a593Smuzhiyun 
hdspm_aes_sync_check(struct hdspm * hdspm,int idx)3948*4882a593Smuzhiyun static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx)
3949*4882a593Smuzhiyun {
3950*4882a593Smuzhiyun 	int status2, lock, sync;
3951*4882a593Smuzhiyun 	status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
3952*4882a593Smuzhiyun 
3953*4882a593Smuzhiyun 	lock = (status2 & (0x0080 >> idx)) ? 1 : 0;
3954*4882a593Smuzhiyun 	sync = (status2 & (0x8000 >> idx)) ? 1 : 0;
3955*4882a593Smuzhiyun 
3956*4882a593Smuzhiyun 	if (sync)
3957*4882a593Smuzhiyun 		return 2;
3958*4882a593Smuzhiyun 	else if (lock)
3959*4882a593Smuzhiyun 		return 1;
3960*4882a593Smuzhiyun 	return 0;
3961*4882a593Smuzhiyun }
3962*4882a593Smuzhiyun 
hdspm_tco_input_check(struct hdspm * hdspm,u32 mask)3963*4882a593Smuzhiyun static int hdspm_tco_input_check(struct hdspm *hdspm, u32 mask)
3964*4882a593Smuzhiyun {
3965*4882a593Smuzhiyun 	u32 status;
3966*4882a593Smuzhiyun 	status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
3967*4882a593Smuzhiyun 
3968*4882a593Smuzhiyun 	return (status & mask) ? 1 : 0;
3969*4882a593Smuzhiyun }
3970*4882a593Smuzhiyun 
3971*4882a593Smuzhiyun 
hdspm_tco_sync_check(struct hdspm * hdspm)3972*4882a593Smuzhiyun static int hdspm_tco_sync_check(struct hdspm *hdspm)
3973*4882a593Smuzhiyun {
3974*4882a593Smuzhiyun 	int status;
3975*4882a593Smuzhiyun 
3976*4882a593Smuzhiyun 	if (hdspm->tco) {
3977*4882a593Smuzhiyun 		switch (hdspm->io_type) {
3978*4882a593Smuzhiyun 		case MADI:
3979*4882a593Smuzhiyun 			status = hdspm_read(hdspm, HDSPM_statusRegister);
3980*4882a593Smuzhiyun 			if (status & HDSPM_tcoLockMadi) {
3981*4882a593Smuzhiyun 				if (status & HDSPM_tcoSync)
3982*4882a593Smuzhiyun 					return 2;
3983*4882a593Smuzhiyun 				else
3984*4882a593Smuzhiyun 					return 1;
3985*4882a593Smuzhiyun 			}
3986*4882a593Smuzhiyun 			return 0;
3987*4882a593Smuzhiyun 		case AES32:
3988*4882a593Smuzhiyun 			status = hdspm_read(hdspm, HDSPM_statusRegister);
3989*4882a593Smuzhiyun 			if (status & HDSPM_tcoLockAes) {
3990*4882a593Smuzhiyun 				if (status & HDSPM_tcoSync)
3991*4882a593Smuzhiyun 					return 2;
3992*4882a593Smuzhiyun 				else
3993*4882a593Smuzhiyun 					return 1;
3994*4882a593Smuzhiyun 			}
3995*4882a593Smuzhiyun 			return 0;
3996*4882a593Smuzhiyun 		case RayDAT:
3997*4882a593Smuzhiyun 		case AIO:
3998*4882a593Smuzhiyun 			status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
3999*4882a593Smuzhiyun 
4000*4882a593Smuzhiyun 			if (status & 0x8000000)
4001*4882a593Smuzhiyun 				return 2; /* Sync */
4002*4882a593Smuzhiyun 			if (status & 0x4000000)
4003*4882a593Smuzhiyun 				return 1; /* Lock */
4004*4882a593Smuzhiyun 			return 0; /* No signal */
4005*4882a593Smuzhiyun 
4006*4882a593Smuzhiyun 		default:
4007*4882a593Smuzhiyun 			break;
4008*4882a593Smuzhiyun 		}
4009*4882a593Smuzhiyun 	}
4010*4882a593Smuzhiyun 
4011*4882a593Smuzhiyun 	return 3; /* N/A */
4012*4882a593Smuzhiyun }
4013*4882a593Smuzhiyun 
4014*4882a593Smuzhiyun 
snd_hdspm_get_sync_check(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4015*4882a593Smuzhiyun static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
4016*4882a593Smuzhiyun 				    struct snd_ctl_elem_value *ucontrol)
4017*4882a593Smuzhiyun {
4018*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4019*4882a593Smuzhiyun 	int val = -1;
4020*4882a593Smuzhiyun 
4021*4882a593Smuzhiyun 	switch (hdspm->io_type) {
4022*4882a593Smuzhiyun 	case RayDAT:
4023*4882a593Smuzhiyun 		switch (kcontrol->private_value) {
4024*4882a593Smuzhiyun 		case 0: /* WC */
4025*4882a593Smuzhiyun 			val = hdspm_wc_sync_check(hdspm); break;
4026*4882a593Smuzhiyun 		case 7: /* TCO */
4027*4882a593Smuzhiyun 			val = hdspm_tco_sync_check(hdspm); break;
4028*4882a593Smuzhiyun 		case 8: /* SYNC IN */
4029*4882a593Smuzhiyun 			val = hdspm_sync_in_sync_check(hdspm); break;
4030*4882a593Smuzhiyun 		default:
4031*4882a593Smuzhiyun 			val = hdspm_s1_sync_check(hdspm,
4032*4882a593Smuzhiyun 					kcontrol->private_value-1);
4033*4882a593Smuzhiyun 		}
4034*4882a593Smuzhiyun 		break;
4035*4882a593Smuzhiyun 
4036*4882a593Smuzhiyun 	case AIO:
4037*4882a593Smuzhiyun 		switch (kcontrol->private_value) {
4038*4882a593Smuzhiyun 		case 0: /* WC */
4039*4882a593Smuzhiyun 			val = hdspm_wc_sync_check(hdspm); break;
4040*4882a593Smuzhiyun 		case 4: /* TCO */
4041*4882a593Smuzhiyun 			val = hdspm_tco_sync_check(hdspm); break;
4042*4882a593Smuzhiyun 		case 5: /* SYNC IN */
4043*4882a593Smuzhiyun 			val = hdspm_sync_in_sync_check(hdspm); break;
4044*4882a593Smuzhiyun 		default:
4045*4882a593Smuzhiyun 			val = hdspm_s1_sync_check(hdspm,
4046*4882a593Smuzhiyun 					kcontrol->private_value-1);
4047*4882a593Smuzhiyun 		}
4048*4882a593Smuzhiyun 		break;
4049*4882a593Smuzhiyun 
4050*4882a593Smuzhiyun 	case MADI:
4051*4882a593Smuzhiyun 		switch (kcontrol->private_value) {
4052*4882a593Smuzhiyun 		case 0: /* WC */
4053*4882a593Smuzhiyun 			val = hdspm_wc_sync_check(hdspm); break;
4054*4882a593Smuzhiyun 		case 1: /* MADI */
4055*4882a593Smuzhiyun 			val = hdspm_madi_sync_check(hdspm); break;
4056*4882a593Smuzhiyun 		case 2: /* TCO */
4057*4882a593Smuzhiyun 			val = hdspm_tco_sync_check(hdspm); break;
4058*4882a593Smuzhiyun 		case 3: /* SYNC_IN */
4059*4882a593Smuzhiyun 			val = hdspm_sync_in_sync_check(hdspm); break;
4060*4882a593Smuzhiyun 		}
4061*4882a593Smuzhiyun 		break;
4062*4882a593Smuzhiyun 
4063*4882a593Smuzhiyun 	case MADIface:
4064*4882a593Smuzhiyun 		val = hdspm_madi_sync_check(hdspm); /* MADI */
4065*4882a593Smuzhiyun 		break;
4066*4882a593Smuzhiyun 
4067*4882a593Smuzhiyun 	case AES32:
4068*4882a593Smuzhiyun 		switch (kcontrol->private_value) {
4069*4882a593Smuzhiyun 		case 0: /* WC */
4070*4882a593Smuzhiyun 			val = hdspm_wc_sync_check(hdspm); break;
4071*4882a593Smuzhiyun 		case 9: /* TCO */
4072*4882a593Smuzhiyun 			val = hdspm_tco_sync_check(hdspm); break;
4073*4882a593Smuzhiyun 		case 10 /* SYNC IN */:
4074*4882a593Smuzhiyun 			val = hdspm_sync_in_sync_check(hdspm); break;
4075*4882a593Smuzhiyun 		default: /* AES1 to AES8 */
4076*4882a593Smuzhiyun 			 val = hdspm_aes_sync_check(hdspm,
4077*4882a593Smuzhiyun 					 kcontrol->private_value-1);
4078*4882a593Smuzhiyun 		}
4079*4882a593Smuzhiyun 		break;
4080*4882a593Smuzhiyun 
4081*4882a593Smuzhiyun 	}
4082*4882a593Smuzhiyun 
4083*4882a593Smuzhiyun 	if (hdspm->tco) {
4084*4882a593Smuzhiyun 		switch (kcontrol->private_value) {
4085*4882a593Smuzhiyun 		case 11:
4086*4882a593Smuzhiyun 			/* Check TCO for lock state of its current input */
4087*4882a593Smuzhiyun 			val = hdspm_tco_input_check(hdspm, HDSPM_TCO1_TCO_lock);
4088*4882a593Smuzhiyun 			break;
4089*4882a593Smuzhiyun 		case 12:
4090*4882a593Smuzhiyun 			/* Check TCO for valid time code on LTC input. */
4091*4882a593Smuzhiyun 			val = hdspm_tco_input_check(hdspm,
4092*4882a593Smuzhiyun 				HDSPM_TCO1_LTC_Input_valid);
4093*4882a593Smuzhiyun 			break;
4094*4882a593Smuzhiyun 		default:
4095*4882a593Smuzhiyun 			break;
4096*4882a593Smuzhiyun 		}
4097*4882a593Smuzhiyun 	}
4098*4882a593Smuzhiyun 
4099*4882a593Smuzhiyun 	if (-1 == val)
4100*4882a593Smuzhiyun 		val = 3;
4101*4882a593Smuzhiyun 
4102*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = val;
4103*4882a593Smuzhiyun 	return 0;
4104*4882a593Smuzhiyun }
4105*4882a593Smuzhiyun 
4106*4882a593Smuzhiyun 
4107*4882a593Smuzhiyun 
4108*4882a593Smuzhiyun /*
4109*4882a593Smuzhiyun  * TCO controls
4110*4882a593Smuzhiyun  */
hdspm_tco_write(struct hdspm * hdspm)4111*4882a593Smuzhiyun static void hdspm_tco_write(struct hdspm *hdspm)
4112*4882a593Smuzhiyun {
4113*4882a593Smuzhiyun 	unsigned int tc[4] = { 0, 0, 0, 0};
4114*4882a593Smuzhiyun 
4115*4882a593Smuzhiyun 	switch (hdspm->tco->input) {
4116*4882a593Smuzhiyun 	case 0:
4117*4882a593Smuzhiyun 		tc[2] |= HDSPM_TCO2_set_input_MSB;
4118*4882a593Smuzhiyun 		break;
4119*4882a593Smuzhiyun 	case 1:
4120*4882a593Smuzhiyun 		tc[2] |= HDSPM_TCO2_set_input_LSB;
4121*4882a593Smuzhiyun 		break;
4122*4882a593Smuzhiyun 	default:
4123*4882a593Smuzhiyun 		break;
4124*4882a593Smuzhiyun 	}
4125*4882a593Smuzhiyun 
4126*4882a593Smuzhiyun 	switch (hdspm->tco->framerate) {
4127*4882a593Smuzhiyun 	case 1:
4128*4882a593Smuzhiyun 		tc[1] |= HDSPM_TCO1_LTC_Format_LSB;
4129*4882a593Smuzhiyun 		break;
4130*4882a593Smuzhiyun 	case 2:
4131*4882a593Smuzhiyun 		tc[1] |= HDSPM_TCO1_LTC_Format_MSB;
4132*4882a593Smuzhiyun 		break;
4133*4882a593Smuzhiyun 	case 3:
4134*4882a593Smuzhiyun 		tc[1] |= HDSPM_TCO1_LTC_Format_MSB +
4135*4882a593Smuzhiyun 			HDSPM_TCO1_set_drop_frame_flag;
4136*4882a593Smuzhiyun 		break;
4137*4882a593Smuzhiyun 	case 4:
4138*4882a593Smuzhiyun 		tc[1] |= HDSPM_TCO1_LTC_Format_LSB +
4139*4882a593Smuzhiyun 			HDSPM_TCO1_LTC_Format_MSB;
4140*4882a593Smuzhiyun 		break;
4141*4882a593Smuzhiyun 	case 5:
4142*4882a593Smuzhiyun 		tc[1] |= HDSPM_TCO1_LTC_Format_LSB +
4143*4882a593Smuzhiyun 			HDSPM_TCO1_LTC_Format_MSB +
4144*4882a593Smuzhiyun 			HDSPM_TCO1_set_drop_frame_flag;
4145*4882a593Smuzhiyun 		break;
4146*4882a593Smuzhiyun 	default:
4147*4882a593Smuzhiyun 		break;
4148*4882a593Smuzhiyun 	}
4149*4882a593Smuzhiyun 
4150*4882a593Smuzhiyun 	switch (hdspm->tco->wordclock) {
4151*4882a593Smuzhiyun 	case 1:
4152*4882a593Smuzhiyun 		tc[2] |= HDSPM_TCO2_WCK_IO_ratio_LSB;
4153*4882a593Smuzhiyun 		break;
4154*4882a593Smuzhiyun 	case 2:
4155*4882a593Smuzhiyun 		tc[2] |= HDSPM_TCO2_WCK_IO_ratio_MSB;
4156*4882a593Smuzhiyun 		break;
4157*4882a593Smuzhiyun 	default:
4158*4882a593Smuzhiyun 		break;
4159*4882a593Smuzhiyun 	}
4160*4882a593Smuzhiyun 
4161*4882a593Smuzhiyun 	switch (hdspm->tco->samplerate) {
4162*4882a593Smuzhiyun 	case 1:
4163*4882a593Smuzhiyun 		tc[2] |= HDSPM_TCO2_set_freq;
4164*4882a593Smuzhiyun 		break;
4165*4882a593Smuzhiyun 	case 2:
4166*4882a593Smuzhiyun 		tc[2] |= HDSPM_TCO2_set_freq_from_app;
4167*4882a593Smuzhiyun 		break;
4168*4882a593Smuzhiyun 	default:
4169*4882a593Smuzhiyun 		break;
4170*4882a593Smuzhiyun 	}
4171*4882a593Smuzhiyun 
4172*4882a593Smuzhiyun 	switch (hdspm->tco->pull) {
4173*4882a593Smuzhiyun 	case 1:
4174*4882a593Smuzhiyun 		tc[2] |= HDSPM_TCO2_set_pull_up;
4175*4882a593Smuzhiyun 		break;
4176*4882a593Smuzhiyun 	case 2:
4177*4882a593Smuzhiyun 		tc[2] |= HDSPM_TCO2_set_pull_down;
4178*4882a593Smuzhiyun 		break;
4179*4882a593Smuzhiyun 	case 3:
4180*4882a593Smuzhiyun 		tc[2] |= HDSPM_TCO2_set_pull_up + HDSPM_TCO2_set_01_4;
4181*4882a593Smuzhiyun 		break;
4182*4882a593Smuzhiyun 	case 4:
4183*4882a593Smuzhiyun 		tc[2] |= HDSPM_TCO2_set_pull_down + HDSPM_TCO2_set_01_4;
4184*4882a593Smuzhiyun 		break;
4185*4882a593Smuzhiyun 	default:
4186*4882a593Smuzhiyun 		break;
4187*4882a593Smuzhiyun 	}
4188*4882a593Smuzhiyun 
4189*4882a593Smuzhiyun 	if (1 == hdspm->tco->term) {
4190*4882a593Smuzhiyun 		tc[2] |= HDSPM_TCO2_set_term_75R;
4191*4882a593Smuzhiyun 	}
4192*4882a593Smuzhiyun 
4193*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_WR_TCO, tc[0]);
4194*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_WR_TCO+4, tc[1]);
4195*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_WR_TCO+8, tc[2]);
4196*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_WR_TCO+12, tc[3]);
4197*4882a593Smuzhiyun }
4198*4882a593Smuzhiyun 
4199*4882a593Smuzhiyun 
4200*4882a593Smuzhiyun #define HDSPM_TCO_SAMPLE_RATE(xname, xindex) \
4201*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4202*4882a593Smuzhiyun 	.name = xname, \
4203*4882a593Smuzhiyun 	.index = xindex, \
4204*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
4205*4882a593Smuzhiyun 		SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
4206*4882a593Smuzhiyun 	.info = snd_hdspm_info_tco_sample_rate, \
4207*4882a593Smuzhiyun 	.get = snd_hdspm_get_tco_sample_rate, \
4208*4882a593Smuzhiyun 	.put = snd_hdspm_put_tco_sample_rate \
4209*4882a593Smuzhiyun }
4210*4882a593Smuzhiyun 
snd_hdspm_info_tco_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)4211*4882a593Smuzhiyun static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol,
4212*4882a593Smuzhiyun 					  struct snd_ctl_elem_info *uinfo)
4213*4882a593Smuzhiyun {
4214*4882a593Smuzhiyun 	/* TODO freq from app could be supported here, see tco->samplerate */
4215*4882a593Smuzhiyun 	static const char *const texts[] = { "44.1 kHz", "48 kHz" };
4216*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
4217*4882a593Smuzhiyun 	return 0;
4218*4882a593Smuzhiyun }
4219*4882a593Smuzhiyun 
snd_hdspm_get_tco_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4220*4882a593Smuzhiyun static int snd_hdspm_get_tco_sample_rate(struct snd_kcontrol *kcontrol,
4221*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
4222*4882a593Smuzhiyun {
4223*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4224*4882a593Smuzhiyun 
4225*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm->tco->samplerate;
4226*4882a593Smuzhiyun 
4227*4882a593Smuzhiyun 	return 0;
4228*4882a593Smuzhiyun }
4229*4882a593Smuzhiyun 
snd_hdspm_put_tco_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4230*4882a593Smuzhiyun static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol,
4231*4882a593Smuzhiyun 					 struct snd_ctl_elem_value *ucontrol)
4232*4882a593Smuzhiyun {
4233*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4234*4882a593Smuzhiyun 
4235*4882a593Smuzhiyun 	if (hdspm->tco->samplerate != ucontrol->value.enumerated.item[0]) {
4236*4882a593Smuzhiyun 		hdspm->tco->samplerate = ucontrol->value.enumerated.item[0];
4237*4882a593Smuzhiyun 
4238*4882a593Smuzhiyun 		hdspm_tco_write(hdspm);
4239*4882a593Smuzhiyun 
4240*4882a593Smuzhiyun 		return 1;
4241*4882a593Smuzhiyun 	}
4242*4882a593Smuzhiyun 
4243*4882a593Smuzhiyun 	return 0;
4244*4882a593Smuzhiyun }
4245*4882a593Smuzhiyun 
4246*4882a593Smuzhiyun 
4247*4882a593Smuzhiyun #define HDSPM_TCO_PULL(xname, xindex) \
4248*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4249*4882a593Smuzhiyun 	.name = xname, \
4250*4882a593Smuzhiyun 	.index = xindex, \
4251*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
4252*4882a593Smuzhiyun 		SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
4253*4882a593Smuzhiyun 	.info = snd_hdspm_info_tco_pull, \
4254*4882a593Smuzhiyun 	.get = snd_hdspm_get_tco_pull, \
4255*4882a593Smuzhiyun 	.put = snd_hdspm_put_tco_pull \
4256*4882a593Smuzhiyun }
4257*4882a593Smuzhiyun 
snd_hdspm_info_tco_pull(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)4258*4882a593Smuzhiyun static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol,
4259*4882a593Smuzhiyun 				   struct snd_ctl_elem_info *uinfo)
4260*4882a593Smuzhiyun {
4261*4882a593Smuzhiyun 	static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %",
4262*4882a593Smuzhiyun 		"+ 4 %", "- 4 %" };
4263*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
4264*4882a593Smuzhiyun 	return 0;
4265*4882a593Smuzhiyun }
4266*4882a593Smuzhiyun 
snd_hdspm_get_tco_pull(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4267*4882a593Smuzhiyun static int snd_hdspm_get_tco_pull(struct snd_kcontrol *kcontrol,
4268*4882a593Smuzhiyun 				  struct snd_ctl_elem_value *ucontrol)
4269*4882a593Smuzhiyun {
4270*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4271*4882a593Smuzhiyun 
4272*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm->tco->pull;
4273*4882a593Smuzhiyun 
4274*4882a593Smuzhiyun 	return 0;
4275*4882a593Smuzhiyun }
4276*4882a593Smuzhiyun 
snd_hdspm_put_tco_pull(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4277*4882a593Smuzhiyun static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol,
4278*4882a593Smuzhiyun 				  struct snd_ctl_elem_value *ucontrol)
4279*4882a593Smuzhiyun {
4280*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4281*4882a593Smuzhiyun 
4282*4882a593Smuzhiyun 	if (hdspm->tco->pull != ucontrol->value.enumerated.item[0]) {
4283*4882a593Smuzhiyun 		hdspm->tco->pull = ucontrol->value.enumerated.item[0];
4284*4882a593Smuzhiyun 
4285*4882a593Smuzhiyun 		hdspm_tco_write(hdspm);
4286*4882a593Smuzhiyun 
4287*4882a593Smuzhiyun 		return 1;
4288*4882a593Smuzhiyun 	}
4289*4882a593Smuzhiyun 
4290*4882a593Smuzhiyun 	return 0;
4291*4882a593Smuzhiyun }
4292*4882a593Smuzhiyun 
4293*4882a593Smuzhiyun #define HDSPM_TCO_WCK_CONVERSION(xname, xindex) \
4294*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4295*4882a593Smuzhiyun 	.name = xname, \
4296*4882a593Smuzhiyun 	.index = xindex, \
4297*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
4298*4882a593Smuzhiyun 			SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
4299*4882a593Smuzhiyun 	.info = snd_hdspm_info_tco_wck_conversion, \
4300*4882a593Smuzhiyun 	.get = snd_hdspm_get_tco_wck_conversion, \
4301*4882a593Smuzhiyun 	.put = snd_hdspm_put_tco_wck_conversion \
4302*4882a593Smuzhiyun }
4303*4882a593Smuzhiyun 
snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)4304*4882a593Smuzhiyun static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol,
4305*4882a593Smuzhiyun 					     struct snd_ctl_elem_info *uinfo)
4306*4882a593Smuzhiyun {
4307*4882a593Smuzhiyun 	static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" };
4308*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
4309*4882a593Smuzhiyun 	return 0;
4310*4882a593Smuzhiyun }
4311*4882a593Smuzhiyun 
snd_hdspm_get_tco_wck_conversion(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4312*4882a593Smuzhiyun static int snd_hdspm_get_tco_wck_conversion(struct snd_kcontrol *kcontrol,
4313*4882a593Smuzhiyun 					    struct snd_ctl_elem_value *ucontrol)
4314*4882a593Smuzhiyun {
4315*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4316*4882a593Smuzhiyun 
4317*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm->tco->wordclock;
4318*4882a593Smuzhiyun 
4319*4882a593Smuzhiyun 	return 0;
4320*4882a593Smuzhiyun }
4321*4882a593Smuzhiyun 
snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4322*4882a593Smuzhiyun static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol,
4323*4882a593Smuzhiyun 					    struct snd_ctl_elem_value *ucontrol)
4324*4882a593Smuzhiyun {
4325*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4326*4882a593Smuzhiyun 
4327*4882a593Smuzhiyun 	if (hdspm->tco->wordclock != ucontrol->value.enumerated.item[0]) {
4328*4882a593Smuzhiyun 		hdspm->tco->wordclock = ucontrol->value.enumerated.item[0];
4329*4882a593Smuzhiyun 
4330*4882a593Smuzhiyun 		hdspm_tco_write(hdspm);
4331*4882a593Smuzhiyun 
4332*4882a593Smuzhiyun 		return 1;
4333*4882a593Smuzhiyun 	}
4334*4882a593Smuzhiyun 
4335*4882a593Smuzhiyun 	return 0;
4336*4882a593Smuzhiyun }
4337*4882a593Smuzhiyun 
4338*4882a593Smuzhiyun 
4339*4882a593Smuzhiyun #define HDSPM_TCO_FRAME_RATE(xname, xindex) \
4340*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4341*4882a593Smuzhiyun 	.name = xname, \
4342*4882a593Smuzhiyun 	.index = xindex, \
4343*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
4344*4882a593Smuzhiyun 			SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
4345*4882a593Smuzhiyun 	.info = snd_hdspm_info_tco_frame_rate, \
4346*4882a593Smuzhiyun 	.get = snd_hdspm_get_tco_frame_rate, \
4347*4882a593Smuzhiyun 	.put = snd_hdspm_put_tco_frame_rate \
4348*4882a593Smuzhiyun }
4349*4882a593Smuzhiyun 
snd_hdspm_info_tco_frame_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)4350*4882a593Smuzhiyun static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol,
4351*4882a593Smuzhiyun 					  struct snd_ctl_elem_info *uinfo)
4352*4882a593Smuzhiyun {
4353*4882a593Smuzhiyun 	static const char *const texts[] = { "24 fps", "25 fps", "29.97fps",
4354*4882a593Smuzhiyun 		"29.97 dfps", "30 fps", "30 dfps" };
4355*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
4356*4882a593Smuzhiyun 	return 0;
4357*4882a593Smuzhiyun }
4358*4882a593Smuzhiyun 
snd_hdspm_get_tco_frame_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4359*4882a593Smuzhiyun static int snd_hdspm_get_tco_frame_rate(struct snd_kcontrol *kcontrol,
4360*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
4361*4882a593Smuzhiyun {
4362*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4363*4882a593Smuzhiyun 
4364*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm->tco->framerate;
4365*4882a593Smuzhiyun 
4366*4882a593Smuzhiyun 	return 0;
4367*4882a593Smuzhiyun }
4368*4882a593Smuzhiyun 
snd_hdspm_put_tco_frame_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4369*4882a593Smuzhiyun static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol,
4370*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
4371*4882a593Smuzhiyun {
4372*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4373*4882a593Smuzhiyun 
4374*4882a593Smuzhiyun 	if (hdspm->tco->framerate != ucontrol->value.enumerated.item[0]) {
4375*4882a593Smuzhiyun 		hdspm->tco->framerate = ucontrol->value.enumerated.item[0];
4376*4882a593Smuzhiyun 
4377*4882a593Smuzhiyun 		hdspm_tco_write(hdspm);
4378*4882a593Smuzhiyun 
4379*4882a593Smuzhiyun 		return 1;
4380*4882a593Smuzhiyun 	}
4381*4882a593Smuzhiyun 
4382*4882a593Smuzhiyun 	return 0;
4383*4882a593Smuzhiyun }
4384*4882a593Smuzhiyun 
4385*4882a593Smuzhiyun 
4386*4882a593Smuzhiyun #define HDSPM_TCO_SYNC_SOURCE(xname, xindex) \
4387*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4388*4882a593Smuzhiyun 	.name = xname, \
4389*4882a593Smuzhiyun 	.index = xindex, \
4390*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
4391*4882a593Smuzhiyun 			SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
4392*4882a593Smuzhiyun 	.info = snd_hdspm_info_tco_sync_source, \
4393*4882a593Smuzhiyun 	.get = snd_hdspm_get_tco_sync_source, \
4394*4882a593Smuzhiyun 	.put = snd_hdspm_put_tco_sync_source \
4395*4882a593Smuzhiyun }
4396*4882a593Smuzhiyun 
snd_hdspm_info_tco_sync_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)4397*4882a593Smuzhiyun static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol,
4398*4882a593Smuzhiyun 					  struct snd_ctl_elem_info *uinfo)
4399*4882a593Smuzhiyun {
4400*4882a593Smuzhiyun 	static const char *const texts[] = { "LTC", "Video", "WCK" };
4401*4882a593Smuzhiyun 	ENUMERATED_CTL_INFO(uinfo, texts);
4402*4882a593Smuzhiyun 	return 0;
4403*4882a593Smuzhiyun }
4404*4882a593Smuzhiyun 
snd_hdspm_get_tco_sync_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4405*4882a593Smuzhiyun static int snd_hdspm_get_tco_sync_source(struct snd_kcontrol *kcontrol,
4406*4882a593Smuzhiyun 					 struct snd_ctl_elem_value *ucontrol)
4407*4882a593Smuzhiyun {
4408*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4409*4882a593Smuzhiyun 
4410*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = hdspm->tco->input;
4411*4882a593Smuzhiyun 
4412*4882a593Smuzhiyun 	return 0;
4413*4882a593Smuzhiyun }
4414*4882a593Smuzhiyun 
snd_hdspm_put_tco_sync_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4415*4882a593Smuzhiyun static int snd_hdspm_put_tco_sync_source(struct snd_kcontrol *kcontrol,
4416*4882a593Smuzhiyun 					 struct snd_ctl_elem_value *ucontrol)
4417*4882a593Smuzhiyun {
4418*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4419*4882a593Smuzhiyun 
4420*4882a593Smuzhiyun 	if (hdspm->tco->input != ucontrol->value.enumerated.item[0]) {
4421*4882a593Smuzhiyun 		hdspm->tco->input = ucontrol->value.enumerated.item[0];
4422*4882a593Smuzhiyun 
4423*4882a593Smuzhiyun 		hdspm_tco_write(hdspm);
4424*4882a593Smuzhiyun 
4425*4882a593Smuzhiyun 		return 1;
4426*4882a593Smuzhiyun 	}
4427*4882a593Smuzhiyun 
4428*4882a593Smuzhiyun 	return 0;
4429*4882a593Smuzhiyun }
4430*4882a593Smuzhiyun 
4431*4882a593Smuzhiyun 
4432*4882a593Smuzhiyun #define HDSPM_TCO_WORD_TERM(xname, xindex) \
4433*4882a593Smuzhiyun {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4434*4882a593Smuzhiyun 	.name = xname, \
4435*4882a593Smuzhiyun 	.index = xindex, \
4436*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
4437*4882a593Smuzhiyun 			SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
4438*4882a593Smuzhiyun 	.info = snd_hdspm_info_tco_word_term, \
4439*4882a593Smuzhiyun 	.get = snd_hdspm_get_tco_word_term, \
4440*4882a593Smuzhiyun 	.put = snd_hdspm_put_tco_word_term \
4441*4882a593Smuzhiyun }
4442*4882a593Smuzhiyun 
snd_hdspm_info_tco_word_term(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)4443*4882a593Smuzhiyun static int snd_hdspm_info_tco_word_term(struct snd_kcontrol *kcontrol,
4444*4882a593Smuzhiyun 					struct snd_ctl_elem_info *uinfo)
4445*4882a593Smuzhiyun {
4446*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
4447*4882a593Smuzhiyun 	uinfo->count = 1;
4448*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
4449*4882a593Smuzhiyun 	uinfo->value.integer.max = 1;
4450*4882a593Smuzhiyun 
4451*4882a593Smuzhiyun 	return 0;
4452*4882a593Smuzhiyun }
4453*4882a593Smuzhiyun 
4454*4882a593Smuzhiyun 
snd_hdspm_get_tco_word_term(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4455*4882a593Smuzhiyun static int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol,
4456*4882a593Smuzhiyun 				       struct snd_ctl_elem_value *ucontrol)
4457*4882a593Smuzhiyun {
4458*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4459*4882a593Smuzhiyun 
4460*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = hdspm->tco->term;
4461*4882a593Smuzhiyun 
4462*4882a593Smuzhiyun 	return 0;
4463*4882a593Smuzhiyun }
4464*4882a593Smuzhiyun 
4465*4882a593Smuzhiyun 
snd_hdspm_put_tco_word_term(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4466*4882a593Smuzhiyun static int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol,
4467*4882a593Smuzhiyun 				       struct snd_ctl_elem_value *ucontrol)
4468*4882a593Smuzhiyun {
4469*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
4470*4882a593Smuzhiyun 
4471*4882a593Smuzhiyun 	if (hdspm->tco->term != ucontrol->value.integer.value[0]) {
4472*4882a593Smuzhiyun 		hdspm->tco->term = ucontrol->value.integer.value[0];
4473*4882a593Smuzhiyun 
4474*4882a593Smuzhiyun 		hdspm_tco_write(hdspm);
4475*4882a593Smuzhiyun 
4476*4882a593Smuzhiyun 		return 1;
4477*4882a593Smuzhiyun 	}
4478*4882a593Smuzhiyun 
4479*4882a593Smuzhiyun 	return 0;
4480*4882a593Smuzhiyun }
4481*4882a593Smuzhiyun 
4482*4882a593Smuzhiyun 
4483*4882a593Smuzhiyun 
4484*4882a593Smuzhiyun 
4485*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_hdspm_controls_madi[] = {
4486*4882a593Smuzhiyun 	HDSPM_MIXER("Mixer", 0),
4487*4882a593Smuzhiyun 	HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
4488*4882a593Smuzhiyun 	HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
4489*4882a593Smuzhiyun 	HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
4490*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
4491*4882a593Smuzhiyun 	HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
4492*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
4493*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("WC SyncCheck", 0),
4494*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("MADI SyncCheck", 1),
4495*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("TCO SyncCheck", 2),
4496*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3),
4497*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut),
4498*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch),
4499*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Disable 96K frames", HDSPM_SMUX),
4500*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms),
4501*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp),
4502*4882a593Smuzhiyun 	HDSPM_INPUT_SELECT("Input Select", 0),
4503*4882a593Smuzhiyun 	HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0)
4504*4882a593Smuzhiyun };
4505*4882a593Smuzhiyun 
4506*4882a593Smuzhiyun 
4507*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_hdspm_controls_madiface[] = {
4508*4882a593Smuzhiyun 	HDSPM_MIXER("Mixer", 0),
4509*4882a593Smuzhiyun 	HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
4510*4882a593Smuzhiyun 	HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
4511*4882a593Smuzhiyun 	HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
4512*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
4513*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("MADI SyncCheck", 0),
4514*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch),
4515*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms),
4516*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp),
4517*4882a593Smuzhiyun 	HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0)
4518*4882a593Smuzhiyun };
4519*4882a593Smuzhiyun 
4520*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
4521*4882a593Smuzhiyun 	HDSPM_MIXER("Mixer", 0),
4522*4882a593Smuzhiyun 	HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
4523*4882a593Smuzhiyun 	HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
4524*4882a593Smuzhiyun 	HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
4525*4882a593Smuzhiyun 	HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
4526*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
4527*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("WC SyncCheck", 0),
4528*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("AES SyncCheck", 1),
4529*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2),
4530*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("ADAT SyncCheck", 3),
4531*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("TCO SyncCheck", 4),
4532*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 5),
4533*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0),
4534*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1),
4535*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2),
4536*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3),
4537*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4),
4538*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5),
4539*4882a593Smuzhiyun 	HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0),
4540*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt),
4541*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro),
4542*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1),
4543*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db),
4544*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48),
4545*4882a593Smuzhiyun 	HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0),
4546*4882a593Smuzhiyun 	HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0),
4547*4882a593Smuzhiyun 	HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0)
4548*4882a593Smuzhiyun 
4549*4882a593Smuzhiyun 		/*
4550*4882a593Smuzhiyun 		   HDSPM_INPUT_SELECT("Input Select", 0),
4551*4882a593Smuzhiyun 		   HDSPM_SPDIF_OPTICAL("SPDIF Out Optical", 0),
4552*4882a593Smuzhiyun 		   HDSPM_PROFESSIONAL("SPDIF Out Professional", 0);
4553*4882a593Smuzhiyun 		   HDSPM_SPDIF_IN("SPDIF In", 0);
4554*4882a593Smuzhiyun 		   HDSPM_BREAKOUT_CABLE("Breakout Cable", 0);
4555*4882a593Smuzhiyun 		   HDSPM_INPUT_LEVEL("Input Level", 0);
4556*4882a593Smuzhiyun 		   HDSPM_OUTPUT_LEVEL("Output Level", 0);
4557*4882a593Smuzhiyun 		   HDSPM_PHONES("Phones", 0);
4558*4882a593Smuzhiyun 		   */
4559*4882a593Smuzhiyun };
4560*4882a593Smuzhiyun 
4561*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_hdspm_controls_raydat[] = {
4562*4882a593Smuzhiyun 	HDSPM_MIXER("Mixer", 0),
4563*4882a593Smuzhiyun 	HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
4564*4882a593Smuzhiyun 	HDSPM_SYSTEM_CLOCK_MODE("Clock Mode", 0),
4565*4882a593Smuzhiyun 	HDSPM_PREF_SYNC_REF("Pref Sync Ref", 0),
4566*4882a593Smuzhiyun 	HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
4567*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("WC SyncCheck", 0),
4568*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("AES SyncCheck", 1),
4569*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2),
4570*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("ADAT1 SyncCheck", 3),
4571*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("ADAT2 SyncCheck", 4),
4572*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("ADAT3 SyncCheck", 5),
4573*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("ADAT4 SyncCheck", 6),
4574*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("TCO SyncCheck", 7),
4575*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 8),
4576*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0),
4577*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1),
4578*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2),
4579*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT1 Frequency", 3),
4580*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT2 Frequency", 4),
4581*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5),
4582*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6),
4583*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7),
4584*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8),
4585*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro),
4586*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48)
4587*4882a593Smuzhiyun };
4588*4882a593Smuzhiyun 
4589*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
4590*4882a593Smuzhiyun 	HDSPM_MIXER("Mixer", 0),
4591*4882a593Smuzhiyun 	HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
4592*4882a593Smuzhiyun 	HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
4593*4882a593Smuzhiyun 	HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
4594*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
4595*4882a593Smuzhiyun 	HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
4596*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11),
4597*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("WC Sync Check", 0),
4598*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("AES1 Sync Check", 1),
4599*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("AES2 Sync Check", 2),
4600*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("AES3 Sync Check", 3),
4601*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("AES4 Sync Check", 4),
4602*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("AES5 Sync Check", 5),
4603*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("AES6 Sync Check", 6),
4604*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("AES7 Sync Check", 7),
4605*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("AES8 Sync Check", 8),
4606*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("TCO Sync Check", 9),
4607*4882a593Smuzhiyun 	HDSPM_SYNC_CHECK("SYNC IN Sync Check", 10),
4608*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0),
4609*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("AES1 Frequency", 1),
4610*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("AES2 Frequency", 2),
4611*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("AES3 Frequency", 3),
4612*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("AES4 Frequency", 4),
4613*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("AES5 Frequency", 5),
4614*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("AES6 Frequency", 6),
4615*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("AES7 Frequency", 7),
4616*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("AES8 Frequency", 8),
4617*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 9),
4618*4882a593Smuzhiyun 	HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 10),
4619*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut),
4620*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Emphasis", HDSPM_Emphasis),
4621*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Non Audio", HDSPM_Dolby),
4622*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Professional", HDSPM_Professional),
4623*4882a593Smuzhiyun 	HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms),
4624*4882a593Smuzhiyun 	HDSPM_DS_WIRE("Double Speed Wire Mode", 0),
4625*4882a593Smuzhiyun 	HDSPM_QS_WIRE("Quad Speed Wire Mode", 0),
4626*4882a593Smuzhiyun };
4627*4882a593Smuzhiyun 
4628*4882a593Smuzhiyun 
4629*4882a593Smuzhiyun 
4630*4882a593Smuzhiyun /* Control elements for the optional TCO module */
4631*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_hdspm_controls_tco[] = {
4632*4882a593Smuzhiyun 	HDSPM_TCO_SAMPLE_RATE("TCO Sample Rate", 0),
4633*4882a593Smuzhiyun 	HDSPM_TCO_PULL("TCO Pull", 0),
4634*4882a593Smuzhiyun 	HDSPM_TCO_WCK_CONVERSION("TCO WCK Conversion", 0),
4635*4882a593Smuzhiyun 	HDSPM_TCO_FRAME_RATE("TCO Frame Rate", 0),
4636*4882a593Smuzhiyun 	HDSPM_TCO_SYNC_SOURCE("TCO Sync Source", 0),
4637*4882a593Smuzhiyun 	HDSPM_TCO_WORD_TERM("TCO Word Term", 0),
4638*4882a593Smuzhiyun 	HDSPM_TCO_LOCK_CHECK("TCO Input Check", 11),
4639*4882a593Smuzhiyun 	HDSPM_TCO_LOCK_CHECK("TCO LTC Valid", 12),
4640*4882a593Smuzhiyun 	HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate", 0),
4641*4882a593Smuzhiyun 	HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format", 0)
4642*4882a593Smuzhiyun };
4643*4882a593Smuzhiyun 
4644*4882a593Smuzhiyun 
4645*4882a593Smuzhiyun static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER;
4646*4882a593Smuzhiyun 
4647*4882a593Smuzhiyun 
hdspm_update_simple_mixer_controls(struct hdspm * hdspm)4648*4882a593Smuzhiyun static int hdspm_update_simple_mixer_controls(struct hdspm * hdspm)
4649*4882a593Smuzhiyun {
4650*4882a593Smuzhiyun 	int i;
4651*4882a593Smuzhiyun 
4652*4882a593Smuzhiyun 	for (i = hdspm->ds_out_channels; i < hdspm->ss_out_channels; ++i) {
4653*4882a593Smuzhiyun 		if (hdspm->system_sample_rate > 48000) {
4654*4882a593Smuzhiyun 			hdspm->playback_mixer_ctls[i]->vd[0].access =
4655*4882a593Smuzhiyun 				SNDRV_CTL_ELEM_ACCESS_INACTIVE |
4656*4882a593Smuzhiyun 				SNDRV_CTL_ELEM_ACCESS_READ |
4657*4882a593Smuzhiyun 				SNDRV_CTL_ELEM_ACCESS_VOLATILE;
4658*4882a593Smuzhiyun 		} else {
4659*4882a593Smuzhiyun 			hdspm->playback_mixer_ctls[i]->vd[0].access =
4660*4882a593Smuzhiyun 				SNDRV_CTL_ELEM_ACCESS_READWRITE |
4661*4882a593Smuzhiyun 				SNDRV_CTL_ELEM_ACCESS_VOLATILE;
4662*4882a593Smuzhiyun 		}
4663*4882a593Smuzhiyun 		snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE |
4664*4882a593Smuzhiyun 				SNDRV_CTL_EVENT_MASK_INFO,
4665*4882a593Smuzhiyun 				&hdspm->playback_mixer_ctls[i]->id);
4666*4882a593Smuzhiyun 	}
4667*4882a593Smuzhiyun 
4668*4882a593Smuzhiyun 	return 0;
4669*4882a593Smuzhiyun }
4670*4882a593Smuzhiyun 
4671*4882a593Smuzhiyun 
snd_hdspm_create_controls(struct snd_card * card,struct hdspm * hdspm)4672*4882a593Smuzhiyun static int snd_hdspm_create_controls(struct snd_card *card,
4673*4882a593Smuzhiyun 					struct hdspm *hdspm)
4674*4882a593Smuzhiyun {
4675*4882a593Smuzhiyun 	unsigned int idx, limit;
4676*4882a593Smuzhiyun 	int err;
4677*4882a593Smuzhiyun 	struct snd_kcontrol *kctl;
4678*4882a593Smuzhiyun 	const struct snd_kcontrol_new *list = NULL;
4679*4882a593Smuzhiyun 
4680*4882a593Smuzhiyun 	switch (hdspm->io_type) {
4681*4882a593Smuzhiyun 	case MADI:
4682*4882a593Smuzhiyun 		list = snd_hdspm_controls_madi;
4683*4882a593Smuzhiyun 		limit = ARRAY_SIZE(snd_hdspm_controls_madi);
4684*4882a593Smuzhiyun 		break;
4685*4882a593Smuzhiyun 	case MADIface:
4686*4882a593Smuzhiyun 		list = snd_hdspm_controls_madiface;
4687*4882a593Smuzhiyun 		limit = ARRAY_SIZE(snd_hdspm_controls_madiface);
4688*4882a593Smuzhiyun 		break;
4689*4882a593Smuzhiyun 	case AIO:
4690*4882a593Smuzhiyun 		list = snd_hdspm_controls_aio;
4691*4882a593Smuzhiyun 		limit = ARRAY_SIZE(snd_hdspm_controls_aio);
4692*4882a593Smuzhiyun 		break;
4693*4882a593Smuzhiyun 	case RayDAT:
4694*4882a593Smuzhiyun 		list = snd_hdspm_controls_raydat;
4695*4882a593Smuzhiyun 		limit = ARRAY_SIZE(snd_hdspm_controls_raydat);
4696*4882a593Smuzhiyun 		break;
4697*4882a593Smuzhiyun 	case AES32:
4698*4882a593Smuzhiyun 		list = snd_hdspm_controls_aes32;
4699*4882a593Smuzhiyun 		limit = ARRAY_SIZE(snd_hdspm_controls_aes32);
4700*4882a593Smuzhiyun 		break;
4701*4882a593Smuzhiyun 	}
4702*4882a593Smuzhiyun 
4703*4882a593Smuzhiyun 	if (list) {
4704*4882a593Smuzhiyun 		for (idx = 0; idx < limit; idx++) {
4705*4882a593Smuzhiyun 			err = snd_ctl_add(card,
4706*4882a593Smuzhiyun 					snd_ctl_new1(&list[idx], hdspm));
4707*4882a593Smuzhiyun 			if (err < 0)
4708*4882a593Smuzhiyun 				return err;
4709*4882a593Smuzhiyun 		}
4710*4882a593Smuzhiyun 	}
4711*4882a593Smuzhiyun 
4712*4882a593Smuzhiyun 
4713*4882a593Smuzhiyun 	/* create simple 1:1 playback mixer controls */
4714*4882a593Smuzhiyun 	snd_hdspm_playback_mixer.name = "Chn";
4715*4882a593Smuzhiyun 	if (hdspm->system_sample_rate >= 128000) {
4716*4882a593Smuzhiyun 		limit = hdspm->qs_out_channels;
4717*4882a593Smuzhiyun 	} else if (hdspm->system_sample_rate >= 64000) {
4718*4882a593Smuzhiyun 		limit = hdspm->ds_out_channels;
4719*4882a593Smuzhiyun 	} else {
4720*4882a593Smuzhiyun 		limit = hdspm->ss_out_channels;
4721*4882a593Smuzhiyun 	}
4722*4882a593Smuzhiyun 	for (idx = 0; idx < limit; ++idx) {
4723*4882a593Smuzhiyun 		snd_hdspm_playback_mixer.index = idx + 1;
4724*4882a593Smuzhiyun 		kctl = snd_ctl_new1(&snd_hdspm_playback_mixer, hdspm);
4725*4882a593Smuzhiyun 		err = snd_ctl_add(card, kctl);
4726*4882a593Smuzhiyun 		if (err < 0)
4727*4882a593Smuzhiyun 			return err;
4728*4882a593Smuzhiyun 		hdspm->playback_mixer_ctls[idx] = kctl;
4729*4882a593Smuzhiyun 	}
4730*4882a593Smuzhiyun 
4731*4882a593Smuzhiyun 
4732*4882a593Smuzhiyun 	if (hdspm->tco) {
4733*4882a593Smuzhiyun 		/* add tco control elements */
4734*4882a593Smuzhiyun 		list = snd_hdspm_controls_tco;
4735*4882a593Smuzhiyun 		limit = ARRAY_SIZE(snd_hdspm_controls_tco);
4736*4882a593Smuzhiyun 		for (idx = 0; idx < limit; idx++) {
4737*4882a593Smuzhiyun 			err = snd_ctl_add(card,
4738*4882a593Smuzhiyun 					snd_ctl_new1(&list[idx], hdspm));
4739*4882a593Smuzhiyun 			if (err < 0)
4740*4882a593Smuzhiyun 				return err;
4741*4882a593Smuzhiyun 		}
4742*4882a593Smuzhiyun 	}
4743*4882a593Smuzhiyun 
4744*4882a593Smuzhiyun 	return 0;
4745*4882a593Smuzhiyun }
4746*4882a593Smuzhiyun 
4747*4882a593Smuzhiyun /*------------------------------------------------------------
4748*4882a593Smuzhiyun    /proc interface
4749*4882a593Smuzhiyun  ------------------------------------------------------------*/
4750*4882a593Smuzhiyun 
4751*4882a593Smuzhiyun static void
snd_hdspm_proc_read_tco(struct snd_info_entry * entry,struct snd_info_buffer * buffer)4752*4882a593Smuzhiyun snd_hdspm_proc_read_tco(struct snd_info_entry *entry,
4753*4882a593Smuzhiyun 					struct snd_info_buffer *buffer)
4754*4882a593Smuzhiyun {
4755*4882a593Smuzhiyun 	struct hdspm *hdspm = entry->private_data;
4756*4882a593Smuzhiyun 	unsigned int status, control;
4757*4882a593Smuzhiyun 	int a, ltc, frames, seconds, minutes, hours;
4758*4882a593Smuzhiyun 	unsigned int period;
4759*4882a593Smuzhiyun 	u64 freq_const = 0;
4760*4882a593Smuzhiyun 	u32 rate;
4761*4882a593Smuzhiyun 
4762*4882a593Smuzhiyun 	snd_iprintf(buffer, "--- TCO ---\n");
4763*4882a593Smuzhiyun 
4764*4882a593Smuzhiyun 	status = hdspm_read(hdspm, HDSPM_statusRegister);
4765*4882a593Smuzhiyun 	control = hdspm->control_register;
4766*4882a593Smuzhiyun 
4767*4882a593Smuzhiyun 
4768*4882a593Smuzhiyun 	if (status & HDSPM_tco_detect) {
4769*4882a593Smuzhiyun 		snd_iprintf(buffer, "TCO module detected.\n");
4770*4882a593Smuzhiyun 		a = hdspm_read(hdspm, HDSPM_RD_TCO+4);
4771*4882a593Smuzhiyun 		if (a & HDSPM_TCO1_LTC_Input_valid) {
4772*4882a593Smuzhiyun 			snd_iprintf(buffer, "  LTC valid, ");
4773*4882a593Smuzhiyun 			switch (a & (HDSPM_TCO1_LTC_Format_LSB |
4774*4882a593Smuzhiyun 						HDSPM_TCO1_LTC_Format_MSB)) {
4775*4882a593Smuzhiyun 			case 0:
4776*4882a593Smuzhiyun 				snd_iprintf(buffer, "24 fps, ");
4777*4882a593Smuzhiyun 				break;
4778*4882a593Smuzhiyun 			case HDSPM_TCO1_LTC_Format_LSB:
4779*4882a593Smuzhiyun 				snd_iprintf(buffer, "25 fps, ");
4780*4882a593Smuzhiyun 				break;
4781*4882a593Smuzhiyun 			case HDSPM_TCO1_LTC_Format_MSB:
4782*4882a593Smuzhiyun 				snd_iprintf(buffer, "29.97 fps, ");
4783*4882a593Smuzhiyun 				break;
4784*4882a593Smuzhiyun 			default:
4785*4882a593Smuzhiyun 				snd_iprintf(buffer, "30 fps, ");
4786*4882a593Smuzhiyun 				break;
4787*4882a593Smuzhiyun 			}
4788*4882a593Smuzhiyun 			if (a & HDSPM_TCO1_set_drop_frame_flag) {
4789*4882a593Smuzhiyun 				snd_iprintf(buffer, "drop frame\n");
4790*4882a593Smuzhiyun 			} else {
4791*4882a593Smuzhiyun 				snd_iprintf(buffer, "full frame\n");
4792*4882a593Smuzhiyun 			}
4793*4882a593Smuzhiyun 		} else {
4794*4882a593Smuzhiyun 			snd_iprintf(buffer, "  no LTC\n");
4795*4882a593Smuzhiyun 		}
4796*4882a593Smuzhiyun 		if (a & HDSPM_TCO1_Video_Input_Format_NTSC) {
4797*4882a593Smuzhiyun 			snd_iprintf(buffer, "  Video: NTSC\n");
4798*4882a593Smuzhiyun 		} else if (a & HDSPM_TCO1_Video_Input_Format_PAL) {
4799*4882a593Smuzhiyun 			snd_iprintf(buffer, "  Video: PAL\n");
4800*4882a593Smuzhiyun 		} else {
4801*4882a593Smuzhiyun 			snd_iprintf(buffer, "  No video\n");
4802*4882a593Smuzhiyun 		}
4803*4882a593Smuzhiyun 		if (a & HDSPM_TCO1_TCO_lock) {
4804*4882a593Smuzhiyun 			snd_iprintf(buffer, "  Sync: lock\n");
4805*4882a593Smuzhiyun 		} else {
4806*4882a593Smuzhiyun 			snd_iprintf(buffer, "  Sync: no lock\n");
4807*4882a593Smuzhiyun 		}
4808*4882a593Smuzhiyun 
4809*4882a593Smuzhiyun 		switch (hdspm->io_type) {
4810*4882a593Smuzhiyun 		case MADI:
4811*4882a593Smuzhiyun 		case AES32:
4812*4882a593Smuzhiyun 			freq_const = 110069313433624ULL;
4813*4882a593Smuzhiyun 			break;
4814*4882a593Smuzhiyun 		case RayDAT:
4815*4882a593Smuzhiyun 		case AIO:
4816*4882a593Smuzhiyun 			freq_const = 104857600000000ULL;
4817*4882a593Smuzhiyun 			break;
4818*4882a593Smuzhiyun 		case MADIface:
4819*4882a593Smuzhiyun 			break; /* no TCO possible */
4820*4882a593Smuzhiyun 		}
4821*4882a593Smuzhiyun 
4822*4882a593Smuzhiyun 		period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
4823*4882a593Smuzhiyun 		snd_iprintf(buffer, "    period: %u\n", period);
4824*4882a593Smuzhiyun 
4825*4882a593Smuzhiyun 
4826*4882a593Smuzhiyun 		/* rate = freq_const/period; */
4827*4882a593Smuzhiyun 		rate = div_u64(freq_const, period);
4828*4882a593Smuzhiyun 
4829*4882a593Smuzhiyun 		if (control & HDSPM_QuadSpeed) {
4830*4882a593Smuzhiyun 			rate *= 4;
4831*4882a593Smuzhiyun 		} else if (control & HDSPM_DoubleSpeed) {
4832*4882a593Smuzhiyun 			rate *= 2;
4833*4882a593Smuzhiyun 		}
4834*4882a593Smuzhiyun 
4835*4882a593Smuzhiyun 		snd_iprintf(buffer, "  Frequency: %u Hz\n",
4836*4882a593Smuzhiyun 				(unsigned int) rate);
4837*4882a593Smuzhiyun 
4838*4882a593Smuzhiyun 		ltc = hdspm_read(hdspm, HDSPM_RD_TCO);
4839*4882a593Smuzhiyun 		frames = ltc & 0xF;
4840*4882a593Smuzhiyun 		ltc >>= 4;
4841*4882a593Smuzhiyun 		frames += (ltc & 0x3) * 10;
4842*4882a593Smuzhiyun 		ltc >>= 4;
4843*4882a593Smuzhiyun 		seconds = ltc & 0xF;
4844*4882a593Smuzhiyun 		ltc >>= 4;
4845*4882a593Smuzhiyun 		seconds += (ltc & 0x7) * 10;
4846*4882a593Smuzhiyun 		ltc >>= 4;
4847*4882a593Smuzhiyun 		minutes = ltc & 0xF;
4848*4882a593Smuzhiyun 		ltc >>= 4;
4849*4882a593Smuzhiyun 		minutes += (ltc & 0x7) * 10;
4850*4882a593Smuzhiyun 		ltc >>= 4;
4851*4882a593Smuzhiyun 		hours = ltc & 0xF;
4852*4882a593Smuzhiyun 		ltc >>= 4;
4853*4882a593Smuzhiyun 		hours += (ltc & 0x3) * 10;
4854*4882a593Smuzhiyun 		snd_iprintf(buffer,
4855*4882a593Smuzhiyun 			"  LTC In: %02d:%02d:%02d:%02d\n",
4856*4882a593Smuzhiyun 			hours, minutes, seconds, frames);
4857*4882a593Smuzhiyun 
4858*4882a593Smuzhiyun 	} else {
4859*4882a593Smuzhiyun 		snd_iprintf(buffer, "No TCO module detected.\n");
4860*4882a593Smuzhiyun 	}
4861*4882a593Smuzhiyun }
4862*4882a593Smuzhiyun 
4863*4882a593Smuzhiyun static void
snd_hdspm_proc_read_madi(struct snd_info_entry * entry,struct snd_info_buffer * buffer)4864*4882a593Smuzhiyun snd_hdspm_proc_read_madi(struct snd_info_entry *entry,
4865*4882a593Smuzhiyun 			 struct snd_info_buffer *buffer)
4866*4882a593Smuzhiyun {
4867*4882a593Smuzhiyun 	struct hdspm *hdspm = entry->private_data;
4868*4882a593Smuzhiyun 	unsigned int status, status2;
4869*4882a593Smuzhiyun 
4870*4882a593Smuzhiyun 	char *pref_sync_ref;
4871*4882a593Smuzhiyun 	char *autosync_ref;
4872*4882a593Smuzhiyun 	char *system_clock_mode;
4873*4882a593Smuzhiyun 	int x, x2;
4874*4882a593Smuzhiyun 
4875*4882a593Smuzhiyun 	status = hdspm_read(hdspm, HDSPM_statusRegister);
4876*4882a593Smuzhiyun 	status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
4877*4882a593Smuzhiyun 
4878*4882a593Smuzhiyun 	snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
4879*4882a593Smuzhiyun 			hdspm->card_name, hdspm->card->number + 1,
4880*4882a593Smuzhiyun 			hdspm->firmware_rev,
4881*4882a593Smuzhiyun 			(status2 & HDSPM_version0) |
4882*4882a593Smuzhiyun 			(status2 & HDSPM_version1) | (status2 &
4883*4882a593Smuzhiyun 				HDSPM_version2));
4884*4882a593Smuzhiyun 
4885*4882a593Smuzhiyun 	snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n",
4886*4882a593Smuzhiyun 			(hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF,
4887*4882a593Smuzhiyun 			hdspm->serial);
4888*4882a593Smuzhiyun 
4889*4882a593Smuzhiyun 	snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
4890*4882a593Smuzhiyun 			hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
4891*4882a593Smuzhiyun 
4892*4882a593Smuzhiyun 	snd_iprintf(buffer, "--- System ---\n");
4893*4882a593Smuzhiyun 
4894*4882a593Smuzhiyun 	snd_iprintf(buffer,
4895*4882a593Smuzhiyun 		"IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
4896*4882a593Smuzhiyun 		status & HDSPM_audioIRQPending,
4897*4882a593Smuzhiyun 		(status & HDSPM_midi0IRQPending) ? 1 : 0,
4898*4882a593Smuzhiyun 		(status & HDSPM_midi1IRQPending) ? 1 : 0,
4899*4882a593Smuzhiyun 		hdspm->irq_count);
4900*4882a593Smuzhiyun 	snd_iprintf(buffer,
4901*4882a593Smuzhiyun 		"HW pointer: id = %d, rawptr = %d (%d->%d) "
4902*4882a593Smuzhiyun 		"estimated= %ld (bytes)\n",
4903*4882a593Smuzhiyun 		((status & HDSPM_BufferID) ? 1 : 0),
4904*4882a593Smuzhiyun 		(status & HDSPM_BufferPositionMask),
4905*4882a593Smuzhiyun 		(status & HDSPM_BufferPositionMask) %
4906*4882a593Smuzhiyun 		(2 * (int)hdspm->period_bytes),
4907*4882a593Smuzhiyun 		((status & HDSPM_BufferPositionMask) - 64) %
4908*4882a593Smuzhiyun 		(2 * (int)hdspm->period_bytes),
4909*4882a593Smuzhiyun 		(long) hdspm_hw_pointer(hdspm) * 4);
4910*4882a593Smuzhiyun 
4911*4882a593Smuzhiyun 	snd_iprintf(buffer,
4912*4882a593Smuzhiyun 		"MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
4913*4882a593Smuzhiyun 		hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
4914*4882a593Smuzhiyun 		hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
4915*4882a593Smuzhiyun 		hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
4916*4882a593Smuzhiyun 		hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
4917*4882a593Smuzhiyun 	snd_iprintf(buffer,
4918*4882a593Smuzhiyun 		"MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
4919*4882a593Smuzhiyun 		hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
4920*4882a593Smuzhiyun 		hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
4921*4882a593Smuzhiyun 	snd_iprintf(buffer,
4922*4882a593Smuzhiyun 		"Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
4923*4882a593Smuzhiyun 		"status2=0x%x\n",
4924*4882a593Smuzhiyun 		hdspm->control_register, hdspm->control2_register,
4925*4882a593Smuzhiyun 		status, status2);
4926*4882a593Smuzhiyun 
4927*4882a593Smuzhiyun 
4928*4882a593Smuzhiyun 	snd_iprintf(buffer, "--- Settings ---\n");
4929*4882a593Smuzhiyun 
4930*4882a593Smuzhiyun 	x = hdspm_get_latency(hdspm);
4931*4882a593Smuzhiyun 
4932*4882a593Smuzhiyun 	snd_iprintf(buffer,
4933*4882a593Smuzhiyun 		"Size (Latency): %d samples (2 periods of %lu bytes)\n",
4934*4882a593Smuzhiyun 		x, (unsigned long) hdspm->period_bytes);
4935*4882a593Smuzhiyun 
4936*4882a593Smuzhiyun 	snd_iprintf(buffer, "Line out: %s\n",
4937*4882a593Smuzhiyun 		(hdspm->control_register & HDSPM_LineOut) ? "on " : "off");
4938*4882a593Smuzhiyun 
4939*4882a593Smuzhiyun 	snd_iprintf(buffer,
4940*4882a593Smuzhiyun 		"ClearTrackMarker = %s, Transmit in %s Channel Mode, "
4941*4882a593Smuzhiyun 		"Auto Input %s\n",
4942*4882a593Smuzhiyun 		(hdspm->control_register & HDSPM_clr_tms) ? "on" : "off",
4943*4882a593Smuzhiyun 		(hdspm->control_register & HDSPM_TX_64ch) ? "64" : "56",
4944*4882a593Smuzhiyun 		(hdspm->control_register & HDSPM_AutoInp) ? "on" : "off");
4945*4882a593Smuzhiyun 
4946*4882a593Smuzhiyun 
4947*4882a593Smuzhiyun 	if (!(hdspm->control_register & HDSPM_ClockModeMaster))
4948*4882a593Smuzhiyun 		system_clock_mode = "AutoSync";
4949*4882a593Smuzhiyun 	else
4950*4882a593Smuzhiyun 		system_clock_mode = "Master";
4951*4882a593Smuzhiyun 	snd_iprintf(buffer, "AutoSync Reference: %s\n", system_clock_mode);
4952*4882a593Smuzhiyun 
4953*4882a593Smuzhiyun 	switch (hdspm_pref_sync_ref(hdspm)) {
4954*4882a593Smuzhiyun 	case HDSPM_SYNC_FROM_WORD:
4955*4882a593Smuzhiyun 		pref_sync_ref = "Word Clock";
4956*4882a593Smuzhiyun 		break;
4957*4882a593Smuzhiyun 	case HDSPM_SYNC_FROM_MADI:
4958*4882a593Smuzhiyun 		pref_sync_ref = "MADI Sync";
4959*4882a593Smuzhiyun 		break;
4960*4882a593Smuzhiyun 	case HDSPM_SYNC_FROM_TCO:
4961*4882a593Smuzhiyun 		pref_sync_ref = "TCO";
4962*4882a593Smuzhiyun 		break;
4963*4882a593Smuzhiyun 	case HDSPM_SYNC_FROM_SYNC_IN:
4964*4882a593Smuzhiyun 		pref_sync_ref = "Sync In";
4965*4882a593Smuzhiyun 		break;
4966*4882a593Smuzhiyun 	default:
4967*4882a593Smuzhiyun 		pref_sync_ref = "XXXX Clock";
4968*4882a593Smuzhiyun 		break;
4969*4882a593Smuzhiyun 	}
4970*4882a593Smuzhiyun 	snd_iprintf(buffer, "Preferred Sync Reference: %s\n",
4971*4882a593Smuzhiyun 			pref_sync_ref);
4972*4882a593Smuzhiyun 
4973*4882a593Smuzhiyun 	snd_iprintf(buffer, "System Clock Frequency: %d\n",
4974*4882a593Smuzhiyun 			hdspm->system_sample_rate);
4975*4882a593Smuzhiyun 
4976*4882a593Smuzhiyun 
4977*4882a593Smuzhiyun 	snd_iprintf(buffer, "--- Status:\n");
4978*4882a593Smuzhiyun 
4979*4882a593Smuzhiyun 	x = status & HDSPM_madiSync;
4980*4882a593Smuzhiyun 	x2 = status2 & HDSPM_wcSync;
4981*4882a593Smuzhiyun 
4982*4882a593Smuzhiyun 	snd_iprintf(buffer, "Inputs MADI=%s, WordClock=%s\n",
4983*4882a593Smuzhiyun 			(status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") :
4984*4882a593Smuzhiyun 			"NoLock",
4985*4882a593Smuzhiyun 			(status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") :
4986*4882a593Smuzhiyun 			"NoLock");
4987*4882a593Smuzhiyun 
4988*4882a593Smuzhiyun 	switch (hdspm_autosync_ref(hdspm)) {
4989*4882a593Smuzhiyun 	case HDSPM_AUTOSYNC_FROM_SYNC_IN:
4990*4882a593Smuzhiyun 		autosync_ref = "Sync In";
4991*4882a593Smuzhiyun 		break;
4992*4882a593Smuzhiyun 	case HDSPM_AUTOSYNC_FROM_TCO:
4993*4882a593Smuzhiyun 		autosync_ref = "TCO";
4994*4882a593Smuzhiyun 		break;
4995*4882a593Smuzhiyun 	case HDSPM_AUTOSYNC_FROM_WORD:
4996*4882a593Smuzhiyun 		autosync_ref = "Word Clock";
4997*4882a593Smuzhiyun 		break;
4998*4882a593Smuzhiyun 	case HDSPM_AUTOSYNC_FROM_MADI:
4999*4882a593Smuzhiyun 		autosync_ref = "MADI Sync";
5000*4882a593Smuzhiyun 		break;
5001*4882a593Smuzhiyun 	case HDSPM_AUTOSYNC_FROM_NONE:
5002*4882a593Smuzhiyun 		autosync_ref = "Input not valid";
5003*4882a593Smuzhiyun 		break;
5004*4882a593Smuzhiyun 	default:
5005*4882a593Smuzhiyun 		autosync_ref = "---";
5006*4882a593Smuzhiyun 		break;
5007*4882a593Smuzhiyun 	}
5008*4882a593Smuzhiyun 	snd_iprintf(buffer,
5009*4882a593Smuzhiyun 		"AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n",
5010*4882a593Smuzhiyun 		autosync_ref, hdspm_external_sample_rate(hdspm),
5011*4882a593Smuzhiyun 		(status & HDSPM_madiFreqMask) >> 22,
5012*4882a593Smuzhiyun 		(status2 & HDSPM_wcFreqMask) >> 5);
5013*4882a593Smuzhiyun 
5014*4882a593Smuzhiyun 	snd_iprintf(buffer, "Input: %s, Mode=%s\n",
5015*4882a593Smuzhiyun 		(status & HDSPM_AB_int) ? "Coax" : "Optical",
5016*4882a593Smuzhiyun 		(status & HDSPM_RX_64ch) ? "64 channels" :
5017*4882a593Smuzhiyun 		"56 channels");
5018*4882a593Smuzhiyun 
5019*4882a593Smuzhiyun 	/* call readout function for TCO specific status */
5020*4882a593Smuzhiyun 	snd_hdspm_proc_read_tco(entry, buffer);
5021*4882a593Smuzhiyun 
5022*4882a593Smuzhiyun 	snd_iprintf(buffer, "\n");
5023*4882a593Smuzhiyun }
5024*4882a593Smuzhiyun 
5025*4882a593Smuzhiyun static void
snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,struct snd_info_buffer * buffer)5026*4882a593Smuzhiyun snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
5027*4882a593Smuzhiyun 			  struct snd_info_buffer *buffer)
5028*4882a593Smuzhiyun {
5029*4882a593Smuzhiyun 	struct hdspm *hdspm = entry->private_data;
5030*4882a593Smuzhiyun 	unsigned int status;
5031*4882a593Smuzhiyun 	unsigned int status2;
5032*4882a593Smuzhiyun 	unsigned int timecode;
5033*4882a593Smuzhiyun 	unsigned int wcLock, wcSync;
5034*4882a593Smuzhiyun 	int pref_syncref;
5035*4882a593Smuzhiyun 	char *autosync_ref;
5036*4882a593Smuzhiyun 	int x;
5037*4882a593Smuzhiyun 
5038*4882a593Smuzhiyun 	status = hdspm_read(hdspm, HDSPM_statusRegister);
5039*4882a593Smuzhiyun 	status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
5040*4882a593Smuzhiyun 	timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
5041*4882a593Smuzhiyun 
5042*4882a593Smuzhiyun 	snd_iprintf(buffer, "%s (Card #%d) Rev.%x\n",
5043*4882a593Smuzhiyun 		    hdspm->card_name, hdspm->card->number + 1,
5044*4882a593Smuzhiyun 		    hdspm->firmware_rev);
5045*4882a593Smuzhiyun 
5046*4882a593Smuzhiyun 	snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
5047*4882a593Smuzhiyun 		    hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
5048*4882a593Smuzhiyun 
5049*4882a593Smuzhiyun 	snd_iprintf(buffer, "--- System ---\n");
5050*4882a593Smuzhiyun 
5051*4882a593Smuzhiyun 	snd_iprintf(buffer,
5052*4882a593Smuzhiyun 		    "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
5053*4882a593Smuzhiyun 		    status & HDSPM_audioIRQPending,
5054*4882a593Smuzhiyun 		    (status & HDSPM_midi0IRQPending) ? 1 : 0,
5055*4882a593Smuzhiyun 		    (status & HDSPM_midi1IRQPending) ? 1 : 0,
5056*4882a593Smuzhiyun 		    hdspm->irq_count);
5057*4882a593Smuzhiyun 	snd_iprintf(buffer,
5058*4882a593Smuzhiyun 		    "HW pointer: id = %d, rawptr = %d (%d->%d) "
5059*4882a593Smuzhiyun 		    "estimated= %ld (bytes)\n",
5060*4882a593Smuzhiyun 		    ((status & HDSPM_BufferID) ? 1 : 0),
5061*4882a593Smuzhiyun 		    (status & HDSPM_BufferPositionMask),
5062*4882a593Smuzhiyun 		    (status & HDSPM_BufferPositionMask) %
5063*4882a593Smuzhiyun 		    (2 * (int)hdspm->period_bytes),
5064*4882a593Smuzhiyun 		    ((status & HDSPM_BufferPositionMask) - 64) %
5065*4882a593Smuzhiyun 		    (2 * (int)hdspm->period_bytes),
5066*4882a593Smuzhiyun 		    (long) hdspm_hw_pointer(hdspm) * 4);
5067*4882a593Smuzhiyun 
5068*4882a593Smuzhiyun 	snd_iprintf(buffer,
5069*4882a593Smuzhiyun 		    "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
5070*4882a593Smuzhiyun 		    hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
5071*4882a593Smuzhiyun 		    hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
5072*4882a593Smuzhiyun 		    hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
5073*4882a593Smuzhiyun 		    hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
5074*4882a593Smuzhiyun 	snd_iprintf(buffer,
5075*4882a593Smuzhiyun 		    "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
5076*4882a593Smuzhiyun 		    hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
5077*4882a593Smuzhiyun 		    hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
5078*4882a593Smuzhiyun 	snd_iprintf(buffer,
5079*4882a593Smuzhiyun 		    "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
5080*4882a593Smuzhiyun 		    "status2=0x%x\n",
5081*4882a593Smuzhiyun 		    hdspm->control_register, hdspm->control2_register,
5082*4882a593Smuzhiyun 		    status, status2);
5083*4882a593Smuzhiyun 
5084*4882a593Smuzhiyun 	snd_iprintf(buffer, "--- Settings ---\n");
5085*4882a593Smuzhiyun 
5086*4882a593Smuzhiyun 	x = hdspm_get_latency(hdspm);
5087*4882a593Smuzhiyun 
5088*4882a593Smuzhiyun 	snd_iprintf(buffer,
5089*4882a593Smuzhiyun 		    "Size (Latency): %d samples (2 periods of %lu bytes)\n",
5090*4882a593Smuzhiyun 		    x, (unsigned long) hdspm->period_bytes);
5091*4882a593Smuzhiyun 
5092*4882a593Smuzhiyun 	snd_iprintf(buffer, "Line out: %s\n",
5093*4882a593Smuzhiyun 		    (hdspm->
5094*4882a593Smuzhiyun 		     control_register & HDSPM_LineOut) ? "on " : "off");
5095*4882a593Smuzhiyun 
5096*4882a593Smuzhiyun 	snd_iprintf(buffer,
5097*4882a593Smuzhiyun 		    "ClearTrackMarker %s, Emphasis %s, Dolby %s\n",
5098*4882a593Smuzhiyun 		    (hdspm->
5099*4882a593Smuzhiyun 		     control_register & HDSPM_clr_tms) ? "on" : "off",
5100*4882a593Smuzhiyun 		    (hdspm->
5101*4882a593Smuzhiyun 		     control_register & HDSPM_Emphasis) ? "on" : "off",
5102*4882a593Smuzhiyun 		    (hdspm->
5103*4882a593Smuzhiyun 		     control_register & HDSPM_Dolby) ? "on" : "off");
5104*4882a593Smuzhiyun 
5105*4882a593Smuzhiyun 
5106*4882a593Smuzhiyun 	pref_syncref = hdspm_pref_sync_ref(hdspm);
5107*4882a593Smuzhiyun 	if (pref_syncref == 0)
5108*4882a593Smuzhiyun 		snd_iprintf(buffer, "Preferred Sync Reference: Word Clock\n");
5109*4882a593Smuzhiyun 	else
5110*4882a593Smuzhiyun 		snd_iprintf(buffer, "Preferred Sync Reference: AES%d\n",
5111*4882a593Smuzhiyun 				pref_syncref);
5112*4882a593Smuzhiyun 
5113*4882a593Smuzhiyun 	snd_iprintf(buffer, "System Clock Frequency: %d\n",
5114*4882a593Smuzhiyun 		    hdspm->system_sample_rate);
5115*4882a593Smuzhiyun 
5116*4882a593Smuzhiyun 	snd_iprintf(buffer, "Double speed: %s\n",
5117*4882a593Smuzhiyun 			hdspm->control_register & HDSPM_DS_DoubleWire?
5118*4882a593Smuzhiyun 			"Double wire" : "Single wire");
5119*4882a593Smuzhiyun 	snd_iprintf(buffer, "Quad speed: %s\n",
5120*4882a593Smuzhiyun 			hdspm->control_register & HDSPM_QS_DoubleWire?
5121*4882a593Smuzhiyun 			"Double wire" :
5122*4882a593Smuzhiyun 			hdspm->control_register & HDSPM_QS_QuadWire?
5123*4882a593Smuzhiyun 			"Quad wire" : "Single wire");
5124*4882a593Smuzhiyun 
5125*4882a593Smuzhiyun 	snd_iprintf(buffer, "--- Status:\n");
5126*4882a593Smuzhiyun 
5127*4882a593Smuzhiyun 	wcLock = status & HDSPM_AES32_wcLock;
5128*4882a593Smuzhiyun 	wcSync = wcLock && (status & HDSPM_AES32_wcSync);
5129*4882a593Smuzhiyun 
5130*4882a593Smuzhiyun 	snd_iprintf(buffer, "Word: %s  Frequency: %d\n",
5131*4882a593Smuzhiyun 		    (wcLock) ? (wcSync ? "Sync   " : "Lock   ") : "No Lock",
5132*4882a593Smuzhiyun 		    HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF));
5133*4882a593Smuzhiyun 
5134*4882a593Smuzhiyun 	for (x = 0; x < 8; x++) {
5135*4882a593Smuzhiyun 		snd_iprintf(buffer, "AES%d: %s  Frequency: %d\n",
5136*4882a593Smuzhiyun 			    x+1,
5137*4882a593Smuzhiyun 			    (status2 & (HDSPM_LockAES >> x)) ?
5138*4882a593Smuzhiyun 			    "Sync   " : "No Lock",
5139*4882a593Smuzhiyun 			    HDSPM_bit2freq((timecode >> (4*x)) & 0xF));
5140*4882a593Smuzhiyun 	}
5141*4882a593Smuzhiyun 
5142*4882a593Smuzhiyun 	switch (hdspm_autosync_ref(hdspm)) {
5143*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_NONE:
5144*4882a593Smuzhiyun 		autosync_ref = "None"; break;
5145*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_WORD:
5146*4882a593Smuzhiyun 		autosync_ref = "Word Clock"; break;
5147*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_AES1:
5148*4882a593Smuzhiyun 		autosync_ref = "AES1"; break;
5149*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_AES2:
5150*4882a593Smuzhiyun 		autosync_ref = "AES2"; break;
5151*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_AES3:
5152*4882a593Smuzhiyun 		autosync_ref = "AES3"; break;
5153*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_AES4:
5154*4882a593Smuzhiyun 		autosync_ref = "AES4"; break;
5155*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_AES5:
5156*4882a593Smuzhiyun 		autosync_ref = "AES5"; break;
5157*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_AES6:
5158*4882a593Smuzhiyun 		autosync_ref = "AES6"; break;
5159*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_AES7:
5160*4882a593Smuzhiyun 		autosync_ref = "AES7"; break;
5161*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_AES8:
5162*4882a593Smuzhiyun 		autosync_ref = "AES8"; break;
5163*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_TCO:
5164*4882a593Smuzhiyun 		autosync_ref = "TCO"; break;
5165*4882a593Smuzhiyun 	case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN:
5166*4882a593Smuzhiyun 		autosync_ref = "Sync In"; break;
5167*4882a593Smuzhiyun 	default:
5168*4882a593Smuzhiyun 		autosync_ref = "---"; break;
5169*4882a593Smuzhiyun 	}
5170*4882a593Smuzhiyun 	snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref);
5171*4882a593Smuzhiyun 
5172*4882a593Smuzhiyun 	/* call readout function for TCO specific status */
5173*4882a593Smuzhiyun 	snd_hdspm_proc_read_tco(entry, buffer);
5174*4882a593Smuzhiyun 
5175*4882a593Smuzhiyun 	snd_iprintf(buffer, "\n");
5176*4882a593Smuzhiyun }
5177*4882a593Smuzhiyun 
5178*4882a593Smuzhiyun static void
snd_hdspm_proc_read_raydat(struct snd_info_entry * entry,struct snd_info_buffer * buffer)5179*4882a593Smuzhiyun snd_hdspm_proc_read_raydat(struct snd_info_entry *entry,
5180*4882a593Smuzhiyun 			 struct snd_info_buffer *buffer)
5181*4882a593Smuzhiyun {
5182*4882a593Smuzhiyun 	struct hdspm *hdspm = entry->private_data;
5183*4882a593Smuzhiyun 	unsigned int status1, status2, status3, i;
5184*4882a593Smuzhiyun 	unsigned int lock, sync;
5185*4882a593Smuzhiyun 
5186*4882a593Smuzhiyun 	status1 = hdspm_read(hdspm, HDSPM_RD_STATUS_1); /* s1 */
5187*4882a593Smuzhiyun 	status2 = hdspm_read(hdspm, HDSPM_RD_STATUS_2); /* freq */
5188*4882a593Smuzhiyun 	status3 = hdspm_read(hdspm, HDSPM_RD_STATUS_3); /* s2 */
5189*4882a593Smuzhiyun 
5190*4882a593Smuzhiyun 	snd_iprintf(buffer, "STATUS1: 0x%08x\n", status1);
5191*4882a593Smuzhiyun 	snd_iprintf(buffer, "STATUS2: 0x%08x\n", status2);
5192*4882a593Smuzhiyun 	snd_iprintf(buffer, "STATUS3: 0x%08x\n", status3);
5193*4882a593Smuzhiyun 
5194*4882a593Smuzhiyun 
5195*4882a593Smuzhiyun 	snd_iprintf(buffer, "\n*** CLOCK MODE\n\n");
5196*4882a593Smuzhiyun 
5197*4882a593Smuzhiyun 	snd_iprintf(buffer, "Clock mode      : %s\n",
5198*4882a593Smuzhiyun 		(hdspm_system_clock_mode(hdspm) == 0) ? "master" : "slave");
5199*4882a593Smuzhiyun 	snd_iprintf(buffer, "System frequency: %d Hz\n",
5200*4882a593Smuzhiyun 		hdspm_get_system_sample_rate(hdspm));
5201*4882a593Smuzhiyun 
5202*4882a593Smuzhiyun 	snd_iprintf(buffer, "\n*** INPUT STATUS\n\n");
5203*4882a593Smuzhiyun 
5204*4882a593Smuzhiyun 	lock = 0x1;
5205*4882a593Smuzhiyun 	sync = 0x100;
5206*4882a593Smuzhiyun 
5207*4882a593Smuzhiyun 	for (i = 0; i < 8; i++) {
5208*4882a593Smuzhiyun 		snd_iprintf(buffer, "s1_input %d: Lock %d, Sync %d, Freq %s\n",
5209*4882a593Smuzhiyun 				i,
5210*4882a593Smuzhiyun 				(status1 & lock) ? 1 : 0,
5211*4882a593Smuzhiyun 				(status1 & sync) ? 1 : 0,
5212*4882a593Smuzhiyun 				texts_freq[(status2 >> (i * 4)) & 0xF]);
5213*4882a593Smuzhiyun 
5214*4882a593Smuzhiyun 		lock = lock<<1;
5215*4882a593Smuzhiyun 		sync = sync<<1;
5216*4882a593Smuzhiyun 	}
5217*4882a593Smuzhiyun 
5218*4882a593Smuzhiyun 	snd_iprintf(buffer, "WC input: Lock %d, Sync %d, Freq %s\n",
5219*4882a593Smuzhiyun 			(status1 & 0x1000000) ? 1 : 0,
5220*4882a593Smuzhiyun 			(status1 & 0x2000000) ? 1 : 0,
5221*4882a593Smuzhiyun 			texts_freq[(status1 >> 16) & 0xF]);
5222*4882a593Smuzhiyun 
5223*4882a593Smuzhiyun 	snd_iprintf(buffer, "TCO input: Lock %d, Sync %d, Freq %s\n",
5224*4882a593Smuzhiyun 			(status1 & 0x4000000) ? 1 : 0,
5225*4882a593Smuzhiyun 			(status1 & 0x8000000) ? 1 : 0,
5226*4882a593Smuzhiyun 			texts_freq[(status1 >> 20) & 0xF]);
5227*4882a593Smuzhiyun 
5228*4882a593Smuzhiyun 	snd_iprintf(buffer, "SYNC IN: Lock %d, Sync %d, Freq %s\n",
5229*4882a593Smuzhiyun 			(status3 & 0x400) ? 1 : 0,
5230*4882a593Smuzhiyun 			(status3 & 0x800) ? 1 : 0,
5231*4882a593Smuzhiyun 			texts_freq[(status2 >> 12) & 0xF]);
5232*4882a593Smuzhiyun 
5233*4882a593Smuzhiyun }
5234*4882a593Smuzhiyun 
5235*4882a593Smuzhiyun #ifdef CONFIG_SND_DEBUG
5236*4882a593Smuzhiyun static void
snd_hdspm_proc_read_debug(struct snd_info_entry * entry,struct snd_info_buffer * buffer)5237*4882a593Smuzhiyun snd_hdspm_proc_read_debug(struct snd_info_entry *entry,
5238*4882a593Smuzhiyun 			  struct snd_info_buffer *buffer)
5239*4882a593Smuzhiyun {
5240*4882a593Smuzhiyun 	struct hdspm *hdspm = entry->private_data;
5241*4882a593Smuzhiyun 
5242*4882a593Smuzhiyun 	int j,i;
5243*4882a593Smuzhiyun 
5244*4882a593Smuzhiyun 	for (i = 0; i < 256 /* 1024*64 */; i += j) {
5245*4882a593Smuzhiyun 		snd_iprintf(buffer, "0x%08X: ", i);
5246*4882a593Smuzhiyun 		for (j = 0; j < 16; j += 4)
5247*4882a593Smuzhiyun 			snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j));
5248*4882a593Smuzhiyun 		snd_iprintf(buffer, "\n");
5249*4882a593Smuzhiyun 	}
5250*4882a593Smuzhiyun }
5251*4882a593Smuzhiyun #endif
5252*4882a593Smuzhiyun 
5253*4882a593Smuzhiyun 
snd_hdspm_proc_ports_in(struct snd_info_entry * entry,struct snd_info_buffer * buffer)5254*4882a593Smuzhiyun static void snd_hdspm_proc_ports_in(struct snd_info_entry *entry,
5255*4882a593Smuzhiyun 			  struct snd_info_buffer *buffer)
5256*4882a593Smuzhiyun {
5257*4882a593Smuzhiyun 	struct hdspm *hdspm = entry->private_data;
5258*4882a593Smuzhiyun 	int i;
5259*4882a593Smuzhiyun 
5260*4882a593Smuzhiyun 	snd_iprintf(buffer, "# generated by hdspm\n");
5261*4882a593Smuzhiyun 
5262*4882a593Smuzhiyun 	for (i = 0; i < hdspm->max_channels_in; i++) {
5263*4882a593Smuzhiyun 		snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_in[i]);
5264*4882a593Smuzhiyun 	}
5265*4882a593Smuzhiyun }
5266*4882a593Smuzhiyun 
snd_hdspm_proc_ports_out(struct snd_info_entry * entry,struct snd_info_buffer * buffer)5267*4882a593Smuzhiyun static void snd_hdspm_proc_ports_out(struct snd_info_entry *entry,
5268*4882a593Smuzhiyun 			  struct snd_info_buffer *buffer)
5269*4882a593Smuzhiyun {
5270*4882a593Smuzhiyun 	struct hdspm *hdspm = entry->private_data;
5271*4882a593Smuzhiyun 	int i;
5272*4882a593Smuzhiyun 
5273*4882a593Smuzhiyun 	snd_iprintf(buffer, "# generated by hdspm\n");
5274*4882a593Smuzhiyun 
5275*4882a593Smuzhiyun 	for (i = 0; i < hdspm->max_channels_out; i++) {
5276*4882a593Smuzhiyun 		snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_out[i]);
5277*4882a593Smuzhiyun 	}
5278*4882a593Smuzhiyun }
5279*4882a593Smuzhiyun 
5280*4882a593Smuzhiyun 
snd_hdspm_proc_init(struct hdspm * hdspm)5281*4882a593Smuzhiyun static void snd_hdspm_proc_init(struct hdspm *hdspm)
5282*4882a593Smuzhiyun {
5283*4882a593Smuzhiyun 	void (*read)(struct snd_info_entry *, struct snd_info_buffer *) = NULL;
5284*4882a593Smuzhiyun 
5285*4882a593Smuzhiyun 	switch (hdspm->io_type) {
5286*4882a593Smuzhiyun 	case AES32:
5287*4882a593Smuzhiyun 		read = snd_hdspm_proc_read_aes32;
5288*4882a593Smuzhiyun 		break;
5289*4882a593Smuzhiyun 	case MADI:
5290*4882a593Smuzhiyun 		read = snd_hdspm_proc_read_madi;
5291*4882a593Smuzhiyun 		break;
5292*4882a593Smuzhiyun 	case MADIface:
5293*4882a593Smuzhiyun 		/* read = snd_hdspm_proc_read_madiface; */
5294*4882a593Smuzhiyun 		break;
5295*4882a593Smuzhiyun 	case RayDAT:
5296*4882a593Smuzhiyun 		read = snd_hdspm_proc_read_raydat;
5297*4882a593Smuzhiyun 		break;
5298*4882a593Smuzhiyun 	case AIO:
5299*4882a593Smuzhiyun 		break;
5300*4882a593Smuzhiyun 	}
5301*4882a593Smuzhiyun 
5302*4882a593Smuzhiyun 	snd_card_ro_proc_new(hdspm->card, "hdspm", hdspm, read);
5303*4882a593Smuzhiyun 	snd_card_ro_proc_new(hdspm->card, "ports.in", hdspm,
5304*4882a593Smuzhiyun 			     snd_hdspm_proc_ports_in);
5305*4882a593Smuzhiyun 	snd_card_ro_proc_new(hdspm->card, "ports.out", hdspm,
5306*4882a593Smuzhiyun 			     snd_hdspm_proc_ports_out);
5307*4882a593Smuzhiyun 
5308*4882a593Smuzhiyun #ifdef CONFIG_SND_DEBUG
5309*4882a593Smuzhiyun 	/* debug file to read all hdspm registers */
5310*4882a593Smuzhiyun 	snd_card_ro_proc_new(hdspm->card, "debug", hdspm,
5311*4882a593Smuzhiyun 			     snd_hdspm_proc_read_debug);
5312*4882a593Smuzhiyun #endif
5313*4882a593Smuzhiyun }
5314*4882a593Smuzhiyun 
5315*4882a593Smuzhiyun /*------------------------------------------------------------
5316*4882a593Smuzhiyun    hdspm intitialize
5317*4882a593Smuzhiyun  ------------------------------------------------------------*/
5318*4882a593Smuzhiyun 
snd_hdspm_set_defaults(struct hdspm * hdspm)5319*4882a593Smuzhiyun static int snd_hdspm_set_defaults(struct hdspm * hdspm)
5320*4882a593Smuzhiyun {
5321*4882a593Smuzhiyun 	/* ASSUMPTION: hdspm->lock is either held, or there is no need to
5322*4882a593Smuzhiyun 	   hold it (e.g. during module initialization).
5323*4882a593Smuzhiyun 	   */
5324*4882a593Smuzhiyun 
5325*4882a593Smuzhiyun 	/* set defaults:       */
5326*4882a593Smuzhiyun 
5327*4882a593Smuzhiyun 	hdspm->settings_register = 0;
5328*4882a593Smuzhiyun 
5329*4882a593Smuzhiyun 	switch (hdspm->io_type) {
5330*4882a593Smuzhiyun 	case MADI:
5331*4882a593Smuzhiyun 	case MADIface:
5332*4882a593Smuzhiyun 		hdspm->control_register =
5333*4882a593Smuzhiyun 			0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000;
5334*4882a593Smuzhiyun 		break;
5335*4882a593Smuzhiyun 
5336*4882a593Smuzhiyun 	case RayDAT:
5337*4882a593Smuzhiyun 	case AIO:
5338*4882a593Smuzhiyun 		hdspm->settings_register = 0x1 + 0x1000;
5339*4882a593Smuzhiyun 		/* Magic values are: LAT_0, LAT_2, Master, freq1, tx64ch, inp_0,
5340*4882a593Smuzhiyun 		 * line_out */
5341*4882a593Smuzhiyun 		hdspm->control_register =
5342*4882a593Smuzhiyun 			0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000;
5343*4882a593Smuzhiyun 		break;
5344*4882a593Smuzhiyun 
5345*4882a593Smuzhiyun 	case AES32:
5346*4882a593Smuzhiyun 		hdspm->control_register =
5347*4882a593Smuzhiyun 			HDSPM_ClockModeMaster |	/* Master Clock Mode on */
5348*4882a593Smuzhiyun 			hdspm_encode_latency(7) | /* latency max=8192samples */
5349*4882a593Smuzhiyun 			HDSPM_SyncRef0 |	/* AES1 is syncclock */
5350*4882a593Smuzhiyun 			HDSPM_LineOut |	/* Analog output in */
5351*4882a593Smuzhiyun 			HDSPM_Professional;  /* Professional mode */
5352*4882a593Smuzhiyun 		break;
5353*4882a593Smuzhiyun 	}
5354*4882a593Smuzhiyun 
5355*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
5356*4882a593Smuzhiyun 
5357*4882a593Smuzhiyun 	if (AES32 == hdspm->io_type) {
5358*4882a593Smuzhiyun 		/* No control2 register for AES32 */
5359*4882a593Smuzhiyun #ifdef SNDRV_BIG_ENDIAN
5360*4882a593Smuzhiyun 		hdspm->control2_register = HDSPM_BIGENDIAN_MODE;
5361*4882a593Smuzhiyun #else
5362*4882a593Smuzhiyun 		hdspm->control2_register = 0;
5363*4882a593Smuzhiyun #endif
5364*4882a593Smuzhiyun 
5365*4882a593Smuzhiyun 		hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register);
5366*4882a593Smuzhiyun 	}
5367*4882a593Smuzhiyun 	hdspm_compute_period_size(hdspm);
5368*4882a593Smuzhiyun 
5369*4882a593Smuzhiyun 	/* silence everything */
5370*4882a593Smuzhiyun 
5371*4882a593Smuzhiyun 	all_in_all_mixer(hdspm, 0 * UNITY_GAIN);
5372*4882a593Smuzhiyun 
5373*4882a593Smuzhiyun 	if (hdspm_is_raydat_or_aio(hdspm))
5374*4882a593Smuzhiyun 		hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
5375*4882a593Smuzhiyun 
5376*4882a593Smuzhiyun 	/* set a default rate so that the channel map is set up. */
5377*4882a593Smuzhiyun 	hdspm_set_rate(hdspm, 48000, 1);
5378*4882a593Smuzhiyun 
5379*4882a593Smuzhiyun 	return 0;
5380*4882a593Smuzhiyun }
5381*4882a593Smuzhiyun 
5382*4882a593Smuzhiyun 
5383*4882a593Smuzhiyun /*------------------------------------------------------------
5384*4882a593Smuzhiyun    interrupt
5385*4882a593Smuzhiyun  ------------------------------------------------------------*/
5386*4882a593Smuzhiyun 
snd_hdspm_interrupt(int irq,void * dev_id)5387*4882a593Smuzhiyun static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
5388*4882a593Smuzhiyun {
5389*4882a593Smuzhiyun 	struct hdspm *hdspm = (struct hdspm *) dev_id;
5390*4882a593Smuzhiyun 	unsigned int status;
5391*4882a593Smuzhiyun 	int i, audio, midi, schedule = 0;
5392*4882a593Smuzhiyun 	/* cycles_t now; */
5393*4882a593Smuzhiyun 
5394*4882a593Smuzhiyun 	status = hdspm_read(hdspm, HDSPM_statusRegister);
5395*4882a593Smuzhiyun 
5396*4882a593Smuzhiyun 	audio = status & HDSPM_audioIRQPending;
5397*4882a593Smuzhiyun 	midi = status & (HDSPM_midi0IRQPending | HDSPM_midi1IRQPending |
5398*4882a593Smuzhiyun 			HDSPM_midi2IRQPending | HDSPM_midi3IRQPending);
5399*4882a593Smuzhiyun 
5400*4882a593Smuzhiyun 	/* now = get_cycles(); */
5401*4882a593Smuzhiyun 	/*
5402*4882a593Smuzhiyun 	 *   LAT_2..LAT_0 period  counter (win)  counter (mac)
5403*4882a593Smuzhiyun 	 *          6       4096   ~256053425     ~514672358
5404*4882a593Smuzhiyun 	 *          5       2048   ~128024983     ~257373821
5405*4882a593Smuzhiyun 	 *          4       1024    ~64023706     ~128718089
5406*4882a593Smuzhiyun 	 *          3        512    ~32005945      ~64385999
5407*4882a593Smuzhiyun 	 *          2        256    ~16003039      ~32260176
5408*4882a593Smuzhiyun 	 *          1        128     ~7998738      ~16194507
5409*4882a593Smuzhiyun 	 *          0         64     ~3998231       ~8191558
5410*4882a593Smuzhiyun 	 */
5411*4882a593Smuzhiyun 	/*
5412*4882a593Smuzhiyun 	  dev_info(hdspm->card->dev, "snd_hdspm_interrupt %llu @ %llx\n",
5413*4882a593Smuzhiyun 	   now-hdspm->last_interrupt, status & 0xFFC0);
5414*4882a593Smuzhiyun 	   hdspm->last_interrupt = now;
5415*4882a593Smuzhiyun 	*/
5416*4882a593Smuzhiyun 
5417*4882a593Smuzhiyun 	if (!audio && !midi)
5418*4882a593Smuzhiyun 		return IRQ_NONE;
5419*4882a593Smuzhiyun 
5420*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_interruptConfirmation, 0);
5421*4882a593Smuzhiyun 	hdspm->irq_count++;
5422*4882a593Smuzhiyun 
5423*4882a593Smuzhiyun 
5424*4882a593Smuzhiyun 	if (audio) {
5425*4882a593Smuzhiyun 		if (hdspm->capture_substream)
5426*4882a593Smuzhiyun 			snd_pcm_period_elapsed(hdspm->capture_substream);
5427*4882a593Smuzhiyun 
5428*4882a593Smuzhiyun 		if (hdspm->playback_substream)
5429*4882a593Smuzhiyun 			snd_pcm_period_elapsed(hdspm->playback_substream);
5430*4882a593Smuzhiyun 	}
5431*4882a593Smuzhiyun 
5432*4882a593Smuzhiyun 	if (midi) {
5433*4882a593Smuzhiyun 		i = 0;
5434*4882a593Smuzhiyun 		while (i < hdspm->midiPorts) {
5435*4882a593Smuzhiyun 			if ((hdspm_read(hdspm,
5436*4882a593Smuzhiyun 				hdspm->midi[i].statusIn) & 0xff) &&
5437*4882a593Smuzhiyun 					(status & hdspm->midi[i].irq)) {
5438*4882a593Smuzhiyun 				/* we disable interrupts for this input until
5439*4882a593Smuzhiyun 				 * processing is done
5440*4882a593Smuzhiyun 				 */
5441*4882a593Smuzhiyun 				hdspm->control_register &= ~hdspm->midi[i].ie;
5442*4882a593Smuzhiyun 				hdspm_write(hdspm, HDSPM_controlRegister,
5443*4882a593Smuzhiyun 						hdspm->control_register);
5444*4882a593Smuzhiyun 				hdspm->midi[i].pending = 1;
5445*4882a593Smuzhiyun 				schedule = 1;
5446*4882a593Smuzhiyun 			}
5447*4882a593Smuzhiyun 
5448*4882a593Smuzhiyun 			i++;
5449*4882a593Smuzhiyun 		}
5450*4882a593Smuzhiyun 
5451*4882a593Smuzhiyun 		if (schedule)
5452*4882a593Smuzhiyun 			queue_work(system_highpri_wq, &hdspm->midi_work);
5453*4882a593Smuzhiyun 	}
5454*4882a593Smuzhiyun 
5455*4882a593Smuzhiyun 	return IRQ_HANDLED;
5456*4882a593Smuzhiyun }
5457*4882a593Smuzhiyun 
5458*4882a593Smuzhiyun /*------------------------------------------------------------
5459*4882a593Smuzhiyun    pcm interface
5460*4882a593Smuzhiyun   ------------------------------------------------------------*/
5461*4882a593Smuzhiyun 
5462*4882a593Smuzhiyun 
snd_hdspm_hw_pointer(struct snd_pcm_substream * substream)5463*4882a593Smuzhiyun static snd_pcm_uframes_t snd_hdspm_hw_pointer(struct snd_pcm_substream
5464*4882a593Smuzhiyun 					      *substream)
5465*4882a593Smuzhiyun {
5466*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
5467*4882a593Smuzhiyun 	return hdspm_hw_pointer(hdspm);
5468*4882a593Smuzhiyun }
5469*4882a593Smuzhiyun 
5470*4882a593Smuzhiyun 
snd_hdspm_reset(struct snd_pcm_substream * substream)5471*4882a593Smuzhiyun static int snd_hdspm_reset(struct snd_pcm_substream *substream)
5472*4882a593Smuzhiyun {
5473*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
5474*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
5475*4882a593Smuzhiyun 	struct snd_pcm_substream *other;
5476*4882a593Smuzhiyun 
5477*4882a593Smuzhiyun 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
5478*4882a593Smuzhiyun 		other = hdspm->capture_substream;
5479*4882a593Smuzhiyun 	else
5480*4882a593Smuzhiyun 		other = hdspm->playback_substream;
5481*4882a593Smuzhiyun 
5482*4882a593Smuzhiyun 	if (hdspm->running)
5483*4882a593Smuzhiyun 		runtime->status->hw_ptr = hdspm_hw_pointer(hdspm);
5484*4882a593Smuzhiyun 	else
5485*4882a593Smuzhiyun 		runtime->status->hw_ptr = 0;
5486*4882a593Smuzhiyun 	if (other) {
5487*4882a593Smuzhiyun 		struct snd_pcm_substream *s;
5488*4882a593Smuzhiyun 		struct snd_pcm_runtime *oruntime = other->runtime;
5489*4882a593Smuzhiyun 		snd_pcm_group_for_each_entry(s, substream) {
5490*4882a593Smuzhiyun 			if (s == other) {
5491*4882a593Smuzhiyun 				oruntime->status->hw_ptr =
5492*4882a593Smuzhiyun 					runtime->status->hw_ptr;
5493*4882a593Smuzhiyun 				break;
5494*4882a593Smuzhiyun 			}
5495*4882a593Smuzhiyun 		}
5496*4882a593Smuzhiyun 	}
5497*4882a593Smuzhiyun 	return 0;
5498*4882a593Smuzhiyun }
5499*4882a593Smuzhiyun 
snd_hdspm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)5500*4882a593Smuzhiyun static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
5501*4882a593Smuzhiyun 			       struct snd_pcm_hw_params *params)
5502*4882a593Smuzhiyun {
5503*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
5504*4882a593Smuzhiyun 	int err;
5505*4882a593Smuzhiyun 	int i;
5506*4882a593Smuzhiyun 	pid_t this_pid;
5507*4882a593Smuzhiyun 	pid_t other_pid;
5508*4882a593Smuzhiyun 
5509*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
5510*4882a593Smuzhiyun 
5511*4882a593Smuzhiyun 	if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
5512*4882a593Smuzhiyun 		this_pid = hdspm->playback_pid;
5513*4882a593Smuzhiyun 		other_pid = hdspm->capture_pid;
5514*4882a593Smuzhiyun 	} else {
5515*4882a593Smuzhiyun 		this_pid = hdspm->capture_pid;
5516*4882a593Smuzhiyun 		other_pid = hdspm->playback_pid;
5517*4882a593Smuzhiyun 	}
5518*4882a593Smuzhiyun 
5519*4882a593Smuzhiyun 	if (other_pid > 0 && this_pid != other_pid) {
5520*4882a593Smuzhiyun 
5521*4882a593Smuzhiyun 		/* The other stream is open, and not by the same
5522*4882a593Smuzhiyun 		   task as this one. Make sure that the parameters
5523*4882a593Smuzhiyun 		   that matter are the same.
5524*4882a593Smuzhiyun 		   */
5525*4882a593Smuzhiyun 
5526*4882a593Smuzhiyun 		if (params_rate(params) != hdspm->system_sample_rate) {
5527*4882a593Smuzhiyun 			spin_unlock_irq(&hdspm->lock);
5528*4882a593Smuzhiyun 			_snd_pcm_hw_param_setempty(params,
5529*4882a593Smuzhiyun 					SNDRV_PCM_HW_PARAM_RATE);
5530*4882a593Smuzhiyun 			return -EBUSY;
5531*4882a593Smuzhiyun 		}
5532*4882a593Smuzhiyun 
5533*4882a593Smuzhiyun 		if (params_period_size(params) != hdspm->period_bytes / 4) {
5534*4882a593Smuzhiyun 			spin_unlock_irq(&hdspm->lock);
5535*4882a593Smuzhiyun 			_snd_pcm_hw_param_setempty(params,
5536*4882a593Smuzhiyun 					SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
5537*4882a593Smuzhiyun 			return -EBUSY;
5538*4882a593Smuzhiyun 		}
5539*4882a593Smuzhiyun 
5540*4882a593Smuzhiyun 	}
5541*4882a593Smuzhiyun 	/* We're fine. */
5542*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
5543*4882a593Smuzhiyun 
5544*4882a593Smuzhiyun 	/* how to make sure that the rate matches an externally-set one ?   */
5545*4882a593Smuzhiyun 
5546*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
5547*4882a593Smuzhiyun 	err = hdspm_set_rate(hdspm, params_rate(params), 0);
5548*4882a593Smuzhiyun 	if (err < 0) {
5549*4882a593Smuzhiyun 		dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err);
5550*4882a593Smuzhiyun 		spin_unlock_irq(&hdspm->lock);
5551*4882a593Smuzhiyun 		_snd_pcm_hw_param_setempty(params,
5552*4882a593Smuzhiyun 				SNDRV_PCM_HW_PARAM_RATE);
5553*4882a593Smuzhiyun 		return err;
5554*4882a593Smuzhiyun 	}
5555*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
5556*4882a593Smuzhiyun 
5557*4882a593Smuzhiyun 	err = hdspm_set_interrupt_interval(hdspm,
5558*4882a593Smuzhiyun 			params_period_size(params));
5559*4882a593Smuzhiyun 	if (err < 0) {
5560*4882a593Smuzhiyun 		dev_info(hdspm->card->dev,
5561*4882a593Smuzhiyun 			 "err on hdspm_set_interrupt_interval: %d\n", err);
5562*4882a593Smuzhiyun 		_snd_pcm_hw_param_setempty(params,
5563*4882a593Smuzhiyun 				SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
5564*4882a593Smuzhiyun 		return err;
5565*4882a593Smuzhiyun 	}
5566*4882a593Smuzhiyun 
5567*4882a593Smuzhiyun 	/* Memory allocation, takashi's method, dont know if we should
5568*4882a593Smuzhiyun 	 * spinlock
5569*4882a593Smuzhiyun 	 */
5570*4882a593Smuzhiyun 	/* malloc all buffer even if not enabled to get sure */
5571*4882a593Smuzhiyun 	/* Update for MADI rev 204: we need to allocate for all channels,
5572*4882a593Smuzhiyun 	 * otherwise it doesn't work at 96kHz */
5573*4882a593Smuzhiyun 
5574*4882a593Smuzhiyun 	err =
5575*4882a593Smuzhiyun 		snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES);
5576*4882a593Smuzhiyun 	if (err < 0) {
5577*4882a593Smuzhiyun 		dev_info(hdspm->card->dev,
5578*4882a593Smuzhiyun 			 "err on snd_pcm_lib_malloc_pages: %d\n", err);
5579*4882a593Smuzhiyun 		return err;
5580*4882a593Smuzhiyun 	}
5581*4882a593Smuzhiyun 
5582*4882a593Smuzhiyun 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
5583*4882a593Smuzhiyun 
5584*4882a593Smuzhiyun 		for (i = 0; i < params_channels(params); ++i) {
5585*4882a593Smuzhiyun 			int c = hdspm->channel_map_out[i];
5586*4882a593Smuzhiyun 
5587*4882a593Smuzhiyun 			if (c < 0)
5588*4882a593Smuzhiyun 				continue;      /* just make sure */
5589*4882a593Smuzhiyun 			hdspm_set_channel_dma_addr(hdspm, substream,
5590*4882a593Smuzhiyun 						   HDSPM_pageAddressBufferOut,
5591*4882a593Smuzhiyun 						   c);
5592*4882a593Smuzhiyun 			snd_hdspm_enable_out(hdspm, c, 1);
5593*4882a593Smuzhiyun 		}
5594*4882a593Smuzhiyun 
5595*4882a593Smuzhiyun 		hdspm->playback_buffer =
5596*4882a593Smuzhiyun 			(unsigned char *) substream->runtime->dma_area;
5597*4882a593Smuzhiyun 		dev_dbg(hdspm->card->dev,
5598*4882a593Smuzhiyun 			"Allocated sample buffer for playback at %p\n",
5599*4882a593Smuzhiyun 				hdspm->playback_buffer);
5600*4882a593Smuzhiyun 	} else {
5601*4882a593Smuzhiyun 		for (i = 0; i < params_channels(params); ++i) {
5602*4882a593Smuzhiyun 			int c = hdspm->channel_map_in[i];
5603*4882a593Smuzhiyun 
5604*4882a593Smuzhiyun 			if (c < 0)
5605*4882a593Smuzhiyun 				continue;
5606*4882a593Smuzhiyun 			hdspm_set_channel_dma_addr(hdspm, substream,
5607*4882a593Smuzhiyun 						   HDSPM_pageAddressBufferIn,
5608*4882a593Smuzhiyun 						   c);
5609*4882a593Smuzhiyun 			snd_hdspm_enable_in(hdspm, c, 1);
5610*4882a593Smuzhiyun 		}
5611*4882a593Smuzhiyun 
5612*4882a593Smuzhiyun 		hdspm->capture_buffer =
5613*4882a593Smuzhiyun 			(unsigned char *) substream->runtime->dma_area;
5614*4882a593Smuzhiyun 		dev_dbg(hdspm->card->dev,
5615*4882a593Smuzhiyun 			"Allocated sample buffer for capture at %p\n",
5616*4882a593Smuzhiyun 				hdspm->capture_buffer);
5617*4882a593Smuzhiyun 	}
5618*4882a593Smuzhiyun 
5619*4882a593Smuzhiyun 	/*
5620*4882a593Smuzhiyun 	   dev_dbg(hdspm->card->dev,
5621*4882a593Smuzhiyun 	   "Allocated sample buffer for %s at 0x%08X\n",
5622*4882a593Smuzhiyun 	   substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
5623*4882a593Smuzhiyun 	   "playback" : "capture",
5624*4882a593Smuzhiyun 	   snd_pcm_sgbuf_get_addr(substream, 0));
5625*4882a593Smuzhiyun 	   */
5626*4882a593Smuzhiyun 	/*
5627*4882a593Smuzhiyun 	   dev_dbg(hdspm->card->dev,
5628*4882a593Smuzhiyun 	   "set_hwparams: %s %d Hz, %d channels, bs = %d\n",
5629*4882a593Smuzhiyun 	   substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
5630*4882a593Smuzhiyun 	   "playback" : "capture",
5631*4882a593Smuzhiyun 	   params_rate(params), params_channels(params),
5632*4882a593Smuzhiyun 	   params_buffer_size(params));
5633*4882a593Smuzhiyun 	   */
5634*4882a593Smuzhiyun 
5635*4882a593Smuzhiyun 
5636*4882a593Smuzhiyun 	/*  For AES cards, the float format bit is the same as the
5637*4882a593Smuzhiyun 	 *  preferred sync reference. Since we don't want to break
5638*4882a593Smuzhiyun 	 *  sync settings, we have to skip the remaining part of this
5639*4882a593Smuzhiyun 	 *  function.
5640*4882a593Smuzhiyun 	 */
5641*4882a593Smuzhiyun 	if (hdspm->io_type == AES32) {
5642*4882a593Smuzhiyun 		return 0;
5643*4882a593Smuzhiyun 	}
5644*4882a593Smuzhiyun 
5645*4882a593Smuzhiyun 
5646*4882a593Smuzhiyun 	/* Switch to native float format if requested */
5647*4882a593Smuzhiyun 	if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) {
5648*4882a593Smuzhiyun 		if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT))
5649*4882a593Smuzhiyun 			dev_info(hdspm->card->dev,
5650*4882a593Smuzhiyun 				 "Switching to native 32bit LE float format.\n");
5651*4882a593Smuzhiyun 
5652*4882a593Smuzhiyun 		hdspm->control_register |= HDSPe_FLOAT_FORMAT;
5653*4882a593Smuzhiyun 	} else if (SNDRV_PCM_FORMAT_S32_LE == params_format(params)) {
5654*4882a593Smuzhiyun 		if (hdspm->control_register & HDSPe_FLOAT_FORMAT)
5655*4882a593Smuzhiyun 			dev_info(hdspm->card->dev,
5656*4882a593Smuzhiyun 				 "Switching to native 32bit LE integer format.\n");
5657*4882a593Smuzhiyun 
5658*4882a593Smuzhiyun 		hdspm->control_register &= ~HDSPe_FLOAT_FORMAT;
5659*4882a593Smuzhiyun 	}
5660*4882a593Smuzhiyun 	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
5661*4882a593Smuzhiyun 
5662*4882a593Smuzhiyun 	return 0;
5663*4882a593Smuzhiyun }
5664*4882a593Smuzhiyun 
snd_hdspm_hw_free(struct snd_pcm_substream * substream)5665*4882a593Smuzhiyun static int snd_hdspm_hw_free(struct snd_pcm_substream *substream)
5666*4882a593Smuzhiyun {
5667*4882a593Smuzhiyun 	int i;
5668*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
5669*4882a593Smuzhiyun 
5670*4882a593Smuzhiyun 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
5671*4882a593Smuzhiyun 		/* Just disable all channels. The saving when disabling a */
5672*4882a593Smuzhiyun 		/* smaller set is not worth the trouble. */
5673*4882a593Smuzhiyun 		for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
5674*4882a593Smuzhiyun 			snd_hdspm_enable_out(hdspm, i, 0);
5675*4882a593Smuzhiyun 
5676*4882a593Smuzhiyun 		hdspm->playback_buffer = NULL;
5677*4882a593Smuzhiyun 	} else {
5678*4882a593Smuzhiyun 		for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
5679*4882a593Smuzhiyun 			snd_hdspm_enable_in(hdspm, i, 0);
5680*4882a593Smuzhiyun 
5681*4882a593Smuzhiyun 		hdspm->capture_buffer = NULL;
5682*4882a593Smuzhiyun 	}
5683*4882a593Smuzhiyun 
5684*4882a593Smuzhiyun 	snd_pcm_lib_free_pages(substream);
5685*4882a593Smuzhiyun 
5686*4882a593Smuzhiyun 	return 0;
5687*4882a593Smuzhiyun }
5688*4882a593Smuzhiyun 
5689*4882a593Smuzhiyun 
snd_hdspm_channel_info(struct snd_pcm_substream * substream,struct snd_pcm_channel_info * info)5690*4882a593Smuzhiyun static int snd_hdspm_channel_info(struct snd_pcm_substream *substream,
5691*4882a593Smuzhiyun 		struct snd_pcm_channel_info *info)
5692*4882a593Smuzhiyun {
5693*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
5694*4882a593Smuzhiyun 	unsigned int channel = info->channel;
5695*4882a593Smuzhiyun 
5696*4882a593Smuzhiyun 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
5697*4882a593Smuzhiyun 		if (snd_BUG_ON(channel >= hdspm->max_channels_out)) {
5698*4882a593Smuzhiyun 			dev_info(hdspm->card->dev,
5699*4882a593Smuzhiyun 				 "snd_hdspm_channel_info: output channel out of range (%d)\n",
5700*4882a593Smuzhiyun 				 channel);
5701*4882a593Smuzhiyun 			return -EINVAL;
5702*4882a593Smuzhiyun 		}
5703*4882a593Smuzhiyun 
5704*4882a593Smuzhiyun 		channel = array_index_nospec(channel, hdspm->max_channels_out);
5705*4882a593Smuzhiyun 		if (hdspm->channel_map_out[channel] < 0) {
5706*4882a593Smuzhiyun 			dev_info(hdspm->card->dev,
5707*4882a593Smuzhiyun 				 "snd_hdspm_channel_info: output channel %d mapped out\n",
5708*4882a593Smuzhiyun 				 channel);
5709*4882a593Smuzhiyun 			return -EINVAL;
5710*4882a593Smuzhiyun 		}
5711*4882a593Smuzhiyun 
5712*4882a593Smuzhiyun 		info->offset = hdspm->channel_map_out[channel] *
5713*4882a593Smuzhiyun 			HDSPM_CHANNEL_BUFFER_BYTES;
5714*4882a593Smuzhiyun 	} else {
5715*4882a593Smuzhiyun 		if (snd_BUG_ON(channel >= hdspm->max_channels_in)) {
5716*4882a593Smuzhiyun 			dev_info(hdspm->card->dev,
5717*4882a593Smuzhiyun 				 "snd_hdspm_channel_info: input channel out of range (%d)\n",
5718*4882a593Smuzhiyun 				 channel);
5719*4882a593Smuzhiyun 			return -EINVAL;
5720*4882a593Smuzhiyun 		}
5721*4882a593Smuzhiyun 
5722*4882a593Smuzhiyun 		channel = array_index_nospec(channel, hdspm->max_channels_in);
5723*4882a593Smuzhiyun 		if (hdspm->channel_map_in[channel] < 0) {
5724*4882a593Smuzhiyun 			dev_info(hdspm->card->dev,
5725*4882a593Smuzhiyun 				 "snd_hdspm_channel_info: input channel %d mapped out\n",
5726*4882a593Smuzhiyun 				 channel);
5727*4882a593Smuzhiyun 			return -EINVAL;
5728*4882a593Smuzhiyun 		}
5729*4882a593Smuzhiyun 
5730*4882a593Smuzhiyun 		info->offset = hdspm->channel_map_in[channel] *
5731*4882a593Smuzhiyun 			HDSPM_CHANNEL_BUFFER_BYTES;
5732*4882a593Smuzhiyun 	}
5733*4882a593Smuzhiyun 
5734*4882a593Smuzhiyun 	info->first = 0;
5735*4882a593Smuzhiyun 	info->step = 32;
5736*4882a593Smuzhiyun 	return 0;
5737*4882a593Smuzhiyun }
5738*4882a593Smuzhiyun 
5739*4882a593Smuzhiyun 
snd_hdspm_ioctl(struct snd_pcm_substream * substream,unsigned int cmd,void * arg)5740*4882a593Smuzhiyun static int snd_hdspm_ioctl(struct snd_pcm_substream *substream,
5741*4882a593Smuzhiyun 		unsigned int cmd, void *arg)
5742*4882a593Smuzhiyun {
5743*4882a593Smuzhiyun 	switch (cmd) {
5744*4882a593Smuzhiyun 	case SNDRV_PCM_IOCTL1_RESET:
5745*4882a593Smuzhiyun 		return snd_hdspm_reset(substream);
5746*4882a593Smuzhiyun 
5747*4882a593Smuzhiyun 	case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
5748*4882a593Smuzhiyun 		{
5749*4882a593Smuzhiyun 			struct snd_pcm_channel_info *info = arg;
5750*4882a593Smuzhiyun 			return snd_hdspm_channel_info(substream, info);
5751*4882a593Smuzhiyun 		}
5752*4882a593Smuzhiyun 	default:
5753*4882a593Smuzhiyun 		break;
5754*4882a593Smuzhiyun 	}
5755*4882a593Smuzhiyun 
5756*4882a593Smuzhiyun 	return snd_pcm_lib_ioctl(substream, cmd, arg);
5757*4882a593Smuzhiyun }
5758*4882a593Smuzhiyun 
snd_hdspm_trigger(struct snd_pcm_substream * substream,int cmd)5759*4882a593Smuzhiyun static int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd)
5760*4882a593Smuzhiyun {
5761*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
5762*4882a593Smuzhiyun 	struct snd_pcm_substream *other;
5763*4882a593Smuzhiyun 	int running;
5764*4882a593Smuzhiyun 
5765*4882a593Smuzhiyun 	spin_lock(&hdspm->lock);
5766*4882a593Smuzhiyun 	running = hdspm->running;
5767*4882a593Smuzhiyun 	switch (cmd) {
5768*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_START:
5769*4882a593Smuzhiyun 		running |= 1 << substream->stream;
5770*4882a593Smuzhiyun 		break;
5771*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_STOP:
5772*4882a593Smuzhiyun 		running &= ~(1 << substream->stream);
5773*4882a593Smuzhiyun 		break;
5774*4882a593Smuzhiyun 	default:
5775*4882a593Smuzhiyun 		snd_BUG();
5776*4882a593Smuzhiyun 		spin_unlock(&hdspm->lock);
5777*4882a593Smuzhiyun 		return -EINVAL;
5778*4882a593Smuzhiyun 	}
5779*4882a593Smuzhiyun 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
5780*4882a593Smuzhiyun 		other = hdspm->capture_substream;
5781*4882a593Smuzhiyun 	else
5782*4882a593Smuzhiyun 		other = hdspm->playback_substream;
5783*4882a593Smuzhiyun 
5784*4882a593Smuzhiyun 	if (other) {
5785*4882a593Smuzhiyun 		struct snd_pcm_substream *s;
5786*4882a593Smuzhiyun 		snd_pcm_group_for_each_entry(s, substream) {
5787*4882a593Smuzhiyun 			if (s == other) {
5788*4882a593Smuzhiyun 				snd_pcm_trigger_done(s, substream);
5789*4882a593Smuzhiyun 				if (cmd == SNDRV_PCM_TRIGGER_START)
5790*4882a593Smuzhiyun 					running |= 1 << s->stream;
5791*4882a593Smuzhiyun 				else
5792*4882a593Smuzhiyun 					running &= ~(1 << s->stream);
5793*4882a593Smuzhiyun 				goto _ok;
5794*4882a593Smuzhiyun 			}
5795*4882a593Smuzhiyun 		}
5796*4882a593Smuzhiyun 		if (cmd == SNDRV_PCM_TRIGGER_START) {
5797*4882a593Smuzhiyun 			if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK))
5798*4882a593Smuzhiyun 					&& substream->stream ==
5799*4882a593Smuzhiyun 					SNDRV_PCM_STREAM_CAPTURE)
5800*4882a593Smuzhiyun 				hdspm_silence_playback(hdspm);
5801*4882a593Smuzhiyun 		} else {
5802*4882a593Smuzhiyun 			if (running &&
5803*4882a593Smuzhiyun 				substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
5804*4882a593Smuzhiyun 				hdspm_silence_playback(hdspm);
5805*4882a593Smuzhiyun 		}
5806*4882a593Smuzhiyun 	} else {
5807*4882a593Smuzhiyun 		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
5808*4882a593Smuzhiyun 			hdspm_silence_playback(hdspm);
5809*4882a593Smuzhiyun 	}
5810*4882a593Smuzhiyun _ok:
5811*4882a593Smuzhiyun 	snd_pcm_trigger_done(substream, substream);
5812*4882a593Smuzhiyun 	if (!hdspm->running && running)
5813*4882a593Smuzhiyun 		hdspm_start_audio(hdspm);
5814*4882a593Smuzhiyun 	else if (hdspm->running && !running)
5815*4882a593Smuzhiyun 		hdspm_stop_audio(hdspm);
5816*4882a593Smuzhiyun 	hdspm->running = running;
5817*4882a593Smuzhiyun 	spin_unlock(&hdspm->lock);
5818*4882a593Smuzhiyun 
5819*4882a593Smuzhiyun 	return 0;
5820*4882a593Smuzhiyun }
5821*4882a593Smuzhiyun 
snd_hdspm_prepare(struct snd_pcm_substream * substream)5822*4882a593Smuzhiyun static int snd_hdspm_prepare(struct snd_pcm_substream *substream)
5823*4882a593Smuzhiyun {
5824*4882a593Smuzhiyun 	return 0;
5825*4882a593Smuzhiyun }
5826*4882a593Smuzhiyun 
5827*4882a593Smuzhiyun static const struct snd_pcm_hardware snd_hdspm_playback_subinfo = {
5828*4882a593Smuzhiyun 	.info = (SNDRV_PCM_INFO_MMAP |
5829*4882a593Smuzhiyun 		 SNDRV_PCM_INFO_MMAP_VALID |
5830*4882a593Smuzhiyun 		 SNDRV_PCM_INFO_NONINTERLEAVED |
5831*4882a593Smuzhiyun 		 SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_DOUBLE),
5832*4882a593Smuzhiyun 	.formats = SNDRV_PCM_FMTBIT_S32_LE,
5833*4882a593Smuzhiyun 	.rates = (SNDRV_PCM_RATE_32000 |
5834*4882a593Smuzhiyun 		  SNDRV_PCM_RATE_44100 |
5835*4882a593Smuzhiyun 		  SNDRV_PCM_RATE_48000 |
5836*4882a593Smuzhiyun 		  SNDRV_PCM_RATE_64000 |
5837*4882a593Smuzhiyun 		  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
5838*4882a593Smuzhiyun 		  SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ),
5839*4882a593Smuzhiyun 	.rate_min = 32000,
5840*4882a593Smuzhiyun 	.rate_max = 192000,
5841*4882a593Smuzhiyun 	.channels_min = 1,
5842*4882a593Smuzhiyun 	.channels_max = HDSPM_MAX_CHANNELS,
5843*4882a593Smuzhiyun 	.buffer_bytes_max =
5844*4882a593Smuzhiyun 	    HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS,
5845*4882a593Smuzhiyun 	.period_bytes_min = (32 * 4),
5846*4882a593Smuzhiyun 	.period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS,
5847*4882a593Smuzhiyun 	.periods_min = 2,
5848*4882a593Smuzhiyun 	.periods_max = 512,
5849*4882a593Smuzhiyun 	.fifo_size = 0
5850*4882a593Smuzhiyun };
5851*4882a593Smuzhiyun 
5852*4882a593Smuzhiyun static const struct snd_pcm_hardware snd_hdspm_capture_subinfo = {
5853*4882a593Smuzhiyun 	.info = (SNDRV_PCM_INFO_MMAP |
5854*4882a593Smuzhiyun 		 SNDRV_PCM_INFO_MMAP_VALID |
5855*4882a593Smuzhiyun 		 SNDRV_PCM_INFO_NONINTERLEAVED |
5856*4882a593Smuzhiyun 		 SNDRV_PCM_INFO_SYNC_START),
5857*4882a593Smuzhiyun 	.formats = SNDRV_PCM_FMTBIT_S32_LE,
5858*4882a593Smuzhiyun 	.rates = (SNDRV_PCM_RATE_32000 |
5859*4882a593Smuzhiyun 		  SNDRV_PCM_RATE_44100 |
5860*4882a593Smuzhiyun 		  SNDRV_PCM_RATE_48000 |
5861*4882a593Smuzhiyun 		  SNDRV_PCM_RATE_64000 |
5862*4882a593Smuzhiyun 		  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
5863*4882a593Smuzhiyun 		  SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000),
5864*4882a593Smuzhiyun 	.rate_min = 32000,
5865*4882a593Smuzhiyun 	.rate_max = 192000,
5866*4882a593Smuzhiyun 	.channels_min = 1,
5867*4882a593Smuzhiyun 	.channels_max = HDSPM_MAX_CHANNELS,
5868*4882a593Smuzhiyun 	.buffer_bytes_max =
5869*4882a593Smuzhiyun 	    HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS,
5870*4882a593Smuzhiyun 	.period_bytes_min = (32 * 4),
5871*4882a593Smuzhiyun 	.period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS,
5872*4882a593Smuzhiyun 	.periods_min = 2,
5873*4882a593Smuzhiyun 	.periods_max = 512,
5874*4882a593Smuzhiyun 	.fifo_size = 0
5875*4882a593Smuzhiyun };
5876*4882a593Smuzhiyun 
snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)5877*4882a593Smuzhiyun static int snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params,
5878*4882a593Smuzhiyun 					   struct snd_pcm_hw_rule *rule)
5879*4882a593Smuzhiyun {
5880*4882a593Smuzhiyun 	struct hdspm *hdspm = rule->private;
5881*4882a593Smuzhiyun 	struct snd_interval *c =
5882*4882a593Smuzhiyun 	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
5883*4882a593Smuzhiyun 	struct snd_interval *r =
5884*4882a593Smuzhiyun 	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
5885*4882a593Smuzhiyun 
5886*4882a593Smuzhiyun 	if (r->min > 96000 && r->max <= 192000) {
5887*4882a593Smuzhiyun 		struct snd_interval t = {
5888*4882a593Smuzhiyun 			.min = hdspm->qs_in_channels,
5889*4882a593Smuzhiyun 			.max = hdspm->qs_in_channels,
5890*4882a593Smuzhiyun 			.integer = 1,
5891*4882a593Smuzhiyun 		};
5892*4882a593Smuzhiyun 		return snd_interval_refine(c, &t);
5893*4882a593Smuzhiyun 	} else if (r->min > 48000 && r->max <= 96000) {
5894*4882a593Smuzhiyun 		struct snd_interval t = {
5895*4882a593Smuzhiyun 			.min = hdspm->ds_in_channels,
5896*4882a593Smuzhiyun 			.max = hdspm->ds_in_channels,
5897*4882a593Smuzhiyun 			.integer = 1,
5898*4882a593Smuzhiyun 		};
5899*4882a593Smuzhiyun 		return snd_interval_refine(c, &t);
5900*4882a593Smuzhiyun 	} else if (r->max < 64000) {
5901*4882a593Smuzhiyun 		struct snd_interval t = {
5902*4882a593Smuzhiyun 			.min = hdspm->ss_in_channels,
5903*4882a593Smuzhiyun 			.max = hdspm->ss_in_channels,
5904*4882a593Smuzhiyun 			.integer = 1,
5905*4882a593Smuzhiyun 		};
5906*4882a593Smuzhiyun 		return snd_interval_refine(c, &t);
5907*4882a593Smuzhiyun 	}
5908*4882a593Smuzhiyun 
5909*4882a593Smuzhiyun 	return 0;
5910*4882a593Smuzhiyun }
5911*4882a593Smuzhiyun 
snd_hdspm_hw_rule_out_channels_rate(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)5912*4882a593Smuzhiyun static int snd_hdspm_hw_rule_out_channels_rate(struct snd_pcm_hw_params *params,
5913*4882a593Smuzhiyun 					   struct snd_pcm_hw_rule * rule)
5914*4882a593Smuzhiyun {
5915*4882a593Smuzhiyun 	struct hdspm *hdspm = rule->private;
5916*4882a593Smuzhiyun 	struct snd_interval *c =
5917*4882a593Smuzhiyun 	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
5918*4882a593Smuzhiyun 	struct snd_interval *r =
5919*4882a593Smuzhiyun 	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
5920*4882a593Smuzhiyun 
5921*4882a593Smuzhiyun 	if (r->min > 96000 && r->max <= 192000) {
5922*4882a593Smuzhiyun 		struct snd_interval t = {
5923*4882a593Smuzhiyun 			.min = hdspm->qs_out_channels,
5924*4882a593Smuzhiyun 			.max = hdspm->qs_out_channels,
5925*4882a593Smuzhiyun 			.integer = 1,
5926*4882a593Smuzhiyun 		};
5927*4882a593Smuzhiyun 		return snd_interval_refine(c, &t);
5928*4882a593Smuzhiyun 	} else if (r->min > 48000 && r->max <= 96000) {
5929*4882a593Smuzhiyun 		struct snd_interval t = {
5930*4882a593Smuzhiyun 			.min = hdspm->ds_out_channels,
5931*4882a593Smuzhiyun 			.max = hdspm->ds_out_channels,
5932*4882a593Smuzhiyun 			.integer = 1,
5933*4882a593Smuzhiyun 		};
5934*4882a593Smuzhiyun 		return snd_interval_refine(c, &t);
5935*4882a593Smuzhiyun 	} else if (r->max < 64000) {
5936*4882a593Smuzhiyun 		struct snd_interval t = {
5937*4882a593Smuzhiyun 			.min = hdspm->ss_out_channels,
5938*4882a593Smuzhiyun 			.max = hdspm->ss_out_channels,
5939*4882a593Smuzhiyun 			.integer = 1,
5940*4882a593Smuzhiyun 		};
5941*4882a593Smuzhiyun 		return snd_interval_refine(c, &t);
5942*4882a593Smuzhiyun 	} else {
5943*4882a593Smuzhiyun 	}
5944*4882a593Smuzhiyun 	return 0;
5945*4882a593Smuzhiyun }
5946*4882a593Smuzhiyun 
snd_hdspm_hw_rule_rate_in_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)5947*4882a593Smuzhiyun static int snd_hdspm_hw_rule_rate_in_channels(struct snd_pcm_hw_params *params,
5948*4882a593Smuzhiyun 					   struct snd_pcm_hw_rule * rule)
5949*4882a593Smuzhiyun {
5950*4882a593Smuzhiyun 	struct hdspm *hdspm = rule->private;
5951*4882a593Smuzhiyun 	struct snd_interval *c =
5952*4882a593Smuzhiyun 	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
5953*4882a593Smuzhiyun 	struct snd_interval *r =
5954*4882a593Smuzhiyun 	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
5955*4882a593Smuzhiyun 
5956*4882a593Smuzhiyun 	if (c->min >= hdspm->ss_in_channels) {
5957*4882a593Smuzhiyun 		struct snd_interval t = {
5958*4882a593Smuzhiyun 			.min = 32000,
5959*4882a593Smuzhiyun 			.max = 48000,
5960*4882a593Smuzhiyun 			.integer = 1,
5961*4882a593Smuzhiyun 		};
5962*4882a593Smuzhiyun 		return snd_interval_refine(r, &t);
5963*4882a593Smuzhiyun 	} else if (c->max <= hdspm->qs_in_channels) {
5964*4882a593Smuzhiyun 		struct snd_interval t = {
5965*4882a593Smuzhiyun 			.min = 128000,
5966*4882a593Smuzhiyun 			.max = 192000,
5967*4882a593Smuzhiyun 			.integer = 1,
5968*4882a593Smuzhiyun 		};
5969*4882a593Smuzhiyun 		return snd_interval_refine(r, &t);
5970*4882a593Smuzhiyun 	} else if (c->max <= hdspm->ds_in_channels) {
5971*4882a593Smuzhiyun 		struct snd_interval t = {
5972*4882a593Smuzhiyun 			.min = 64000,
5973*4882a593Smuzhiyun 			.max = 96000,
5974*4882a593Smuzhiyun 			.integer = 1,
5975*4882a593Smuzhiyun 		};
5976*4882a593Smuzhiyun 		return snd_interval_refine(r, &t);
5977*4882a593Smuzhiyun 	}
5978*4882a593Smuzhiyun 
5979*4882a593Smuzhiyun 	return 0;
5980*4882a593Smuzhiyun }
snd_hdspm_hw_rule_rate_out_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)5981*4882a593Smuzhiyun static int snd_hdspm_hw_rule_rate_out_channels(struct snd_pcm_hw_params *params,
5982*4882a593Smuzhiyun 					   struct snd_pcm_hw_rule *rule)
5983*4882a593Smuzhiyun {
5984*4882a593Smuzhiyun 	struct hdspm *hdspm = rule->private;
5985*4882a593Smuzhiyun 	struct snd_interval *c =
5986*4882a593Smuzhiyun 	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
5987*4882a593Smuzhiyun 	struct snd_interval *r =
5988*4882a593Smuzhiyun 	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
5989*4882a593Smuzhiyun 
5990*4882a593Smuzhiyun 	if (c->min >= hdspm->ss_out_channels) {
5991*4882a593Smuzhiyun 		struct snd_interval t = {
5992*4882a593Smuzhiyun 			.min = 32000,
5993*4882a593Smuzhiyun 			.max = 48000,
5994*4882a593Smuzhiyun 			.integer = 1,
5995*4882a593Smuzhiyun 		};
5996*4882a593Smuzhiyun 		return snd_interval_refine(r, &t);
5997*4882a593Smuzhiyun 	} else if (c->max <= hdspm->qs_out_channels) {
5998*4882a593Smuzhiyun 		struct snd_interval t = {
5999*4882a593Smuzhiyun 			.min = 128000,
6000*4882a593Smuzhiyun 			.max = 192000,
6001*4882a593Smuzhiyun 			.integer = 1,
6002*4882a593Smuzhiyun 		};
6003*4882a593Smuzhiyun 		return snd_interval_refine(r, &t);
6004*4882a593Smuzhiyun 	} else if (c->max <= hdspm->ds_out_channels) {
6005*4882a593Smuzhiyun 		struct snd_interval t = {
6006*4882a593Smuzhiyun 			.min = 64000,
6007*4882a593Smuzhiyun 			.max = 96000,
6008*4882a593Smuzhiyun 			.integer = 1,
6009*4882a593Smuzhiyun 		};
6010*4882a593Smuzhiyun 		return snd_interval_refine(r, &t);
6011*4882a593Smuzhiyun 	}
6012*4882a593Smuzhiyun 
6013*4882a593Smuzhiyun 	return 0;
6014*4882a593Smuzhiyun }
6015*4882a593Smuzhiyun 
snd_hdspm_hw_rule_in_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)6016*4882a593Smuzhiyun static int snd_hdspm_hw_rule_in_channels(struct snd_pcm_hw_params *params,
6017*4882a593Smuzhiyun 				      struct snd_pcm_hw_rule *rule)
6018*4882a593Smuzhiyun {
6019*4882a593Smuzhiyun 	unsigned int list[3];
6020*4882a593Smuzhiyun 	struct hdspm *hdspm = rule->private;
6021*4882a593Smuzhiyun 	struct snd_interval *c = hw_param_interval(params,
6022*4882a593Smuzhiyun 			SNDRV_PCM_HW_PARAM_CHANNELS);
6023*4882a593Smuzhiyun 
6024*4882a593Smuzhiyun 	list[0] = hdspm->qs_in_channels;
6025*4882a593Smuzhiyun 	list[1] = hdspm->ds_in_channels;
6026*4882a593Smuzhiyun 	list[2] = hdspm->ss_in_channels;
6027*4882a593Smuzhiyun 	return snd_interval_list(c, 3, list, 0);
6028*4882a593Smuzhiyun }
6029*4882a593Smuzhiyun 
snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)6030*4882a593Smuzhiyun static int snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params *params,
6031*4882a593Smuzhiyun 				      struct snd_pcm_hw_rule *rule)
6032*4882a593Smuzhiyun {
6033*4882a593Smuzhiyun 	unsigned int list[3];
6034*4882a593Smuzhiyun 	struct hdspm *hdspm = rule->private;
6035*4882a593Smuzhiyun 	struct snd_interval *c = hw_param_interval(params,
6036*4882a593Smuzhiyun 			SNDRV_PCM_HW_PARAM_CHANNELS);
6037*4882a593Smuzhiyun 
6038*4882a593Smuzhiyun 	list[0] = hdspm->qs_out_channels;
6039*4882a593Smuzhiyun 	list[1] = hdspm->ds_out_channels;
6040*4882a593Smuzhiyun 	list[2] = hdspm->ss_out_channels;
6041*4882a593Smuzhiyun 	return snd_interval_list(c, 3, list, 0);
6042*4882a593Smuzhiyun }
6043*4882a593Smuzhiyun 
6044*4882a593Smuzhiyun 
6045*4882a593Smuzhiyun static const unsigned int hdspm_aes32_sample_rates[] = {
6046*4882a593Smuzhiyun 	32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000
6047*4882a593Smuzhiyun };
6048*4882a593Smuzhiyun 
6049*4882a593Smuzhiyun static const struct snd_pcm_hw_constraint_list
6050*4882a593Smuzhiyun hdspm_hw_constraints_aes32_sample_rates = {
6051*4882a593Smuzhiyun 	.count = ARRAY_SIZE(hdspm_aes32_sample_rates),
6052*4882a593Smuzhiyun 	.list = hdspm_aes32_sample_rates,
6053*4882a593Smuzhiyun 	.mask = 0
6054*4882a593Smuzhiyun };
6055*4882a593Smuzhiyun 
snd_hdspm_open(struct snd_pcm_substream * substream)6056*4882a593Smuzhiyun static int snd_hdspm_open(struct snd_pcm_substream *substream)
6057*4882a593Smuzhiyun {
6058*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
6059*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
6060*4882a593Smuzhiyun 	bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
6061*4882a593Smuzhiyun 
6062*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
6063*4882a593Smuzhiyun 	snd_pcm_set_sync(substream);
6064*4882a593Smuzhiyun 	runtime->hw = (playback) ? snd_hdspm_playback_subinfo :
6065*4882a593Smuzhiyun 		snd_hdspm_capture_subinfo;
6066*4882a593Smuzhiyun 
6067*4882a593Smuzhiyun 	if (playback) {
6068*4882a593Smuzhiyun 		if (!hdspm->capture_substream)
6069*4882a593Smuzhiyun 			hdspm_stop_audio(hdspm);
6070*4882a593Smuzhiyun 
6071*4882a593Smuzhiyun 		hdspm->playback_pid = current->pid;
6072*4882a593Smuzhiyun 		hdspm->playback_substream = substream;
6073*4882a593Smuzhiyun 	} else {
6074*4882a593Smuzhiyun 		if (!hdspm->playback_substream)
6075*4882a593Smuzhiyun 			hdspm_stop_audio(hdspm);
6076*4882a593Smuzhiyun 
6077*4882a593Smuzhiyun 		hdspm->capture_pid = current->pid;
6078*4882a593Smuzhiyun 		hdspm->capture_substream = substream;
6079*4882a593Smuzhiyun 	}
6080*4882a593Smuzhiyun 
6081*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
6082*4882a593Smuzhiyun 
6083*4882a593Smuzhiyun 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
6084*4882a593Smuzhiyun 	snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
6085*4882a593Smuzhiyun 
6086*4882a593Smuzhiyun 	switch (hdspm->io_type) {
6087*4882a593Smuzhiyun 	case AIO:
6088*4882a593Smuzhiyun 	case RayDAT:
6089*4882a593Smuzhiyun 		snd_pcm_hw_constraint_minmax(runtime,
6090*4882a593Smuzhiyun 					     SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
6091*4882a593Smuzhiyun 					     32, 4096);
6092*4882a593Smuzhiyun 		/* RayDAT & AIO have a fixed buffer of 16384 samples per channel */
6093*4882a593Smuzhiyun 		snd_pcm_hw_constraint_single(runtime,
6094*4882a593Smuzhiyun 					     SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
6095*4882a593Smuzhiyun 					     16384);
6096*4882a593Smuzhiyun 		break;
6097*4882a593Smuzhiyun 
6098*4882a593Smuzhiyun 	default:
6099*4882a593Smuzhiyun 		snd_pcm_hw_constraint_minmax(runtime,
6100*4882a593Smuzhiyun 					     SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
6101*4882a593Smuzhiyun 					     64, 8192);
6102*4882a593Smuzhiyun 		snd_pcm_hw_constraint_single(runtime,
6103*4882a593Smuzhiyun 					     SNDRV_PCM_HW_PARAM_PERIODS, 2);
6104*4882a593Smuzhiyun 		break;
6105*4882a593Smuzhiyun 	}
6106*4882a593Smuzhiyun 
6107*4882a593Smuzhiyun 	if (AES32 == hdspm->io_type) {
6108*4882a593Smuzhiyun 		runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
6109*4882a593Smuzhiyun 		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
6110*4882a593Smuzhiyun 				&hdspm_hw_constraints_aes32_sample_rates);
6111*4882a593Smuzhiyun 	} else {
6112*4882a593Smuzhiyun 		snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
6113*4882a593Smuzhiyun 				(playback ?
6114*4882a593Smuzhiyun 				 snd_hdspm_hw_rule_rate_out_channels :
6115*4882a593Smuzhiyun 				 snd_hdspm_hw_rule_rate_in_channels), hdspm,
6116*4882a593Smuzhiyun 				SNDRV_PCM_HW_PARAM_CHANNELS, -1);
6117*4882a593Smuzhiyun 	}
6118*4882a593Smuzhiyun 
6119*4882a593Smuzhiyun 	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
6120*4882a593Smuzhiyun 			(playback ? snd_hdspm_hw_rule_out_channels :
6121*4882a593Smuzhiyun 			 snd_hdspm_hw_rule_in_channels), hdspm,
6122*4882a593Smuzhiyun 			SNDRV_PCM_HW_PARAM_CHANNELS, -1);
6123*4882a593Smuzhiyun 
6124*4882a593Smuzhiyun 	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
6125*4882a593Smuzhiyun 			(playback ? snd_hdspm_hw_rule_out_channels_rate :
6126*4882a593Smuzhiyun 			 snd_hdspm_hw_rule_in_channels_rate), hdspm,
6127*4882a593Smuzhiyun 			SNDRV_PCM_HW_PARAM_RATE, -1);
6128*4882a593Smuzhiyun 
6129*4882a593Smuzhiyun 	return 0;
6130*4882a593Smuzhiyun }
6131*4882a593Smuzhiyun 
snd_hdspm_release(struct snd_pcm_substream * substream)6132*4882a593Smuzhiyun static int snd_hdspm_release(struct snd_pcm_substream *substream)
6133*4882a593Smuzhiyun {
6134*4882a593Smuzhiyun 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
6135*4882a593Smuzhiyun 	bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
6136*4882a593Smuzhiyun 
6137*4882a593Smuzhiyun 	spin_lock_irq(&hdspm->lock);
6138*4882a593Smuzhiyun 
6139*4882a593Smuzhiyun 	if (playback) {
6140*4882a593Smuzhiyun 		hdspm->playback_pid = -1;
6141*4882a593Smuzhiyun 		hdspm->playback_substream = NULL;
6142*4882a593Smuzhiyun 	} else {
6143*4882a593Smuzhiyun 		hdspm->capture_pid = -1;
6144*4882a593Smuzhiyun 		hdspm->capture_substream = NULL;
6145*4882a593Smuzhiyun 	}
6146*4882a593Smuzhiyun 
6147*4882a593Smuzhiyun 	spin_unlock_irq(&hdspm->lock);
6148*4882a593Smuzhiyun 
6149*4882a593Smuzhiyun 	return 0;
6150*4882a593Smuzhiyun }
6151*4882a593Smuzhiyun 
snd_hdspm_hwdep_dummy_op(struct snd_hwdep * hw,struct file * file)6152*4882a593Smuzhiyun static int snd_hdspm_hwdep_dummy_op(struct snd_hwdep *hw, struct file *file)
6153*4882a593Smuzhiyun {
6154*4882a593Smuzhiyun 	/* we have nothing to initialize but the call is required */
6155*4882a593Smuzhiyun 	return 0;
6156*4882a593Smuzhiyun }
6157*4882a593Smuzhiyun 
copy_u32_le(void __user * dest,void __iomem * src)6158*4882a593Smuzhiyun static inline int copy_u32_le(void __user *dest, void __iomem *src)
6159*4882a593Smuzhiyun {
6160*4882a593Smuzhiyun 	u32 val = readl(src);
6161*4882a593Smuzhiyun 	return copy_to_user(dest, &val, 4);
6162*4882a593Smuzhiyun }
6163*4882a593Smuzhiyun 
snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw,struct file * file,unsigned int cmd,unsigned long arg)6164*4882a593Smuzhiyun static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
6165*4882a593Smuzhiyun 		unsigned int cmd, unsigned long arg)
6166*4882a593Smuzhiyun {
6167*4882a593Smuzhiyun 	void __user *argp = (void __user *)arg;
6168*4882a593Smuzhiyun 	struct hdspm *hdspm = hw->private_data;
6169*4882a593Smuzhiyun 	struct hdspm_mixer_ioctl mixer;
6170*4882a593Smuzhiyun 	struct hdspm_config info;
6171*4882a593Smuzhiyun 	struct hdspm_status status;
6172*4882a593Smuzhiyun 	struct hdspm_version hdspm_version;
6173*4882a593Smuzhiyun 	struct hdspm_peak_rms *levels;
6174*4882a593Smuzhiyun 	struct hdspm_ltc ltc;
6175*4882a593Smuzhiyun 	unsigned int statusregister;
6176*4882a593Smuzhiyun 	long unsigned int s;
6177*4882a593Smuzhiyun 	int i = 0;
6178*4882a593Smuzhiyun 
6179*4882a593Smuzhiyun 	switch (cmd) {
6180*4882a593Smuzhiyun 
6181*4882a593Smuzhiyun 	case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS:
6182*4882a593Smuzhiyun 		levels = &hdspm->peak_rms;
6183*4882a593Smuzhiyun 		for (i = 0; i < HDSPM_MAX_CHANNELS; i++) {
6184*4882a593Smuzhiyun 			levels->input_peaks[i] =
6185*4882a593Smuzhiyun 				readl(hdspm->iobase +
6186*4882a593Smuzhiyun 						HDSPM_MADI_INPUT_PEAK + i*4);
6187*4882a593Smuzhiyun 			levels->playback_peaks[i] =
6188*4882a593Smuzhiyun 				readl(hdspm->iobase +
6189*4882a593Smuzhiyun 						HDSPM_MADI_PLAYBACK_PEAK + i*4);
6190*4882a593Smuzhiyun 			levels->output_peaks[i] =
6191*4882a593Smuzhiyun 				readl(hdspm->iobase +
6192*4882a593Smuzhiyun 						HDSPM_MADI_OUTPUT_PEAK + i*4);
6193*4882a593Smuzhiyun 
6194*4882a593Smuzhiyun 			levels->input_rms[i] =
6195*4882a593Smuzhiyun 				((uint64_t) readl(hdspm->iobase +
6196*4882a593Smuzhiyun 					HDSPM_MADI_INPUT_RMS_H + i*4) << 32) |
6197*4882a593Smuzhiyun 				(uint64_t) readl(hdspm->iobase +
6198*4882a593Smuzhiyun 						HDSPM_MADI_INPUT_RMS_L + i*4);
6199*4882a593Smuzhiyun 			levels->playback_rms[i] =
6200*4882a593Smuzhiyun 				((uint64_t)readl(hdspm->iobase +
6201*4882a593Smuzhiyun 					HDSPM_MADI_PLAYBACK_RMS_H+i*4) << 32) |
6202*4882a593Smuzhiyun 				(uint64_t)readl(hdspm->iobase +
6203*4882a593Smuzhiyun 					HDSPM_MADI_PLAYBACK_RMS_L + i*4);
6204*4882a593Smuzhiyun 			levels->output_rms[i] =
6205*4882a593Smuzhiyun 				((uint64_t)readl(hdspm->iobase +
6206*4882a593Smuzhiyun 					HDSPM_MADI_OUTPUT_RMS_H + i*4) << 32) |
6207*4882a593Smuzhiyun 				(uint64_t)readl(hdspm->iobase +
6208*4882a593Smuzhiyun 						HDSPM_MADI_OUTPUT_RMS_L + i*4);
6209*4882a593Smuzhiyun 		}
6210*4882a593Smuzhiyun 
6211*4882a593Smuzhiyun 		if (hdspm->system_sample_rate > 96000) {
6212*4882a593Smuzhiyun 			levels->speed = qs;
6213*4882a593Smuzhiyun 		} else if (hdspm->system_sample_rate > 48000) {
6214*4882a593Smuzhiyun 			levels->speed = ds;
6215*4882a593Smuzhiyun 		} else {
6216*4882a593Smuzhiyun 			levels->speed = ss;
6217*4882a593Smuzhiyun 		}
6218*4882a593Smuzhiyun 		levels->status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
6219*4882a593Smuzhiyun 
6220*4882a593Smuzhiyun 		s = copy_to_user(argp, levels, sizeof(*levels));
6221*4882a593Smuzhiyun 		if (0 != s) {
6222*4882a593Smuzhiyun 			/* dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu
6223*4882a593Smuzhiyun 			 [Levels]\n", sizeof(struct hdspm_peak_rms), s);
6224*4882a593Smuzhiyun 			 */
6225*4882a593Smuzhiyun 			return -EFAULT;
6226*4882a593Smuzhiyun 		}
6227*4882a593Smuzhiyun 		break;
6228*4882a593Smuzhiyun 
6229*4882a593Smuzhiyun 	case SNDRV_HDSPM_IOCTL_GET_LTC:
6230*4882a593Smuzhiyun 		ltc.ltc = hdspm_read(hdspm, HDSPM_RD_TCO);
6231*4882a593Smuzhiyun 		i = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
6232*4882a593Smuzhiyun 		if (i & HDSPM_TCO1_LTC_Input_valid) {
6233*4882a593Smuzhiyun 			switch (i & (HDSPM_TCO1_LTC_Format_LSB |
6234*4882a593Smuzhiyun 				HDSPM_TCO1_LTC_Format_MSB)) {
6235*4882a593Smuzhiyun 			case 0:
6236*4882a593Smuzhiyun 				ltc.format = fps_24;
6237*4882a593Smuzhiyun 				break;
6238*4882a593Smuzhiyun 			case HDSPM_TCO1_LTC_Format_LSB:
6239*4882a593Smuzhiyun 				ltc.format = fps_25;
6240*4882a593Smuzhiyun 				break;
6241*4882a593Smuzhiyun 			case HDSPM_TCO1_LTC_Format_MSB:
6242*4882a593Smuzhiyun 				ltc.format = fps_2997;
6243*4882a593Smuzhiyun 				break;
6244*4882a593Smuzhiyun 			default:
6245*4882a593Smuzhiyun 				ltc.format = fps_30;
6246*4882a593Smuzhiyun 				break;
6247*4882a593Smuzhiyun 			}
6248*4882a593Smuzhiyun 			if (i & HDSPM_TCO1_set_drop_frame_flag) {
6249*4882a593Smuzhiyun 				ltc.frame = drop_frame;
6250*4882a593Smuzhiyun 			} else {
6251*4882a593Smuzhiyun 				ltc.frame = full_frame;
6252*4882a593Smuzhiyun 			}
6253*4882a593Smuzhiyun 		} else {
6254*4882a593Smuzhiyun 			ltc.format = format_invalid;
6255*4882a593Smuzhiyun 			ltc.frame = frame_invalid;
6256*4882a593Smuzhiyun 		}
6257*4882a593Smuzhiyun 		if (i & HDSPM_TCO1_Video_Input_Format_NTSC) {
6258*4882a593Smuzhiyun 			ltc.input_format = ntsc;
6259*4882a593Smuzhiyun 		} else if (i & HDSPM_TCO1_Video_Input_Format_PAL) {
6260*4882a593Smuzhiyun 			ltc.input_format = pal;
6261*4882a593Smuzhiyun 		} else {
6262*4882a593Smuzhiyun 			ltc.input_format = no_video;
6263*4882a593Smuzhiyun 		}
6264*4882a593Smuzhiyun 
6265*4882a593Smuzhiyun 		s = copy_to_user(argp, &ltc, sizeof(ltc));
6266*4882a593Smuzhiyun 		if (0 != s) {
6267*4882a593Smuzhiyun 			/*
6268*4882a593Smuzhiyun 			  dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */
6269*4882a593Smuzhiyun 			return -EFAULT;
6270*4882a593Smuzhiyun 		}
6271*4882a593Smuzhiyun 
6272*4882a593Smuzhiyun 		break;
6273*4882a593Smuzhiyun 
6274*4882a593Smuzhiyun 	case SNDRV_HDSPM_IOCTL_GET_CONFIG:
6275*4882a593Smuzhiyun 
6276*4882a593Smuzhiyun 		memset(&info, 0, sizeof(info));
6277*4882a593Smuzhiyun 		spin_lock_irq(&hdspm->lock);
6278*4882a593Smuzhiyun 		info.pref_sync_ref = hdspm_pref_sync_ref(hdspm);
6279*4882a593Smuzhiyun 		info.wordclock_sync_check = hdspm_wc_sync_check(hdspm);
6280*4882a593Smuzhiyun 
6281*4882a593Smuzhiyun 		info.system_sample_rate = hdspm->system_sample_rate;
6282*4882a593Smuzhiyun 		info.autosync_sample_rate =
6283*4882a593Smuzhiyun 			hdspm_external_sample_rate(hdspm);
6284*4882a593Smuzhiyun 		info.system_clock_mode = hdspm_system_clock_mode(hdspm);
6285*4882a593Smuzhiyun 		info.clock_source = hdspm_clock_source(hdspm);
6286*4882a593Smuzhiyun 		info.autosync_ref = hdspm_autosync_ref(hdspm);
6287*4882a593Smuzhiyun 		info.line_out = hdspm_toggle_setting(hdspm, HDSPM_LineOut);
6288*4882a593Smuzhiyun 		info.passthru = 0;
6289*4882a593Smuzhiyun 		spin_unlock_irq(&hdspm->lock);
6290*4882a593Smuzhiyun 		if (copy_to_user(argp, &info, sizeof(info)))
6291*4882a593Smuzhiyun 			return -EFAULT;
6292*4882a593Smuzhiyun 		break;
6293*4882a593Smuzhiyun 
6294*4882a593Smuzhiyun 	case SNDRV_HDSPM_IOCTL_GET_STATUS:
6295*4882a593Smuzhiyun 		memset(&status, 0, sizeof(status));
6296*4882a593Smuzhiyun 
6297*4882a593Smuzhiyun 		status.card_type = hdspm->io_type;
6298*4882a593Smuzhiyun 
6299*4882a593Smuzhiyun 		status.autosync_source = hdspm_autosync_ref(hdspm);
6300*4882a593Smuzhiyun 
6301*4882a593Smuzhiyun 		status.card_clock = 110069313433624ULL;
6302*4882a593Smuzhiyun 		status.master_period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
6303*4882a593Smuzhiyun 
6304*4882a593Smuzhiyun 		switch (hdspm->io_type) {
6305*4882a593Smuzhiyun 		case MADI:
6306*4882a593Smuzhiyun 		case MADIface:
6307*4882a593Smuzhiyun 			status.card_specific.madi.sync_wc =
6308*4882a593Smuzhiyun 				hdspm_wc_sync_check(hdspm);
6309*4882a593Smuzhiyun 			status.card_specific.madi.sync_madi =
6310*4882a593Smuzhiyun 				hdspm_madi_sync_check(hdspm);
6311*4882a593Smuzhiyun 			status.card_specific.madi.sync_tco =
6312*4882a593Smuzhiyun 				hdspm_tco_sync_check(hdspm);
6313*4882a593Smuzhiyun 			status.card_specific.madi.sync_in =
6314*4882a593Smuzhiyun 				hdspm_sync_in_sync_check(hdspm);
6315*4882a593Smuzhiyun 
6316*4882a593Smuzhiyun 			statusregister =
6317*4882a593Smuzhiyun 				hdspm_read(hdspm, HDSPM_statusRegister);
6318*4882a593Smuzhiyun 			status.card_specific.madi.madi_input =
6319*4882a593Smuzhiyun 				(statusregister & HDSPM_AB_int) ? 1 : 0;
6320*4882a593Smuzhiyun 			status.card_specific.madi.channel_format =
6321*4882a593Smuzhiyun 				(statusregister & HDSPM_RX_64ch) ? 1 : 0;
6322*4882a593Smuzhiyun 			/* TODO: Mac driver sets it when f_s>48kHz */
6323*4882a593Smuzhiyun 			status.card_specific.madi.frame_format = 0;
6324*4882a593Smuzhiyun 
6325*4882a593Smuzhiyun 		default:
6326*4882a593Smuzhiyun 			break;
6327*4882a593Smuzhiyun 		}
6328*4882a593Smuzhiyun 
6329*4882a593Smuzhiyun 		if (copy_to_user(argp, &status, sizeof(status)))
6330*4882a593Smuzhiyun 			return -EFAULT;
6331*4882a593Smuzhiyun 
6332*4882a593Smuzhiyun 
6333*4882a593Smuzhiyun 		break;
6334*4882a593Smuzhiyun 
6335*4882a593Smuzhiyun 	case SNDRV_HDSPM_IOCTL_GET_VERSION:
6336*4882a593Smuzhiyun 		memset(&hdspm_version, 0, sizeof(hdspm_version));
6337*4882a593Smuzhiyun 
6338*4882a593Smuzhiyun 		hdspm_version.card_type = hdspm->io_type;
6339*4882a593Smuzhiyun 		strlcpy(hdspm_version.cardname, hdspm->card_name,
6340*4882a593Smuzhiyun 				sizeof(hdspm_version.cardname));
6341*4882a593Smuzhiyun 		hdspm_version.serial = hdspm->serial;
6342*4882a593Smuzhiyun 		hdspm_version.firmware_rev = hdspm->firmware_rev;
6343*4882a593Smuzhiyun 		hdspm_version.addons = 0;
6344*4882a593Smuzhiyun 		if (hdspm->tco)
6345*4882a593Smuzhiyun 			hdspm_version.addons |= HDSPM_ADDON_TCO;
6346*4882a593Smuzhiyun 
6347*4882a593Smuzhiyun 		if (copy_to_user(argp, &hdspm_version,
6348*4882a593Smuzhiyun 					sizeof(hdspm_version)))
6349*4882a593Smuzhiyun 			return -EFAULT;
6350*4882a593Smuzhiyun 		break;
6351*4882a593Smuzhiyun 
6352*4882a593Smuzhiyun 	case SNDRV_HDSPM_IOCTL_GET_MIXER:
6353*4882a593Smuzhiyun 		if (copy_from_user(&mixer, argp, sizeof(mixer)))
6354*4882a593Smuzhiyun 			return -EFAULT;
6355*4882a593Smuzhiyun 		if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer,
6356*4882a593Smuzhiyun 				 sizeof(*mixer.mixer)))
6357*4882a593Smuzhiyun 			return -EFAULT;
6358*4882a593Smuzhiyun 		break;
6359*4882a593Smuzhiyun 
6360*4882a593Smuzhiyun 	default:
6361*4882a593Smuzhiyun 		return -EINVAL;
6362*4882a593Smuzhiyun 	}
6363*4882a593Smuzhiyun 	return 0;
6364*4882a593Smuzhiyun }
6365*4882a593Smuzhiyun 
6366*4882a593Smuzhiyun static const struct snd_pcm_ops snd_hdspm_ops = {
6367*4882a593Smuzhiyun 	.open = snd_hdspm_open,
6368*4882a593Smuzhiyun 	.close = snd_hdspm_release,
6369*4882a593Smuzhiyun 	.ioctl = snd_hdspm_ioctl,
6370*4882a593Smuzhiyun 	.hw_params = snd_hdspm_hw_params,
6371*4882a593Smuzhiyun 	.hw_free = snd_hdspm_hw_free,
6372*4882a593Smuzhiyun 	.prepare = snd_hdspm_prepare,
6373*4882a593Smuzhiyun 	.trigger = snd_hdspm_trigger,
6374*4882a593Smuzhiyun 	.pointer = snd_hdspm_hw_pointer,
6375*4882a593Smuzhiyun };
6376*4882a593Smuzhiyun 
snd_hdspm_create_hwdep(struct snd_card * card,struct hdspm * hdspm)6377*4882a593Smuzhiyun static int snd_hdspm_create_hwdep(struct snd_card *card,
6378*4882a593Smuzhiyun 				  struct hdspm *hdspm)
6379*4882a593Smuzhiyun {
6380*4882a593Smuzhiyun 	struct snd_hwdep *hw;
6381*4882a593Smuzhiyun 	int err;
6382*4882a593Smuzhiyun 
6383*4882a593Smuzhiyun 	err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw);
6384*4882a593Smuzhiyun 	if (err < 0)
6385*4882a593Smuzhiyun 		return err;
6386*4882a593Smuzhiyun 
6387*4882a593Smuzhiyun 	hdspm->hwdep = hw;
6388*4882a593Smuzhiyun 	hw->private_data = hdspm;
6389*4882a593Smuzhiyun 	strcpy(hw->name, "HDSPM hwdep interface");
6390*4882a593Smuzhiyun 
6391*4882a593Smuzhiyun 	hw->ops.open = snd_hdspm_hwdep_dummy_op;
6392*4882a593Smuzhiyun 	hw->ops.ioctl = snd_hdspm_hwdep_ioctl;
6393*4882a593Smuzhiyun 	hw->ops.ioctl_compat = snd_hdspm_hwdep_ioctl;
6394*4882a593Smuzhiyun 	hw->ops.release = snd_hdspm_hwdep_dummy_op;
6395*4882a593Smuzhiyun 
6396*4882a593Smuzhiyun 	return 0;
6397*4882a593Smuzhiyun }
6398*4882a593Smuzhiyun 
6399*4882a593Smuzhiyun 
6400*4882a593Smuzhiyun /*------------------------------------------------------------
6401*4882a593Smuzhiyun    memory interface
6402*4882a593Smuzhiyun  ------------------------------------------------------------*/
snd_hdspm_preallocate_memory(struct hdspm * hdspm)6403*4882a593Smuzhiyun static int snd_hdspm_preallocate_memory(struct hdspm *hdspm)
6404*4882a593Smuzhiyun {
6405*4882a593Smuzhiyun 	struct snd_pcm *pcm;
6406*4882a593Smuzhiyun 	size_t wanted;
6407*4882a593Smuzhiyun 
6408*4882a593Smuzhiyun 	pcm = hdspm->pcm;
6409*4882a593Smuzhiyun 
6410*4882a593Smuzhiyun 	wanted = HDSPM_DMA_AREA_BYTES;
6411*4882a593Smuzhiyun 
6412*4882a593Smuzhiyun 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
6413*4882a593Smuzhiyun 					      &hdspm->pci->dev,
6414*4882a593Smuzhiyun 					      wanted, wanted);
6415*4882a593Smuzhiyun 	dev_dbg(hdspm->card->dev, " Preallocated %zd Bytes\n", wanted);
6416*4882a593Smuzhiyun 	return 0;
6417*4882a593Smuzhiyun }
6418*4882a593Smuzhiyun 
6419*4882a593Smuzhiyun /* Inform the card what DMA addresses to use for the indicated channel. */
6420*4882a593Smuzhiyun /* Each channel got 16 4K pages allocated for DMA transfers. */
hdspm_set_channel_dma_addr(struct hdspm * hdspm,struct snd_pcm_substream * substream,unsigned int reg,int channel)6421*4882a593Smuzhiyun static void hdspm_set_channel_dma_addr(struct hdspm *hdspm,
6422*4882a593Smuzhiyun 				       struct snd_pcm_substream *substream,
6423*4882a593Smuzhiyun 				       unsigned int reg, int channel)
6424*4882a593Smuzhiyun {
6425*4882a593Smuzhiyun 	int i;
6426*4882a593Smuzhiyun 
6427*4882a593Smuzhiyun 	for (i = channel * 16; i < channel * 16 + 16; i++)
6428*4882a593Smuzhiyun 		hdspm_write(hdspm, reg + 4 * i,
6429*4882a593Smuzhiyun 			    snd_pcm_sgbuf_get_addr(substream, 4096 * i));
6430*4882a593Smuzhiyun }
6431*4882a593Smuzhiyun 
6432*4882a593Smuzhiyun 
6433*4882a593Smuzhiyun /* ------------- ALSA Devices ---------------------------- */
snd_hdspm_create_pcm(struct snd_card * card,struct hdspm * hdspm)6434*4882a593Smuzhiyun static int snd_hdspm_create_pcm(struct snd_card *card,
6435*4882a593Smuzhiyun 				struct hdspm *hdspm)
6436*4882a593Smuzhiyun {
6437*4882a593Smuzhiyun 	struct snd_pcm *pcm;
6438*4882a593Smuzhiyun 	int err;
6439*4882a593Smuzhiyun 
6440*4882a593Smuzhiyun 	err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm);
6441*4882a593Smuzhiyun 	if (err < 0)
6442*4882a593Smuzhiyun 		return err;
6443*4882a593Smuzhiyun 
6444*4882a593Smuzhiyun 	hdspm->pcm = pcm;
6445*4882a593Smuzhiyun 	pcm->private_data = hdspm;
6446*4882a593Smuzhiyun 	strcpy(pcm->name, hdspm->card_name);
6447*4882a593Smuzhiyun 
6448*4882a593Smuzhiyun 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
6449*4882a593Smuzhiyun 			&snd_hdspm_ops);
6450*4882a593Smuzhiyun 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
6451*4882a593Smuzhiyun 			&snd_hdspm_ops);
6452*4882a593Smuzhiyun 
6453*4882a593Smuzhiyun 	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
6454*4882a593Smuzhiyun 
6455*4882a593Smuzhiyun 	err = snd_hdspm_preallocate_memory(hdspm);
6456*4882a593Smuzhiyun 	if (err < 0)
6457*4882a593Smuzhiyun 		return err;
6458*4882a593Smuzhiyun 
6459*4882a593Smuzhiyun 	return 0;
6460*4882a593Smuzhiyun }
6461*4882a593Smuzhiyun 
snd_hdspm_initialize_midi_flush(struct hdspm * hdspm)6462*4882a593Smuzhiyun static inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm)
6463*4882a593Smuzhiyun {
6464*4882a593Smuzhiyun 	int i;
6465*4882a593Smuzhiyun 
6466*4882a593Smuzhiyun 	for (i = 0; i < hdspm->midiPorts; i++)
6467*4882a593Smuzhiyun 		snd_hdspm_flush_midi_input(hdspm, i);
6468*4882a593Smuzhiyun }
6469*4882a593Smuzhiyun 
snd_hdspm_create_alsa_devices(struct snd_card * card,struct hdspm * hdspm)6470*4882a593Smuzhiyun static int snd_hdspm_create_alsa_devices(struct snd_card *card,
6471*4882a593Smuzhiyun 					 struct hdspm *hdspm)
6472*4882a593Smuzhiyun {
6473*4882a593Smuzhiyun 	int err, i;
6474*4882a593Smuzhiyun 
6475*4882a593Smuzhiyun 	dev_dbg(card->dev, "Create card...\n");
6476*4882a593Smuzhiyun 	err = snd_hdspm_create_pcm(card, hdspm);
6477*4882a593Smuzhiyun 	if (err < 0)
6478*4882a593Smuzhiyun 		return err;
6479*4882a593Smuzhiyun 
6480*4882a593Smuzhiyun 	i = 0;
6481*4882a593Smuzhiyun 	while (i < hdspm->midiPorts) {
6482*4882a593Smuzhiyun 		err = snd_hdspm_create_midi(card, hdspm, i);
6483*4882a593Smuzhiyun 		if (err < 0) {
6484*4882a593Smuzhiyun 			return err;
6485*4882a593Smuzhiyun 		}
6486*4882a593Smuzhiyun 		i++;
6487*4882a593Smuzhiyun 	}
6488*4882a593Smuzhiyun 
6489*4882a593Smuzhiyun 	err = snd_hdspm_create_controls(card, hdspm);
6490*4882a593Smuzhiyun 	if (err < 0)
6491*4882a593Smuzhiyun 		return err;
6492*4882a593Smuzhiyun 
6493*4882a593Smuzhiyun 	err = snd_hdspm_create_hwdep(card, hdspm);
6494*4882a593Smuzhiyun 	if (err < 0)
6495*4882a593Smuzhiyun 		return err;
6496*4882a593Smuzhiyun 
6497*4882a593Smuzhiyun 	dev_dbg(card->dev, "proc init...\n");
6498*4882a593Smuzhiyun 	snd_hdspm_proc_init(hdspm);
6499*4882a593Smuzhiyun 
6500*4882a593Smuzhiyun 	hdspm->system_sample_rate = -1;
6501*4882a593Smuzhiyun 	hdspm->last_external_sample_rate = -1;
6502*4882a593Smuzhiyun 	hdspm->last_internal_sample_rate = -1;
6503*4882a593Smuzhiyun 	hdspm->playback_pid = -1;
6504*4882a593Smuzhiyun 	hdspm->capture_pid = -1;
6505*4882a593Smuzhiyun 	hdspm->capture_substream = NULL;
6506*4882a593Smuzhiyun 	hdspm->playback_substream = NULL;
6507*4882a593Smuzhiyun 
6508*4882a593Smuzhiyun 	dev_dbg(card->dev, "Set defaults...\n");
6509*4882a593Smuzhiyun 	err = snd_hdspm_set_defaults(hdspm);
6510*4882a593Smuzhiyun 	if (err < 0)
6511*4882a593Smuzhiyun 		return err;
6512*4882a593Smuzhiyun 
6513*4882a593Smuzhiyun 	dev_dbg(card->dev, "Update mixer controls...\n");
6514*4882a593Smuzhiyun 	hdspm_update_simple_mixer_controls(hdspm);
6515*4882a593Smuzhiyun 
6516*4882a593Smuzhiyun 	dev_dbg(card->dev, "Initializing complete?\n");
6517*4882a593Smuzhiyun 
6518*4882a593Smuzhiyun 	err = snd_card_register(card);
6519*4882a593Smuzhiyun 	if (err < 0) {
6520*4882a593Smuzhiyun 		dev_err(card->dev, "error registering card\n");
6521*4882a593Smuzhiyun 		return err;
6522*4882a593Smuzhiyun 	}
6523*4882a593Smuzhiyun 
6524*4882a593Smuzhiyun 	dev_dbg(card->dev, "... yes now\n");
6525*4882a593Smuzhiyun 
6526*4882a593Smuzhiyun 	return 0;
6527*4882a593Smuzhiyun }
6528*4882a593Smuzhiyun 
snd_hdspm_create(struct snd_card * card,struct hdspm * hdspm)6529*4882a593Smuzhiyun static int snd_hdspm_create(struct snd_card *card,
6530*4882a593Smuzhiyun 			    struct hdspm *hdspm)
6531*4882a593Smuzhiyun {
6532*4882a593Smuzhiyun 
6533*4882a593Smuzhiyun 	struct pci_dev *pci = hdspm->pci;
6534*4882a593Smuzhiyun 	int err;
6535*4882a593Smuzhiyun 	unsigned long io_extent;
6536*4882a593Smuzhiyun 
6537*4882a593Smuzhiyun 	hdspm->irq = -1;
6538*4882a593Smuzhiyun 	hdspm->card = card;
6539*4882a593Smuzhiyun 
6540*4882a593Smuzhiyun 	spin_lock_init(&hdspm->lock);
6541*4882a593Smuzhiyun 	INIT_WORK(&hdspm->midi_work, hdspm_midi_work);
6542*4882a593Smuzhiyun 
6543*4882a593Smuzhiyun 	pci_read_config_word(hdspm->pci,
6544*4882a593Smuzhiyun 			PCI_CLASS_REVISION, &hdspm->firmware_rev);
6545*4882a593Smuzhiyun 
6546*4882a593Smuzhiyun 	strcpy(card->mixername, "Xilinx FPGA");
6547*4882a593Smuzhiyun 	strcpy(card->driver, "HDSPM");
6548*4882a593Smuzhiyun 
6549*4882a593Smuzhiyun 	switch (hdspm->firmware_rev) {
6550*4882a593Smuzhiyun 	case HDSPM_RAYDAT_REV:
6551*4882a593Smuzhiyun 		hdspm->io_type = RayDAT;
6552*4882a593Smuzhiyun 		hdspm->card_name = "RME RayDAT";
6553*4882a593Smuzhiyun 		hdspm->midiPorts = 2;
6554*4882a593Smuzhiyun 		break;
6555*4882a593Smuzhiyun 	case HDSPM_AIO_REV:
6556*4882a593Smuzhiyun 		hdspm->io_type = AIO;
6557*4882a593Smuzhiyun 		hdspm->card_name = "RME AIO";
6558*4882a593Smuzhiyun 		hdspm->midiPorts = 1;
6559*4882a593Smuzhiyun 		break;
6560*4882a593Smuzhiyun 	case HDSPM_MADIFACE_REV:
6561*4882a593Smuzhiyun 		hdspm->io_type = MADIface;
6562*4882a593Smuzhiyun 		hdspm->card_name = "RME MADIface";
6563*4882a593Smuzhiyun 		hdspm->midiPorts = 1;
6564*4882a593Smuzhiyun 		break;
6565*4882a593Smuzhiyun 	default:
6566*4882a593Smuzhiyun 		if ((hdspm->firmware_rev == 0xf0) ||
6567*4882a593Smuzhiyun 			((hdspm->firmware_rev >= 0xe6) &&
6568*4882a593Smuzhiyun 					(hdspm->firmware_rev <= 0xea))) {
6569*4882a593Smuzhiyun 			hdspm->io_type = AES32;
6570*4882a593Smuzhiyun 			hdspm->card_name = "RME AES32";
6571*4882a593Smuzhiyun 			hdspm->midiPorts = 2;
6572*4882a593Smuzhiyun 		} else if ((hdspm->firmware_rev == 0xd2) ||
6573*4882a593Smuzhiyun 			((hdspm->firmware_rev >= 0xc8)  &&
6574*4882a593Smuzhiyun 				(hdspm->firmware_rev <= 0xcf))) {
6575*4882a593Smuzhiyun 			hdspm->io_type = MADI;
6576*4882a593Smuzhiyun 			hdspm->card_name = "RME MADI";
6577*4882a593Smuzhiyun 			hdspm->midiPorts = 3;
6578*4882a593Smuzhiyun 		} else {
6579*4882a593Smuzhiyun 			dev_err(card->dev,
6580*4882a593Smuzhiyun 				"unknown firmware revision %x\n",
6581*4882a593Smuzhiyun 				hdspm->firmware_rev);
6582*4882a593Smuzhiyun 			return -ENODEV;
6583*4882a593Smuzhiyun 		}
6584*4882a593Smuzhiyun 	}
6585*4882a593Smuzhiyun 
6586*4882a593Smuzhiyun 	err = pci_enable_device(pci);
6587*4882a593Smuzhiyun 	if (err < 0)
6588*4882a593Smuzhiyun 		return err;
6589*4882a593Smuzhiyun 
6590*4882a593Smuzhiyun 	pci_set_master(hdspm->pci);
6591*4882a593Smuzhiyun 
6592*4882a593Smuzhiyun 	err = pci_request_regions(pci, "hdspm");
6593*4882a593Smuzhiyun 	if (err < 0)
6594*4882a593Smuzhiyun 		return err;
6595*4882a593Smuzhiyun 
6596*4882a593Smuzhiyun 	hdspm->port = pci_resource_start(pci, 0);
6597*4882a593Smuzhiyun 	io_extent = pci_resource_len(pci, 0);
6598*4882a593Smuzhiyun 
6599*4882a593Smuzhiyun 	dev_dbg(card->dev, "grabbed memory region 0x%lx-0x%lx\n",
6600*4882a593Smuzhiyun 			hdspm->port, hdspm->port + io_extent - 1);
6601*4882a593Smuzhiyun 
6602*4882a593Smuzhiyun 	hdspm->iobase = ioremap(hdspm->port, io_extent);
6603*4882a593Smuzhiyun 	if (!hdspm->iobase) {
6604*4882a593Smuzhiyun 		dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n",
6605*4882a593Smuzhiyun 				hdspm->port, hdspm->port + io_extent - 1);
6606*4882a593Smuzhiyun 		return -EBUSY;
6607*4882a593Smuzhiyun 	}
6608*4882a593Smuzhiyun 	dev_dbg(card->dev, "remapped region (0x%lx) 0x%lx-0x%lx\n",
6609*4882a593Smuzhiyun 			(unsigned long)hdspm->iobase, hdspm->port,
6610*4882a593Smuzhiyun 			hdspm->port + io_extent - 1);
6611*4882a593Smuzhiyun 
6612*4882a593Smuzhiyun 	if (request_irq(pci->irq, snd_hdspm_interrupt,
6613*4882a593Smuzhiyun 			IRQF_SHARED, KBUILD_MODNAME, hdspm)) {
6614*4882a593Smuzhiyun 		dev_err(card->dev, "unable to use IRQ %d\n", pci->irq);
6615*4882a593Smuzhiyun 		return -EBUSY;
6616*4882a593Smuzhiyun 	}
6617*4882a593Smuzhiyun 
6618*4882a593Smuzhiyun 	dev_dbg(card->dev, "use IRQ %d\n", pci->irq);
6619*4882a593Smuzhiyun 
6620*4882a593Smuzhiyun 	hdspm->irq = pci->irq;
6621*4882a593Smuzhiyun 	card->sync_irq = hdspm->irq;
6622*4882a593Smuzhiyun 
6623*4882a593Smuzhiyun 	dev_dbg(card->dev, "kmalloc Mixer memory of %zd Bytes\n",
6624*4882a593Smuzhiyun 		sizeof(*hdspm->mixer));
6625*4882a593Smuzhiyun 	hdspm->mixer = kzalloc(sizeof(*hdspm->mixer), GFP_KERNEL);
6626*4882a593Smuzhiyun 	if (!hdspm->mixer)
6627*4882a593Smuzhiyun 		return -ENOMEM;
6628*4882a593Smuzhiyun 
6629*4882a593Smuzhiyun 	hdspm->port_names_in = NULL;
6630*4882a593Smuzhiyun 	hdspm->port_names_out = NULL;
6631*4882a593Smuzhiyun 
6632*4882a593Smuzhiyun 	switch (hdspm->io_type) {
6633*4882a593Smuzhiyun 	case AES32:
6634*4882a593Smuzhiyun 		hdspm->ss_in_channels = hdspm->ss_out_channels = AES32_CHANNELS;
6635*4882a593Smuzhiyun 		hdspm->ds_in_channels = hdspm->ds_out_channels = AES32_CHANNELS;
6636*4882a593Smuzhiyun 		hdspm->qs_in_channels = hdspm->qs_out_channels = AES32_CHANNELS;
6637*4882a593Smuzhiyun 
6638*4882a593Smuzhiyun 		hdspm->channel_map_in_ss = hdspm->channel_map_out_ss =
6639*4882a593Smuzhiyun 			channel_map_aes32;
6640*4882a593Smuzhiyun 		hdspm->channel_map_in_ds = hdspm->channel_map_out_ds =
6641*4882a593Smuzhiyun 			channel_map_aes32;
6642*4882a593Smuzhiyun 		hdspm->channel_map_in_qs = hdspm->channel_map_out_qs =
6643*4882a593Smuzhiyun 			channel_map_aes32;
6644*4882a593Smuzhiyun 		hdspm->port_names_in_ss = hdspm->port_names_out_ss =
6645*4882a593Smuzhiyun 			texts_ports_aes32;
6646*4882a593Smuzhiyun 		hdspm->port_names_in_ds = hdspm->port_names_out_ds =
6647*4882a593Smuzhiyun 			texts_ports_aes32;
6648*4882a593Smuzhiyun 		hdspm->port_names_in_qs = hdspm->port_names_out_qs =
6649*4882a593Smuzhiyun 			texts_ports_aes32;
6650*4882a593Smuzhiyun 
6651*4882a593Smuzhiyun 		hdspm->max_channels_out = hdspm->max_channels_in =
6652*4882a593Smuzhiyun 			AES32_CHANNELS;
6653*4882a593Smuzhiyun 		hdspm->port_names_in = hdspm->port_names_out =
6654*4882a593Smuzhiyun 			texts_ports_aes32;
6655*4882a593Smuzhiyun 		hdspm->channel_map_in = hdspm->channel_map_out =
6656*4882a593Smuzhiyun 			channel_map_aes32;
6657*4882a593Smuzhiyun 
6658*4882a593Smuzhiyun 		break;
6659*4882a593Smuzhiyun 
6660*4882a593Smuzhiyun 	case MADI:
6661*4882a593Smuzhiyun 	case MADIface:
6662*4882a593Smuzhiyun 		hdspm->ss_in_channels = hdspm->ss_out_channels =
6663*4882a593Smuzhiyun 			MADI_SS_CHANNELS;
6664*4882a593Smuzhiyun 		hdspm->ds_in_channels = hdspm->ds_out_channels =
6665*4882a593Smuzhiyun 			MADI_DS_CHANNELS;
6666*4882a593Smuzhiyun 		hdspm->qs_in_channels = hdspm->qs_out_channels =
6667*4882a593Smuzhiyun 			MADI_QS_CHANNELS;
6668*4882a593Smuzhiyun 
6669*4882a593Smuzhiyun 		hdspm->channel_map_in_ss = hdspm->channel_map_out_ss =
6670*4882a593Smuzhiyun 			channel_map_unity_ss;
6671*4882a593Smuzhiyun 		hdspm->channel_map_in_ds = hdspm->channel_map_out_ds =
6672*4882a593Smuzhiyun 			channel_map_unity_ss;
6673*4882a593Smuzhiyun 		hdspm->channel_map_in_qs = hdspm->channel_map_out_qs =
6674*4882a593Smuzhiyun 			channel_map_unity_ss;
6675*4882a593Smuzhiyun 
6676*4882a593Smuzhiyun 		hdspm->port_names_in_ss = hdspm->port_names_out_ss =
6677*4882a593Smuzhiyun 			texts_ports_madi;
6678*4882a593Smuzhiyun 		hdspm->port_names_in_ds = hdspm->port_names_out_ds =
6679*4882a593Smuzhiyun 			texts_ports_madi;
6680*4882a593Smuzhiyun 		hdspm->port_names_in_qs = hdspm->port_names_out_qs =
6681*4882a593Smuzhiyun 			texts_ports_madi;
6682*4882a593Smuzhiyun 		break;
6683*4882a593Smuzhiyun 
6684*4882a593Smuzhiyun 	case AIO:
6685*4882a593Smuzhiyun 		hdspm->ss_in_channels = AIO_IN_SS_CHANNELS;
6686*4882a593Smuzhiyun 		hdspm->ds_in_channels = AIO_IN_DS_CHANNELS;
6687*4882a593Smuzhiyun 		hdspm->qs_in_channels = AIO_IN_QS_CHANNELS;
6688*4882a593Smuzhiyun 		hdspm->ss_out_channels = AIO_OUT_SS_CHANNELS;
6689*4882a593Smuzhiyun 		hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS;
6690*4882a593Smuzhiyun 		hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS;
6691*4882a593Smuzhiyun 
6692*4882a593Smuzhiyun 		if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) {
6693*4882a593Smuzhiyun 			dev_info(card->dev, "AEB input board found\n");
6694*4882a593Smuzhiyun 			hdspm->ss_in_channels += 4;
6695*4882a593Smuzhiyun 			hdspm->ds_in_channels += 4;
6696*4882a593Smuzhiyun 			hdspm->qs_in_channels += 4;
6697*4882a593Smuzhiyun 		}
6698*4882a593Smuzhiyun 
6699*4882a593Smuzhiyun 		if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) {
6700*4882a593Smuzhiyun 			dev_info(card->dev, "AEB output board found\n");
6701*4882a593Smuzhiyun 			hdspm->ss_out_channels += 4;
6702*4882a593Smuzhiyun 			hdspm->ds_out_channels += 4;
6703*4882a593Smuzhiyun 			hdspm->qs_out_channels += 4;
6704*4882a593Smuzhiyun 		}
6705*4882a593Smuzhiyun 
6706*4882a593Smuzhiyun 		hdspm->channel_map_out_ss = channel_map_aio_out_ss;
6707*4882a593Smuzhiyun 		hdspm->channel_map_out_ds = channel_map_aio_out_ds;
6708*4882a593Smuzhiyun 		hdspm->channel_map_out_qs = channel_map_aio_out_qs;
6709*4882a593Smuzhiyun 
6710*4882a593Smuzhiyun 		hdspm->channel_map_in_ss = channel_map_aio_in_ss;
6711*4882a593Smuzhiyun 		hdspm->channel_map_in_ds = channel_map_aio_in_ds;
6712*4882a593Smuzhiyun 		hdspm->channel_map_in_qs = channel_map_aio_in_qs;
6713*4882a593Smuzhiyun 
6714*4882a593Smuzhiyun 		hdspm->port_names_in_ss = texts_ports_aio_in_ss;
6715*4882a593Smuzhiyun 		hdspm->port_names_out_ss = texts_ports_aio_out_ss;
6716*4882a593Smuzhiyun 		hdspm->port_names_in_ds = texts_ports_aio_in_ds;
6717*4882a593Smuzhiyun 		hdspm->port_names_out_ds = texts_ports_aio_out_ds;
6718*4882a593Smuzhiyun 		hdspm->port_names_in_qs = texts_ports_aio_in_qs;
6719*4882a593Smuzhiyun 		hdspm->port_names_out_qs = texts_ports_aio_out_qs;
6720*4882a593Smuzhiyun 
6721*4882a593Smuzhiyun 		break;
6722*4882a593Smuzhiyun 
6723*4882a593Smuzhiyun 	case RayDAT:
6724*4882a593Smuzhiyun 		hdspm->ss_in_channels = hdspm->ss_out_channels =
6725*4882a593Smuzhiyun 			RAYDAT_SS_CHANNELS;
6726*4882a593Smuzhiyun 		hdspm->ds_in_channels = hdspm->ds_out_channels =
6727*4882a593Smuzhiyun 			RAYDAT_DS_CHANNELS;
6728*4882a593Smuzhiyun 		hdspm->qs_in_channels = hdspm->qs_out_channels =
6729*4882a593Smuzhiyun 			RAYDAT_QS_CHANNELS;
6730*4882a593Smuzhiyun 
6731*4882a593Smuzhiyun 		hdspm->max_channels_in = RAYDAT_SS_CHANNELS;
6732*4882a593Smuzhiyun 		hdspm->max_channels_out = RAYDAT_SS_CHANNELS;
6733*4882a593Smuzhiyun 
6734*4882a593Smuzhiyun 		hdspm->channel_map_in_ss = hdspm->channel_map_out_ss =
6735*4882a593Smuzhiyun 			channel_map_raydat_ss;
6736*4882a593Smuzhiyun 		hdspm->channel_map_in_ds = hdspm->channel_map_out_ds =
6737*4882a593Smuzhiyun 			channel_map_raydat_ds;
6738*4882a593Smuzhiyun 		hdspm->channel_map_in_qs = hdspm->channel_map_out_qs =
6739*4882a593Smuzhiyun 			channel_map_raydat_qs;
6740*4882a593Smuzhiyun 		hdspm->channel_map_in = hdspm->channel_map_out =
6741*4882a593Smuzhiyun 			channel_map_raydat_ss;
6742*4882a593Smuzhiyun 
6743*4882a593Smuzhiyun 		hdspm->port_names_in_ss = hdspm->port_names_out_ss =
6744*4882a593Smuzhiyun 			texts_ports_raydat_ss;
6745*4882a593Smuzhiyun 		hdspm->port_names_in_ds = hdspm->port_names_out_ds =
6746*4882a593Smuzhiyun 			texts_ports_raydat_ds;
6747*4882a593Smuzhiyun 		hdspm->port_names_in_qs = hdspm->port_names_out_qs =
6748*4882a593Smuzhiyun 			texts_ports_raydat_qs;
6749*4882a593Smuzhiyun 
6750*4882a593Smuzhiyun 
6751*4882a593Smuzhiyun 		break;
6752*4882a593Smuzhiyun 
6753*4882a593Smuzhiyun 	}
6754*4882a593Smuzhiyun 
6755*4882a593Smuzhiyun 	/* TCO detection */
6756*4882a593Smuzhiyun 	switch (hdspm->io_type) {
6757*4882a593Smuzhiyun 	case AIO:
6758*4882a593Smuzhiyun 	case RayDAT:
6759*4882a593Smuzhiyun 		if (hdspm_read(hdspm, HDSPM_statusRegister2) &
6760*4882a593Smuzhiyun 				HDSPM_s2_tco_detect) {
6761*4882a593Smuzhiyun 			hdspm->midiPorts++;
6762*4882a593Smuzhiyun 			hdspm->tco = kzalloc(sizeof(*hdspm->tco), GFP_KERNEL);
6763*4882a593Smuzhiyun 			if (hdspm->tco)
6764*4882a593Smuzhiyun 				hdspm_tco_write(hdspm);
6765*4882a593Smuzhiyun 
6766*4882a593Smuzhiyun 			dev_info(card->dev, "AIO/RayDAT TCO module found\n");
6767*4882a593Smuzhiyun 		} else {
6768*4882a593Smuzhiyun 			hdspm->tco = NULL;
6769*4882a593Smuzhiyun 		}
6770*4882a593Smuzhiyun 		break;
6771*4882a593Smuzhiyun 
6772*4882a593Smuzhiyun 	case MADI:
6773*4882a593Smuzhiyun 	case AES32:
6774*4882a593Smuzhiyun 		if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) {
6775*4882a593Smuzhiyun 			hdspm->midiPorts++;
6776*4882a593Smuzhiyun 			hdspm->tco = kzalloc(sizeof(*hdspm->tco), GFP_KERNEL);
6777*4882a593Smuzhiyun 			if (hdspm->tco)
6778*4882a593Smuzhiyun 				hdspm_tco_write(hdspm);
6779*4882a593Smuzhiyun 
6780*4882a593Smuzhiyun 			dev_info(card->dev, "MADI/AES TCO module found\n");
6781*4882a593Smuzhiyun 		} else {
6782*4882a593Smuzhiyun 			hdspm->tco = NULL;
6783*4882a593Smuzhiyun 		}
6784*4882a593Smuzhiyun 		break;
6785*4882a593Smuzhiyun 
6786*4882a593Smuzhiyun 	default:
6787*4882a593Smuzhiyun 		hdspm->tco = NULL;
6788*4882a593Smuzhiyun 	}
6789*4882a593Smuzhiyun 
6790*4882a593Smuzhiyun 	/* texts */
6791*4882a593Smuzhiyun 	switch (hdspm->io_type) {
6792*4882a593Smuzhiyun 	case AES32:
6793*4882a593Smuzhiyun 		if (hdspm->tco) {
6794*4882a593Smuzhiyun 			hdspm->texts_autosync = texts_autosync_aes_tco;
6795*4882a593Smuzhiyun 			hdspm->texts_autosync_items =
6796*4882a593Smuzhiyun 				ARRAY_SIZE(texts_autosync_aes_tco);
6797*4882a593Smuzhiyun 		} else {
6798*4882a593Smuzhiyun 			hdspm->texts_autosync = texts_autosync_aes;
6799*4882a593Smuzhiyun 			hdspm->texts_autosync_items =
6800*4882a593Smuzhiyun 				ARRAY_SIZE(texts_autosync_aes);
6801*4882a593Smuzhiyun 		}
6802*4882a593Smuzhiyun 		break;
6803*4882a593Smuzhiyun 
6804*4882a593Smuzhiyun 	case MADI:
6805*4882a593Smuzhiyun 		if (hdspm->tco) {
6806*4882a593Smuzhiyun 			hdspm->texts_autosync = texts_autosync_madi_tco;
6807*4882a593Smuzhiyun 			hdspm->texts_autosync_items = 4;
6808*4882a593Smuzhiyun 		} else {
6809*4882a593Smuzhiyun 			hdspm->texts_autosync = texts_autosync_madi;
6810*4882a593Smuzhiyun 			hdspm->texts_autosync_items = 3;
6811*4882a593Smuzhiyun 		}
6812*4882a593Smuzhiyun 		break;
6813*4882a593Smuzhiyun 
6814*4882a593Smuzhiyun 	case MADIface:
6815*4882a593Smuzhiyun 
6816*4882a593Smuzhiyun 		break;
6817*4882a593Smuzhiyun 
6818*4882a593Smuzhiyun 	case RayDAT:
6819*4882a593Smuzhiyun 		if (hdspm->tco) {
6820*4882a593Smuzhiyun 			hdspm->texts_autosync = texts_autosync_raydat_tco;
6821*4882a593Smuzhiyun 			hdspm->texts_autosync_items = 9;
6822*4882a593Smuzhiyun 		} else {
6823*4882a593Smuzhiyun 			hdspm->texts_autosync = texts_autosync_raydat;
6824*4882a593Smuzhiyun 			hdspm->texts_autosync_items = 8;
6825*4882a593Smuzhiyun 		}
6826*4882a593Smuzhiyun 		break;
6827*4882a593Smuzhiyun 
6828*4882a593Smuzhiyun 	case AIO:
6829*4882a593Smuzhiyun 		if (hdspm->tco) {
6830*4882a593Smuzhiyun 			hdspm->texts_autosync = texts_autosync_aio_tco;
6831*4882a593Smuzhiyun 			hdspm->texts_autosync_items = 6;
6832*4882a593Smuzhiyun 		} else {
6833*4882a593Smuzhiyun 			hdspm->texts_autosync = texts_autosync_aio;
6834*4882a593Smuzhiyun 			hdspm->texts_autosync_items = 5;
6835*4882a593Smuzhiyun 		}
6836*4882a593Smuzhiyun 		break;
6837*4882a593Smuzhiyun 
6838*4882a593Smuzhiyun 	}
6839*4882a593Smuzhiyun 
6840*4882a593Smuzhiyun 	if (hdspm->io_type != MADIface) {
6841*4882a593Smuzhiyun 		hdspm->serial = (hdspm_read(hdspm,
6842*4882a593Smuzhiyun 				HDSPM_midiStatusIn0)>>8) & 0xFFFFFF;
6843*4882a593Smuzhiyun 		/* id contains either a user-provided value or the default
6844*4882a593Smuzhiyun 		 * NULL. If it's the default, we're safe to
6845*4882a593Smuzhiyun 		 * fill card->id with the serial number.
6846*4882a593Smuzhiyun 		 *
6847*4882a593Smuzhiyun 		 * If the serial number is 0xFFFFFF, then we're dealing with
6848*4882a593Smuzhiyun 		 * an old PCI revision that comes without a sane number. In
6849*4882a593Smuzhiyun 		 * this case, we don't set card->id to avoid collisions
6850*4882a593Smuzhiyun 		 * when running with multiple cards.
6851*4882a593Smuzhiyun 		 */
6852*4882a593Smuzhiyun 		if (!id[hdspm->dev] && hdspm->serial != 0xFFFFFF) {
6853*4882a593Smuzhiyun 			snprintf(card->id, sizeof(card->id),
6854*4882a593Smuzhiyun 				 "HDSPMx%06x", hdspm->serial);
6855*4882a593Smuzhiyun 			snd_card_set_id(card, card->id);
6856*4882a593Smuzhiyun 		}
6857*4882a593Smuzhiyun 	}
6858*4882a593Smuzhiyun 
6859*4882a593Smuzhiyun 	dev_dbg(card->dev, "create alsa devices.\n");
6860*4882a593Smuzhiyun 	err = snd_hdspm_create_alsa_devices(card, hdspm);
6861*4882a593Smuzhiyun 	if (err < 0)
6862*4882a593Smuzhiyun 		return err;
6863*4882a593Smuzhiyun 
6864*4882a593Smuzhiyun 	snd_hdspm_initialize_midi_flush(hdspm);
6865*4882a593Smuzhiyun 
6866*4882a593Smuzhiyun 	return 0;
6867*4882a593Smuzhiyun }
6868*4882a593Smuzhiyun 
6869*4882a593Smuzhiyun 
snd_hdspm_free(struct hdspm * hdspm)6870*4882a593Smuzhiyun static int snd_hdspm_free(struct hdspm * hdspm)
6871*4882a593Smuzhiyun {
6872*4882a593Smuzhiyun 
6873*4882a593Smuzhiyun 	if (hdspm->port) {
6874*4882a593Smuzhiyun 		cancel_work_sync(&hdspm->midi_work);
6875*4882a593Smuzhiyun 
6876*4882a593Smuzhiyun 		/* stop th audio, and cancel all interrupts */
6877*4882a593Smuzhiyun 		hdspm->control_register &=
6878*4882a593Smuzhiyun 		    ~(HDSPM_Start | HDSPM_AudioInterruptEnable |
6879*4882a593Smuzhiyun 		      HDSPM_Midi0InterruptEnable | HDSPM_Midi1InterruptEnable |
6880*4882a593Smuzhiyun 		      HDSPM_Midi2InterruptEnable | HDSPM_Midi3InterruptEnable);
6881*4882a593Smuzhiyun 		hdspm_write(hdspm, HDSPM_controlRegister,
6882*4882a593Smuzhiyun 			    hdspm->control_register);
6883*4882a593Smuzhiyun 	}
6884*4882a593Smuzhiyun 
6885*4882a593Smuzhiyun 	if (hdspm->irq >= 0)
6886*4882a593Smuzhiyun 		free_irq(hdspm->irq, (void *) hdspm);
6887*4882a593Smuzhiyun 
6888*4882a593Smuzhiyun 	kfree(hdspm->mixer);
6889*4882a593Smuzhiyun 	iounmap(hdspm->iobase);
6890*4882a593Smuzhiyun 
6891*4882a593Smuzhiyun 	if (hdspm->port)
6892*4882a593Smuzhiyun 		pci_release_regions(hdspm->pci);
6893*4882a593Smuzhiyun 
6894*4882a593Smuzhiyun 	if (pci_is_enabled(hdspm->pci))
6895*4882a593Smuzhiyun 		pci_disable_device(hdspm->pci);
6896*4882a593Smuzhiyun 	return 0;
6897*4882a593Smuzhiyun }
6898*4882a593Smuzhiyun 
6899*4882a593Smuzhiyun 
snd_hdspm_card_free(struct snd_card * card)6900*4882a593Smuzhiyun static void snd_hdspm_card_free(struct snd_card *card)
6901*4882a593Smuzhiyun {
6902*4882a593Smuzhiyun 	struct hdspm *hdspm = card->private_data;
6903*4882a593Smuzhiyun 
6904*4882a593Smuzhiyun 	if (hdspm)
6905*4882a593Smuzhiyun 		snd_hdspm_free(hdspm);
6906*4882a593Smuzhiyun }
6907*4882a593Smuzhiyun 
6908*4882a593Smuzhiyun 
snd_hdspm_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)6909*4882a593Smuzhiyun static int snd_hdspm_probe(struct pci_dev *pci,
6910*4882a593Smuzhiyun 			   const struct pci_device_id *pci_id)
6911*4882a593Smuzhiyun {
6912*4882a593Smuzhiyun 	static int dev;
6913*4882a593Smuzhiyun 	struct hdspm *hdspm;
6914*4882a593Smuzhiyun 	struct snd_card *card;
6915*4882a593Smuzhiyun 	int err;
6916*4882a593Smuzhiyun 
6917*4882a593Smuzhiyun 	if (dev >= SNDRV_CARDS)
6918*4882a593Smuzhiyun 		return -ENODEV;
6919*4882a593Smuzhiyun 	if (!enable[dev]) {
6920*4882a593Smuzhiyun 		dev++;
6921*4882a593Smuzhiyun 		return -ENOENT;
6922*4882a593Smuzhiyun 	}
6923*4882a593Smuzhiyun 
6924*4882a593Smuzhiyun 	err = snd_card_new(&pci->dev, index[dev], id[dev],
6925*4882a593Smuzhiyun 			   THIS_MODULE, sizeof(*hdspm), &card);
6926*4882a593Smuzhiyun 	if (err < 0)
6927*4882a593Smuzhiyun 		return err;
6928*4882a593Smuzhiyun 
6929*4882a593Smuzhiyun 	hdspm = card->private_data;
6930*4882a593Smuzhiyun 	card->private_free = snd_hdspm_card_free;
6931*4882a593Smuzhiyun 	hdspm->dev = dev;
6932*4882a593Smuzhiyun 	hdspm->pci = pci;
6933*4882a593Smuzhiyun 
6934*4882a593Smuzhiyun 	err = snd_hdspm_create(card, hdspm);
6935*4882a593Smuzhiyun 	if (err < 0)
6936*4882a593Smuzhiyun 		goto free_card;
6937*4882a593Smuzhiyun 
6938*4882a593Smuzhiyun 	if (hdspm->io_type != MADIface) {
6939*4882a593Smuzhiyun 		snprintf(card->shortname, sizeof(card->shortname), "%s_%x",
6940*4882a593Smuzhiyun 			hdspm->card_name, hdspm->serial);
6941*4882a593Smuzhiyun 		snprintf(card->longname, sizeof(card->longname),
6942*4882a593Smuzhiyun 			 "%s S/N 0x%x at 0x%lx, irq %d",
6943*4882a593Smuzhiyun 			 hdspm->card_name, hdspm->serial,
6944*4882a593Smuzhiyun 			 hdspm->port, hdspm->irq);
6945*4882a593Smuzhiyun 	} else {
6946*4882a593Smuzhiyun 		snprintf(card->shortname, sizeof(card->shortname), "%s",
6947*4882a593Smuzhiyun 			 hdspm->card_name);
6948*4882a593Smuzhiyun 		snprintf(card->longname, sizeof(card->longname),
6949*4882a593Smuzhiyun 			 "%s at 0x%lx, irq %d",
6950*4882a593Smuzhiyun 			 hdspm->card_name, hdspm->port, hdspm->irq);
6951*4882a593Smuzhiyun 	}
6952*4882a593Smuzhiyun 
6953*4882a593Smuzhiyun 	err = snd_card_register(card);
6954*4882a593Smuzhiyun 	if (err < 0)
6955*4882a593Smuzhiyun 		goto free_card;
6956*4882a593Smuzhiyun 
6957*4882a593Smuzhiyun 	pci_set_drvdata(pci, card);
6958*4882a593Smuzhiyun 
6959*4882a593Smuzhiyun 	dev++;
6960*4882a593Smuzhiyun 	return 0;
6961*4882a593Smuzhiyun 
6962*4882a593Smuzhiyun free_card:
6963*4882a593Smuzhiyun 	snd_card_free(card);
6964*4882a593Smuzhiyun 	return err;
6965*4882a593Smuzhiyun }
6966*4882a593Smuzhiyun 
snd_hdspm_remove(struct pci_dev * pci)6967*4882a593Smuzhiyun static void snd_hdspm_remove(struct pci_dev *pci)
6968*4882a593Smuzhiyun {
6969*4882a593Smuzhiyun 	snd_card_free(pci_get_drvdata(pci));
6970*4882a593Smuzhiyun }
6971*4882a593Smuzhiyun 
6972*4882a593Smuzhiyun static struct pci_driver hdspm_driver = {
6973*4882a593Smuzhiyun 	.name = KBUILD_MODNAME,
6974*4882a593Smuzhiyun 	.id_table = snd_hdspm_ids,
6975*4882a593Smuzhiyun 	.probe = snd_hdspm_probe,
6976*4882a593Smuzhiyun 	.remove = snd_hdspm_remove,
6977*4882a593Smuzhiyun };
6978*4882a593Smuzhiyun 
6979*4882a593Smuzhiyun module_pci_driver(hdspm_driver);
6980