11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ef5fa1a4STakashi Iwai /*
3763f356cSTakashi Iwai * ALSA driver for RME Hammerfall DSP MADI audio interface(s)
4763f356cSTakashi Iwai *
5763f356cSTakashi Iwai * Copyright (c) 2003 Winfried Ritsch (IEM)
6763f356cSTakashi Iwai * code based on hdsp.c Paul Davis
7763f356cSTakashi Iwai * Marcus Andersson
8763f356cSTakashi Iwai * Thomas Charbonnel
93cee5a60SRemy Bruno * Modified 2006-06-01 for AES32 support by Remy Bruno
103cee5a60SRemy Bruno * <remy.bruno@trinnov.com>
11763f356cSTakashi Iwai *
120dca1793SAdrian Knoth * Modified 2009-04-13 for proper metering by Florian Faber
130dca1793SAdrian Knoth * <faber@faberman.de>
140dca1793SAdrian Knoth *
150dca1793SAdrian Knoth * Modified 2009-04-14 for native float support by Florian Faber
160dca1793SAdrian Knoth * <faber@faberman.de>
170dca1793SAdrian Knoth *
180dca1793SAdrian Knoth * Modified 2009-04-26 fixed bug in rms metering by Florian Faber
190dca1793SAdrian Knoth * <faber@faberman.de>
200dca1793SAdrian Knoth *
210dca1793SAdrian Knoth * Modified 2009-04-30 added hw serial number support by Florian Faber
220dca1793SAdrian Knoth *
230dca1793SAdrian Knoth * Modified 2011-01-14 added S/PDIF input on RayDATs by Adrian Knoth
240dca1793SAdrian Knoth *
250dca1793SAdrian Knoth * Modified 2011-01-25 variable period sizes on RayDAT/AIO by Adrian Knoth
260dca1793SAdrian Knoth *
27e4e07c6cSPhilippe Bekaert * Modified 2019-05-23 fix AIO single speed ADAT capture and playback
28e4e07c6cSPhilippe Bekaert * by Philippe.Bekaert@uhasselt.be
29763f356cSTakashi Iwai */
3069358fcaSMartin Dausel
3169358fcaSMartin Dausel /* ************* Register Documentation *******************************************************
3269358fcaSMartin Dausel *
3369358fcaSMartin Dausel * Work in progress! Documentation is based on the code in this file.
3469358fcaSMartin Dausel *
3569358fcaSMartin Dausel * --------- HDSPM_controlRegister ---------
3669358fcaSMartin Dausel * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
3769358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||:
3869358fcaSMartin Dausel * :3322.2222:2222.1111:1111.1100:0000.0000: bit number
3969358fcaSMartin Dausel * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
4069358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||:
4169358fcaSMartin Dausel * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
4269358fcaSMartin Dausel * : . : . : . : x . : HDSPM_AudioInterruptEnable \_ setting both bits
4369358fcaSMartin Dausel * : . : . : . : . x: HDSPM_Start / enables audio IO
4469358fcaSMartin Dausel * : . : . : . : x. : HDSPM_ClockModeMaster - 1: Master, 0: Slave
4569358fcaSMartin Dausel * : . : . : . : .210 : HDSPM_LatencyMask - 3 Bit value for latency
4669358fcaSMartin Dausel * : . : . : . : . : 0:64, 1:128, 2:256, 3:512,
4769358fcaSMartin Dausel * : . : . : . : . : 4:1024, 5:2048, 6:4096, 7:8192
4869358fcaSMartin Dausel * :x . : . : . x:xx . : HDSPM_FrequencyMask
4969358fcaSMartin Dausel * : . : . : . :10 . : HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=??
5069358fcaSMartin Dausel * : . : . : . x: . : <MADI> HDSPM_DoubleSpeed
5169358fcaSMartin Dausel * :x . : . : . : . : <MADI> HDSPM_QuadSpeed
5269358fcaSMartin Dausel * : . 3 : . 10: 2 . : . : HDSPM_SyncRefMask :
5369358fcaSMartin Dausel * : . : . x: . : . : HDSPM_SyncRef0
5469358fcaSMartin Dausel * : . : . x : . : . : HDSPM_SyncRef1
5569358fcaSMartin Dausel * : . : . : x . : . : <AES32> HDSPM_SyncRef2
5669358fcaSMartin Dausel * : . x : . : . : . : <AES32> HDSPM_SyncRef3
5769358fcaSMartin Dausel * : . : . 10: . : . : <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn
5869358fcaSMartin Dausel * : . 3 : . 10: 2 . : . : <AES32> 0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn?
5969358fcaSMartin Dausel * : . x : . : . : . : <MADIe> HDSPe_FLOAT_FORMAT
6069358fcaSMartin Dausel * : . : . : x . : . : <MADI> HDSPM_InputSelect0 : 0=optical,1=coax
6169358fcaSMartin Dausel * : . : . :x . : . : <MADI> HDSPM_InputSelect1
6269358fcaSMartin Dausel * : . : .x : . : . : <MADI> HDSPM_clr_tms
6369358fcaSMartin Dausel * : . : . : . x : . : <MADI> HDSPM_TX_64ch
6469358fcaSMartin Dausel * : . : . : . x : . : <AES32> HDSPM_Emphasis
6569358fcaSMartin Dausel * : . : . : .x : . : <MADI> HDSPM_AutoInp
6669358fcaSMartin Dausel * : . : . x : . : . : <MADI> HDSPM_SMUX
6769358fcaSMartin Dausel * : . : .x : . : . : <MADI> HDSPM_clr_tms
6869358fcaSMartin Dausel * : . : x. : . : . : <MADI> HDSPM_taxi_reset
6969358fcaSMartin Dausel * : . x: . : . : . : <MADI> HDSPM_LineOut
7069358fcaSMartin Dausel * : . x: . : . : . : <AES32> ??????????????????
7169358fcaSMartin Dausel * : . : x. : . : . : <AES32> HDSPM_WCK48
7269358fcaSMartin Dausel * : . : . : .x : . : <AES32> HDSPM_Dolby
7369358fcaSMartin Dausel * : . : x . : . : . : HDSPM_Midi0InterruptEnable
7469358fcaSMartin Dausel * : . :x . : . : . : HDSPM_Midi1InterruptEnable
7569358fcaSMartin Dausel * : . : x . : . : . : HDSPM_Midi2InterruptEnable
7669358fcaSMartin Dausel * : . x : . : . : . : <MADI> HDSPM_Midi3InterruptEnable
7769358fcaSMartin Dausel * : . x : . : . : . : <AES32> HDSPM_DS_DoubleWire
7869358fcaSMartin Dausel * : .x : . : . : . : <AES32> HDSPM_QS_DoubleWire
7969358fcaSMartin Dausel * : x. : . : . : . : <AES32> HDSPM_QS_QuadWire
8069358fcaSMartin Dausel * : . : . : . x : . : <AES32> HDSPM_Professional
8169358fcaSMartin Dausel * : x . : . : . : . : HDSPM_wclk_sel
8269358fcaSMartin Dausel * : . : . : . : . :
8369358fcaSMartin Dausel * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
8469358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||:
8569358fcaSMartin Dausel * :3322.2222:2222.1111:1111.1100:0000.0000: bit number
8669358fcaSMartin Dausel * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
8769358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||:
8869358fcaSMartin Dausel * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit
8969358fcaSMartin Dausel *
9069358fcaSMartin Dausel *
9169358fcaSMartin Dausel *
9269358fcaSMartin Dausel * AIO / RayDAT only
9369358fcaSMartin Dausel *
9469358fcaSMartin Dausel * ------------ HDSPM_WR_SETTINGS ----------
9569358fcaSMartin Dausel * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
9669358fcaSMartin Dausel * :1098.7654:3210.9876:5432.1098:7654.3210:
9769358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||: bit number
9869358fcaSMartin Dausel * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
9969358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||:
10069358fcaSMartin Dausel * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
10169358fcaSMartin Dausel * : . : . : . : . x: HDSPM_c0Master 1: Master, 0: Slave
10269358fcaSMartin Dausel * : . : . : . : . x : HDSPM_c0_SyncRef0
10369358fcaSMartin Dausel * : . : . : . : . x : HDSPM_c0_SyncRef1
10469358fcaSMartin Dausel * : . : . : . : .x : HDSPM_c0_SyncRef2
10569358fcaSMartin Dausel * : . : . : . : x. : HDSPM_c0_SyncRef3
10669358fcaSMartin Dausel * : . : . : . : 3.210 : HDSPM_c0_SyncRefMask:
10769358fcaSMartin Dausel * : . : . : . : . : RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4,
10869358fcaSMartin Dausel * : . : . : . : . : 9:TCO, 10:SyncIn
10969358fcaSMartin Dausel * : . : . : . : . : AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT,
11069358fcaSMartin Dausel * : . : . : . : . : 9:TCO, 10:SyncIn
11169358fcaSMartin Dausel * : . : . : . : . :
11269358fcaSMartin Dausel * : . : . : . : . :
11369358fcaSMartin Dausel * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
11469358fcaSMartin Dausel * :1098.7654:3210.9876:5432.1098:7654.3210:
11569358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||: bit number
11669358fcaSMartin Dausel * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
11769358fcaSMartin Dausel * :||||.||||:||||.||||:||||.||||:||||.||||:
11869358fcaSMartin Dausel * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
11969358fcaSMartin Dausel *
12069358fcaSMartin Dausel */
121763f356cSTakashi Iwai #include <linux/init.h>
122763f356cSTakashi Iwai #include <linux/delay.h>
123763f356cSTakashi Iwai #include <linux/interrupt.h>
12465a77217SPaul Gortmaker #include <linux/module.h>
125763f356cSTakashi Iwai #include <linux/slab.h>
126763f356cSTakashi Iwai #include <linux/pci.h>
1273f7440a6STakashi Iwai #include <linux/math64.h>
1286cbbfe1cSTakashi Iwai #include <linux/io.h>
12910513142STakashi Iwai #include <linux/nospec.h>
130763f356cSTakashi Iwai
131763f356cSTakashi Iwai #include <sound/core.h>
132763f356cSTakashi Iwai #include <sound/control.h>
133763f356cSTakashi Iwai #include <sound/pcm.h>
1340dca1793SAdrian Knoth #include <sound/pcm_params.h>
135763f356cSTakashi Iwai #include <sound/info.h>
136763f356cSTakashi Iwai #include <sound/asoundef.h>
137763f356cSTakashi Iwai #include <sound/rawmidi.h>
138763f356cSTakashi Iwai #include <sound/hwdep.h>
139763f356cSTakashi Iwai #include <sound/initval.h>
140763f356cSTakashi Iwai
141763f356cSTakashi Iwai #include <sound/hdspm.h>
142763f356cSTakashi Iwai
143763f356cSTakashi Iwai static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
144763f356cSTakashi Iwai static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
145a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
146763f356cSTakashi Iwai
147763f356cSTakashi Iwai module_param_array(index, int, NULL, 0444);
148763f356cSTakashi Iwai MODULE_PARM_DESC(index, "Index value for RME HDSPM interface.");
149763f356cSTakashi Iwai
150763f356cSTakashi Iwai module_param_array(id, charp, NULL, 0444);
151763f356cSTakashi Iwai MODULE_PARM_DESC(id, "ID string for RME HDSPM interface.");
152763f356cSTakashi Iwai
153763f356cSTakashi Iwai module_param_array(enable, bool, NULL, 0444);
154763f356cSTakashi Iwai MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards.");
155763f356cSTakashi Iwai
156763f356cSTakashi Iwai
157763f356cSTakashi Iwai MODULE_AUTHOR
1580dca1793SAdrian Knoth (
1590dca1793SAdrian Knoth "Winfried Ritsch <ritsch_AT_iem.at>, "
160ef5fa1a4STakashi Iwai "Paul Davis <paul@linuxaudiosystems.com>, "
1613cee5a60SRemy Bruno "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, "
1620dca1793SAdrian Knoth "Remy Bruno <remy.bruno@trinnov.com>, "
1630dca1793SAdrian Knoth "Florian Faber <faberman@linuxproaudio.org>, "
1640dca1793SAdrian Knoth "Adrian Knoth <adi@drcomp.erfurt.thur.de>"
1650dca1793SAdrian Knoth );
166763f356cSTakashi Iwai MODULE_DESCRIPTION("RME HDSPM");
167763f356cSTakashi Iwai MODULE_LICENSE("GPL");
168763f356cSTakashi Iwai
169763f356cSTakashi Iwai /* --- Write registers. ---
170763f356cSTakashi Iwai These are defined as byte-offsets from the iobase value. */
171763f356cSTakashi Iwai
1720dca1793SAdrian Knoth #define HDSPM_WR_SETTINGS 0
1730dca1793SAdrian Knoth #define HDSPM_outputBufferAddress 32
1740dca1793SAdrian Knoth #define HDSPM_inputBufferAddress 36
175763f356cSTakashi Iwai #define HDSPM_controlRegister 64
176763f356cSTakashi Iwai #define HDSPM_interruptConfirmation 96
177763f356cSTakashi Iwai #define HDSPM_control2Reg 256 /* not in specs ???????? */
17869358fcaSMartin Dausel #define HDSPM_freqReg 256 /* for setting arbitrary clock values (DDS feature) */
179763f356cSTakashi Iwai #define HDSPM_midiDataOut0 352 /* just believe in old code */
180763f356cSTakashi Iwai #define HDSPM_midiDataOut1 356
181ffb2c3c0SRemy Bruno #define HDSPM_eeprom_wr 384 /* for AES32 */
182763f356cSTakashi Iwai
183763f356cSTakashi Iwai /* DMA enable for 64 channels, only Bit 0 is relevant */
184763f356cSTakashi Iwai #define HDSPM_outputEnableBase 512 /* 512-767 input DMA */
185763f356cSTakashi Iwai #define HDSPM_inputEnableBase 768 /* 768-1023 output DMA */
186763f356cSTakashi Iwai
187763f356cSTakashi Iwai /* 16 page addresses for each of the 64 channels DMA buffer in and out
188763f356cSTakashi Iwai (each 64k=16*4k) Buffer must be 4k aligned (which is default i386 ????) */
189763f356cSTakashi Iwai #define HDSPM_pageAddressBufferOut 8192
190763f356cSTakashi Iwai #define HDSPM_pageAddressBufferIn (HDSPM_pageAddressBufferOut+64*16*4)
191763f356cSTakashi Iwai
192763f356cSTakashi Iwai #define HDSPM_MADI_mixerBase 32768 /* 32768-65535 for 2x64x64 Fader */
193763f356cSTakashi Iwai
194763f356cSTakashi Iwai #define HDSPM_MATRIX_MIXER_SIZE 8192 /* = 2*64*64 * 4 Byte => 32kB */
195763f356cSTakashi Iwai
196763f356cSTakashi Iwai /* --- Read registers. ---
197763f356cSTakashi Iwai These are defined as byte-offsets from the iobase value */
198763f356cSTakashi Iwai #define HDSPM_statusRegister 0
1993cee5a60SRemy Bruno /*#define HDSPM_statusRegister2 96 */
2003cee5a60SRemy Bruno /* after RME Windows driver sources, status2 is 4-byte word # 48 = word at
2013cee5a60SRemy Bruno * offset 192, for AES32 *and* MADI
2023cee5a60SRemy Bruno * => need to check that offset 192 is working on MADI */
2033cee5a60SRemy Bruno #define HDSPM_statusRegister2 192
2043cee5a60SRemy Bruno #define HDSPM_timecodeRegister 128
205763f356cSTakashi Iwai
2060dca1793SAdrian Knoth /* AIO, RayDAT */
2070dca1793SAdrian Knoth #define HDSPM_RD_STATUS_0 0
2080dca1793SAdrian Knoth #define HDSPM_RD_STATUS_1 64
2090dca1793SAdrian Knoth #define HDSPM_RD_STATUS_2 128
2100dca1793SAdrian Knoth #define HDSPM_RD_STATUS_3 192
2110dca1793SAdrian Knoth
2120dca1793SAdrian Knoth #define HDSPM_RD_TCO 256
2130dca1793SAdrian Knoth #define HDSPM_RD_PLL_FREQ 512
2140dca1793SAdrian Knoth #define HDSPM_WR_TCO 128
2150dca1793SAdrian Knoth
2160dca1793SAdrian Knoth #define HDSPM_TCO1_TCO_lock 0x00000001
2170dca1793SAdrian Knoth #define HDSPM_TCO1_WCK_Input_Range_LSB 0x00000002
2180dca1793SAdrian Knoth #define HDSPM_TCO1_WCK_Input_Range_MSB 0x00000004
2190dca1793SAdrian Knoth #define HDSPM_TCO1_LTC_Input_valid 0x00000008
2200dca1793SAdrian Knoth #define HDSPM_TCO1_WCK_Input_valid 0x00000010
2210dca1793SAdrian Knoth #define HDSPM_TCO1_Video_Input_Format_NTSC 0x00000020
2220dca1793SAdrian Knoth #define HDSPM_TCO1_Video_Input_Format_PAL 0x00000040
2230dca1793SAdrian Knoth
2240dca1793SAdrian Knoth #define HDSPM_TCO1_set_TC 0x00000100
2250dca1793SAdrian Knoth #define HDSPM_TCO1_set_drop_frame_flag 0x00000200
2260dca1793SAdrian Knoth #define HDSPM_TCO1_LTC_Format_LSB 0x00000400
2270dca1793SAdrian Knoth #define HDSPM_TCO1_LTC_Format_MSB 0x00000800
2280dca1793SAdrian Knoth
2290dca1793SAdrian Knoth #define HDSPM_TCO2_TC_run 0x00010000
2300dca1793SAdrian Knoth #define HDSPM_TCO2_WCK_IO_ratio_LSB 0x00020000
2310dca1793SAdrian Knoth #define HDSPM_TCO2_WCK_IO_ratio_MSB 0x00040000
2320dca1793SAdrian Knoth #define HDSPM_TCO2_set_num_drop_frames_LSB 0x00080000
2330dca1793SAdrian Knoth #define HDSPM_TCO2_set_num_drop_frames_MSB 0x00100000
2340dca1793SAdrian Knoth #define HDSPM_TCO2_set_jam_sync 0x00200000
2350dca1793SAdrian Knoth #define HDSPM_TCO2_set_flywheel 0x00400000
2360dca1793SAdrian Knoth
2370dca1793SAdrian Knoth #define HDSPM_TCO2_set_01_4 0x01000000
2380dca1793SAdrian Knoth #define HDSPM_TCO2_set_pull_down 0x02000000
2390dca1793SAdrian Knoth #define HDSPM_TCO2_set_pull_up 0x04000000
2400dca1793SAdrian Knoth #define HDSPM_TCO2_set_freq 0x08000000
2410dca1793SAdrian Knoth #define HDSPM_TCO2_set_term_75R 0x10000000
2420dca1793SAdrian Knoth #define HDSPM_TCO2_set_input_LSB 0x20000000
2430dca1793SAdrian Knoth #define HDSPM_TCO2_set_input_MSB 0x40000000
2440dca1793SAdrian Knoth #define HDSPM_TCO2_set_freq_from_app 0x80000000
2450dca1793SAdrian Knoth
2460dca1793SAdrian Knoth
2470dca1793SAdrian Knoth #define HDSPM_midiDataOut0 352
2480dca1793SAdrian Knoth #define HDSPM_midiDataOut1 356
2490dca1793SAdrian Knoth #define HDSPM_midiDataOut2 368
2500dca1793SAdrian Knoth
251763f356cSTakashi Iwai #define HDSPM_midiDataIn0 360
252763f356cSTakashi Iwai #define HDSPM_midiDataIn1 364
2530dca1793SAdrian Knoth #define HDSPM_midiDataIn2 372
2540dca1793SAdrian Knoth #define HDSPM_midiDataIn3 376
255763f356cSTakashi Iwai
256763f356cSTakashi Iwai /* status is data bytes in MIDI-FIFO (0-128) */
257763f356cSTakashi Iwai #define HDSPM_midiStatusOut0 384
258763f356cSTakashi Iwai #define HDSPM_midiStatusOut1 388
2590dca1793SAdrian Knoth #define HDSPM_midiStatusOut2 400
2600dca1793SAdrian Knoth
261763f356cSTakashi Iwai #define HDSPM_midiStatusIn0 392
262763f356cSTakashi Iwai #define HDSPM_midiStatusIn1 396
2630dca1793SAdrian Knoth #define HDSPM_midiStatusIn2 404
2640dca1793SAdrian Knoth #define HDSPM_midiStatusIn3 408
265763f356cSTakashi Iwai
266763f356cSTakashi Iwai
267763f356cSTakashi Iwai /* the meters are regular i/o-mapped registers, but offset
268763f356cSTakashi Iwai considerably from the rest. the peak registers are reset
269763f356cSTakashi Iwai when read; the least-significant 4 bits are full-scale counters;
270763f356cSTakashi Iwai the actual peak value is in the most-significant 24 bits.
271763f356cSTakashi Iwai */
2720dca1793SAdrian Knoth
2730dca1793SAdrian Knoth #define HDSPM_MADI_INPUT_PEAK 4096
2740dca1793SAdrian Knoth #define HDSPM_MADI_PLAYBACK_PEAK 4352
2750dca1793SAdrian Knoth #define HDSPM_MADI_OUTPUT_PEAK 4608
2760dca1793SAdrian Knoth
2770dca1793SAdrian Knoth #define HDSPM_MADI_INPUT_RMS_L 6144
2780dca1793SAdrian Knoth #define HDSPM_MADI_PLAYBACK_RMS_L 6400
2790dca1793SAdrian Knoth #define HDSPM_MADI_OUTPUT_RMS_L 6656
2800dca1793SAdrian Knoth
2810dca1793SAdrian Knoth #define HDSPM_MADI_INPUT_RMS_H 7168
2820dca1793SAdrian Knoth #define HDSPM_MADI_PLAYBACK_RMS_H 7424
2830dca1793SAdrian Knoth #define HDSPM_MADI_OUTPUT_RMS_H 7680
284763f356cSTakashi Iwai
285763f356cSTakashi Iwai /* --- Control Register bits --------- */
286763f356cSTakashi Iwai #define HDSPM_Start (1<<0) /* start engine */
287763f356cSTakashi Iwai
288763f356cSTakashi Iwai #define HDSPM_Latency0 (1<<1) /* buffer size = 2^n */
289763f356cSTakashi Iwai #define HDSPM_Latency1 (1<<2) /* where n is defined */
290763f356cSTakashi Iwai #define HDSPM_Latency2 (1<<3) /* by Latency{2,1,0} */
291763f356cSTakashi Iwai
2920dca1793SAdrian Knoth #define HDSPM_ClockModeMaster (1<<4) /* 1=Master, 0=Autosync */
2930dca1793SAdrian Knoth #define HDSPM_c0Master 0x1 /* Master clock bit in settings
2940dca1793SAdrian Knoth register [RayDAT, AIO] */
295763f356cSTakashi Iwai
296763f356cSTakashi Iwai #define HDSPM_AudioInterruptEnable (1<<5) /* what do you think ? */
297763f356cSTakashi Iwai
298763f356cSTakashi Iwai #define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */
299763f356cSTakashi Iwai #define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */
300763f356cSTakashi Iwai #define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */
3013cee5a60SRemy Bruno #define HDSPM_QuadSpeed (1<<31) /* quad speed bit */
302763f356cSTakashi Iwai
3033cee5a60SRemy Bruno #define HDSPM_Professional (1<<9) /* Professional */ /* AES32 ONLY */
304763f356cSTakashi Iwai #define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1,
3053cee5a60SRemy Bruno 56channelMODE=0 */ /* MADI ONLY*/
3063cee5a60SRemy Bruno #define HDSPM_Emphasis (1<<10) /* Emphasis */ /* AES32 ONLY */
307763f356cSTakashi Iwai
308763f356cSTakashi Iwai #define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode,
3093cee5a60SRemy Bruno 0=off, 1=on */ /* MADI ONLY */
3103cee5a60SRemy Bruno #define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */
311763f356cSTakashi Iwai
312ef5fa1a4STakashi Iwai #define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax
313ef5fa1a4STakashi Iwai * -- MADI ONLY
314ef5fa1a4STakashi Iwai */
315763f356cSTakashi Iwai #define HDSPM_InputSelect1 (1<<15) /* should be 0 */
316763f356cSTakashi Iwai
3173cee5a60SRemy Bruno #define HDSPM_SyncRef2 (1<<13)
3183cee5a60SRemy Bruno #define HDSPM_SyncRef3 (1<<25)
319763f356cSTakashi Iwai
3203cee5a60SRemy Bruno #define HDSPM_SMUX (1<<18) /* Frame ??? */ /* MADI ONY */
321763f356cSTakashi Iwai #define HDSPM_clr_tms (1<<19) /* clear track marker, do not use
322763f356cSTakashi Iwai AES additional bits in
323763f356cSTakashi Iwai lower 5 Audiodatabits ??? */
3243cee5a60SRemy Bruno #define HDSPM_taxi_reset (1<<20) /* ??? */ /* MADI ONLY ? */
3253cee5a60SRemy Bruno #define HDSPM_WCK48 (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */
326763f356cSTakashi Iwai
3270dca1793SAdrian Knoth #define HDSPM_Midi0InterruptEnable 0x0400000
3280dca1793SAdrian Knoth #define HDSPM_Midi1InterruptEnable 0x0800000
3290dca1793SAdrian Knoth #define HDSPM_Midi2InterruptEnable 0x0200000
3300dca1793SAdrian Knoth #define HDSPM_Midi3InterruptEnable 0x4000000
331763f356cSTakashi Iwai
332763f356cSTakashi Iwai #define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */
3330dca1793SAdrian Knoth #define HDSPe_FLOAT_FORMAT 0x2000000
334763f356cSTakashi Iwai
3353cee5a60SRemy Bruno #define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */
3363cee5a60SRemy Bruno #define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */
3373cee5a60SRemy Bruno #define HDSPM_QS_QuadWire (1<<28) /* AES32 ONLY */
3383cee5a60SRemy Bruno
3393cee5a60SRemy Bruno #define HDSPM_wclk_sel (1<<30)
340763f356cSTakashi Iwai
341384f778fSAdrian Knoth /* additional control register bits for AIO*/
342384f778fSAdrian Knoth #define HDSPM_c0_Wck48 0x20 /* also RayDAT */
343384f778fSAdrian Knoth #define HDSPM_c0_Input0 0x1000
344384f778fSAdrian Knoth #define HDSPM_c0_Input1 0x2000
345384f778fSAdrian Knoth #define HDSPM_c0_Spdif_Opt 0x4000
346384f778fSAdrian Knoth #define HDSPM_c0_Pro 0x8000
347384f778fSAdrian Knoth #define HDSPM_c0_clr_tms 0x10000
348384f778fSAdrian Knoth #define HDSPM_c0_AEB1 0x20000
349384f778fSAdrian Knoth #define HDSPM_c0_AEB2 0x40000
350384f778fSAdrian Knoth #define HDSPM_c0_LineOut 0x80000
351384f778fSAdrian Knoth #define HDSPM_c0_AD_GAIN0 0x100000
352384f778fSAdrian Knoth #define HDSPM_c0_AD_GAIN1 0x200000
353384f778fSAdrian Knoth #define HDSPM_c0_DA_GAIN0 0x400000
354384f778fSAdrian Knoth #define HDSPM_c0_DA_GAIN1 0x800000
355384f778fSAdrian Knoth #define HDSPM_c0_PH_GAIN0 0x1000000
356384f778fSAdrian Knoth #define HDSPM_c0_PH_GAIN1 0x2000000
357384f778fSAdrian Knoth #define HDSPM_c0_Sym6db 0x4000000
358384f778fSAdrian Knoth
359384f778fSAdrian Knoth
360763f356cSTakashi Iwai /* --- bit helper defines */
361763f356cSTakashi Iwai #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2)
362ef5fa1a4STakashi Iwai #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\
363ef5fa1a4STakashi Iwai HDSPM_DoubleSpeed|HDSPM_QuadSpeed)
364763f356cSTakashi Iwai #define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1)
365763f356cSTakashi Iwai #define HDSPM_InputOptical 0
366763f356cSTakashi Iwai #define HDSPM_InputCoaxial (HDSPM_InputSelect0)
367ef5fa1a4STakashi Iwai #define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|\
368ef5fa1a4STakashi Iwai HDSPM_SyncRef2|HDSPM_SyncRef3)
3690dca1793SAdrian Knoth
3700dca1793SAdrian Knoth #define HDSPM_c0_SyncRef0 0x2
3710dca1793SAdrian Knoth #define HDSPM_c0_SyncRef1 0x4
3720dca1793SAdrian Knoth #define HDSPM_c0_SyncRef2 0x8
3730dca1793SAdrian Knoth #define HDSPM_c0_SyncRef3 0x10
3740dca1793SAdrian Knoth #define HDSPM_c0_SyncRefMask (HDSPM_c0_SyncRef0 | HDSPM_c0_SyncRef1 |\
3750dca1793SAdrian Knoth HDSPM_c0_SyncRef2 | HDSPM_c0_SyncRef3)
376763f356cSTakashi Iwai
377763f356cSTakashi Iwai #define HDSPM_SYNC_FROM_WORD 0 /* Preferred sync reference */
378763f356cSTakashi Iwai #define HDSPM_SYNC_FROM_MADI 1 /* choices - used by "pref_sync_ref" */
3790dca1793SAdrian Knoth #define HDSPM_SYNC_FROM_TCO 2
3800dca1793SAdrian Knoth #define HDSPM_SYNC_FROM_SYNC_IN 3
381763f356cSTakashi Iwai
382763f356cSTakashi Iwai #define HDSPM_Frequency32KHz HDSPM_Frequency0
383763f356cSTakashi Iwai #define HDSPM_Frequency44_1KHz HDSPM_Frequency1
384763f356cSTakashi Iwai #define HDSPM_Frequency48KHz (HDSPM_Frequency1|HDSPM_Frequency0)
385763f356cSTakashi Iwai #define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0)
386763f356cSTakashi Iwai #define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1)
387ef5fa1a4STakashi Iwai #define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|\
388ef5fa1a4STakashi Iwai HDSPM_Frequency0)
3893cee5a60SRemy Bruno #define HDSPM_Frequency128KHz (HDSPM_QuadSpeed|HDSPM_Frequency0)
3903cee5a60SRemy Bruno #define HDSPM_Frequency176_4KHz (HDSPM_QuadSpeed|HDSPM_Frequency1)
391ef5fa1a4STakashi Iwai #define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|\
392ef5fa1a4STakashi Iwai HDSPM_Frequency0)
393763f356cSTakashi Iwai
394763f356cSTakashi Iwai
395763f356cSTakashi Iwai /* Synccheck Status */
396763f356cSTakashi Iwai #define HDSPM_SYNC_CHECK_NO_LOCK 0
397763f356cSTakashi Iwai #define HDSPM_SYNC_CHECK_LOCK 1
398763f356cSTakashi Iwai #define HDSPM_SYNC_CHECK_SYNC 2
399763f356cSTakashi Iwai
400763f356cSTakashi Iwai /* AutoSync References - used by "autosync_ref" control switch */
401763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_FROM_WORD 0
402763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_FROM_MADI 1
4030dca1793SAdrian Knoth #define HDSPM_AUTOSYNC_FROM_TCO 2
4040dca1793SAdrian Knoth #define HDSPM_AUTOSYNC_FROM_SYNC_IN 3
4050dca1793SAdrian Knoth #define HDSPM_AUTOSYNC_FROM_NONE 4
406763f356cSTakashi Iwai
407763f356cSTakashi Iwai /* Possible sources of MADI input */
408763f356cSTakashi Iwai #define HDSPM_OPTICAL 0 /* optical */
409763f356cSTakashi Iwai #define HDSPM_COAXIAL 1 /* BNC */
410763f356cSTakashi Iwai
411763f356cSTakashi Iwai #define hdspm_encode_latency(x) (((x)<<1) & HDSPM_LatencyMask)
4120dca1793SAdrian Knoth #define hdspm_decode_latency(x) ((((x) & HDSPM_LatencyMask)>>1))
413763f356cSTakashi Iwai
414763f356cSTakashi Iwai #define hdspm_encode_in(x) (((x)&0x3)<<14)
415763f356cSTakashi Iwai #define hdspm_decode_in(x) (((x)>>14)&0x3)
416763f356cSTakashi Iwai
417763f356cSTakashi Iwai /* --- control2 register bits --- */
418763f356cSTakashi Iwai #define HDSPM_TMS (1<<0)
419763f356cSTakashi Iwai #define HDSPM_TCK (1<<1)
420763f356cSTakashi Iwai #define HDSPM_TDI (1<<2)
421763f356cSTakashi Iwai #define HDSPM_JTAG (1<<3)
422763f356cSTakashi Iwai #define HDSPM_PWDN (1<<4)
423763f356cSTakashi Iwai #define HDSPM_PROGRAM (1<<5)
424763f356cSTakashi Iwai #define HDSPM_CONFIG_MODE_0 (1<<6)
425763f356cSTakashi Iwai #define HDSPM_CONFIG_MODE_1 (1<<7)
426763f356cSTakashi Iwai /*#define HDSPM_VERSION_BIT (1<<8) not defined any more*/
427763f356cSTakashi Iwai #define HDSPM_BIGENDIAN_MODE (1<<9)
428763f356cSTakashi Iwai #define HDSPM_RD_MULTIPLE (1<<10)
429763f356cSTakashi Iwai
4303cee5a60SRemy Bruno /* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and
431ef5fa1a4STakashi Iwai that do not conflict with specific bits for AES32 seem to be valid also
432ef5fa1a4STakashi Iwai for the AES32
433ef5fa1a4STakashi Iwai */
434763f356cSTakashi Iwai #define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */
435ef5fa1a4STakashi Iwai #define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn MODE=0 */
436ef5fa1a4STakashi Iwai #define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1
437ef5fa1a4STakashi Iwai * (like inp0)
438ef5fa1a4STakashi Iwai */
4390dca1793SAdrian Knoth
440763f356cSTakashi Iwai #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */
4410dca1793SAdrian Knoth #define HDSPM_madiSync (1<<18) /* MADI is in sync */
4420dca1793SAdrian Knoth
443b0bf5504SAdrian Knoth #define HDSPM_tcoLockMadi 0x00000020 /* Optional TCO locked status for HDSPe MADI*/
444b0bf5504SAdrian Knoth #define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/
4450dca1793SAdrian Knoth
446b0bf5504SAdrian Knoth #define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */
447b0bf5504SAdrian Knoth #define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */
448763f356cSTakashi Iwai
449763f356cSTakashi Iwai #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */
4500dca1793SAdrian Knoth /* since 64byte accurate, last 6 bits are not used */
451763f356cSTakashi Iwai
4520dca1793SAdrian Knoth
4530dca1793SAdrian Knoth
454763f356cSTakashi Iwai #define HDSPM_DoubleSpeedStatus (1<<19) /* (input) card in double speed */
455763f356cSTakashi Iwai
456763f356cSTakashi Iwai #define HDSPM_madiFreq0 (1<<22) /* system freq 0=error */
457763f356cSTakashi Iwai #define HDSPM_madiFreq1 (1<<23) /* 1=32, 2=44.1 3=48 */
458763f356cSTakashi Iwai #define HDSPM_madiFreq2 (1<<24) /* 4=64, 5=88.2 6=96 */
459763f356cSTakashi Iwai #define HDSPM_madiFreq3 (1<<25) /* 7=128, 8=176.4 9=192 */
460763f356cSTakashi Iwai
461ef5fa1a4STakashi Iwai #define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with
462ef5fa1a4STakashi Iwai * Interrupt
463ef5fa1a4STakashi Iwai */
4640dca1793SAdrian Knoth #define HDSPM_tco_detect 0x08000000
465b0bf5504SAdrian Knoth #define HDSPM_tcoLockAes 0x20000000 /* Optional TCO locked status for HDSPe AES */
4660dca1793SAdrian Knoth
4670dca1793SAdrian Knoth #define HDSPM_s2_tco_detect 0x00000040
4680dca1793SAdrian Knoth #define HDSPM_s2_AEBO_D 0x00000080
4690dca1793SAdrian Knoth #define HDSPM_s2_AEBI_D 0x00000100
4700dca1793SAdrian Knoth
4710dca1793SAdrian Knoth
4720dca1793SAdrian Knoth #define HDSPM_midi0IRQPending 0x40000000
4730dca1793SAdrian Knoth #define HDSPM_midi1IRQPending 0x80000000
4740dca1793SAdrian Knoth #define HDSPM_midi2IRQPending 0x20000000
4750dca1793SAdrian Knoth #define HDSPM_midi2IRQPendingAES 0x00000020
4760dca1793SAdrian Knoth #define HDSPM_midi3IRQPending 0x00200000
477763f356cSTakashi Iwai
478763f356cSTakashi Iwai /* --- status bit helpers */
479ef5fa1a4STakashi Iwai #define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|\
480ef5fa1a4STakashi Iwai HDSPM_madiFreq2|HDSPM_madiFreq3)
481763f356cSTakashi Iwai #define HDSPM_madiFreq32 (HDSPM_madiFreq0)
482763f356cSTakashi Iwai #define HDSPM_madiFreq44_1 (HDSPM_madiFreq1)
483763f356cSTakashi Iwai #define HDSPM_madiFreq48 (HDSPM_madiFreq0|HDSPM_madiFreq1)
484763f356cSTakashi Iwai #define HDSPM_madiFreq64 (HDSPM_madiFreq2)
485763f356cSTakashi Iwai #define HDSPM_madiFreq88_2 (HDSPM_madiFreq0|HDSPM_madiFreq2)
486763f356cSTakashi Iwai #define HDSPM_madiFreq96 (HDSPM_madiFreq1|HDSPM_madiFreq2)
487763f356cSTakashi Iwai #define HDSPM_madiFreq128 (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2)
488763f356cSTakashi Iwai #define HDSPM_madiFreq176_4 (HDSPM_madiFreq3)
489763f356cSTakashi Iwai #define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0)
490763f356cSTakashi Iwai
4913cee5a60SRemy Bruno /* Status2 Register bits */ /* MADI ONLY */
492763f356cSTakashi Iwai
49325985edcSLucas De Marchi #define HDSPM_version0 (1<<0) /* not really defined but I guess */
494763f356cSTakashi Iwai #define HDSPM_version1 (1<<1) /* in former cards it was ??? */
495763f356cSTakashi Iwai #define HDSPM_version2 (1<<2)
496763f356cSTakashi Iwai
497763f356cSTakashi Iwai #define HDSPM_wcLock (1<<3) /* Wordclock is detected and locked */
498763f356cSTakashi Iwai #define HDSPM_wcSync (1<<4) /* Wordclock is in sync with systemclock */
499763f356cSTakashi Iwai
500763f356cSTakashi Iwai #define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */
501763f356cSTakashi Iwai #define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */
502a8cd7148SAdrian Knoth #define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, 111=128 */
503a8cd7148SAdrian Knoth #define HDSPM_wc_freq3 0x800 /* 1000=176.4, 1001=192 */
504763f356cSTakashi Iwai
5050dca1793SAdrian Knoth #define HDSPM_SyncRef0 0x10000 /* Sync Reference */
5060dca1793SAdrian Knoth #define HDSPM_SyncRef1 0x20000
5070dca1793SAdrian Knoth
5080dca1793SAdrian Knoth #define HDSPM_SelSyncRef0 (1<<8) /* AutoSync Source */
509763f356cSTakashi Iwai #define HDSPM_SelSyncRef1 (1<<9) /* 000=word, 001=MADI, */
510763f356cSTakashi Iwai #define HDSPM_SelSyncRef2 (1<<10) /* 111=no valid signal */
511763f356cSTakashi Iwai
512763f356cSTakashi Iwai #define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync)
513763f356cSTakashi Iwai
514a8cd7148SAdrian Knoth #define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2|\
515a8cd7148SAdrian Knoth HDSPM_wc_freq3)
516763f356cSTakashi Iwai #define HDSPM_wcFreq32 (HDSPM_wc_freq0)
517763f356cSTakashi Iwai #define HDSPM_wcFreq44_1 (HDSPM_wc_freq1)
518763f356cSTakashi Iwai #define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1)
519763f356cSTakashi Iwai #define HDSPM_wcFreq64 (HDSPM_wc_freq2)
520763f356cSTakashi Iwai #define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2)
521763f356cSTakashi Iwai #define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2)
522a8cd7148SAdrian Knoth #define HDSPM_wcFreq128 (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2)
523a8cd7148SAdrian Knoth #define HDSPM_wcFreq176_4 (HDSPM_wc_freq3)
524a8cd7148SAdrian Knoth #define HDSPM_wcFreq192 (HDSPM_wc_freq0|HDSPM_wc_freq3)
525763f356cSTakashi Iwai
5260dca1793SAdrian Knoth #define HDSPM_status1_F_0 0x0400000
5270dca1793SAdrian Knoth #define HDSPM_status1_F_1 0x0800000
5280dca1793SAdrian Knoth #define HDSPM_status1_F_2 0x1000000
5290dca1793SAdrian Knoth #define HDSPM_status1_F_3 0x2000000
5300dca1793SAdrian Knoth #define HDSPM_status1_freqMask (HDSPM_status1_F_0|HDSPM_status1_F_1|HDSPM_status1_F_2|HDSPM_status1_F_3)
5310dca1793SAdrian Knoth
532763f356cSTakashi Iwai
533ef5fa1a4STakashi Iwai #define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\
534ef5fa1a4STakashi Iwai HDSPM_SelSyncRef2)
535763f356cSTakashi Iwai #define HDSPM_SelSyncRef_WORD 0
536763f356cSTakashi Iwai #define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0)
5370dca1793SAdrian Knoth #define HDSPM_SelSyncRef_TCO (HDSPM_SelSyncRef1)
5380dca1793SAdrian Knoth #define HDSPM_SelSyncRef_SyncIn (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1)
539ef5fa1a4STakashi Iwai #define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\
540ef5fa1a4STakashi Iwai HDSPM_SelSyncRef2)
541763f356cSTakashi Iwai
5423cee5a60SRemy Bruno /*
5433cee5a60SRemy Bruno For AES32, bits for status, status2 and timecode are different
5443cee5a60SRemy Bruno */
5453cee5a60SRemy Bruno /* status */
5463cee5a60SRemy Bruno #define HDSPM_AES32_wcLock 0x0200000
54756bde0f3SAndre Schramm #define HDSPM_AES32_wcSync 0x0100000
5483cee5a60SRemy Bruno #define HDSPM_AES32_wcFreq_bit 22
5493cee5a60SRemy Bruno /* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function
5503cee5a60SRemy Bruno HDSPM_bit2freq */
5513cee5a60SRemy Bruno #define HDSPM_AES32_syncref_bit 16
5523cee5a60SRemy Bruno /* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */
5533cee5a60SRemy Bruno
5543cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_WORD 0
5553cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES1 1
5563cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES2 2
5573cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES3 3
5583cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES4 4
5593cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES5 5
5603cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6
5613cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7
5623cee5a60SRemy Bruno #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8
563b0bf5504SAdrian Knoth #define HDSPM_AES32_AUTOSYNC_FROM_TCO 9
564b0bf5504SAdrian Knoth #define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10
565b0bf5504SAdrian Knoth #define HDSPM_AES32_AUTOSYNC_FROM_NONE 11
5663cee5a60SRemy Bruno
5673cee5a60SRemy Bruno /* status2 */
5683cee5a60SRemy Bruno /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */
5693cee5a60SRemy Bruno #define HDSPM_LockAES 0x80
5703cee5a60SRemy Bruno #define HDSPM_LockAES1 0x80
5713cee5a60SRemy Bruno #define HDSPM_LockAES2 0x40
5723cee5a60SRemy Bruno #define HDSPM_LockAES3 0x20
5733cee5a60SRemy Bruno #define HDSPM_LockAES4 0x10
5743cee5a60SRemy Bruno #define HDSPM_LockAES5 0x8
5753cee5a60SRemy Bruno #define HDSPM_LockAES6 0x4
5763cee5a60SRemy Bruno #define HDSPM_LockAES7 0x2
5773cee5a60SRemy Bruno #define HDSPM_LockAES8 0x1
5783cee5a60SRemy Bruno /*
5793cee5a60SRemy Bruno Timecode
5803cee5a60SRemy Bruno After windows driver sources, bits 4*i to 4*i+3 give the input frequency on
5813cee5a60SRemy Bruno AES i+1
5823cee5a60SRemy Bruno bits 3210
5833cee5a60SRemy Bruno 0001 32kHz
5843cee5a60SRemy Bruno 0010 44.1kHz
5853cee5a60SRemy Bruno 0011 48kHz
5863cee5a60SRemy Bruno 0100 64kHz
5873cee5a60SRemy Bruno 0101 88.2kHz
5883cee5a60SRemy Bruno 0110 96kHz
5893cee5a60SRemy Bruno 0111 128kHz
5903cee5a60SRemy Bruno 1000 176.4kHz
5913cee5a60SRemy Bruno 1001 192kHz
5923cee5a60SRemy Bruno NB: Timecode register doesn't seem to work on AES32 card revision 230
5933cee5a60SRemy Bruno */
5943cee5a60SRemy Bruno
595763f356cSTakashi Iwai /* Mixer Values */
596763f356cSTakashi Iwai #define UNITY_GAIN 32768 /* = 65536/2 */
597763f356cSTakashi Iwai #define MINUS_INFINITY_GAIN 0
598763f356cSTakashi Iwai
599763f356cSTakashi Iwai /* Number of channels for different Speed Modes */
600763f356cSTakashi Iwai #define MADI_SS_CHANNELS 64
601763f356cSTakashi Iwai #define MADI_DS_CHANNELS 32
602763f356cSTakashi Iwai #define MADI_QS_CHANNELS 16
603763f356cSTakashi Iwai
6040dca1793SAdrian Knoth #define RAYDAT_SS_CHANNELS 36
6050dca1793SAdrian Knoth #define RAYDAT_DS_CHANNELS 20
6060dca1793SAdrian Knoth #define RAYDAT_QS_CHANNELS 12
6070dca1793SAdrian Knoth
6080dca1793SAdrian Knoth #define AIO_IN_SS_CHANNELS 14
6090dca1793SAdrian Knoth #define AIO_IN_DS_CHANNELS 10
6100dca1793SAdrian Knoth #define AIO_IN_QS_CHANNELS 8
6110dca1793SAdrian Knoth #define AIO_OUT_SS_CHANNELS 16
6120dca1793SAdrian Knoth #define AIO_OUT_DS_CHANNELS 12
6130dca1793SAdrian Knoth #define AIO_OUT_QS_CHANNELS 10
6140dca1793SAdrian Knoth
615d2d10a21SAdrian Knoth #define AES32_CHANNELS 16
616d2d10a21SAdrian Knoth
617763f356cSTakashi Iwai /* the size of a substream (1 mono data stream) */
618763f356cSTakashi Iwai #define HDSPM_CHANNEL_BUFFER_SAMPLES (16*1024)
619763f356cSTakashi Iwai #define HDSPM_CHANNEL_BUFFER_BYTES (4*HDSPM_CHANNEL_BUFFER_SAMPLES)
620763f356cSTakashi Iwai
621763f356cSTakashi Iwai /* the size of the area we need to allocate for DMA transfers. the
622763f356cSTakashi Iwai size is the same regardless of the number of channels, and
623763f356cSTakashi Iwai also the latency to use.
624763f356cSTakashi Iwai for one direction !!!
625763f356cSTakashi Iwai */
626ffb2c3c0SRemy Bruno #define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
627763f356cSTakashi Iwai #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024)
628763f356cSTakashi Iwai
6290dca1793SAdrian Knoth #define HDSPM_RAYDAT_REV 211
6300dca1793SAdrian Knoth #define HDSPM_AIO_REV 212
6310dca1793SAdrian Knoth #define HDSPM_MADIFACE_REV 213
6323cee5a60SRemy Bruno
6336534599dSRemy Bruno /* speed factor modes */
6346534599dSRemy Bruno #define HDSPM_SPEED_SINGLE 0
6356534599dSRemy Bruno #define HDSPM_SPEED_DOUBLE 1
6366534599dSRemy Bruno #define HDSPM_SPEED_QUAD 2
6370dca1793SAdrian Knoth
6386534599dSRemy Bruno /* names for speed modes */
639e315cc3fSTakashi Iwai static const char * const hdspm_speed_names[] = { "single", "double", "quad" };
6406534599dSRemy Bruno
641eb0d4dbfSAdrian Knoth static const char *const texts_autosync_aes_tco[] = { "Word Clock",
6420dca1793SAdrian Knoth "AES1", "AES2", "AES3", "AES4",
6430dca1793SAdrian Knoth "AES5", "AES6", "AES7", "AES8",
644db2d1a91SAdrian Knoth "TCO", "Sync In"
645db2d1a91SAdrian Knoth };
646eb0d4dbfSAdrian Knoth static const char *const texts_autosync_aes[] = { "Word Clock",
6470dca1793SAdrian Knoth "AES1", "AES2", "AES3", "AES4",
648db2d1a91SAdrian Knoth "AES5", "AES6", "AES7", "AES8",
649db2d1a91SAdrian Knoth "Sync In"
650db2d1a91SAdrian Knoth };
651eb0d4dbfSAdrian Knoth static const char *const texts_autosync_madi_tco[] = { "Word Clock",
6520dca1793SAdrian Knoth "MADI", "TCO", "Sync In" };
653eb0d4dbfSAdrian Knoth static const char *const texts_autosync_madi[] = { "Word Clock",
6540dca1793SAdrian Knoth "MADI", "Sync In" };
6550dca1793SAdrian Knoth
656eb0d4dbfSAdrian Knoth static const char *const texts_autosync_raydat_tco[] = {
6570dca1793SAdrian Knoth "Word Clock",
6580dca1793SAdrian Knoth "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
6590dca1793SAdrian Knoth "AES", "SPDIF", "TCO", "Sync In"
6600dca1793SAdrian Knoth };
661eb0d4dbfSAdrian Knoth static const char *const texts_autosync_raydat[] = {
6620dca1793SAdrian Knoth "Word Clock",
6630dca1793SAdrian Knoth "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
6640dca1793SAdrian Knoth "AES", "SPDIF", "Sync In"
6650dca1793SAdrian Knoth };
666eb0d4dbfSAdrian Knoth static const char *const texts_autosync_aio_tco[] = {
6670dca1793SAdrian Knoth "Word Clock",
6680dca1793SAdrian Knoth "ADAT", "AES", "SPDIF", "TCO", "Sync In"
6690dca1793SAdrian Knoth };
670eb0d4dbfSAdrian Knoth static const char *const texts_autosync_aio[] = { "Word Clock",
6710dca1793SAdrian Knoth "ADAT", "AES", "SPDIF", "Sync In" };
6720dca1793SAdrian Knoth
67338816545SAdrian Knoth static const char *const texts_freq[] = {
6740dca1793SAdrian Knoth "No Lock",
6750dca1793SAdrian Knoth "32 kHz",
6760dca1793SAdrian Knoth "44.1 kHz",
6770dca1793SAdrian Knoth "48 kHz",
6780dca1793SAdrian Knoth "64 kHz",
6790dca1793SAdrian Knoth "88.2 kHz",
6800dca1793SAdrian Knoth "96 kHz",
6810dca1793SAdrian Knoth "128 kHz",
6820dca1793SAdrian Knoth "176.4 kHz",
6830dca1793SAdrian Knoth "192 kHz"
6840dca1793SAdrian Knoth };
6850dca1793SAdrian Knoth
686e315cc3fSTakashi Iwai static const char * const texts_ports_madi[] = {
6870dca1793SAdrian Knoth "MADI.1", "MADI.2", "MADI.3", "MADI.4", "MADI.5", "MADI.6",
6880dca1793SAdrian Knoth "MADI.7", "MADI.8", "MADI.9", "MADI.10", "MADI.11", "MADI.12",
6890dca1793SAdrian Knoth "MADI.13", "MADI.14", "MADI.15", "MADI.16", "MADI.17", "MADI.18",
6900dca1793SAdrian Knoth "MADI.19", "MADI.20", "MADI.21", "MADI.22", "MADI.23", "MADI.24",
6910dca1793SAdrian Knoth "MADI.25", "MADI.26", "MADI.27", "MADI.28", "MADI.29", "MADI.30",
6920dca1793SAdrian Knoth "MADI.31", "MADI.32", "MADI.33", "MADI.34", "MADI.35", "MADI.36",
6930dca1793SAdrian Knoth "MADI.37", "MADI.38", "MADI.39", "MADI.40", "MADI.41", "MADI.42",
6940dca1793SAdrian Knoth "MADI.43", "MADI.44", "MADI.45", "MADI.46", "MADI.47", "MADI.48",
6950dca1793SAdrian Knoth "MADI.49", "MADI.50", "MADI.51", "MADI.52", "MADI.53", "MADI.54",
6960dca1793SAdrian Knoth "MADI.55", "MADI.56", "MADI.57", "MADI.58", "MADI.59", "MADI.60",
6970dca1793SAdrian Knoth "MADI.61", "MADI.62", "MADI.63", "MADI.64",
6980dca1793SAdrian Knoth };
6990dca1793SAdrian Knoth
7000dca1793SAdrian Knoth
701e315cc3fSTakashi Iwai static const char * const texts_ports_raydat_ss[] = {
7020dca1793SAdrian Knoth "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4", "ADAT1.5", "ADAT1.6",
7030dca1793SAdrian Knoth "ADAT1.7", "ADAT1.8", "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4",
7040dca1793SAdrian Knoth "ADAT2.5", "ADAT2.6", "ADAT2.7", "ADAT2.8", "ADAT3.1", "ADAT3.2",
7050dca1793SAdrian Knoth "ADAT3.3", "ADAT3.4", "ADAT3.5", "ADAT3.6", "ADAT3.7", "ADAT3.8",
7060dca1793SAdrian Knoth "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4", "ADAT4.5", "ADAT4.6",
7070dca1793SAdrian Knoth "ADAT4.7", "ADAT4.8",
7080dca1793SAdrian Knoth "AES.L", "AES.R",
7090dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R"
7100dca1793SAdrian Knoth };
7110dca1793SAdrian Knoth
712e315cc3fSTakashi Iwai static const char * const texts_ports_raydat_ds[] = {
7130dca1793SAdrian Knoth "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4",
7140dca1793SAdrian Knoth "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4",
7150dca1793SAdrian Knoth "ADAT3.1", "ADAT3.2", "ADAT3.3", "ADAT3.4",
7160dca1793SAdrian Knoth "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4",
7170dca1793SAdrian Knoth "AES.L", "AES.R",
7180dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R"
7190dca1793SAdrian Knoth };
7200dca1793SAdrian Knoth
721e315cc3fSTakashi Iwai static const char * const texts_ports_raydat_qs[] = {
7220dca1793SAdrian Knoth "ADAT1.1", "ADAT1.2",
7230dca1793SAdrian Knoth "ADAT2.1", "ADAT2.2",
7240dca1793SAdrian Knoth "ADAT3.1", "ADAT3.2",
7250dca1793SAdrian Knoth "ADAT4.1", "ADAT4.2",
7260dca1793SAdrian Knoth "AES.L", "AES.R",
7270dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R"
7280dca1793SAdrian Knoth };
7290dca1793SAdrian Knoth
7300dca1793SAdrian Knoth
731e315cc3fSTakashi Iwai static const char * const texts_ports_aio_in_ss[] = {
7320dca1793SAdrian Knoth "Analogue.L", "Analogue.R",
7330dca1793SAdrian Knoth "AES.L", "AES.R",
7340dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R",
7350dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
7363de9db26SAdrian Knoth "ADAT.7", "ADAT.8",
7373de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4"
7380dca1793SAdrian Knoth };
7390dca1793SAdrian Knoth
740e315cc3fSTakashi Iwai static const char * const texts_ports_aio_out_ss[] = {
7410dca1793SAdrian Knoth "Analogue.L", "Analogue.R",
7420dca1793SAdrian Knoth "AES.L", "AES.R",
7430dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R",
7440dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
7450dca1793SAdrian Knoth "ADAT.7", "ADAT.8",
7463de9db26SAdrian Knoth "Phone.L", "Phone.R",
7473de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4"
7480dca1793SAdrian Knoth };
7490dca1793SAdrian Knoth
750e315cc3fSTakashi Iwai static const char * const texts_ports_aio_in_ds[] = {
7510dca1793SAdrian Knoth "Analogue.L", "Analogue.R",
7520dca1793SAdrian Knoth "AES.L", "AES.R",
7530dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R",
7543de9db26SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
7553de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4"
7560dca1793SAdrian Knoth };
7570dca1793SAdrian Knoth
758e315cc3fSTakashi Iwai static const char * const texts_ports_aio_out_ds[] = {
7590dca1793SAdrian Knoth "Analogue.L", "Analogue.R",
7600dca1793SAdrian Knoth "AES.L", "AES.R",
7610dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R",
7620dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
7633de9db26SAdrian Knoth "Phone.L", "Phone.R",
7643de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4"
7650dca1793SAdrian Knoth };
7660dca1793SAdrian Knoth
767e315cc3fSTakashi Iwai static const char * const texts_ports_aio_in_qs[] = {
7680dca1793SAdrian Knoth "Analogue.L", "Analogue.R",
7690dca1793SAdrian Knoth "AES.L", "AES.R",
7700dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R",
7713de9db26SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
7723de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4"
7730dca1793SAdrian Knoth };
7740dca1793SAdrian Knoth
775e315cc3fSTakashi Iwai static const char * const texts_ports_aio_out_qs[] = {
7760dca1793SAdrian Knoth "Analogue.L", "Analogue.R",
7770dca1793SAdrian Knoth "AES.L", "AES.R",
7780dca1793SAdrian Knoth "SPDIF.L", "SPDIF.R",
7790dca1793SAdrian Knoth "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
7803de9db26SAdrian Knoth "Phone.L", "Phone.R",
7813de9db26SAdrian Knoth "AEB.1", "AEB.2", "AEB.3", "AEB.4"
7820dca1793SAdrian Knoth };
7830dca1793SAdrian Knoth
784e315cc3fSTakashi Iwai static const char * const texts_ports_aes32[] = {
785432d2500SAdrian Knoth "AES.1", "AES.2", "AES.3", "AES.4", "AES.5", "AES.6", "AES.7",
786432d2500SAdrian Knoth "AES.8", "AES.9.", "AES.10", "AES.11", "AES.12", "AES.13", "AES.14",
787432d2500SAdrian Knoth "AES.15", "AES.16"
788432d2500SAdrian Knoth };
789432d2500SAdrian Knoth
79055a57606SAdrian Knoth /* These tables map the ALSA channels 1..N to the channels that we
79155a57606SAdrian Knoth need to use in order to find the relevant channel buffer. RME
79255a57606SAdrian Knoth refers to this kind of mapping as between "the ADAT channel and
79355a57606SAdrian Knoth the DMA channel." We index it using the logical audio channel,
79455a57606SAdrian Knoth and the value is the DMA channel (i.e. channel buffer number)
79555a57606SAdrian Knoth where the data for that channel can be read/written from/to.
79655a57606SAdrian Knoth */
79755a57606SAdrian Knoth
798e315cc3fSTakashi Iwai static const char channel_map_unity_ss[HDSPM_MAX_CHANNELS] = {
79955a57606SAdrian Knoth 0, 1, 2, 3, 4, 5, 6, 7,
80055a57606SAdrian Knoth 8, 9, 10, 11, 12, 13, 14, 15,
80155a57606SAdrian Knoth 16, 17, 18, 19, 20, 21, 22, 23,
80255a57606SAdrian Knoth 24, 25, 26, 27, 28, 29, 30, 31,
80355a57606SAdrian Knoth 32, 33, 34, 35, 36, 37, 38, 39,
80455a57606SAdrian Knoth 40, 41, 42, 43, 44, 45, 46, 47,
80555a57606SAdrian Knoth 48, 49, 50, 51, 52, 53, 54, 55,
80655a57606SAdrian Knoth 56, 57, 58, 59, 60, 61, 62, 63
80755a57606SAdrian Knoth };
80855a57606SAdrian Knoth
809e315cc3fSTakashi Iwai static const char channel_map_raydat_ss[HDSPM_MAX_CHANNELS] = {
81055a57606SAdrian Knoth 4, 5, 6, 7, 8, 9, 10, 11, /* ADAT 1 */
81155a57606SAdrian Knoth 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT 2 */
81255a57606SAdrian Knoth 20, 21, 22, 23, 24, 25, 26, 27, /* ADAT 3 */
81355a57606SAdrian Knoth 28, 29, 30, 31, 32, 33, 34, 35, /* ADAT 4 */
81455a57606SAdrian Knoth 0, 1, /* AES */
81555a57606SAdrian Knoth 2, 3, /* SPDIF */
81655a57606SAdrian Knoth -1, -1, -1, -1,
81755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
81855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
81955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
82055a57606SAdrian Knoth };
82155a57606SAdrian Knoth
822e315cc3fSTakashi Iwai static const char channel_map_raydat_ds[HDSPM_MAX_CHANNELS] = {
82355a57606SAdrian Knoth 4, 5, 6, 7, /* ADAT 1 */
82455a57606SAdrian Knoth 8, 9, 10, 11, /* ADAT 2 */
82555a57606SAdrian Knoth 12, 13, 14, 15, /* ADAT 3 */
82655a57606SAdrian Knoth 16, 17, 18, 19, /* ADAT 4 */
82755a57606SAdrian Knoth 0, 1, /* AES */
82855a57606SAdrian Knoth 2, 3, /* SPDIF */
82955a57606SAdrian Knoth -1, -1, -1, -1,
83055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
83155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
83255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
83355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
83455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
83555a57606SAdrian Knoth };
83655a57606SAdrian Knoth
837e315cc3fSTakashi Iwai static const char channel_map_raydat_qs[HDSPM_MAX_CHANNELS] = {
83855a57606SAdrian Knoth 4, 5, /* ADAT 1 */
83955a57606SAdrian Knoth 6, 7, /* ADAT 2 */
84055a57606SAdrian Knoth 8, 9, /* ADAT 3 */
84155a57606SAdrian Knoth 10, 11, /* ADAT 4 */
84255a57606SAdrian Knoth 0, 1, /* AES */
84355a57606SAdrian Knoth 2, 3, /* SPDIF */
84455a57606SAdrian Knoth -1, -1, -1, -1,
84555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
84655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
84755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
84855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
84955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
85055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
85155a57606SAdrian Knoth };
85255a57606SAdrian Knoth
853e315cc3fSTakashi Iwai static const char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = {
85455a57606SAdrian Knoth 0, 1, /* line in */
85555a57606SAdrian Knoth 8, 9, /* aes in, */
85655a57606SAdrian Knoth 10, 11, /* spdif in */
85755a57606SAdrian Knoth 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */
8583de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */
8593de9db26SAdrian Knoth -1, -1, -1, -1, -1, -1,
86055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
86155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
86255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
86355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
86455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
86555a57606SAdrian Knoth };
86655a57606SAdrian Knoth
867e315cc3fSTakashi Iwai static const char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = {
86855a57606SAdrian Knoth 0, 1, /* line out */
86955a57606SAdrian Knoth 8, 9, /* aes out */
87055a57606SAdrian Knoth 10, 11, /* spdif out */
87155a57606SAdrian Knoth 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */
87255a57606SAdrian Knoth 6, 7, /* phone out */
8733de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */
8743de9db26SAdrian Knoth -1, -1, -1, -1,
87555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
87655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
87755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
87855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
87955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
88055a57606SAdrian Knoth };
88155a57606SAdrian Knoth
882e315cc3fSTakashi Iwai static const char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = {
88355a57606SAdrian Knoth 0, 1, /* line in */
88455a57606SAdrian Knoth 8, 9, /* aes in */
88555a57606SAdrian Knoth 10, 11, /* spdif in */
88655a57606SAdrian Knoth 12, 14, 16, 18, /* adat in */
8873de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */
8883de9db26SAdrian Knoth -1, -1,
88955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
89055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
89155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
89255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
89355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
89455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1
89555a57606SAdrian Knoth };
89655a57606SAdrian Knoth
897e315cc3fSTakashi Iwai static const char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = {
89855a57606SAdrian Knoth 0, 1, /* line out */
89955a57606SAdrian Knoth 8, 9, /* aes out */
90055a57606SAdrian Knoth 10, 11, /* spdif out */
90155a57606SAdrian Knoth 12, 14, 16, 18, /* adat out */
90255a57606SAdrian Knoth 6, 7, /* phone out */
9033de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */
90455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
90555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
90655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
90755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
90855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
90955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1
91055a57606SAdrian Knoth };
91155a57606SAdrian Knoth
912e315cc3fSTakashi Iwai static const char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = {
91355a57606SAdrian Knoth 0, 1, /* line in */
91455a57606SAdrian Knoth 8, 9, /* aes in */
91555a57606SAdrian Knoth 10, 11, /* spdif in */
91655a57606SAdrian Knoth 12, 16, /* adat in */
9173de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */
9183de9db26SAdrian Knoth -1, -1, -1, -1,
91955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
92055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
92155a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
92255a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
92355a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
92455a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1
92555a57606SAdrian Knoth };
92655a57606SAdrian Knoth
927e315cc3fSTakashi Iwai static const char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = {
92855a57606SAdrian Knoth 0, 1, /* line out */
92955a57606SAdrian Knoth 8, 9, /* aes out */
93055a57606SAdrian Knoth 10, 11, /* spdif out */
93155a57606SAdrian Knoth 12, 16, /* adat out */
93255a57606SAdrian Knoth 6, 7, /* phone out */
9333de9db26SAdrian Knoth 2, 3, 4, 5, /* AEB */
9343de9db26SAdrian Knoth -1, -1,
93555a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
93655a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
93755a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
93855a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
93955a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
94055a57606SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1
94155a57606SAdrian Knoth };
94255a57606SAdrian Knoth
943e315cc3fSTakashi Iwai static const char channel_map_aes32[HDSPM_MAX_CHANNELS] = {
944432d2500SAdrian Knoth 0, 1, 2, 3, 4, 5, 6, 7,
945432d2500SAdrian Knoth 8, 9, 10, 11, 12, 13, 14, 15,
946432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
947432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
948432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
949432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
950432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1,
951432d2500SAdrian Knoth -1, -1, -1, -1, -1, -1, -1, -1
952432d2500SAdrian Knoth };
953432d2500SAdrian Knoth
95498274f07STakashi Iwai struct hdspm_midi {
95598274f07STakashi Iwai struct hdspm *hdspm;
956763f356cSTakashi Iwai int id;
95798274f07STakashi Iwai struct snd_rawmidi *rmidi;
95898274f07STakashi Iwai struct snd_rawmidi_substream *input;
95998274f07STakashi Iwai struct snd_rawmidi_substream *output;
960763f356cSTakashi Iwai char istimer; /* timer in use */
961763f356cSTakashi Iwai struct timer_list timer;
962763f356cSTakashi Iwai spinlock_t lock;
963763f356cSTakashi Iwai int pending;
9640dca1793SAdrian Knoth int dataIn;
9650dca1793SAdrian Knoth int statusIn;
9660dca1793SAdrian Knoth int dataOut;
9670dca1793SAdrian Knoth int statusOut;
9680dca1793SAdrian Knoth int ie;
9690dca1793SAdrian Knoth int irq;
9700dca1793SAdrian Knoth };
9710dca1793SAdrian Knoth
9720dca1793SAdrian Knoth struct hdspm_tco {
97369358fcaSMartin Dausel int input; /* 0: LTC, 1:Video, 2: WC*/
97469358fcaSMartin Dausel int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */
97569358fcaSMartin Dausel int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */
97669358fcaSMartin Dausel int samplerate; /* 0=44.1, 1=48, 2= freq from app */
97769358fcaSMartin Dausel int pull; /* 0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/
9780dca1793SAdrian Knoth int term; /* 0 = off, 1 = on */
979763f356cSTakashi Iwai };
980763f356cSTakashi Iwai
98198274f07STakashi Iwai struct hdspm {
982763f356cSTakashi Iwai spinlock_t lock;
983ef5fa1a4STakashi Iwai /* only one playback and/or capture stream */
984ef5fa1a4STakashi Iwai struct snd_pcm_substream *capture_substream;
985ef5fa1a4STakashi Iwai struct snd_pcm_substream *playback_substream;
986763f356cSTakashi Iwai
987763f356cSTakashi Iwai char *card_name; /* for procinfo */
9883cee5a60SRemy Bruno unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/
9893cee5a60SRemy Bruno
9900dca1793SAdrian Knoth uint8_t io_type;
991763f356cSTakashi Iwai
992763f356cSTakashi Iwai int monitor_outs; /* set up monitoring outs init flag */
993763f356cSTakashi Iwai
994763f356cSTakashi Iwai u32 control_register; /* cached value */
995763f356cSTakashi Iwai u32 control2_register; /* cached value */
99669358fcaSMartin Dausel u32 settings_register; /* cached value for AIO / RayDat (sync reference, master/slave) */
997763f356cSTakashi Iwai
9980dca1793SAdrian Knoth struct hdspm_midi midi[4];
999a2e527c5STakashi Iwai struct work_struct midi_work;
1000763f356cSTakashi Iwai
1001763f356cSTakashi Iwai size_t period_bytes;
10020dca1793SAdrian Knoth unsigned char ss_in_channels;
10030dca1793SAdrian Knoth unsigned char ds_in_channels;
10040dca1793SAdrian Knoth unsigned char qs_in_channels;
10050dca1793SAdrian Knoth unsigned char ss_out_channels;
10060dca1793SAdrian Knoth unsigned char ds_out_channels;
10070dca1793SAdrian Knoth unsigned char qs_out_channels;
10080dca1793SAdrian Knoth
10090dca1793SAdrian Knoth unsigned char max_channels_in;
10100dca1793SAdrian Knoth unsigned char max_channels_out;
10110dca1793SAdrian Knoth
1012e315cc3fSTakashi Iwai const signed char *channel_map_in;
1013e315cc3fSTakashi Iwai const signed char *channel_map_out;
10140dca1793SAdrian Knoth
1015e315cc3fSTakashi Iwai const signed char *channel_map_in_ss, *channel_map_in_ds, *channel_map_in_qs;
1016e315cc3fSTakashi Iwai const signed char *channel_map_out_ss, *channel_map_out_ds, *channel_map_out_qs;
10170dca1793SAdrian Knoth
1018e315cc3fSTakashi Iwai const char * const *port_names_in;
1019e315cc3fSTakashi Iwai const char * const *port_names_out;
10200dca1793SAdrian Knoth
1021e315cc3fSTakashi Iwai const char * const *port_names_in_ss;
1022e315cc3fSTakashi Iwai const char * const *port_names_in_ds;
1023e315cc3fSTakashi Iwai const char * const *port_names_in_qs;
1024e315cc3fSTakashi Iwai const char * const *port_names_out_ss;
1025e315cc3fSTakashi Iwai const char * const *port_names_out_ds;
1026e315cc3fSTakashi Iwai const char * const *port_names_out_qs;
1027763f356cSTakashi Iwai
1028763f356cSTakashi Iwai unsigned char *playback_buffer; /* suitably aligned address */
1029763f356cSTakashi Iwai unsigned char *capture_buffer; /* suitably aligned address */
1030763f356cSTakashi Iwai
1031763f356cSTakashi Iwai pid_t capture_pid; /* process id which uses capture */
1032763f356cSTakashi Iwai pid_t playback_pid; /* process id which uses capture */
1033763f356cSTakashi Iwai int running; /* running status */
1034763f356cSTakashi Iwai
1035763f356cSTakashi Iwai int last_external_sample_rate; /* samplerate mystic ... */
1036763f356cSTakashi Iwai int last_internal_sample_rate;
1037763f356cSTakashi Iwai int system_sample_rate;
1038763f356cSTakashi Iwai
1039763f356cSTakashi Iwai int dev; /* Hardware vars... */
1040763f356cSTakashi Iwai int irq;
1041763f356cSTakashi Iwai unsigned long port;
1042763f356cSTakashi Iwai void __iomem *iobase;
1043763f356cSTakashi Iwai
1044763f356cSTakashi Iwai int irq_count; /* for debug */
10450dca1793SAdrian Knoth int midiPorts;
1046763f356cSTakashi Iwai
104798274f07STakashi Iwai struct snd_card *card; /* one card */
104898274f07STakashi Iwai struct snd_pcm *pcm; /* has one pcm */
104998274f07STakashi Iwai struct snd_hwdep *hwdep; /* and a hwdep for additional ioctl */
1050763f356cSTakashi Iwai struct pci_dev *pci; /* and an pci info */
1051763f356cSTakashi Iwai
1052763f356cSTakashi Iwai /* Mixer vars */
1053ef5fa1a4STakashi Iwai /* fast alsa mixer */
1054ef5fa1a4STakashi Iwai struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS];
1055ef5fa1a4STakashi Iwai /* but input to much, so not used */
1056ef5fa1a4STakashi Iwai struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS];
105725985edcSLucas De Marchi /* full mixer accessible over mixer ioctl or hwdep-device */
1058ef5fa1a4STakashi Iwai struct hdspm_mixer *mixer;
1059763f356cSTakashi Iwai
10600dca1793SAdrian Knoth struct hdspm_tco *tco; /* NULL if no TCO detected */
1061763f356cSTakashi Iwai
1062eb0d4dbfSAdrian Knoth const char *const *texts_autosync;
10630dca1793SAdrian Knoth int texts_autosync_items;
1064763f356cSTakashi Iwai
10650dca1793SAdrian Knoth cycles_t last_interrupt;
1066730a5865SJaroslav Kysela
10677d53a631SAdrian Knoth unsigned int serial;
10687d53a631SAdrian Knoth
1069730a5865SJaroslav Kysela struct hdspm_peak_rms peak_rms;
1070763f356cSTakashi Iwai };
1071763f356cSTakashi Iwai
1072763f356cSTakashi Iwai
10739baa3c34SBenoit Taine static const struct pci_device_id snd_hdspm_ids[] = {
1074763f356cSTakashi Iwai {
1075763f356cSTakashi Iwai .vendor = PCI_VENDOR_ID_XILINX,
1076763f356cSTakashi Iwai .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI,
1077763f356cSTakashi Iwai .subvendor = PCI_ANY_ID,
1078763f356cSTakashi Iwai .subdevice = PCI_ANY_ID,
1079763f356cSTakashi Iwai .class = 0,
1080763f356cSTakashi Iwai .class_mask = 0,
1081763f356cSTakashi Iwai .driver_data = 0},
1082763f356cSTakashi Iwai {0,}
1083763f356cSTakashi Iwai };
1084763f356cSTakashi Iwai
1085763f356cSTakashi Iwai MODULE_DEVICE_TABLE(pci, snd_hdspm_ids);
1086763f356cSTakashi Iwai
1087763f356cSTakashi Iwai /* prototypes */
1088e23e7a14SBill Pemberton static int snd_hdspm_create_alsa_devices(struct snd_card *card,
108998274f07STakashi Iwai struct hdspm *hdspm);
1090e23e7a14SBill Pemberton static int snd_hdspm_create_pcm(struct snd_card *card,
109198274f07STakashi Iwai struct hdspm *hdspm);
1092763f356cSTakashi Iwai
109398274f07STakashi Iwai static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm);
10943f7bf918SAdrian Knoth static inline int hdspm_get_pll_freq(struct hdspm *hdspm);
109598274f07STakashi Iwai static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm);
109698274f07STakashi Iwai static int hdspm_autosync_ref(struct hdspm *hdspm);
109734be7ebbSAdrian Knoth static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out);
109898274f07STakashi Iwai static int snd_hdspm_set_defaults(struct hdspm *hdspm);
109921a164dfSAdrian Knoth static int hdspm_system_clock_mode(struct hdspm *hdspm);
1100e4e07c6cSPhilippe Bekaert static void hdspm_set_channel_dma_addr(struct hdspm *hdspm,
110177a23f26STakashi Iwai struct snd_pcm_substream *substream,
1102763f356cSTakashi Iwai unsigned int reg, int channels);
1103763f356cSTakashi Iwai
11045b266354SAdrian Knoth static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx);
11055b266354SAdrian Knoth static int hdspm_wc_sync_check(struct hdspm *hdspm);
11065b266354SAdrian Knoth static int hdspm_tco_sync_check(struct hdspm *hdspm);
11075b266354SAdrian Knoth static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
11085b266354SAdrian Knoth
11095b266354SAdrian Knoth static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index);
11105b266354SAdrian Knoth static int hdspm_get_tco_sample_rate(struct hdspm *hdspm);
11115b266354SAdrian Knoth static int hdspm_get_wc_sample_rate(struct hdspm *hdspm);
11125b266354SAdrian Knoth
11135b266354SAdrian Knoth
11145b266354SAdrian Knoth
HDSPM_bit2freq(int n)11153cee5a60SRemy Bruno static inline int HDSPM_bit2freq(int n)
11163cee5a60SRemy Bruno {
111762cef821SDenys Vlasenko static const int bit2freq_tab[] = {
111862cef821SDenys Vlasenko 0, 32000, 44100, 48000, 64000, 88200,
11193cee5a60SRemy Bruno 96000, 128000, 176400, 192000 };
11203cee5a60SRemy Bruno if (n < 1 || n > 9)
11213cee5a60SRemy Bruno return 0;
11223cee5a60SRemy Bruno return bit2freq_tab[n];
11233cee5a60SRemy Bruno }
11243cee5a60SRemy Bruno
hdspm_is_raydat_or_aio(struct hdspm * hdspm)1125b2ed6326SAdrian Knoth static bool hdspm_is_raydat_or_aio(struct hdspm *hdspm)
1126b2ed6326SAdrian Knoth {
1127b2ed6326SAdrian Knoth return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type));
1128b2ed6326SAdrian Knoth }
1129b2ed6326SAdrian Knoth
1130b2ed6326SAdrian Knoth
11310dca1793SAdrian Knoth /* Write/read to/from HDSPM with Adresses in Bytes
1132763f356cSTakashi Iwai not words but only 32Bit writes are allowed */
1133763f356cSTakashi Iwai
hdspm_write(struct hdspm * hdspm,unsigned int reg,unsigned int val)113498274f07STakashi Iwai static inline void hdspm_write(struct hdspm * hdspm, unsigned int reg,
1135763f356cSTakashi Iwai unsigned int val)
1136763f356cSTakashi Iwai {
1137763f356cSTakashi Iwai writel(val, hdspm->iobase + reg);
1138763f356cSTakashi Iwai }
1139763f356cSTakashi Iwai
hdspm_read(struct hdspm * hdspm,unsigned int reg)114098274f07STakashi Iwai static inline unsigned int hdspm_read(struct hdspm * hdspm, unsigned int reg)
1141763f356cSTakashi Iwai {
1142763f356cSTakashi Iwai return readl(hdspm->iobase + reg);
1143763f356cSTakashi Iwai }
1144763f356cSTakashi Iwai
1145763f356cSTakashi Iwai /* for each output channel (chan) I have an Input (in) and Playback (pb) Fader
1146763f356cSTakashi Iwai mixer is write only on hardware so we have to cache him for read
1147763f356cSTakashi Iwai each fader is a u32, but uses only the first 16 bit */
1148763f356cSTakashi Iwai
hdspm_read_in_gain(struct hdspm * hdspm,unsigned int chan,unsigned int in)114998274f07STakashi Iwai static inline int hdspm_read_in_gain(struct hdspm * hdspm, unsigned int chan,
1150763f356cSTakashi Iwai unsigned int in)
1151763f356cSTakashi Iwai {
11525bab2482SAdrian Bunk if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS)
1153763f356cSTakashi Iwai return 0;
1154763f356cSTakashi Iwai
1155763f356cSTakashi Iwai return hdspm->mixer->ch[chan].in[in];
1156763f356cSTakashi Iwai }
1157763f356cSTakashi Iwai
hdspm_read_pb_gain(struct hdspm * hdspm,unsigned int chan,unsigned int pb)115898274f07STakashi Iwai static inline int hdspm_read_pb_gain(struct hdspm * hdspm, unsigned int chan,
1159763f356cSTakashi Iwai unsigned int pb)
1160763f356cSTakashi Iwai {
11615bab2482SAdrian Bunk if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS)
1162763f356cSTakashi Iwai return 0;
1163763f356cSTakashi Iwai return hdspm->mixer->ch[chan].pb[pb];
1164763f356cSTakashi Iwai }
1165763f356cSTakashi Iwai
hdspm_write_in_gain(struct hdspm * hdspm,unsigned int chan,unsigned int in,unsigned short data)116662cef821SDenys Vlasenko static int hdspm_write_in_gain(struct hdspm *hdspm, unsigned int chan,
1167763f356cSTakashi Iwai unsigned int in, unsigned short data)
1168763f356cSTakashi Iwai {
1169763f356cSTakashi Iwai if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS)
1170763f356cSTakashi Iwai return -1;
1171763f356cSTakashi Iwai
1172763f356cSTakashi Iwai hdspm_write(hdspm,
1173763f356cSTakashi Iwai HDSPM_MADI_mixerBase +
1174763f356cSTakashi Iwai ((in + 128 * chan) * sizeof(u32)),
1175763f356cSTakashi Iwai (hdspm->mixer->ch[chan].in[in] = data & 0xFFFF));
1176763f356cSTakashi Iwai return 0;
1177763f356cSTakashi Iwai }
1178763f356cSTakashi Iwai
hdspm_write_pb_gain(struct hdspm * hdspm,unsigned int chan,unsigned int pb,unsigned short data)117962cef821SDenys Vlasenko static int hdspm_write_pb_gain(struct hdspm *hdspm, unsigned int chan,
1180763f356cSTakashi Iwai unsigned int pb, unsigned short data)
1181763f356cSTakashi Iwai {
1182763f356cSTakashi Iwai if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS)
1183763f356cSTakashi Iwai return -1;
1184763f356cSTakashi Iwai
1185763f356cSTakashi Iwai hdspm_write(hdspm,
1186763f356cSTakashi Iwai HDSPM_MADI_mixerBase +
1187763f356cSTakashi Iwai ((64 + pb + 128 * chan) * sizeof(u32)),
1188763f356cSTakashi Iwai (hdspm->mixer->ch[chan].pb[pb] = data & 0xFFFF));
1189763f356cSTakashi Iwai return 0;
1190763f356cSTakashi Iwai }
1191763f356cSTakashi Iwai
1192763f356cSTakashi Iwai
1193763f356cSTakashi Iwai /* enable DMA for specific channels, now available for DSP-MADI */
snd_hdspm_enable_in(struct hdspm * hdspm,int i,int v)119498274f07STakashi Iwai static inline void snd_hdspm_enable_in(struct hdspm * hdspm, int i, int v)
1195763f356cSTakashi Iwai {
1196763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_inputEnableBase + (4 * i), v);
1197763f356cSTakashi Iwai }
1198763f356cSTakashi Iwai
snd_hdspm_enable_out(struct hdspm * hdspm,int i,int v)119998274f07STakashi Iwai static inline void snd_hdspm_enable_out(struct hdspm * hdspm, int i, int v)
1200763f356cSTakashi Iwai {
1201763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_outputEnableBase + (4 * i), v);
1202763f356cSTakashi Iwai }
1203763f356cSTakashi Iwai
1204763f356cSTakashi Iwai /* check if same process is writing and reading */
snd_hdspm_use_is_exclusive(struct hdspm * hdspm)120562cef821SDenys Vlasenko static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm)
1206763f356cSTakashi Iwai {
1207763f356cSTakashi Iwai unsigned long flags;
1208763f356cSTakashi Iwai int ret = 1;
1209763f356cSTakashi Iwai
1210763f356cSTakashi Iwai spin_lock_irqsave(&hdspm->lock, flags);
1211763f356cSTakashi Iwai if ((hdspm->playback_pid != hdspm->capture_pid) &&
1212763f356cSTakashi Iwai (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) {
1213763f356cSTakashi Iwai ret = 0;
1214763f356cSTakashi Iwai }
1215763f356cSTakashi Iwai spin_unlock_irqrestore(&hdspm->lock, flags);
1216763f356cSTakashi Iwai return ret;
1217763f356cSTakashi Iwai }
1218763f356cSTakashi Iwai
12197dcd5612SNaoki Hayama /* round arbitrary sample rates to commonly known rates */
hdspm_round_frequency(int rate)1220fcdc4ba1SAdrian Knoth static int hdspm_round_frequency(int rate)
1221fcdc4ba1SAdrian Knoth {
1222fcdc4ba1SAdrian Knoth if (rate < 38050)
1223fcdc4ba1SAdrian Knoth return 32000;
1224fcdc4ba1SAdrian Knoth if (rate < 46008)
1225fcdc4ba1SAdrian Knoth return 44100;
1226fcdc4ba1SAdrian Knoth else
1227fcdc4ba1SAdrian Knoth return 48000;
1228fcdc4ba1SAdrian Knoth }
1229fcdc4ba1SAdrian Knoth
1230a8a729faSAdrian Knoth /* QS and DS rates normally can not be detected
1231a8a729faSAdrian Knoth * automatically by the card. Only exception is MADI
1232a8a729faSAdrian Knoth * in 96k frame mode.
1233a8a729faSAdrian Knoth *
1234a8a729faSAdrian Knoth * So if we read SS values (32 .. 48k), check for
1235a8a729faSAdrian Knoth * user-provided DS/QS bits in the control register
1236a8a729faSAdrian Knoth * and multiply the base frequency accordingly.
1237a8a729faSAdrian Knoth */
hdspm_rate_multiplier(struct hdspm * hdspm,int rate)1238a8a729faSAdrian Knoth static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate)
1239a8a729faSAdrian Knoth {
1240a8a729faSAdrian Knoth if (rate <= 48000) {
1241a8a729faSAdrian Knoth if (hdspm->control_register & HDSPM_QuadSpeed)
1242a8a729faSAdrian Knoth return rate * 4;
1243a8a729faSAdrian Knoth else if (hdspm->control_register &
1244a8a729faSAdrian Knoth HDSPM_DoubleSpeed)
1245a8a729faSAdrian Knoth return rate * 2;
124668593c93SFengguang Wu }
1247a8a729faSAdrian Knoth return rate;
1248a8a729faSAdrian Knoth }
1249a8a729faSAdrian Knoth
12505b266354SAdrian Knoth /* check for external sample rate, returns the sample rate in Hz*/
hdspm_external_sample_rate(struct hdspm * hdspm)125162cef821SDenys Vlasenko static int hdspm_external_sample_rate(struct hdspm *hdspm)
1252763f356cSTakashi Iwai {
1253df57de17SSudip Mukherjee unsigned int status, status2;
12540dca1793SAdrian Knoth int syncref, rate = 0, rate_bits;
12553cee5a60SRemy Bruno
12560dca1793SAdrian Knoth switch (hdspm->io_type) {
12570dca1793SAdrian Knoth case AES32:
12580dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
12590dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister);
12600dca1793SAdrian Knoth
12610dca1793SAdrian Knoth syncref = hdspm_autosync_ref(hdspm);
1262dbae4a0cSAdrian Knoth switch (syncref) {
1263dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_WORD:
1264dbae4a0cSAdrian Knoth /* Check WC sync and get sample rate */
1265dbae4a0cSAdrian Knoth if (hdspm_wc_sync_check(hdspm))
1266dbae4a0cSAdrian Knoth return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm));
1267dbae4a0cSAdrian Knoth break;
12683cee5a60SRemy Bruno
1269dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES1:
1270dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES2:
1271dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES3:
1272dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES4:
1273dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES5:
1274dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES6:
1275dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES7:
1276dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES8:
1277dbae4a0cSAdrian Knoth /* Check AES sync and get sample rate */
1278dbae4a0cSAdrian Knoth if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))
1279dbae4a0cSAdrian Knoth return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm,
1280dbae4a0cSAdrian Knoth syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1));
1281dbae4a0cSAdrian Knoth break;
12820dca1793SAdrian Knoth
1283dbae4a0cSAdrian Knoth
1284dbae4a0cSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_TCO:
1285dbae4a0cSAdrian Knoth /* Check TCO sync and get sample rate */
1286dbae4a0cSAdrian Knoth if (hdspm_tco_sync_check(hdspm))
1287dbae4a0cSAdrian Knoth return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm));
1288dbae4a0cSAdrian Knoth break;
1289dbae4a0cSAdrian Knoth default:
12903cee5a60SRemy Bruno return 0;
1291dbae4a0cSAdrian Knoth } /* end switch(syncref) */
12920dca1793SAdrian Knoth break;
12930dca1793SAdrian Knoth
12940dca1793SAdrian Knoth case MADIface:
12950dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister);
12960dca1793SAdrian Knoth
12970dca1793SAdrian Knoth if (!(status & HDSPM_madiLock)) {
12980dca1793SAdrian Knoth rate = 0; /* no lock */
12993cee5a60SRemy Bruno } else {
13000dca1793SAdrian Knoth switch (status & (HDSPM_status1_freqMask)) {
13010dca1793SAdrian Knoth case HDSPM_status1_F_0*1:
13020dca1793SAdrian Knoth rate = 32000; break;
13030dca1793SAdrian Knoth case HDSPM_status1_F_0*2:
13040dca1793SAdrian Knoth rate = 44100; break;
13050dca1793SAdrian Knoth case HDSPM_status1_F_0*3:
13060dca1793SAdrian Knoth rate = 48000; break;
13070dca1793SAdrian Knoth case HDSPM_status1_F_0*4:
13080dca1793SAdrian Knoth rate = 64000; break;
13090dca1793SAdrian Knoth case HDSPM_status1_F_0*5:
13100dca1793SAdrian Knoth rate = 88200; break;
13110dca1793SAdrian Knoth case HDSPM_status1_F_0*6:
13120dca1793SAdrian Knoth rate = 96000; break;
13130dca1793SAdrian Knoth case HDSPM_status1_F_0*7:
13140dca1793SAdrian Knoth rate = 128000; break;
13150dca1793SAdrian Knoth case HDSPM_status1_F_0*8:
13160dca1793SAdrian Knoth rate = 176400; break;
13170dca1793SAdrian Knoth case HDSPM_status1_F_0*9:
13180dca1793SAdrian Knoth rate = 192000; break;
13190dca1793SAdrian Knoth default:
13200dca1793SAdrian Knoth rate = 0; break;
13210dca1793SAdrian Knoth }
13220dca1793SAdrian Knoth }
13230dca1793SAdrian Knoth
13240dca1793SAdrian Knoth break;
13250dca1793SAdrian Knoth
13260dca1793SAdrian Knoth case MADI:
13270dca1793SAdrian Knoth case AIO:
13280dca1793SAdrian Knoth case RayDAT:
13290dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
13300dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister);
13310dca1793SAdrian Knoth rate = 0;
1332763f356cSTakashi Iwai
1333763f356cSTakashi Iwai /* if wordclock has synced freq and wordclock is valid */
1334763f356cSTakashi Iwai if ((status2 & HDSPM_wcLock) != 0 &&
1335fedf1535SAdrian Knoth (status2 & HDSPM_SelSyncRef0) == 0) {
1336763f356cSTakashi Iwai
1337763f356cSTakashi Iwai rate_bits = status2 & HDSPM_wcFreqMask;
1338763f356cSTakashi Iwai
13390dca1793SAdrian Knoth
1340763f356cSTakashi Iwai switch (rate_bits) {
1341763f356cSTakashi Iwai case HDSPM_wcFreq32:
1342763f356cSTakashi Iwai rate = 32000;
1343763f356cSTakashi Iwai break;
1344763f356cSTakashi Iwai case HDSPM_wcFreq44_1:
1345763f356cSTakashi Iwai rate = 44100;
1346763f356cSTakashi Iwai break;
1347763f356cSTakashi Iwai case HDSPM_wcFreq48:
1348763f356cSTakashi Iwai rate = 48000;
1349763f356cSTakashi Iwai break;
1350763f356cSTakashi Iwai case HDSPM_wcFreq64:
1351763f356cSTakashi Iwai rate = 64000;
1352763f356cSTakashi Iwai break;
1353763f356cSTakashi Iwai case HDSPM_wcFreq88_2:
1354763f356cSTakashi Iwai rate = 88200;
1355763f356cSTakashi Iwai break;
1356763f356cSTakashi Iwai case HDSPM_wcFreq96:
1357763f356cSTakashi Iwai rate = 96000;
1358763f356cSTakashi Iwai break;
1359a8cd7148SAdrian Knoth case HDSPM_wcFreq128:
1360a8cd7148SAdrian Knoth rate = 128000;
1361a8cd7148SAdrian Knoth break;
1362a8cd7148SAdrian Knoth case HDSPM_wcFreq176_4:
1363a8cd7148SAdrian Knoth rate = 176400;
1364a8cd7148SAdrian Knoth break;
1365a8cd7148SAdrian Knoth case HDSPM_wcFreq192:
1366a8cd7148SAdrian Knoth rate = 192000;
1367a8cd7148SAdrian Knoth break;
1368763f356cSTakashi Iwai default:
1369763f356cSTakashi Iwai rate = 0;
1370763f356cSTakashi Iwai break;
1371763f356cSTakashi Iwai }
1372763f356cSTakashi Iwai }
1373763f356cSTakashi Iwai
1374ef5fa1a4STakashi Iwai /* if rate detected and Syncref is Word than have it,
1375ef5fa1a4STakashi Iwai * word has priority to MADI
1376ef5fa1a4STakashi Iwai */
13773cee5a60SRemy Bruno if (rate != 0 &&
13783cee5a60SRemy Bruno (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
13797b559397SAdrian Knoth return hdspm_rate_multiplier(hdspm, rate);
1380763f356cSTakashi Iwai
13810dca1793SAdrian Knoth /* maybe a madi input (which is taken if sel sync is madi) */
1382763f356cSTakashi Iwai if (status & HDSPM_madiLock) {
1383763f356cSTakashi Iwai rate_bits = status & HDSPM_madiFreqMask;
1384763f356cSTakashi Iwai
1385763f356cSTakashi Iwai switch (rate_bits) {
1386763f356cSTakashi Iwai case HDSPM_madiFreq32:
1387763f356cSTakashi Iwai rate = 32000;
1388763f356cSTakashi Iwai break;
1389763f356cSTakashi Iwai case HDSPM_madiFreq44_1:
1390763f356cSTakashi Iwai rate = 44100;
1391763f356cSTakashi Iwai break;
1392763f356cSTakashi Iwai case HDSPM_madiFreq48:
1393763f356cSTakashi Iwai rate = 48000;
1394763f356cSTakashi Iwai break;
1395763f356cSTakashi Iwai case HDSPM_madiFreq64:
1396763f356cSTakashi Iwai rate = 64000;
1397763f356cSTakashi Iwai break;
1398763f356cSTakashi Iwai case HDSPM_madiFreq88_2:
1399763f356cSTakashi Iwai rate = 88200;
1400763f356cSTakashi Iwai break;
1401763f356cSTakashi Iwai case HDSPM_madiFreq96:
1402763f356cSTakashi Iwai rate = 96000;
1403763f356cSTakashi Iwai break;
1404763f356cSTakashi Iwai case HDSPM_madiFreq128:
1405763f356cSTakashi Iwai rate = 128000;
1406763f356cSTakashi Iwai break;
1407763f356cSTakashi Iwai case HDSPM_madiFreq176_4:
1408763f356cSTakashi Iwai rate = 176400;
1409763f356cSTakashi Iwai break;
1410763f356cSTakashi Iwai case HDSPM_madiFreq192:
1411763f356cSTakashi Iwai rate = 192000;
1412763f356cSTakashi Iwai break;
1413763f356cSTakashi Iwai default:
1414763f356cSTakashi Iwai rate = 0;
1415763f356cSTakashi Iwai break;
1416763f356cSTakashi Iwai }
1417d12c51d8SAdrian Knoth
1418fcdc4ba1SAdrian Knoth } /* endif HDSPM_madiLock */
1419fcdc4ba1SAdrian Knoth
1420fcdc4ba1SAdrian Knoth /* check sample rate from TCO or SYNC_IN */
1421fcdc4ba1SAdrian Knoth {
1422fcdc4ba1SAdrian Knoth bool is_valid_input = 0;
1423fcdc4ba1SAdrian Knoth bool has_sync = 0;
1424fcdc4ba1SAdrian Knoth
1425fcdc4ba1SAdrian Knoth syncref = hdspm_autosync_ref(hdspm);
1426fcdc4ba1SAdrian Knoth if (HDSPM_AUTOSYNC_FROM_TCO == syncref) {
1427fcdc4ba1SAdrian Knoth is_valid_input = 1;
1428fcdc4ba1SAdrian Knoth has_sync = (HDSPM_SYNC_CHECK_SYNC ==
1429fcdc4ba1SAdrian Knoth hdspm_tco_sync_check(hdspm));
1430fcdc4ba1SAdrian Knoth } else if (HDSPM_AUTOSYNC_FROM_SYNC_IN == syncref) {
1431fcdc4ba1SAdrian Knoth is_valid_input = 1;
1432fcdc4ba1SAdrian Knoth has_sync = (HDSPM_SYNC_CHECK_SYNC ==
1433fcdc4ba1SAdrian Knoth hdspm_sync_in_sync_check(hdspm));
1434fcdc4ba1SAdrian Knoth }
1435fcdc4ba1SAdrian Knoth
1436fcdc4ba1SAdrian Knoth if (is_valid_input && has_sync) {
1437fcdc4ba1SAdrian Knoth rate = hdspm_round_frequency(
1438fcdc4ba1SAdrian Knoth hdspm_get_pll_freq(hdspm));
1439fcdc4ba1SAdrian Knoth }
1440fcdc4ba1SAdrian Knoth }
1441fcdc4ba1SAdrian Knoth
1442a8a729faSAdrian Knoth rate = hdspm_rate_multiplier(hdspm, rate);
1443a8a729faSAdrian Knoth
14440dca1793SAdrian Knoth break;
1445763f356cSTakashi Iwai }
14460dca1793SAdrian Knoth
14470dca1793SAdrian Knoth return rate;
14483cee5a60SRemy Bruno }
1449763f356cSTakashi Iwai
14507cb155ffSAdrian Knoth /* return latency in samples per period */
hdspm_get_latency(struct hdspm * hdspm)14517cb155ffSAdrian Knoth static int hdspm_get_latency(struct hdspm *hdspm)
14527cb155ffSAdrian Knoth {
14537cb155ffSAdrian Knoth int n;
14547cb155ffSAdrian Knoth
14557cb155ffSAdrian Knoth n = hdspm_decode_latency(hdspm->control_register);
14567cb155ffSAdrian Knoth
14577cb155ffSAdrian Knoth /* Special case for new RME cards with 32 samples period size.
14587cb155ffSAdrian Knoth * The three latency bits in the control register
14597cb155ffSAdrian Knoth * (HDSP_LatencyMask) encode latency values of 64 samples as
14607cb155ffSAdrian Knoth * 0, 128 samples as 1 ... 4096 samples as 6. For old cards, 7
14617cb155ffSAdrian Knoth * denotes 8192 samples, but on new cards like RayDAT or AIO,
14627cb155ffSAdrian Knoth * it corresponds to 32 samples.
14637cb155ffSAdrian Knoth */
14647cb155ffSAdrian Knoth if ((7 == n) && (RayDAT == hdspm->io_type || AIO == hdspm->io_type))
14657cb155ffSAdrian Knoth n = -1;
14667cb155ffSAdrian Knoth
14677cb155ffSAdrian Knoth return 1 << (n + 6);
14687cb155ffSAdrian Knoth }
14697cb155ffSAdrian Knoth
1470763f356cSTakashi Iwai /* Latency function */
hdspm_compute_period_size(struct hdspm * hdspm)147198274f07STakashi Iwai static inline void hdspm_compute_period_size(struct hdspm *hdspm)
1472763f356cSTakashi Iwai {
14737cb155ffSAdrian Knoth hdspm->period_bytes = 4 * hdspm_get_latency(hdspm);
1474763f356cSTakashi Iwai }
1475763f356cSTakashi Iwai
14760dca1793SAdrian Knoth
hdspm_hw_pointer(struct hdspm * hdspm)147798274f07STakashi Iwai static snd_pcm_uframes_t hdspm_hw_pointer(struct hdspm *hdspm)
1478763f356cSTakashi Iwai {
1479763f356cSTakashi Iwai int position;
1480763f356cSTakashi Iwai
1481763f356cSTakashi Iwai position = hdspm_read(hdspm, HDSPM_statusRegister);
1482483cee77SAdrian Knoth
1483483cee77SAdrian Knoth switch (hdspm->io_type) {
1484483cee77SAdrian Knoth case RayDAT:
1485483cee77SAdrian Knoth case AIO:
1486763f356cSTakashi Iwai position &= HDSPM_BufferPositionMask;
14870dca1793SAdrian Knoth position /= 4; /* Bytes per sample */
1488483cee77SAdrian Knoth break;
1489483cee77SAdrian Knoth default:
1490483cee77SAdrian Knoth position = (position & HDSPM_BufferID) ?
1491483cee77SAdrian Knoth (hdspm->period_bytes / 4) : 0;
1492483cee77SAdrian Knoth }
1493763f356cSTakashi Iwai
1494763f356cSTakashi Iwai return position;
1495763f356cSTakashi Iwai }
1496763f356cSTakashi Iwai
1497763f356cSTakashi Iwai
hdspm_start_audio(struct hdspm * s)149898274f07STakashi Iwai static inline void hdspm_start_audio(struct hdspm * s)
1499763f356cSTakashi Iwai {
1500763f356cSTakashi Iwai s->control_register |= (HDSPM_AudioInterruptEnable | HDSPM_Start);
1501763f356cSTakashi Iwai hdspm_write(s, HDSPM_controlRegister, s->control_register);
1502763f356cSTakashi Iwai }
1503763f356cSTakashi Iwai
hdspm_stop_audio(struct hdspm * s)150498274f07STakashi Iwai static inline void hdspm_stop_audio(struct hdspm * s)
1505763f356cSTakashi Iwai {
1506763f356cSTakashi Iwai s->control_register &= ~(HDSPM_Start | HDSPM_AudioInterruptEnable);
1507763f356cSTakashi Iwai hdspm_write(s, HDSPM_controlRegister, s->control_register);
1508763f356cSTakashi Iwai }
1509763f356cSTakashi Iwai
1510763f356cSTakashi Iwai /* should I silence all or only opened ones ? doit all for first even is 4MB*/
hdspm_silence_playback(struct hdspm * hdspm)151162cef821SDenys Vlasenko static void hdspm_silence_playback(struct hdspm *hdspm)
1512763f356cSTakashi Iwai {
1513763f356cSTakashi Iwai int i;
1514763f356cSTakashi Iwai int n = hdspm->period_bytes;
1515763f356cSTakashi Iwai void *buf = hdspm->playback_buffer;
1516763f356cSTakashi Iwai
1517da2ea374SMarkus Elfring if (!buf)
15183cee5a60SRemy Bruno return;
1519763f356cSTakashi Iwai
1520763f356cSTakashi Iwai for (i = 0; i < HDSPM_MAX_CHANNELS; i++) {
1521763f356cSTakashi Iwai memset(buf, 0, n);
1522763f356cSTakashi Iwai buf += HDSPM_CHANNEL_BUFFER_BYTES;
1523763f356cSTakashi Iwai }
1524763f356cSTakashi Iwai }
1525763f356cSTakashi Iwai
hdspm_set_interrupt_interval(struct hdspm * s,unsigned int frames)152698274f07STakashi Iwai static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames)
1527763f356cSTakashi Iwai {
1528763f356cSTakashi Iwai int n;
1529763f356cSTakashi Iwai
1530763f356cSTakashi Iwai spin_lock_irq(&s->lock);
1531763f356cSTakashi Iwai
15322e610270SAdrian Knoth if (32 == frames) {
15332e610270SAdrian Knoth /* Special case for new RME cards like RayDAT/AIO which
15342e610270SAdrian Knoth * support period sizes of 32 samples. Since latency is
15352e610270SAdrian Knoth * encoded in the three bits of HDSP_LatencyMask, we can only
15362e610270SAdrian Knoth * have values from 0 .. 7. While 0 still means 64 samples and
15372e610270SAdrian Knoth * 6 represents 4096 samples on all cards, 7 represents 8192
15382e610270SAdrian Knoth * on older cards and 32 samples on new cards.
15392e610270SAdrian Knoth *
15402e610270SAdrian Knoth * In other words, period size in samples is calculated by
15412e610270SAdrian Knoth * 2^(n+6) with n ranging from 0 .. 7.
15422e610270SAdrian Knoth */
15432e610270SAdrian Knoth n = 7;
15442e610270SAdrian Knoth } else {
1545763f356cSTakashi Iwai frames >>= 7;
1546763f356cSTakashi Iwai n = 0;
1547763f356cSTakashi Iwai while (frames) {
1548763f356cSTakashi Iwai n++;
1549763f356cSTakashi Iwai frames >>= 1;
1550763f356cSTakashi Iwai }
15512e610270SAdrian Knoth }
15522e610270SAdrian Knoth
1553763f356cSTakashi Iwai s->control_register &= ~HDSPM_LatencyMask;
1554763f356cSTakashi Iwai s->control_register |= hdspm_encode_latency(n);
1555763f356cSTakashi Iwai
1556763f356cSTakashi Iwai hdspm_write(s, HDSPM_controlRegister, s->control_register);
1557763f356cSTakashi Iwai
1558763f356cSTakashi Iwai hdspm_compute_period_size(s);
1559763f356cSTakashi Iwai
1560763f356cSTakashi Iwai spin_unlock_irq(&s->lock);
1561763f356cSTakashi Iwai
1562763f356cSTakashi Iwai return 0;
1563763f356cSTakashi Iwai }
1564763f356cSTakashi Iwai
hdspm_calc_dds_value(struct hdspm * hdspm,u64 period)15650dca1793SAdrian Knoth static u64 hdspm_calc_dds_value(struct hdspm *hdspm, u64 period)
15660dca1793SAdrian Knoth {
15670dca1793SAdrian Knoth u64 freq_const;
15680dca1793SAdrian Knoth
15690dca1793SAdrian Knoth if (period == 0)
15700dca1793SAdrian Knoth return 0;
15710dca1793SAdrian Knoth
15720dca1793SAdrian Knoth switch (hdspm->io_type) {
15730dca1793SAdrian Knoth case MADI:
15740dca1793SAdrian Knoth case AES32:
15750dca1793SAdrian Knoth freq_const = 110069313433624ULL;
15760dca1793SAdrian Knoth break;
15770dca1793SAdrian Knoth case RayDAT:
15780dca1793SAdrian Knoth case AIO:
15790dca1793SAdrian Knoth freq_const = 104857600000000ULL;
15800dca1793SAdrian Knoth break;
15810dca1793SAdrian Knoth case MADIface:
15820dca1793SAdrian Knoth freq_const = 131072000000000ULL;
15833d56c8e6STakashi Iwai break;
15843d56c8e6STakashi Iwai default:
15853d56c8e6STakashi Iwai snd_BUG();
15863d56c8e6STakashi Iwai return 0;
15870dca1793SAdrian Knoth }
15880dca1793SAdrian Knoth
15890dca1793SAdrian Knoth return div_u64(freq_const, period);
15900dca1793SAdrian Knoth }
15910dca1793SAdrian Knoth
15920dca1793SAdrian Knoth
hdspm_set_dds_value(struct hdspm * hdspm,int rate)1593ffb2c3c0SRemy Bruno static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
1594ffb2c3c0SRemy Bruno {
1595ffb2c3c0SRemy Bruno u64 n;
1596ffb2c3c0SRemy Bruno
1597c1099c32STakashi Iwai if (snd_BUG_ON(rate <= 0))
1598c1099c32STakashi Iwai return;
1599c1099c32STakashi Iwai
1600ffb2c3c0SRemy Bruno if (rate >= 112000)
1601ffb2c3c0SRemy Bruno rate /= 4;
1602ffb2c3c0SRemy Bruno else if (rate >= 56000)
1603ffb2c3c0SRemy Bruno rate /= 2;
1604ffb2c3c0SRemy Bruno
16050dca1793SAdrian Knoth switch (hdspm->io_type) {
16060dca1793SAdrian Knoth case MADIface:
16070dca1793SAdrian Knoth n = 131072000000000ULL; /* 125 MHz */
16080dca1793SAdrian Knoth break;
16090dca1793SAdrian Knoth case MADI:
16100dca1793SAdrian Knoth case AES32:
16110dca1793SAdrian Knoth n = 110069313433624ULL; /* 105 MHz */
16120dca1793SAdrian Knoth break;
16130dca1793SAdrian Knoth case RayDAT:
16140dca1793SAdrian Knoth case AIO:
16150dca1793SAdrian Knoth n = 104857600000000ULL; /* 100 MHz */
16160dca1793SAdrian Knoth break;
16173d56c8e6STakashi Iwai default:
16183d56c8e6STakashi Iwai snd_BUG();
16193d56c8e6STakashi Iwai return;
16200dca1793SAdrian Knoth }
16210dca1793SAdrian Knoth
16223f7440a6STakashi Iwai n = div_u64(n, rate);
1623ffb2c3c0SRemy Bruno /* n should be less than 2^32 for being written to FREQ register */
1624da3cec35STakashi Iwai snd_BUG_ON(n >> 32);
1625ffb2c3c0SRemy Bruno hdspm_write(hdspm, HDSPM_freqReg, (u32)n);
1626ffb2c3c0SRemy Bruno }
1627763f356cSTakashi Iwai
1628763f356cSTakashi Iwai /* dummy set rate lets see what happens */
hdspm_set_rate(struct hdspm * hdspm,int rate,int called_internally)162998274f07STakashi Iwai static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
1630763f356cSTakashi Iwai {
1631763f356cSTakashi Iwai int current_rate;
1632763f356cSTakashi Iwai int rate_bits;
1633763f356cSTakashi Iwai int not_set = 0;
16346534599dSRemy Bruno int current_speed, target_speed;
1635763f356cSTakashi Iwai
1636763f356cSTakashi Iwai /* ASSUMPTION: hdspm->lock is either set, or there is no need for
1637763f356cSTakashi Iwai it (e.g. during module initialization).
1638763f356cSTakashi Iwai */
1639763f356cSTakashi Iwai
1640763f356cSTakashi Iwai if (!(hdspm->control_register & HDSPM_ClockModeMaster)) {
1641763f356cSTakashi Iwai
1642763f356cSTakashi Iwai /* SLAVE --- */
1643763f356cSTakashi Iwai if (called_internally) {
1644763f356cSTakashi Iwai
1645763f356cSTakashi Iwai /* request from ctl or card initialization
1646763f356cSTakashi Iwai just make a warning an remember setting
1647763f356cSTakashi Iwai for future master mode switching */
1648763f356cSTakashi Iwai
1649e3a471d6STakashi Iwai dev_warn(hdspm->card->dev,
1650e3a471d6STakashi Iwai "Warning: device is not running as a clock master.\n");
1651763f356cSTakashi Iwai not_set = 1;
1652763f356cSTakashi Iwai } else {
1653763f356cSTakashi Iwai
1654763f356cSTakashi Iwai /* hw_param request while in AutoSync mode */
1655763f356cSTakashi Iwai int external_freq =
1656763f356cSTakashi Iwai hdspm_external_sample_rate(hdspm);
1657763f356cSTakashi Iwai
1658ef5fa1a4STakashi Iwai if (hdspm_autosync_ref(hdspm) ==
1659ef5fa1a4STakashi Iwai HDSPM_AUTOSYNC_FROM_NONE) {
1660763f356cSTakashi Iwai
1661e3a471d6STakashi Iwai dev_warn(hdspm->card->dev,
166207cb3272SColin Ian King "Detected no External Sync\n");
1663763f356cSTakashi Iwai not_set = 1;
1664763f356cSTakashi Iwai
1665763f356cSTakashi Iwai } else if (rate != external_freq) {
1666763f356cSTakashi Iwai
1667e3a471d6STakashi Iwai dev_warn(hdspm->card->dev,
1668e3a471d6STakashi Iwai "Warning: No AutoSync source for requested rate\n");
1669763f356cSTakashi Iwai not_set = 1;
1670763f356cSTakashi Iwai }
1671763f356cSTakashi Iwai }
1672763f356cSTakashi Iwai }
1673763f356cSTakashi Iwai
1674763f356cSTakashi Iwai current_rate = hdspm->system_sample_rate;
1675763f356cSTakashi Iwai
1676763f356cSTakashi Iwai /* Changing between Singe, Double and Quad speed is not
1677763f356cSTakashi Iwai allowed if any substreams are open. This is because such a change
1678763f356cSTakashi Iwai causes a shift in the location of the DMA buffers and a reduction
1679763f356cSTakashi Iwai in the number of available buffers.
1680763f356cSTakashi Iwai
1681763f356cSTakashi Iwai Note that a similar but essentially insoluble problem exists for
1682763f356cSTakashi Iwai externally-driven rate changes. All we can do is to flag rate
1683763f356cSTakashi Iwai changes in the read/write routines.
1684763f356cSTakashi Iwai */
1685763f356cSTakashi Iwai
16866534599dSRemy Bruno if (current_rate <= 48000)
16876534599dSRemy Bruno current_speed = HDSPM_SPEED_SINGLE;
16886534599dSRemy Bruno else if (current_rate <= 96000)
16896534599dSRemy Bruno current_speed = HDSPM_SPEED_DOUBLE;
16906534599dSRemy Bruno else
16916534599dSRemy Bruno current_speed = HDSPM_SPEED_QUAD;
16926534599dSRemy Bruno
16936534599dSRemy Bruno if (rate <= 48000)
16946534599dSRemy Bruno target_speed = HDSPM_SPEED_SINGLE;
16956534599dSRemy Bruno else if (rate <= 96000)
16966534599dSRemy Bruno target_speed = HDSPM_SPEED_DOUBLE;
16976534599dSRemy Bruno else
16986534599dSRemy Bruno target_speed = HDSPM_SPEED_QUAD;
16993cee5a60SRemy Bruno
1700763f356cSTakashi Iwai switch (rate) {
1701763f356cSTakashi Iwai case 32000:
1702763f356cSTakashi Iwai rate_bits = HDSPM_Frequency32KHz;
1703763f356cSTakashi Iwai break;
1704763f356cSTakashi Iwai case 44100:
1705763f356cSTakashi Iwai rate_bits = HDSPM_Frequency44_1KHz;
1706763f356cSTakashi Iwai break;
1707763f356cSTakashi Iwai case 48000:
1708763f356cSTakashi Iwai rate_bits = HDSPM_Frequency48KHz;
1709763f356cSTakashi Iwai break;
1710763f356cSTakashi Iwai case 64000:
1711763f356cSTakashi Iwai rate_bits = HDSPM_Frequency64KHz;
1712763f356cSTakashi Iwai break;
1713763f356cSTakashi Iwai case 88200:
1714763f356cSTakashi Iwai rate_bits = HDSPM_Frequency88_2KHz;
1715763f356cSTakashi Iwai break;
1716763f356cSTakashi Iwai case 96000:
1717763f356cSTakashi Iwai rate_bits = HDSPM_Frequency96KHz;
1718763f356cSTakashi Iwai break;
17193cee5a60SRemy Bruno case 128000:
17203cee5a60SRemy Bruno rate_bits = HDSPM_Frequency128KHz;
17213cee5a60SRemy Bruno break;
17223cee5a60SRemy Bruno case 176400:
17233cee5a60SRemy Bruno rate_bits = HDSPM_Frequency176_4KHz;
17243cee5a60SRemy Bruno break;
17253cee5a60SRemy Bruno case 192000:
17263cee5a60SRemy Bruno rate_bits = HDSPM_Frequency192KHz;
17273cee5a60SRemy Bruno break;
1728763f356cSTakashi Iwai default:
1729763f356cSTakashi Iwai return -EINVAL;
1730763f356cSTakashi Iwai }
1731763f356cSTakashi Iwai
17326534599dSRemy Bruno if (current_speed != target_speed
1733763f356cSTakashi Iwai && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) {
1734e3a471d6STakashi Iwai dev_err(hdspm->card->dev,
1735e3a471d6STakashi Iwai "cannot change from %s speed to %s speed mode (capture PID = %d, playback PID = %d)\n",
17366534599dSRemy Bruno hdspm_speed_names[current_speed],
17376534599dSRemy Bruno hdspm_speed_names[target_speed],
1738763f356cSTakashi Iwai hdspm->capture_pid, hdspm->playback_pid);
1739763f356cSTakashi Iwai return -EBUSY;
1740763f356cSTakashi Iwai }
1741763f356cSTakashi Iwai
1742763f356cSTakashi Iwai hdspm->control_register &= ~HDSPM_FrequencyMask;
1743763f356cSTakashi Iwai hdspm->control_register |= rate_bits;
1744763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
1745763f356cSTakashi Iwai
1746ffb2c3c0SRemy Bruno /* For AES32, need to set DDS value in FREQ register
1747ffb2c3c0SRemy Bruno For MADI, also apparently */
1748ffb2c3c0SRemy Bruno hdspm_set_dds_value(hdspm, rate);
1749ffb2c3c0SRemy Bruno
17500dca1793SAdrian Knoth if (AES32 == hdspm->io_type && rate != current_rate)
1751ffb2c3c0SRemy Bruno hdspm_write(hdspm, HDSPM_eeprom_wr, 0);
1752ffb2c3c0SRemy Bruno
1753763f356cSTakashi Iwai hdspm->system_sample_rate = rate;
1754763f356cSTakashi Iwai
17550dca1793SAdrian Knoth if (rate <= 48000) {
17560dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_in_ss;
17570dca1793SAdrian Knoth hdspm->channel_map_out = hdspm->channel_map_out_ss;
17580dca1793SAdrian Knoth hdspm->max_channels_in = hdspm->ss_in_channels;
17590dca1793SAdrian Knoth hdspm->max_channels_out = hdspm->ss_out_channels;
17600dca1793SAdrian Knoth hdspm->port_names_in = hdspm->port_names_in_ss;
17610dca1793SAdrian Knoth hdspm->port_names_out = hdspm->port_names_out_ss;
17620dca1793SAdrian Knoth } else if (rate <= 96000) {
17630dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_in_ds;
17640dca1793SAdrian Knoth hdspm->channel_map_out = hdspm->channel_map_out_ds;
17650dca1793SAdrian Knoth hdspm->max_channels_in = hdspm->ds_in_channels;
17660dca1793SAdrian Knoth hdspm->max_channels_out = hdspm->ds_out_channels;
17670dca1793SAdrian Knoth hdspm->port_names_in = hdspm->port_names_in_ds;
17680dca1793SAdrian Knoth hdspm->port_names_out = hdspm->port_names_out_ds;
17690dca1793SAdrian Knoth } else {
17700dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_in_qs;
17710dca1793SAdrian Knoth hdspm->channel_map_out = hdspm->channel_map_out_qs;
17720dca1793SAdrian Knoth hdspm->max_channels_in = hdspm->qs_in_channels;
17730dca1793SAdrian Knoth hdspm->max_channels_out = hdspm->qs_out_channels;
17740dca1793SAdrian Knoth hdspm->port_names_in = hdspm->port_names_in_qs;
17750dca1793SAdrian Knoth hdspm->port_names_out = hdspm->port_names_out_qs;
17760dca1793SAdrian Knoth }
17770dca1793SAdrian Knoth
1778763f356cSTakashi Iwai if (not_set != 0)
1779763f356cSTakashi Iwai return -1;
1780763f356cSTakashi Iwai
1781763f356cSTakashi Iwai return 0;
1782763f356cSTakashi Iwai }
1783763f356cSTakashi Iwai
1784763f356cSTakashi Iwai /* mainly for init to 0 on load */
all_in_all_mixer(struct hdspm * hdspm,int sgain)178598274f07STakashi Iwai static void all_in_all_mixer(struct hdspm * hdspm, int sgain)
1786763f356cSTakashi Iwai {
1787763f356cSTakashi Iwai int i, j;
1788ef5fa1a4STakashi Iwai unsigned int gain;
1789ef5fa1a4STakashi Iwai
1790ef5fa1a4STakashi Iwai if (sgain > UNITY_GAIN)
1791ef5fa1a4STakashi Iwai gain = UNITY_GAIN;
1792ef5fa1a4STakashi Iwai else if (sgain < 0)
1793ef5fa1a4STakashi Iwai gain = 0;
1794ef5fa1a4STakashi Iwai else
1795ef5fa1a4STakashi Iwai gain = sgain;
1796763f356cSTakashi Iwai
1797763f356cSTakashi Iwai for (i = 0; i < HDSPM_MIXER_CHANNELS; i++)
1798763f356cSTakashi Iwai for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) {
1799763f356cSTakashi Iwai hdspm_write_in_gain(hdspm, i, j, gain);
1800763f356cSTakashi Iwai hdspm_write_pb_gain(hdspm, i, j, gain);
1801763f356cSTakashi Iwai }
1802763f356cSTakashi Iwai }
1803763f356cSTakashi Iwai
1804763f356cSTakashi Iwai /*----------------------------------------------------------------------------
1805763f356cSTakashi Iwai MIDI
1806763f356cSTakashi Iwai ----------------------------------------------------------------------------*/
1807763f356cSTakashi Iwai
snd_hdspm_midi_read_byte(struct hdspm * hdspm,int id)1808ef5fa1a4STakashi Iwai static inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm,
1809ef5fa1a4STakashi Iwai int id)
1810763f356cSTakashi Iwai {
1811763f356cSTakashi Iwai /* the hardware already does the relevant bit-mask with 0xff */
18120dca1793SAdrian Knoth return hdspm_read(hdspm, hdspm->midi[id].dataIn);
1813763f356cSTakashi Iwai }
1814763f356cSTakashi Iwai
snd_hdspm_midi_write_byte(struct hdspm * hdspm,int id,int val)1815ef5fa1a4STakashi Iwai static inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id,
1816ef5fa1a4STakashi Iwai int val)
1817763f356cSTakashi Iwai {
1818763f356cSTakashi Iwai /* the hardware already does the relevant bit-mask with 0xff */
18190dca1793SAdrian Knoth return hdspm_write(hdspm, hdspm->midi[id].dataOut, val);
1820763f356cSTakashi Iwai }
1821763f356cSTakashi Iwai
snd_hdspm_midi_input_available(struct hdspm * hdspm,int id)182298274f07STakashi Iwai static inline int snd_hdspm_midi_input_available (struct hdspm *hdspm, int id)
1823763f356cSTakashi Iwai {
18240dca1793SAdrian Knoth return hdspm_read(hdspm, hdspm->midi[id].statusIn) & 0xFF;
1825763f356cSTakashi Iwai }
1826763f356cSTakashi Iwai
snd_hdspm_midi_output_possible(struct hdspm * hdspm,int id)182798274f07STakashi Iwai static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id)
1828763f356cSTakashi Iwai {
1829763f356cSTakashi Iwai int fifo_bytes_used;
1830763f356cSTakashi Iwai
18310dca1793SAdrian Knoth fifo_bytes_used = hdspm_read(hdspm, hdspm->midi[id].statusOut) & 0xFF;
1832763f356cSTakashi Iwai
1833763f356cSTakashi Iwai if (fifo_bytes_used < 128)
1834763f356cSTakashi Iwai return 128 - fifo_bytes_used;
1835763f356cSTakashi Iwai else
1836763f356cSTakashi Iwai return 0;
1837763f356cSTakashi Iwai }
1838763f356cSTakashi Iwai
snd_hdspm_flush_midi_input(struct hdspm * hdspm,int id)183962cef821SDenys Vlasenko static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id)
1840763f356cSTakashi Iwai {
1841*6cc4e5eaSTakashi Iwai int count = 256;
1842*6cc4e5eaSTakashi Iwai
1843*6cc4e5eaSTakashi Iwai while (snd_hdspm_midi_input_available(hdspm, id) && --count)
1844763f356cSTakashi Iwai snd_hdspm_midi_read_byte(hdspm, id);
1845763f356cSTakashi Iwai }
1846763f356cSTakashi Iwai
snd_hdspm_midi_output_write(struct hdspm_midi * hmidi)184798274f07STakashi Iwai static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi)
1848763f356cSTakashi Iwai {
1849763f356cSTakashi Iwai unsigned long flags;
1850763f356cSTakashi Iwai int n_pending;
1851763f356cSTakashi Iwai int to_write;
1852763f356cSTakashi Iwai int i;
1853763f356cSTakashi Iwai unsigned char buf[128];
1854763f356cSTakashi Iwai
1855763f356cSTakashi Iwai /* Output is not interrupt driven */
1856763f356cSTakashi Iwai
1857763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags);
1858ef5fa1a4STakashi Iwai if (hmidi->output &&
1859ef5fa1a4STakashi Iwai !snd_rawmidi_transmit_empty (hmidi->output)) {
1860ef5fa1a4STakashi Iwai n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm,
1861ef5fa1a4STakashi Iwai hmidi->id);
1862ef5fa1a4STakashi Iwai if (n_pending > 0) {
1863763f356cSTakashi Iwai if (n_pending > (int)sizeof (buf))
1864763f356cSTakashi Iwai n_pending = sizeof (buf);
1865763f356cSTakashi Iwai
1866ef5fa1a4STakashi Iwai to_write = snd_rawmidi_transmit (hmidi->output, buf,
1867ef5fa1a4STakashi Iwai n_pending);
1868ef5fa1a4STakashi Iwai if (to_write > 0) {
1869763f356cSTakashi Iwai for (i = 0; i < to_write; ++i)
1870ef5fa1a4STakashi Iwai snd_hdspm_midi_write_byte (hmidi->hdspm,
1871ef5fa1a4STakashi Iwai hmidi->id,
1872ef5fa1a4STakashi Iwai buf[i]);
1873763f356cSTakashi Iwai }
1874763f356cSTakashi Iwai }
1875763f356cSTakashi Iwai }
1876763f356cSTakashi Iwai spin_unlock_irqrestore (&hmidi->lock, flags);
1877763f356cSTakashi Iwai return 0;
1878763f356cSTakashi Iwai }
1879763f356cSTakashi Iwai
snd_hdspm_midi_input_read(struct hdspm_midi * hmidi)188098274f07STakashi Iwai static int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi)
1881763f356cSTakashi Iwai {
1882ef5fa1a4STakashi Iwai unsigned char buf[128]; /* this buffer is designed to match the MIDI
1883ef5fa1a4STakashi Iwai * input FIFO size
1884ef5fa1a4STakashi Iwai */
1885763f356cSTakashi Iwai unsigned long flags;
1886763f356cSTakashi Iwai int n_pending;
1887763f356cSTakashi Iwai int i;
1888763f356cSTakashi Iwai
1889763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags);
1890ef5fa1a4STakashi Iwai n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id);
1891ef5fa1a4STakashi Iwai if (n_pending > 0) {
1892763f356cSTakashi Iwai if (hmidi->input) {
1893ef5fa1a4STakashi Iwai if (n_pending > (int)sizeof (buf))
1894763f356cSTakashi Iwai n_pending = sizeof (buf);
1895ef5fa1a4STakashi Iwai for (i = 0; i < n_pending; ++i)
1896ef5fa1a4STakashi Iwai buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm,
1897ef5fa1a4STakashi Iwai hmidi->id);
1898ef5fa1a4STakashi Iwai if (n_pending)
1899ef5fa1a4STakashi Iwai snd_rawmidi_receive (hmidi->input, buf,
1900ef5fa1a4STakashi Iwai n_pending);
1901763f356cSTakashi Iwai } else {
1902763f356cSTakashi Iwai /* flush the MIDI input FIFO */
1903ef5fa1a4STakashi Iwai while (n_pending--)
1904ef5fa1a4STakashi Iwai snd_hdspm_midi_read_byte (hmidi->hdspm,
1905ef5fa1a4STakashi Iwai hmidi->id);
1906763f356cSTakashi Iwai }
1907763f356cSTakashi Iwai }
1908763f356cSTakashi Iwai hmidi->pending = 0;
1909c0da0014SAdrian Knoth spin_unlock_irqrestore(&hmidi->lock, flags);
19100dca1793SAdrian Knoth
1911c0da0014SAdrian Knoth spin_lock_irqsave(&hmidi->hdspm->lock, flags);
19120dca1793SAdrian Knoth hmidi->hdspm->control_register |= hmidi->ie;
1913ef5fa1a4STakashi Iwai hdspm_write(hmidi->hdspm, HDSPM_controlRegister,
1914ef5fa1a4STakashi Iwai hmidi->hdspm->control_register);
1915c0da0014SAdrian Knoth spin_unlock_irqrestore(&hmidi->hdspm->lock, flags);
19160dca1793SAdrian Knoth
1917763f356cSTakashi Iwai return snd_hdspm_midi_output_write (hmidi);
1918763f356cSTakashi Iwai }
1919763f356cSTakashi Iwai
1920ef5fa1a4STakashi Iwai static void
snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream * substream,int up)1921ef5fa1a4STakashi Iwai snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
1922763f356cSTakashi Iwai {
192398274f07STakashi Iwai struct hdspm *hdspm;
192498274f07STakashi Iwai struct hdspm_midi *hmidi;
1925763f356cSTakashi Iwai unsigned long flags;
1926763f356cSTakashi Iwai
1927ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data;
1928763f356cSTakashi Iwai hdspm = hmidi->hdspm;
19290dca1793SAdrian Knoth
1930763f356cSTakashi Iwai spin_lock_irqsave (&hdspm->lock, flags);
1931763f356cSTakashi Iwai if (up) {
19320dca1793SAdrian Knoth if (!(hdspm->control_register & hmidi->ie)) {
1933763f356cSTakashi Iwai snd_hdspm_flush_midi_input (hdspm, hmidi->id);
19340dca1793SAdrian Knoth hdspm->control_register |= hmidi->ie;
1935763f356cSTakashi Iwai }
1936763f356cSTakashi Iwai } else {
19370dca1793SAdrian Knoth hdspm->control_register &= ~hmidi->ie;
1938763f356cSTakashi Iwai }
1939763f356cSTakashi Iwai
1940763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
1941763f356cSTakashi Iwai spin_unlock_irqrestore (&hdspm->lock, flags);
1942763f356cSTakashi Iwai }
1943763f356cSTakashi Iwai
snd_hdspm_midi_output_timer(struct timer_list * t)19447211ec63SKees Cook static void snd_hdspm_midi_output_timer(struct timer_list *t)
1945763f356cSTakashi Iwai {
19467211ec63SKees Cook struct hdspm_midi *hmidi = from_timer(hmidi, t, timer);
1947763f356cSTakashi Iwai unsigned long flags;
1948763f356cSTakashi Iwai
1949763f356cSTakashi Iwai snd_hdspm_midi_output_write(hmidi);
1950763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags);
1951763f356cSTakashi Iwai
1952763f356cSTakashi Iwai /* this does not bump hmidi->istimer, because the
1953763f356cSTakashi Iwai kernel automatically removed the timer when it
1954763f356cSTakashi Iwai expired, and we are now adding it back, thus
1955763f356cSTakashi Iwai leaving istimer wherever it was set before.
1956763f356cSTakashi Iwai */
1957763f356cSTakashi Iwai
195804018e13STakashi Iwai if (hmidi->istimer)
195904018e13STakashi Iwai mod_timer(&hmidi->timer, 1 + jiffies);
1960763f356cSTakashi Iwai
1961763f356cSTakashi Iwai spin_unlock_irqrestore (&hmidi->lock, flags);
1962763f356cSTakashi Iwai }
1963763f356cSTakashi Iwai
1964ef5fa1a4STakashi Iwai static void
snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream * substream,int up)1965ef5fa1a4STakashi Iwai snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
1966763f356cSTakashi Iwai {
196798274f07STakashi Iwai struct hdspm_midi *hmidi;
1968763f356cSTakashi Iwai unsigned long flags;
1969763f356cSTakashi Iwai
1970ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data;
1971763f356cSTakashi Iwai spin_lock_irqsave (&hmidi->lock, flags);
1972763f356cSTakashi Iwai if (up) {
1973763f356cSTakashi Iwai if (!hmidi->istimer) {
19747211ec63SKees Cook timer_setup(&hmidi->timer,
19757211ec63SKees Cook snd_hdspm_midi_output_timer, 0);
197604018e13STakashi Iwai mod_timer(&hmidi->timer, 1 + jiffies);
1977763f356cSTakashi Iwai hmidi->istimer++;
1978763f356cSTakashi Iwai }
1979763f356cSTakashi Iwai } else {
1980ef5fa1a4STakashi Iwai if (hmidi->istimer && --hmidi->istimer <= 0)
1981763f356cSTakashi Iwai del_timer (&hmidi->timer);
1982763f356cSTakashi Iwai }
1983763f356cSTakashi Iwai spin_unlock_irqrestore (&hmidi->lock, flags);
1984763f356cSTakashi Iwai if (up)
1985763f356cSTakashi Iwai snd_hdspm_midi_output_write(hmidi);
1986763f356cSTakashi Iwai }
1987763f356cSTakashi Iwai
snd_hdspm_midi_input_open(struct snd_rawmidi_substream * substream)198898274f07STakashi Iwai static int snd_hdspm_midi_input_open(struct snd_rawmidi_substream *substream)
1989763f356cSTakashi Iwai {
199098274f07STakashi Iwai struct hdspm_midi *hmidi;
1991763f356cSTakashi Iwai
1992ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data;
1993763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock);
1994763f356cSTakashi Iwai snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id);
1995763f356cSTakashi Iwai hmidi->input = substream;
1996763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock);
1997763f356cSTakashi Iwai
1998763f356cSTakashi Iwai return 0;
1999763f356cSTakashi Iwai }
2000763f356cSTakashi Iwai
snd_hdspm_midi_output_open(struct snd_rawmidi_substream * substream)200198274f07STakashi Iwai static int snd_hdspm_midi_output_open(struct snd_rawmidi_substream *substream)
2002763f356cSTakashi Iwai {
200398274f07STakashi Iwai struct hdspm_midi *hmidi;
2004763f356cSTakashi Iwai
2005ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data;
2006763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock);
2007763f356cSTakashi Iwai hmidi->output = substream;
2008763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock);
2009763f356cSTakashi Iwai
2010763f356cSTakashi Iwai return 0;
2011763f356cSTakashi Iwai }
2012763f356cSTakashi Iwai
snd_hdspm_midi_input_close(struct snd_rawmidi_substream * substream)201398274f07STakashi Iwai static int snd_hdspm_midi_input_close(struct snd_rawmidi_substream *substream)
2014763f356cSTakashi Iwai {
201598274f07STakashi Iwai struct hdspm_midi *hmidi;
2016763f356cSTakashi Iwai
2017763f356cSTakashi Iwai snd_hdspm_midi_input_trigger (substream, 0);
2018763f356cSTakashi Iwai
2019ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data;
2020763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock);
2021763f356cSTakashi Iwai hmidi->input = NULL;
2022763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock);
2023763f356cSTakashi Iwai
2024763f356cSTakashi Iwai return 0;
2025763f356cSTakashi Iwai }
2026763f356cSTakashi Iwai
snd_hdspm_midi_output_close(struct snd_rawmidi_substream * substream)202798274f07STakashi Iwai static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream)
2028763f356cSTakashi Iwai {
202998274f07STakashi Iwai struct hdspm_midi *hmidi;
2030763f356cSTakashi Iwai
2031763f356cSTakashi Iwai snd_hdspm_midi_output_trigger (substream, 0);
2032763f356cSTakashi Iwai
2033ef5fa1a4STakashi Iwai hmidi = substream->rmidi->private_data;
2034763f356cSTakashi Iwai spin_lock_irq (&hmidi->lock);
2035763f356cSTakashi Iwai hmidi->output = NULL;
2036763f356cSTakashi Iwai spin_unlock_irq (&hmidi->lock);
2037763f356cSTakashi Iwai
2038763f356cSTakashi Iwai return 0;
2039763f356cSTakashi Iwai }
2040763f356cSTakashi Iwai
2041485885b9STakashi Iwai static const struct snd_rawmidi_ops snd_hdspm_midi_output =
2042763f356cSTakashi Iwai {
2043763f356cSTakashi Iwai .open = snd_hdspm_midi_output_open,
2044763f356cSTakashi Iwai .close = snd_hdspm_midi_output_close,
2045763f356cSTakashi Iwai .trigger = snd_hdspm_midi_output_trigger,
2046763f356cSTakashi Iwai };
2047763f356cSTakashi Iwai
2048485885b9STakashi Iwai static const struct snd_rawmidi_ops snd_hdspm_midi_input =
2049763f356cSTakashi Iwai {
2050763f356cSTakashi Iwai .open = snd_hdspm_midi_input_open,
2051763f356cSTakashi Iwai .close = snd_hdspm_midi_input_close,
2052763f356cSTakashi Iwai .trigger = snd_hdspm_midi_input_trigger,
2053763f356cSTakashi Iwai };
2054763f356cSTakashi Iwai
snd_hdspm_create_midi(struct snd_card * card,struct hdspm * hdspm,int id)2055e23e7a14SBill Pemberton static int snd_hdspm_create_midi(struct snd_card *card,
2056ef5fa1a4STakashi Iwai struct hdspm *hdspm, int id)
2057763f356cSTakashi Iwai {
2058763f356cSTakashi Iwai int err;
20597ad210acSArnd Bergmann char buf[64];
2060763f356cSTakashi Iwai
2061763f356cSTakashi Iwai hdspm->midi[id].id = id;
2062763f356cSTakashi Iwai hdspm->midi[id].hdspm = hdspm;
2063763f356cSTakashi Iwai spin_lock_init (&hdspm->midi[id].lock);
2064763f356cSTakashi Iwai
20650dca1793SAdrian Knoth if (0 == id) {
20660dca1793SAdrian Knoth if (MADIface == hdspm->io_type) {
20670dca1793SAdrian Knoth /* MIDI-over-MADI on HDSPe MADIface */
20680dca1793SAdrian Knoth hdspm->midi[0].dataIn = HDSPM_midiDataIn2;
20690dca1793SAdrian Knoth hdspm->midi[0].statusIn = HDSPM_midiStatusIn2;
20700dca1793SAdrian Knoth hdspm->midi[0].dataOut = HDSPM_midiDataOut2;
20710dca1793SAdrian Knoth hdspm->midi[0].statusOut = HDSPM_midiStatusOut2;
20720dca1793SAdrian Knoth hdspm->midi[0].ie = HDSPM_Midi2InterruptEnable;
20730dca1793SAdrian Knoth hdspm->midi[0].irq = HDSPM_midi2IRQPending;
20740dca1793SAdrian Knoth } else {
20750dca1793SAdrian Knoth hdspm->midi[0].dataIn = HDSPM_midiDataIn0;
20760dca1793SAdrian Knoth hdspm->midi[0].statusIn = HDSPM_midiStatusIn0;
20770dca1793SAdrian Knoth hdspm->midi[0].dataOut = HDSPM_midiDataOut0;
20780dca1793SAdrian Knoth hdspm->midi[0].statusOut = HDSPM_midiStatusOut0;
20790dca1793SAdrian Knoth hdspm->midi[0].ie = HDSPM_Midi0InterruptEnable;
20800dca1793SAdrian Knoth hdspm->midi[0].irq = HDSPM_midi0IRQPending;
20810dca1793SAdrian Knoth }
20820dca1793SAdrian Knoth } else if (1 == id) {
20830dca1793SAdrian Knoth hdspm->midi[1].dataIn = HDSPM_midiDataIn1;
20840dca1793SAdrian Knoth hdspm->midi[1].statusIn = HDSPM_midiStatusIn1;
20850dca1793SAdrian Knoth hdspm->midi[1].dataOut = HDSPM_midiDataOut1;
20860dca1793SAdrian Knoth hdspm->midi[1].statusOut = HDSPM_midiStatusOut1;
20870dca1793SAdrian Knoth hdspm->midi[1].ie = HDSPM_Midi1InterruptEnable;
20880dca1793SAdrian Knoth hdspm->midi[1].irq = HDSPM_midi1IRQPending;
20890dca1793SAdrian Knoth } else if ((2 == id) && (MADI == hdspm->io_type)) {
20900dca1793SAdrian Knoth /* MIDI-over-MADI on HDSPe MADI */
20910dca1793SAdrian Knoth hdspm->midi[2].dataIn = HDSPM_midiDataIn2;
20920dca1793SAdrian Knoth hdspm->midi[2].statusIn = HDSPM_midiStatusIn2;
20930dca1793SAdrian Knoth hdspm->midi[2].dataOut = HDSPM_midiDataOut2;
20940dca1793SAdrian Knoth hdspm->midi[2].statusOut = HDSPM_midiStatusOut2;
20950dca1793SAdrian Knoth hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable;
20960dca1793SAdrian Knoth hdspm->midi[2].irq = HDSPM_midi2IRQPending;
20970dca1793SAdrian Knoth } else if (2 == id) {
20980dca1793SAdrian Knoth /* TCO MTC, read only */
20990dca1793SAdrian Knoth hdspm->midi[2].dataIn = HDSPM_midiDataIn2;
21000dca1793SAdrian Knoth hdspm->midi[2].statusIn = HDSPM_midiStatusIn2;
21010dca1793SAdrian Knoth hdspm->midi[2].dataOut = -1;
21020dca1793SAdrian Knoth hdspm->midi[2].statusOut = -1;
21030dca1793SAdrian Knoth hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable;
21040dca1793SAdrian Knoth hdspm->midi[2].irq = HDSPM_midi2IRQPendingAES;
21050dca1793SAdrian Knoth } else if (3 == id) {
21060dca1793SAdrian Knoth /* TCO MTC on HDSPe MADI */
21070dca1793SAdrian Knoth hdspm->midi[3].dataIn = HDSPM_midiDataIn3;
21080dca1793SAdrian Knoth hdspm->midi[3].statusIn = HDSPM_midiStatusIn3;
21090dca1793SAdrian Knoth hdspm->midi[3].dataOut = -1;
21100dca1793SAdrian Knoth hdspm->midi[3].statusOut = -1;
21110dca1793SAdrian Knoth hdspm->midi[3].ie = HDSPM_Midi3InterruptEnable;
21120dca1793SAdrian Knoth hdspm->midi[3].irq = HDSPM_midi3IRQPending;
21130dca1793SAdrian Knoth }
21140dca1793SAdrian Knoth
21150dca1793SAdrian Knoth if ((id < 2) || ((2 == id) && ((MADI == hdspm->io_type) ||
21160dca1793SAdrian Knoth (MADIface == hdspm->io_type)))) {
21170dca1793SAdrian Knoth if ((id == 0) && (MADIface == hdspm->io_type)) {
21187ad210acSArnd Bergmann snprintf(buf, sizeof(buf), "%s MIDIoverMADI",
21197ad210acSArnd Bergmann card->shortname);
21200dca1793SAdrian Knoth } else if ((id == 2) && (MADI == hdspm->io_type)) {
21217ad210acSArnd Bergmann snprintf(buf, sizeof(buf), "%s MIDIoverMADI",
21227ad210acSArnd Bergmann card->shortname);
21230dca1793SAdrian Knoth } else {
21247ad210acSArnd Bergmann snprintf(buf, sizeof(buf), "%s MIDI %d",
21257ad210acSArnd Bergmann card->shortname, id+1);
21260dca1793SAdrian Knoth }
21270dca1793SAdrian Knoth err = snd_rawmidi_new(card, buf, id, 1, 1,
21280dca1793SAdrian Knoth &hdspm->midi[id].rmidi);
2129ef5fa1a4STakashi Iwai if (err < 0)
2130763f356cSTakashi Iwai return err;
2131763f356cSTakashi Iwai
21327ad210acSArnd Bergmann snprintf(hdspm->midi[id].rmidi->name,
21337ad210acSArnd Bergmann sizeof(hdspm->midi[id].rmidi->name),
21347ad210acSArnd Bergmann "%s MIDI %d", card->id, id+1);
2135763f356cSTakashi Iwai hdspm->midi[id].rmidi->private_data = &hdspm->midi[id];
2136763f356cSTakashi Iwai
21370dca1793SAdrian Knoth snd_rawmidi_set_ops(hdspm->midi[id].rmidi,
21380dca1793SAdrian Knoth SNDRV_RAWMIDI_STREAM_OUTPUT,
2139ef5fa1a4STakashi Iwai &snd_hdspm_midi_output);
21400dca1793SAdrian Knoth snd_rawmidi_set_ops(hdspm->midi[id].rmidi,
21410dca1793SAdrian Knoth SNDRV_RAWMIDI_STREAM_INPUT,
2142ef5fa1a4STakashi Iwai &snd_hdspm_midi_input);
2143763f356cSTakashi Iwai
21440dca1793SAdrian Knoth hdspm->midi[id].rmidi->info_flags |=
21450dca1793SAdrian Knoth SNDRV_RAWMIDI_INFO_OUTPUT |
2146763f356cSTakashi Iwai SNDRV_RAWMIDI_INFO_INPUT |
2147763f356cSTakashi Iwai SNDRV_RAWMIDI_INFO_DUPLEX;
21480dca1793SAdrian Knoth } else {
21490dca1793SAdrian Knoth /* TCO MTC, read only */
21507ad210acSArnd Bergmann snprintf(buf, sizeof(buf), "%s MTC %d",
21517ad210acSArnd Bergmann card->shortname, id+1);
21520dca1793SAdrian Knoth err = snd_rawmidi_new(card, buf, id, 1, 1,
21530dca1793SAdrian Knoth &hdspm->midi[id].rmidi);
21540dca1793SAdrian Knoth if (err < 0)
21550dca1793SAdrian Knoth return err;
21560dca1793SAdrian Knoth
21577ad210acSArnd Bergmann snprintf(hdspm->midi[id].rmidi->name,
21587ad210acSArnd Bergmann sizeof(hdspm->midi[id].rmidi->name),
21590dca1793SAdrian Knoth "%s MTC %d", card->id, id+1);
21600dca1793SAdrian Knoth hdspm->midi[id].rmidi->private_data = &hdspm->midi[id];
21610dca1793SAdrian Knoth
21620dca1793SAdrian Knoth snd_rawmidi_set_ops(hdspm->midi[id].rmidi,
21630dca1793SAdrian Knoth SNDRV_RAWMIDI_STREAM_INPUT,
21640dca1793SAdrian Knoth &snd_hdspm_midi_input);
21650dca1793SAdrian Knoth
21660dca1793SAdrian Knoth hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
21670dca1793SAdrian Knoth }
2168763f356cSTakashi Iwai
2169763f356cSTakashi Iwai return 0;
2170763f356cSTakashi Iwai }
2171763f356cSTakashi Iwai
2172763f356cSTakashi Iwai
hdspm_midi_work(struct work_struct * work)2173a2e527c5STakashi Iwai static void hdspm_midi_work(struct work_struct *work)
2174763f356cSTakashi Iwai {
2175a2e527c5STakashi Iwai struct hdspm *hdspm = container_of(work, struct hdspm, midi_work);
21760dca1793SAdrian Knoth int i = 0;
2177763f356cSTakashi Iwai
21780dca1793SAdrian Knoth while (i < hdspm->midiPorts) {
21790dca1793SAdrian Knoth if (hdspm->midi[i].pending)
21800dca1793SAdrian Knoth snd_hdspm_midi_input_read(&hdspm->midi[i]);
21810dca1793SAdrian Knoth
21820dca1793SAdrian Knoth i++;
21830dca1793SAdrian Knoth }
2184763f356cSTakashi Iwai }
2185763f356cSTakashi Iwai
2186763f356cSTakashi Iwai
2187763f356cSTakashi Iwai /*-----------------------------------------------------------------------------
2188763f356cSTakashi Iwai Status Interface
2189763f356cSTakashi Iwai ----------------------------------------------------------------------------*/
2190763f356cSTakashi Iwai
2191763f356cSTakashi Iwai /* get the system sample rate which is set */
2192763f356cSTakashi Iwai
21930dca1793SAdrian Knoth
hdspm_get_pll_freq(struct hdspm * hdspm)21943f7bf918SAdrian Knoth static inline int hdspm_get_pll_freq(struct hdspm *hdspm)
21953f7bf918SAdrian Knoth {
21963f7bf918SAdrian Knoth unsigned int period, rate;
21973f7bf918SAdrian Knoth
21983f7bf918SAdrian Knoth period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
21993f7bf918SAdrian Knoth rate = hdspm_calc_dds_value(hdspm, period);
22003f7bf918SAdrian Knoth
22013f7bf918SAdrian Knoth return rate;
22023f7bf918SAdrian Knoth }
22033f7bf918SAdrian Knoth
2204ddcecf6bSTakashi Iwai /*
22050dca1793SAdrian Knoth * Calculate the real sample rate from the
22060dca1793SAdrian Knoth * current DDS value.
2207ddcecf6bSTakashi Iwai */
hdspm_get_system_sample_rate(struct hdspm * hdspm)22080dca1793SAdrian Knoth static int hdspm_get_system_sample_rate(struct hdspm *hdspm)
22090dca1793SAdrian Knoth {
22103f7bf918SAdrian Knoth unsigned int rate;
22110dca1793SAdrian Knoth
22123f7bf918SAdrian Knoth rate = hdspm_get_pll_freq(hdspm);
22130dca1793SAdrian Knoth
2214a97bda7dSAdrian Knoth if (rate > 207000) {
221521a164dfSAdrian Knoth /* Unreasonable high sample rate as seen on PCI MADI cards. */
221621a164dfSAdrian Knoth if (0 == hdspm_system_clock_mode(hdspm)) {
221721a164dfSAdrian Knoth /* master mode, return internal sample rate */
2218a97bda7dSAdrian Knoth rate = hdspm->system_sample_rate;
221921a164dfSAdrian Knoth } else {
222021a164dfSAdrian Knoth /* slave mode, return external sample rate */
222121a164dfSAdrian Knoth rate = hdspm_external_sample_rate(hdspm);
2222c1099c32STakashi Iwai if (!rate)
2223c1099c32STakashi Iwai rate = hdspm->system_sample_rate;
222421a164dfSAdrian Knoth }
2225a97bda7dSAdrian Knoth }
2226a97bda7dSAdrian Knoth
22270dca1793SAdrian Knoth return rate;
22280dca1793SAdrian Knoth }
22290dca1793SAdrian Knoth
22300dca1793SAdrian Knoth
2231763f356cSTakashi Iwai #define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \
223267ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2233763f356cSTakashi Iwai .name = xname, \
2234763f356cSTakashi Iwai .index = xindex, \
223541285a98SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
223641285a98SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
2237763f356cSTakashi Iwai .info = snd_hdspm_info_system_sample_rate, \
223841285a98SAdrian Knoth .put = snd_hdspm_put_system_sample_rate, \
2239763f356cSTakashi Iwai .get = snd_hdspm_get_system_sample_rate \
2240763f356cSTakashi Iwai }
2241763f356cSTakashi Iwai
snd_hdspm_info_system_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)224298274f07STakashi Iwai static int snd_hdspm_info_system_sample_rate(struct snd_kcontrol *kcontrol,
224398274f07STakashi Iwai struct snd_ctl_elem_info *uinfo)
2244763f356cSTakashi Iwai {
2245763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2246763f356cSTakashi Iwai uinfo->count = 1;
22470dca1793SAdrian Knoth uinfo->value.integer.min = 27000;
22480dca1793SAdrian Knoth uinfo->value.integer.max = 207000;
22490dca1793SAdrian Knoth uinfo->value.integer.step = 1;
2250763f356cSTakashi Iwai return 0;
2251763f356cSTakashi Iwai }
2252763f356cSTakashi Iwai
22530dca1793SAdrian Knoth
snd_hdspm_get_system_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)225498274f07STakashi Iwai static int snd_hdspm_get_system_sample_rate(struct snd_kcontrol *kcontrol,
225598274f07STakashi Iwai struct snd_ctl_elem_value *
2256763f356cSTakashi Iwai ucontrol)
2257763f356cSTakashi Iwai {
225898274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2259763f356cSTakashi Iwai
22600dca1793SAdrian Knoth ucontrol->value.integer.value[0] = hdspm_get_system_sample_rate(hdspm);
2261763f356cSTakashi Iwai return 0;
2262763f356cSTakashi Iwai }
2263763f356cSTakashi Iwai
snd_hdspm_put_system_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)226441285a98SAdrian Knoth static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol,
226541285a98SAdrian Knoth struct snd_ctl_elem_value *
226641285a98SAdrian Knoth ucontrol)
226741285a98SAdrian Knoth {
226841285a98SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2269c1099c32STakashi Iwai int rate = ucontrol->value.integer.value[0];
227041285a98SAdrian Knoth
2271c1099c32STakashi Iwai if (rate < 27000 || rate > 207000)
2272c1099c32STakashi Iwai return -EINVAL;
2273537e4813STakashi Iwai hdspm_set_dds_value(hdspm, ucontrol->value.integer.value[0]);
227441285a98SAdrian Knoth return 0;
227541285a98SAdrian Knoth }
227641285a98SAdrian Knoth
22770dca1793SAdrian Knoth
2278ddcecf6bSTakashi Iwai /*
22790dca1793SAdrian Knoth * Returns the WordClock sample rate class for the given card.
2280ddcecf6bSTakashi Iwai */
hdspm_get_wc_sample_rate(struct hdspm * hdspm)22810dca1793SAdrian Knoth static int hdspm_get_wc_sample_rate(struct hdspm *hdspm)
22820dca1793SAdrian Knoth {
22830dca1793SAdrian Knoth int status;
22840dca1793SAdrian Knoth
22850dca1793SAdrian Knoth switch (hdspm->io_type) {
22860dca1793SAdrian Knoth case RayDAT:
22870dca1793SAdrian Knoth case AIO:
22880dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
22890dca1793SAdrian Knoth return (status >> 16) & 0xF;
2290a57fea8eSAdrian Knoth case AES32:
2291a57fea8eSAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister);
2292a57fea8eSAdrian Knoth return (status >> HDSPM_AES32_wcFreq_bit) & 0xF;
22930dca1793SAdrian Knoth default:
22940dca1793SAdrian Knoth break;
22950dca1793SAdrian Knoth }
22960dca1793SAdrian Knoth
22970dca1793SAdrian Knoth
22980dca1793SAdrian Knoth return 0;
22990dca1793SAdrian Knoth }
23000dca1793SAdrian Knoth
23010dca1793SAdrian Knoth
2302ddcecf6bSTakashi Iwai /*
23030dca1793SAdrian Knoth * Returns the TCO sample rate class for the given card.
2304ddcecf6bSTakashi Iwai */
hdspm_get_tco_sample_rate(struct hdspm * hdspm)23050dca1793SAdrian Knoth static int hdspm_get_tco_sample_rate(struct hdspm *hdspm)
23060dca1793SAdrian Knoth {
23070dca1793SAdrian Knoth int status;
23080dca1793SAdrian Knoth
23090dca1793SAdrian Knoth if (hdspm->tco) {
23100dca1793SAdrian Knoth switch (hdspm->io_type) {
23110dca1793SAdrian Knoth case RayDAT:
23120dca1793SAdrian Knoth case AIO:
23130dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
23140dca1793SAdrian Knoth return (status >> 20) & 0xF;
2315051c44feSAdrian Knoth case AES32:
2316051c44feSAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister);
2317051c44feSAdrian Knoth return (status >> 1) & 0xF;
23180dca1793SAdrian Knoth default:
23190dca1793SAdrian Knoth break;
23200dca1793SAdrian Knoth }
23210dca1793SAdrian Knoth }
23220dca1793SAdrian Knoth
23230dca1793SAdrian Knoth return 0;
23240dca1793SAdrian Knoth }
23250dca1793SAdrian Knoth
23260dca1793SAdrian Knoth
2327ddcecf6bSTakashi Iwai /*
23280dca1793SAdrian Knoth * Returns the SYNC_IN sample rate class for the given card.
2329ddcecf6bSTakashi Iwai */
hdspm_get_sync_in_sample_rate(struct hdspm * hdspm)23300dca1793SAdrian Knoth static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm)
23310dca1793SAdrian Knoth {
23320dca1793SAdrian Knoth int status;
23330dca1793SAdrian Knoth
23340dca1793SAdrian Knoth if (hdspm->tco) {
23350dca1793SAdrian Knoth switch (hdspm->io_type) {
23360dca1793SAdrian Knoth case RayDAT:
23370dca1793SAdrian Knoth case AIO:
23380dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_2);
23390dca1793SAdrian Knoth return (status >> 12) & 0xF;
23400dca1793SAdrian Knoth default:
23410dca1793SAdrian Knoth break;
23420dca1793SAdrian Knoth }
23430dca1793SAdrian Knoth }
23440dca1793SAdrian Knoth
23450dca1793SAdrian Knoth return 0;
23460dca1793SAdrian Knoth }
23470dca1793SAdrian Knoth
2348ddcecf6bSTakashi Iwai /*
2349d3c36ed8SAdrian Knoth * Returns the AES sample rate class for the given card.
2350ddcecf6bSTakashi Iwai */
hdspm_get_aes_sample_rate(struct hdspm * hdspm,int index)2351d3c36ed8SAdrian Knoth static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index)
2352d3c36ed8SAdrian Knoth {
2353d3c36ed8SAdrian Knoth int timecode;
2354d3c36ed8SAdrian Knoth
2355d3c36ed8SAdrian Knoth switch (hdspm->io_type) {
2356d3c36ed8SAdrian Knoth case AES32:
2357d3c36ed8SAdrian Knoth timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
2358d3c36ed8SAdrian Knoth return (timecode >> (4*index)) & 0xF;
2359d3c36ed8SAdrian Knoth default:
2360d3c36ed8SAdrian Knoth break;
2361d3c36ed8SAdrian Knoth }
2362d3c36ed8SAdrian Knoth return 0;
2363d3c36ed8SAdrian Knoth }
23640dca1793SAdrian Knoth
2365ddcecf6bSTakashi Iwai /*
23660dca1793SAdrian Knoth * Returns the sample rate class for input source <idx> for
23670dca1793SAdrian Knoth * 'new style' cards like the AIO and RayDAT.
2368ddcecf6bSTakashi Iwai */
hdspm_get_s1_sample_rate(struct hdspm * hdspm,unsigned int idx)23690dca1793SAdrian Knoth static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
23700dca1793SAdrian Knoth {
23710dca1793SAdrian Knoth int status = hdspm_read(hdspm, HDSPM_RD_STATUS_2);
23720dca1793SAdrian Knoth
23730dca1793SAdrian Knoth return (status >> (idx*4)) & 0xF;
23740dca1793SAdrian Knoth }
23750dca1793SAdrian Knoth
23768cea5710SAdrian Knoth #define ENUMERATED_CTL_INFO(info, texts) \
237738816545SAdrian Knoth snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts)
23788cea5710SAdrian Knoth
23790dca1793SAdrian Knoth
23802336142fSAdrian Knoth /* Helper function to query the external sample rate and return the
23812336142fSAdrian Knoth * corresponding enum to be returned to userspace.
23822336142fSAdrian Knoth */
hdspm_external_rate_to_enum(struct hdspm * hdspm)23832336142fSAdrian Knoth static int hdspm_external_rate_to_enum(struct hdspm *hdspm)
23842336142fSAdrian Knoth {
23852336142fSAdrian Knoth int rate = hdspm_external_sample_rate(hdspm);
23862336142fSAdrian Knoth int i, selected_rate = 0;
23872336142fSAdrian Knoth for (i = 1; i < 10; i++)
23882336142fSAdrian Knoth if (HDSPM_bit2freq(i) == rate) {
23892336142fSAdrian Knoth selected_rate = i;
23902336142fSAdrian Knoth break;
23912336142fSAdrian Knoth }
23922336142fSAdrian Knoth return selected_rate;
23932336142fSAdrian Knoth }
23942336142fSAdrian Knoth
23950dca1793SAdrian Knoth
2396763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
239767ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2398763f356cSTakashi Iwai .name = xname, \
23990dca1793SAdrian Knoth .private_value = xindex, \
2400763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ, \
2401763f356cSTakashi Iwai .info = snd_hdspm_info_autosync_sample_rate, \
2402763f356cSTakashi Iwai .get = snd_hdspm_get_autosync_sample_rate \
2403763f356cSTakashi Iwai }
2404763f356cSTakashi Iwai
24050dca1793SAdrian Knoth
snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)240698274f07STakashi Iwai static int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol,
240798274f07STakashi Iwai struct snd_ctl_elem_info *uinfo)
2408763f356cSTakashi Iwai {
2409e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts_freq);
2410763f356cSTakashi Iwai return 0;
2411763f356cSTakashi Iwai }
2412763f356cSTakashi Iwai
24130dca1793SAdrian Knoth
snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)241498274f07STakashi Iwai static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
241598274f07STakashi Iwai struct snd_ctl_elem_value *
2416763f356cSTakashi Iwai ucontrol)
2417763f356cSTakashi Iwai {
241898274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2419763f356cSTakashi Iwai
24200dca1793SAdrian Knoth switch (hdspm->io_type) {
24210dca1793SAdrian Knoth case RayDAT:
24220dca1793SAdrian Knoth switch (kcontrol->private_value) {
24230dca1793SAdrian Knoth case 0:
24240dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] =
24250dca1793SAdrian Knoth hdspm_get_wc_sample_rate(hdspm);
2426763f356cSTakashi Iwai break;
24270dca1793SAdrian Knoth case 7:
24280dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] =
24290dca1793SAdrian Knoth hdspm_get_tco_sample_rate(hdspm);
2430763f356cSTakashi Iwai break;
24310dca1793SAdrian Knoth case 8:
24320dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] =
24330dca1793SAdrian Knoth hdspm_get_sync_in_sample_rate(hdspm);
2434763f356cSTakashi Iwai break;
2435763f356cSTakashi Iwai default:
24360dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] =
24370dca1793SAdrian Knoth hdspm_get_s1_sample_rate(hdspm,
24380dca1793SAdrian Knoth kcontrol->private_value-1);
2439763f356cSTakashi Iwai }
2440d681deaaSAdrian Knoth break;
24410dca1793SAdrian Knoth
24420dca1793SAdrian Knoth case AIO:
24430dca1793SAdrian Knoth switch (kcontrol->private_value) {
24440dca1793SAdrian Knoth case 0: /* WC */
24450dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] =
24460dca1793SAdrian Knoth hdspm_get_wc_sample_rate(hdspm);
24470dca1793SAdrian Knoth break;
24480dca1793SAdrian Knoth case 4: /* TCO */
24490dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] =
24500dca1793SAdrian Knoth hdspm_get_tco_sample_rate(hdspm);
24510dca1793SAdrian Knoth break;
24520dca1793SAdrian Knoth case 5: /* SYNC_IN */
24530dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] =
24540dca1793SAdrian Knoth hdspm_get_sync_in_sample_rate(hdspm);
24550dca1793SAdrian Knoth break;
24560dca1793SAdrian Knoth default:
24570dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] =
24580dca1793SAdrian Knoth hdspm_get_s1_sample_rate(hdspm,
24591cb7dbf4SAdrian Knoth kcontrol->private_value-1);
24600dca1793SAdrian Knoth }
2461d681deaaSAdrian Knoth break;
24627c4a95b5SAdrian Knoth
24637c4a95b5SAdrian Knoth case AES32:
24647c4a95b5SAdrian Knoth
24657c4a95b5SAdrian Knoth switch (kcontrol->private_value) {
24667c4a95b5SAdrian Knoth case 0: /* WC */
24677c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] =
24687c4a95b5SAdrian Knoth hdspm_get_wc_sample_rate(hdspm);
24697c4a95b5SAdrian Knoth break;
24707c4a95b5SAdrian Knoth case 9: /* TCO */
24717c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] =
24727c4a95b5SAdrian Knoth hdspm_get_tco_sample_rate(hdspm);
24737c4a95b5SAdrian Knoth break;
24747c4a95b5SAdrian Knoth case 10: /* SYNC_IN */
24757c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] =
24767c4a95b5SAdrian Knoth hdspm_get_sync_in_sample_rate(hdspm);
24777c4a95b5SAdrian Knoth break;
24782d63ec38SAdrian Knoth case 11: /* External Rate */
24792d63ec38SAdrian Knoth ucontrol->value.enumerated.item[0] =
24802d63ec38SAdrian Knoth hdspm_external_rate_to_enum(hdspm);
24812d63ec38SAdrian Knoth break;
24827c4a95b5SAdrian Knoth default: /* AES1 to AES8 */
24837c4a95b5SAdrian Knoth ucontrol->value.enumerated.item[0] =
24842d63ec38SAdrian Knoth hdspm_get_aes_sample_rate(hdspm,
24852d63ec38SAdrian Knoth kcontrol->private_value -
24862d63ec38SAdrian Knoth HDSPM_AES32_AUTOSYNC_FROM_AES1);
24877c4a95b5SAdrian Knoth break;
24887c4a95b5SAdrian Knoth }
2489d681deaaSAdrian Knoth break;
2490b8812c55SAdrian Knoth
2491b8812c55SAdrian Knoth case MADI:
2492b8812c55SAdrian Knoth case MADIface:
24932336142fSAdrian Knoth ucontrol->value.enumerated.item[0] =
24942336142fSAdrian Knoth hdspm_external_rate_to_enum(hdspm);
2495b8812c55SAdrian Knoth break;
24960dca1793SAdrian Knoth default:
24970dca1793SAdrian Knoth break;
24980dca1793SAdrian Knoth }
24990dca1793SAdrian Knoth
2500763f356cSTakashi Iwai return 0;
2501763f356cSTakashi Iwai }
2502763f356cSTakashi Iwai
25030dca1793SAdrian Knoth
2504763f356cSTakashi Iwai #define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \
250567ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2506763f356cSTakashi Iwai .name = xname, \
2507763f356cSTakashi Iwai .index = xindex, \
25080dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
25090dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
2510763f356cSTakashi Iwai .info = snd_hdspm_info_system_clock_mode, \
2511763f356cSTakashi Iwai .get = snd_hdspm_get_system_clock_mode, \
25120dca1793SAdrian Knoth .put = snd_hdspm_put_system_clock_mode, \
2513763f356cSTakashi Iwai }
2514763f356cSTakashi Iwai
2515763f356cSTakashi Iwai
2516ddcecf6bSTakashi Iwai /*
25170dca1793SAdrian Knoth * Returns the system clock mode for the given card.
25180dca1793SAdrian Knoth * @returns 0 - master, 1 - slave
2519ddcecf6bSTakashi Iwai */
hdspm_system_clock_mode(struct hdspm * hdspm)252098274f07STakashi Iwai static int hdspm_system_clock_mode(struct hdspm *hdspm)
2521763f356cSTakashi Iwai {
25220dca1793SAdrian Knoth switch (hdspm->io_type) {
25230dca1793SAdrian Knoth case AIO:
25240dca1793SAdrian Knoth case RayDAT:
25250dca1793SAdrian Knoth if (hdspm->settings_register & HDSPM_c0Master)
25260dca1793SAdrian Knoth return 0;
25270dca1793SAdrian Knoth break;
2528763f356cSTakashi Iwai
25290dca1793SAdrian Knoth default:
2530763f356cSTakashi Iwai if (hdspm->control_register & HDSPM_ClockModeMaster)
2531763f356cSTakashi Iwai return 0;
25320dca1793SAdrian Knoth }
25330dca1793SAdrian Knoth
2534763f356cSTakashi Iwai return 1;
2535763f356cSTakashi Iwai }
2536763f356cSTakashi Iwai
25370dca1793SAdrian Knoth
2538ddcecf6bSTakashi Iwai /*
25390dca1793SAdrian Knoth * Sets the system clock mode.
25400dca1793SAdrian Knoth * @param mode 0 - master, 1 - slave
2541ddcecf6bSTakashi Iwai */
hdspm_set_system_clock_mode(struct hdspm * hdspm,int mode)25420dca1793SAdrian Knoth static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode)
25430dca1793SAdrian Knoth {
254434be7ebbSAdrian Knoth hdspm_set_toggle_setting(hdspm,
254534be7ebbSAdrian Knoth (hdspm_is_raydat_or_aio(hdspm)) ?
254634be7ebbSAdrian Knoth HDSPM_c0Master : HDSPM_ClockModeMaster,
254734be7ebbSAdrian Knoth (0 == mode));
25480dca1793SAdrian Knoth }
25490dca1793SAdrian Knoth
25500dca1793SAdrian Knoth
snd_hdspm_info_system_clock_mode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)255198274f07STakashi Iwai static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol,
255298274f07STakashi Iwai struct snd_ctl_elem_info *uinfo)
2553763f356cSTakashi Iwai {
255438816545SAdrian Knoth static const char *const texts[] = { "Master", "AutoSync" };
2555e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
2556763f356cSTakashi Iwai return 0;
2557763f356cSTakashi Iwai }
2558763f356cSTakashi Iwai
snd_hdspm_get_system_clock_mode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)255998274f07STakashi Iwai static int snd_hdspm_get_system_clock_mode(struct snd_kcontrol *kcontrol,
256098274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
2561763f356cSTakashi Iwai {
256298274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2563763f356cSTakashi Iwai
25640dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm_system_clock_mode(hdspm);
2565763f356cSTakashi Iwai return 0;
2566763f356cSTakashi Iwai }
2567763f356cSTakashi Iwai
snd_hdspm_put_system_clock_mode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)25680dca1793SAdrian Knoth static int snd_hdspm_put_system_clock_mode(struct snd_kcontrol *kcontrol,
25690dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
25700dca1793SAdrian Knoth {
25710dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
25720dca1793SAdrian Knoth int val;
25730dca1793SAdrian Knoth
25740dca1793SAdrian Knoth if (!snd_hdspm_use_is_exclusive(hdspm))
25750dca1793SAdrian Knoth return -EBUSY;
25760dca1793SAdrian Knoth
25770dca1793SAdrian Knoth val = ucontrol->value.enumerated.item[0];
25780dca1793SAdrian Knoth if (val < 0)
25790dca1793SAdrian Knoth val = 0;
25800dca1793SAdrian Knoth else if (val > 1)
25810dca1793SAdrian Knoth val = 1;
25820dca1793SAdrian Knoth
25830dca1793SAdrian Knoth hdspm_set_system_clock_mode(hdspm, val);
25840dca1793SAdrian Knoth
25850dca1793SAdrian Knoth return 0;
25860dca1793SAdrian Knoth }
25870dca1793SAdrian Knoth
25880dca1793SAdrian Knoth
25890dca1793SAdrian Knoth #define HDSPM_INTERNAL_CLOCK(xname, xindex) \
259067ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2591763f356cSTakashi Iwai .name = xname, \
2592763f356cSTakashi Iwai .index = xindex, \
2593763f356cSTakashi Iwai .info = snd_hdspm_info_clock_source, \
2594763f356cSTakashi Iwai .get = snd_hdspm_get_clock_source, \
2595763f356cSTakashi Iwai .put = snd_hdspm_put_clock_source \
2596763f356cSTakashi Iwai }
2597763f356cSTakashi Iwai
25980dca1793SAdrian Knoth
hdspm_clock_source(struct hdspm * hdspm)259998274f07STakashi Iwai static int hdspm_clock_source(struct hdspm * hdspm)
2600763f356cSTakashi Iwai {
2601763f356cSTakashi Iwai switch (hdspm->system_sample_rate) {
26020dca1793SAdrian Knoth case 32000: return 0;
26030dca1793SAdrian Knoth case 44100: return 1;
26040dca1793SAdrian Knoth case 48000: return 2;
26050dca1793SAdrian Knoth case 64000: return 3;
26060dca1793SAdrian Knoth case 88200: return 4;
26070dca1793SAdrian Knoth case 96000: return 5;
26080dca1793SAdrian Knoth case 128000: return 6;
26090dca1793SAdrian Knoth case 176400: return 7;
26100dca1793SAdrian Knoth case 192000: return 8;
2611763f356cSTakashi Iwai }
26120dca1793SAdrian Knoth
26130dca1793SAdrian Knoth return -1;
2614763f356cSTakashi Iwai }
2615763f356cSTakashi Iwai
hdspm_set_clock_source(struct hdspm * hdspm,int mode)261698274f07STakashi Iwai static int hdspm_set_clock_source(struct hdspm * hdspm, int mode)
2617763f356cSTakashi Iwai {
2618763f356cSTakashi Iwai int rate;
2619763f356cSTakashi Iwai switch (mode) {
26200dca1793SAdrian Knoth case 0:
26210dca1793SAdrian Knoth rate = 32000; break;
26220dca1793SAdrian Knoth case 1:
26230dca1793SAdrian Knoth rate = 44100; break;
26240dca1793SAdrian Knoth case 2:
26250dca1793SAdrian Knoth rate = 48000; break;
26260dca1793SAdrian Knoth case 3:
26270dca1793SAdrian Knoth rate = 64000; break;
26280dca1793SAdrian Knoth case 4:
26290dca1793SAdrian Knoth rate = 88200; break;
26300dca1793SAdrian Knoth case 5:
26310dca1793SAdrian Knoth rate = 96000; break;
26320dca1793SAdrian Knoth case 6:
26330dca1793SAdrian Knoth rate = 128000; break;
26340dca1793SAdrian Knoth case 7:
26350dca1793SAdrian Knoth rate = 176400; break;
26360dca1793SAdrian Knoth case 8:
26370dca1793SAdrian Knoth rate = 192000; break;
2638763f356cSTakashi Iwai default:
26390dca1793SAdrian Knoth rate = 48000;
2640763f356cSTakashi Iwai }
2641763f356cSTakashi Iwai hdspm_set_rate(hdspm, rate, 1);
2642763f356cSTakashi Iwai return 0;
2643763f356cSTakashi Iwai }
2644763f356cSTakashi Iwai
snd_hdspm_info_clock_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)264598274f07STakashi Iwai static int snd_hdspm_info_clock_source(struct snd_kcontrol *kcontrol,
264698274f07STakashi Iwai struct snd_ctl_elem_info *uinfo)
2647763f356cSTakashi Iwai {
2648c69a637bSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 9, texts_freq + 1);
2649763f356cSTakashi Iwai }
2650763f356cSTakashi Iwai
snd_hdspm_get_clock_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)265198274f07STakashi Iwai static int snd_hdspm_get_clock_source(struct snd_kcontrol *kcontrol,
265298274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
2653763f356cSTakashi Iwai {
265498274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2655763f356cSTakashi Iwai
2656763f356cSTakashi Iwai ucontrol->value.enumerated.item[0] = hdspm_clock_source(hdspm);
2657763f356cSTakashi Iwai return 0;
2658763f356cSTakashi Iwai }
2659763f356cSTakashi Iwai
snd_hdspm_put_clock_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)266098274f07STakashi Iwai static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol,
266198274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
2662763f356cSTakashi Iwai {
266398274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
2664763f356cSTakashi Iwai int change;
2665763f356cSTakashi Iwai int val;
2666763f356cSTakashi Iwai
2667763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm))
2668763f356cSTakashi Iwai return -EBUSY;
2669763f356cSTakashi Iwai val = ucontrol->value.enumerated.item[0];
2670763f356cSTakashi Iwai if (val < 0)
2671763f356cSTakashi Iwai val = 0;
26726534599dSRemy Bruno if (val > 9)
26736534599dSRemy Bruno val = 9;
2674763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
2675763f356cSTakashi Iwai if (val != hdspm_clock_source(hdspm))
2676763f356cSTakashi Iwai change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0;
2677763f356cSTakashi Iwai else
2678763f356cSTakashi Iwai change = 0;
2679763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
2680763f356cSTakashi Iwai return change;
2681763f356cSTakashi Iwai }
2682763f356cSTakashi Iwai
26830dca1793SAdrian Knoth
2684763f356cSTakashi Iwai #define HDSPM_PREF_SYNC_REF(xname, xindex) \
268567ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2686763f356cSTakashi Iwai .name = xname, \
2687763f356cSTakashi Iwai .index = xindex, \
26880dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
26890dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
2690763f356cSTakashi Iwai .info = snd_hdspm_info_pref_sync_ref, \
2691763f356cSTakashi Iwai .get = snd_hdspm_get_pref_sync_ref, \
2692763f356cSTakashi Iwai .put = snd_hdspm_put_pref_sync_ref \
2693763f356cSTakashi Iwai }
2694763f356cSTakashi Iwai
26950dca1793SAdrian Knoth
2696ddcecf6bSTakashi Iwai /*
26970dca1793SAdrian Knoth * Returns the current preferred sync reference setting.
26980dca1793SAdrian Knoth * The semantics of the return value are depending on the
26990dca1793SAdrian Knoth * card, please see the comments for clarification.
2700ddcecf6bSTakashi Iwai */
hdspm_pref_sync_ref(struct hdspm * hdspm)270198274f07STakashi Iwai static int hdspm_pref_sync_ref(struct hdspm * hdspm)
2702763f356cSTakashi Iwai {
27030dca1793SAdrian Knoth switch (hdspm->io_type) {
27040dca1793SAdrian Knoth case AES32:
27053cee5a60SRemy Bruno switch (hdspm->control_register & HDSPM_SyncRefMask) {
27060dca1793SAdrian Knoth case 0: return 0; /* WC */
27070dca1793SAdrian Knoth case HDSPM_SyncRef0: return 1; /* AES 1 */
27080dca1793SAdrian Knoth case HDSPM_SyncRef1: return 2; /* AES 2 */
27090dca1793SAdrian Knoth case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3; /* AES 3 */
27100dca1793SAdrian Knoth case HDSPM_SyncRef2: return 4; /* AES 4 */
27110dca1793SAdrian Knoth case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5; /* AES 5 */
27120dca1793SAdrian Knoth case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6; /* AES 6 */
27130dca1793SAdrian Knoth case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0:
27140dca1793SAdrian Knoth return 7; /* AES 7 */
27150dca1793SAdrian Knoth case HDSPM_SyncRef3: return 8; /* AES 8 */
27160dca1793SAdrian Knoth case HDSPM_SyncRef3+HDSPM_SyncRef0: return 9; /* TCO */
27170dca1793SAdrian Knoth }
27180dca1793SAdrian Knoth break;
27190dca1793SAdrian Knoth
27200dca1793SAdrian Knoth case MADI:
27210dca1793SAdrian Knoth case MADIface:
27220dca1793SAdrian Knoth if (hdspm->tco) {
27230dca1793SAdrian Knoth switch (hdspm->control_register & HDSPM_SyncRefMask) {
27240dca1793SAdrian Knoth case 0: return 0; /* WC */
27250dca1793SAdrian Knoth case HDSPM_SyncRef0: return 1; /* MADI */
27260dca1793SAdrian Knoth case HDSPM_SyncRef1: return 2; /* TCO */
27270dca1793SAdrian Knoth case HDSPM_SyncRef1+HDSPM_SyncRef0:
27280dca1793SAdrian Knoth return 3; /* SYNC_IN */
27293cee5a60SRemy Bruno }
27303cee5a60SRemy Bruno } else {
2731763f356cSTakashi Iwai switch (hdspm->control_register & HDSPM_SyncRefMask) {
27320dca1793SAdrian Knoth case 0: return 0; /* WC */
27330dca1793SAdrian Knoth case HDSPM_SyncRef0: return 1; /* MADI */
27340dca1793SAdrian Knoth case HDSPM_SyncRef1+HDSPM_SyncRef0:
27350dca1793SAdrian Knoth return 2; /* SYNC_IN */
27360dca1793SAdrian Knoth }
27370dca1793SAdrian Knoth }
27380dca1793SAdrian Knoth break;
27390dca1793SAdrian Knoth
27400dca1793SAdrian Knoth case RayDAT:
27410dca1793SAdrian Knoth if (hdspm->tco) {
27420dca1793SAdrian Knoth switch ((hdspm->settings_register &
27430dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
27440dca1793SAdrian Knoth case 0: return 0; /* WC */
27450dca1793SAdrian Knoth case 3: return 1; /* ADAT 1 */
27460dca1793SAdrian Knoth case 4: return 2; /* ADAT 2 */
27470dca1793SAdrian Knoth case 5: return 3; /* ADAT 3 */
27480dca1793SAdrian Knoth case 6: return 4; /* ADAT 4 */
27490dca1793SAdrian Knoth case 1: return 5; /* AES */
27500dca1793SAdrian Knoth case 2: return 6; /* SPDIF */
27510dca1793SAdrian Knoth case 9: return 7; /* TCO */
27520dca1793SAdrian Knoth case 10: return 8; /* SYNC_IN */
27530dca1793SAdrian Knoth }
27540dca1793SAdrian Knoth } else {
27550dca1793SAdrian Knoth switch ((hdspm->settings_register &
27560dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
27570dca1793SAdrian Knoth case 0: return 0; /* WC */
27580dca1793SAdrian Knoth case 3: return 1; /* ADAT 1 */
27590dca1793SAdrian Knoth case 4: return 2; /* ADAT 2 */
27600dca1793SAdrian Knoth case 5: return 3; /* ADAT 3 */
27610dca1793SAdrian Knoth case 6: return 4; /* ADAT 4 */
27620dca1793SAdrian Knoth case 1: return 5; /* AES */
27630dca1793SAdrian Knoth case 2: return 6; /* SPDIF */
27640dca1793SAdrian Knoth case 10: return 7; /* SYNC_IN */
2765763f356cSTakashi Iwai }
27663cee5a60SRemy Bruno }
2767763f356cSTakashi Iwai
27680dca1793SAdrian Knoth break;
27690dca1793SAdrian Knoth
27700dca1793SAdrian Knoth case AIO:
27710dca1793SAdrian Knoth if (hdspm->tco) {
27720dca1793SAdrian Knoth switch ((hdspm->settings_register &
27730dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
27740dca1793SAdrian Knoth case 0: return 0; /* WC */
27750dca1793SAdrian Knoth case 3: return 1; /* ADAT */
27760dca1793SAdrian Knoth case 1: return 2; /* AES */
27770dca1793SAdrian Knoth case 2: return 3; /* SPDIF */
27780dca1793SAdrian Knoth case 9: return 4; /* TCO */
27790dca1793SAdrian Knoth case 10: return 5; /* SYNC_IN */
27800dca1793SAdrian Knoth }
27810dca1793SAdrian Knoth } else {
27820dca1793SAdrian Knoth switch ((hdspm->settings_register &
27830dca1793SAdrian Knoth HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
27840dca1793SAdrian Knoth case 0: return 0; /* WC */
27850dca1793SAdrian Knoth case 3: return 1; /* ADAT */
27860dca1793SAdrian Knoth case 1: return 2; /* AES */
27870dca1793SAdrian Knoth case 2: return 3; /* SPDIF */
27880dca1793SAdrian Knoth case 10: return 4; /* SYNC_IN */
27890dca1793SAdrian Knoth }
2790763f356cSTakashi Iwai }
2791763f356cSTakashi Iwai
27920dca1793SAdrian Knoth break;
27930dca1793SAdrian Knoth }
27940dca1793SAdrian Knoth
27950dca1793SAdrian Knoth return -1;
27960dca1793SAdrian Knoth }
27970dca1793SAdrian Knoth
27980dca1793SAdrian Knoth
2799ddcecf6bSTakashi Iwai /*
28000dca1793SAdrian Knoth * Set the preferred sync reference to <pref>. The semantics
28010dca1793SAdrian Knoth * of <pref> are depending on the card type, see the comments
28020dca1793SAdrian Knoth * for clarification.
2803ddcecf6bSTakashi Iwai */
hdspm_set_pref_sync_ref(struct hdspm * hdspm,int pref)280498274f07STakashi Iwai static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref)
2805763f356cSTakashi Iwai {
28060dca1793SAdrian Knoth int p = 0;
2807763f356cSTakashi Iwai
28080dca1793SAdrian Knoth switch (hdspm->io_type) {
28090dca1793SAdrian Knoth case AES32:
28100dca1793SAdrian Knoth hdspm->control_register &= ~HDSPM_SyncRefMask;
28113cee5a60SRemy Bruno switch (pref) {
28120dca1793SAdrian Knoth case 0: /* WC */
28133cee5a60SRemy Bruno break;
28140dca1793SAdrian Knoth case 1: /* AES 1 */
28153cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef0;
28163cee5a60SRemy Bruno break;
28170dca1793SAdrian Knoth case 2: /* AES 2 */
28183cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef1;
28193cee5a60SRemy Bruno break;
28200dca1793SAdrian Knoth case 3: /* AES 3 */
28210dca1793SAdrian Knoth hdspm->control_register |=
28220dca1793SAdrian Knoth HDSPM_SyncRef1+HDSPM_SyncRef0;
28233cee5a60SRemy Bruno break;
28240dca1793SAdrian Knoth case 4: /* AES 4 */
28253cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef2;
28263cee5a60SRemy Bruno break;
28270dca1793SAdrian Knoth case 5: /* AES 5 */
28280dca1793SAdrian Knoth hdspm->control_register |=
28290dca1793SAdrian Knoth HDSPM_SyncRef2+HDSPM_SyncRef0;
28303cee5a60SRemy Bruno break;
28310dca1793SAdrian Knoth case 6: /* AES 6 */
28320dca1793SAdrian Knoth hdspm->control_register |=
28330dca1793SAdrian Knoth HDSPM_SyncRef2+HDSPM_SyncRef1;
28343cee5a60SRemy Bruno break;
28350dca1793SAdrian Knoth case 7: /* AES 7 */
2836ef5fa1a4STakashi Iwai hdspm->control_register |=
2837ef5fa1a4STakashi Iwai HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0;
28383cee5a60SRemy Bruno break;
28390dca1793SAdrian Knoth case 8: /* AES 8 */
28403cee5a60SRemy Bruno hdspm->control_register |= HDSPM_SyncRef3;
28413cee5a60SRemy Bruno break;
28420dca1793SAdrian Knoth case 9: /* TCO */
28430dca1793SAdrian Knoth hdspm->control_register |=
28440dca1793SAdrian Knoth HDSPM_SyncRef3+HDSPM_SyncRef0;
28450dca1793SAdrian Knoth break;
28460dca1793SAdrian Knoth default:
28470dca1793SAdrian Knoth return -1;
28480dca1793SAdrian Knoth }
28490dca1793SAdrian Knoth
28500dca1793SAdrian Knoth break;
28510dca1793SAdrian Knoth
28520dca1793SAdrian Knoth case MADI:
28530dca1793SAdrian Knoth case MADIface:
28540dca1793SAdrian Knoth hdspm->control_register &= ~HDSPM_SyncRefMask;
28550dca1793SAdrian Knoth if (hdspm->tco) {
28560dca1793SAdrian Knoth switch (pref) {
28570dca1793SAdrian Knoth case 0: /* WC */
28580dca1793SAdrian Knoth break;
28590dca1793SAdrian Knoth case 1: /* MADI */
28600dca1793SAdrian Knoth hdspm->control_register |= HDSPM_SyncRef0;
28610dca1793SAdrian Knoth break;
28620dca1793SAdrian Knoth case 2: /* TCO */
28630dca1793SAdrian Knoth hdspm->control_register |= HDSPM_SyncRef1;
28640dca1793SAdrian Knoth break;
28650dca1793SAdrian Knoth case 3: /* SYNC_IN */
28660dca1793SAdrian Knoth hdspm->control_register |=
28670dca1793SAdrian Knoth HDSPM_SyncRef0+HDSPM_SyncRef1;
28680dca1793SAdrian Knoth break;
28693cee5a60SRemy Bruno default:
28703cee5a60SRemy Bruno return -1;
28713cee5a60SRemy Bruno }
28723cee5a60SRemy Bruno } else {
2873763f356cSTakashi Iwai switch (pref) {
28740dca1793SAdrian Knoth case 0: /* WC */
2875763f356cSTakashi Iwai break;
28760dca1793SAdrian Knoth case 1: /* MADI */
28770dca1793SAdrian Knoth hdspm->control_register |= HDSPM_SyncRef0;
28780dca1793SAdrian Knoth break;
28790dca1793SAdrian Knoth case 2: /* SYNC_IN */
28800dca1793SAdrian Knoth hdspm->control_register |=
28810dca1793SAdrian Knoth HDSPM_SyncRef0+HDSPM_SyncRef1;
2882763f356cSTakashi Iwai break;
2883763f356cSTakashi Iwai default:
2884763f356cSTakashi Iwai return -1;
2885763f356cSTakashi Iwai }
28863cee5a60SRemy Bruno }
28870dca1793SAdrian Knoth
28880dca1793SAdrian Knoth break;
28890dca1793SAdrian Knoth
28900dca1793SAdrian Knoth case RayDAT:
28910dca1793SAdrian Knoth if (hdspm->tco) {
28920dca1793SAdrian Knoth switch (pref) {
28930dca1793SAdrian Knoth case 0: p = 0; break; /* WC */
28940dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT 1 */
28950dca1793SAdrian Knoth case 2: p = 4; break; /* ADAT 2 */
28960dca1793SAdrian Knoth case 3: p = 5; break; /* ADAT 3 */
28970dca1793SAdrian Knoth case 4: p = 6; break; /* ADAT 4 */
28980dca1793SAdrian Knoth case 5: p = 1; break; /* AES */
28990dca1793SAdrian Knoth case 6: p = 2; break; /* SPDIF */
29000dca1793SAdrian Knoth case 7: p = 9; break; /* TCO */
29010dca1793SAdrian Knoth case 8: p = 10; break; /* SYNC_IN */
29020dca1793SAdrian Knoth default: return -1;
29030dca1793SAdrian Knoth }
29040dca1793SAdrian Knoth } else {
29050dca1793SAdrian Knoth switch (pref) {
29060dca1793SAdrian Knoth case 0: p = 0; break; /* WC */
29070dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT 1 */
29080dca1793SAdrian Knoth case 2: p = 4; break; /* ADAT 2 */
29090dca1793SAdrian Knoth case 3: p = 5; break; /* ADAT 3 */
29100dca1793SAdrian Knoth case 4: p = 6; break; /* ADAT 4 */
29110dca1793SAdrian Knoth case 5: p = 1; break; /* AES */
29120dca1793SAdrian Knoth case 6: p = 2; break; /* SPDIF */
29130dca1793SAdrian Knoth case 7: p = 10; break; /* SYNC_IN */
29140dca1793SAdrian Knoth default: return -1;
29150dca1793SAdrian Knoth }
29160dca1793SAdrian Knoth }
29170dca1793SAdrian Knoth break;
29180dca1793SAdrian Knoth
29190dca1793SAdrian Knoth case AIO:
29200dca1793SAdrian Knoth if (hdspm->tco) {
29210dca1793SAdrian Knoth switch (pref) {
29220dca1793SAdrian Knoth case 0: p = 0; break; /* WC */
29230dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT */
29240dca1793SAdrian Knoth case 2: p = 1; break; /* AES */
29250dca1793SAdrian Knoth case 3: p = 2; break; /* SPDIF */
29260dca1793SAdrian Knoth case 4: p = 9; break; /* TCO */
29270dca1793SAdrian Knoth case 5: p = 10; break; /* SYNC_IN */
29280dca1793SAdrian Knoth default: return -1;
29290dca1793SAdrian Knoth }
29300dca1793SAdrian Knoth } else {
29310dca1793SAdrian Knoth switch (pref) {
29320dca1793SAdrian Knoth case 0: p = 0; break; /* WC */
29330dca1793SAdrian Knoth case 1: p = 3; break; /* ADAT */
29340dca1793SAdrian Knoth case 2: p = 1; break; /* AES */
29350dca1793SAdrian Knoth case 3: p = 2; break; /* SPDIF */
29360dca1793SAdrian Knoth case 4: p = 10; break; /* SYNC_IN */
29370dca1793SAdrian Knoth default: return -1;
29380dca1793SAdrian Knoth }
29390dca1793SAdrian Knoth }
29400dca1793SAdrian Knoth break;
29410dca1793SAdrian Knoth }
29420dca1793SAdrian Knoth
29430dca1793SAdrian Knoth switch (hdspm->io_type) {
29440dca1793SAdrian Knoth case RayDAT:
29450dca1793SAdrian Knoth case AIO:
29460dca1793SAdrian Knoth hdspm->settings_register &= ~HDSPM_c0_SyncRefMask;
29470dca1793SAdrian Knoth hdspm->settings_register |= HDSPM_c0_SyncRef0 * p;
29480dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
29490dca1793SAdrian Knoth break;
29500dca1793SAdrian Knoth
29510dca1793SAdrian Knoth case MADI:
29520dca1793SAdrian Knoth case MADIface:
29530dca1793SAdrian Knoth case AES32:
29540dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_controlRegister,
29550dca1793SAdrian Knoth hdspm->control_register);
29560dca1793SAdrian Knoth }
29570dca1793SAdrian Knoth
2958763f356cSTakashi Iwai return 0;
2959763f356cSTakashi Iwai }
2960763f356cSTakashi Iwai
29610dca1793SAdrian Knoth
snd_hdspm_info_pref_sync_ref(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)296298274f07STakashi Iwai static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol,
296398274f07STakashi Iwai struct snd_ctl_elem_info *uinfo)
2964763f356cSTakashi Iwai {
29653cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
29663cee5a60SRemy Bruno
2967eb0d4dbfSAdrian Knoth snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync);
2968763f356cSTakashi Iwai
2969763f356cSTakashi Iwai return 0;
2970763f356cSTakashi Iwai }
2971763f356cSTakashi Iwai
snd_hdspm_get_pref_sync_ref(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)297298274f07STakashi Iwai static int snd_hdspm_get_pref_sync_ref(struct snd_kcontrol *kcontrol,
297398274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
2974763f356cSTakashi Iwai {
297598274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
29760dca1793SAdrian Knoth int psf = hdspm_pref_sync_ref(hdspm);
2977763f356cSTakashi Iwai
29780dca1793SAdrian Knoth if (psf >= 0) {
29790dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = psf;
2980763f356cSTakashi Iwai return 0;
2981763f356cSTakashi Iwai }
2982763f356cSTakashi Iwai
29830dca1793SAdrian Knoth return -1;
29840dca1793SAdrian Knoth }
29850dca1793SAdrian Knoth
snd_hdspm_put_pref_sync_ref(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)298698274f07STakashi Iwai static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
298798274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
2988763f356cSTakashi Iwai {
298998274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
29900dca1793SAdrian Knoth int val, change = 0;
2991763f356cSTakashi Iwai
2992763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm))
2993763f356cSTakashi Iwai return -EBUSY;
2994763f356cSTakashi Iwai
29950dca1793SAdrian Knoth val = ucontrol->value.enumerated.item[0];
29960dca1793SAdrian Knoth
29970dca1793SAdrian Knoth if (val < 0)
29980dca1793SAdrian Knoth val = 0;
29990dca1793SAdrian Knoth else if (val >= hdspm->texts_autosync_items)
30000dca1793SAdrian Knoth val = hdspm->texts_autosync_items-1;
3001763f356cSTakashi Iwai
3002763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
30030dca1793SAdrian Knoth if (val != hdspm_pref_sync_ref(hdspm))
30040dca1793SAdrian Knoth change = (0 == hdspm_set_pref_sync_ref(hdspm, val)) ? 1 : 0;
30050dca1793SAdrian Knoth
3006763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
3007763f356cSTakashi Iwai return change;
3008763f356cSTakashi Iwai }
3009763f356cSTakashi Iwai
30100dca1793SAdrian Knoth
3011763f356cSTakashi Iwai #define HDSPM_AUTOSYNC_REF(xname, xindex) \
301267ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3013763f356cSTakashi Iwai .name = xname, \
3014763f356cSTakashi Iwai .index = xindex, \
3015763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ, \
3016763f356cSTakashi Iwai .info = snd_hdspm_info_autosync_ref, \
3017763f356cSTakashi Iwai .get = snd_hdspm_get_autosync_ref, \
3018763f356cSTakashi Iwai }
3019763f356cSTakashi Iwai
hdspm_autosync_ref(struct hdspm * hdspm)302098274f07STakashi Iwai static int hdspm_autosync_ref(struct hdspm *hdspm)
3021763f356cSTakashi Iwai {
3022763f356cSTakashi Iwai /* This looks at the autosync selected sync reference */
30232d60fc7fSAdrian Knoth if (AES32 == hdspm->io_type) {
3024763f356cSTakashi Iwai
30252d60fc7fSAdrian Knoth unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
30262d60fc7fSAdrian Knoth unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF;
3027ab3ee092SPierre-Louis Bossart /* syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD is always true */
3028ab3ee092SPierre-Louis Bossart if (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN) {
30292d60fc7fSAdrian Knoth return syncref;
30302d60fc7fSAdrian Knoth }
30312d60fc7fSAdrian Knoth return HDSPM_AES32_AUTOSYNC_FROM_NONE;
30322d60fc7fSAdrian Knoth
30332d60fc7fSAdrian Knoth } else if (MADI == hdspm->io_type) {
30342d60fc7fSAdrian Knoth
30352d60fc7fSAdrian Knoth unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
3036763f356cSTakashi Iwai switch (status2 & HDSPM_SelSyncRefMask) {
3037763f356cSTakashi Iwai case HDSPM_SelSyncRef_WORD:
3038763f356cSTakashi Iwai return HDSPM_AUTOSYNC_FROM_WORD;
3039763f356cSTakashi Iwai case HDSPM_SelSyncRef_MADI:
3040763f356cSTakashi Iwai return HDSPM_AUTOSYNC_FROM_MADI;
30410dca1793SAdrian Knoth case HDSPM_SelSyncRef_TCO:
30420dca1793SAdrian Knoth return HDSPM_AUTOSYNC_FROM_TCO;
30430dca1793SAdrian Knoth case HDSPM_SelSyncRef_SyncIn:
30440dca1793SAdrian Knoth return HDSPM_AUTOSYNC_FROM_SYNC_IN;
3045763f356cSTakashi Iwai case HDSPM_SelSyncRef_NVALID:
3046763f356cSTakashi Iwai return HDSPM_AUTOSYNC_FROM_NONE;
3047763f356cSTakashi Iwai default:
3048e71b95adSAdrian Knoth return HDSPM_AUTOSYNC_FROM_NONE;
3049763f356cSTakashi Iwai }
3050763f356cSTakashi Iwai
30510dca1793SAdrian Knoth }
3052763f356cSTakashi Iwai return 0;
3053763f356cSTakashi Iwai }
30540dca1793SAdrian Knoth
3055763f356cSTakashi Iwai
snd_hdspm_info_autosync_ref(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)305698274f07STakashi Iwai static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol,
305798274f07STakashi Iwai struct snd_ctl_elem_info *uinfo)
3058763f356cSTakashi Iwai {
30593cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
30603cee5a60SRemy Bruno
30610dca1793SAdrian Knoth if (AES32 == hdspm->io_type) {
306204659f9eSAdrian Knoth static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3",
3063db2d1a91SAdrian Knoth "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"};
30643cee5a60SRemy Bruno
306504659f9eSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
30660dca1793SAdrian Knoth } else if (MADI == hdspm->io_type) {
306704659f9eSAdrian Knoth static const char *const texts[] = {"Word Clock", "MADI", "TCO",
30680dca1793SAdrian Knoth "Sync In", "None" };
3069763f356cSTakashi Iwai
307004659f9eSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
30713cee5a60SRemy Bruno }
3072763f356cSTakashi Iwai return 0;
3073763f356cSTakashi Iwai }
3074763f356cSTakashi Iwai
snd_hdspm_get_autosync_ref(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)307598274f07STakashi Iwai static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol,
307698274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3077763f356cSTakashi Iwai {
307898274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3079763f356cSTakashi Iwai
30806534599dSRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_autosync_ref(hdspm);
3081763f356cSTakashi Iwai return 0;
3082763f356cSTakashi Iwai }
3083763f356cSTakashi Iwai
3084f99c7881SAdrian Knoth
3085f99c7881SAdrian Knoth
3086f99c7881SAdrian Knoth #define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname, xindex) \
3087f99c7881SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3088f99c7881SAdrian Knoth .name = xname, \
3089f99c7881SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READ |\
3090f99c7881SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3091f99c7881SAdrian Knoth .info = snd_hdspm_info_tco_video_input_format, \
3092f99c7881SAdrian Knoth .get = snd_hdspm_get_tco_video_input_format, \
3093f99c7881SAdrian Knoth }
3094f99c7881SAdrian Knoth
snd_hdspm_info_tco_video_input_format(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3095f99c7881SAdrian Knoth static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol,
3096f99c7881SAdrian Knoth struct snd_ctl_elem_info *uinfo)
3097f99c7881SAdrian Knoth {
309838816545SAdrian Knoth static const char *const texts[] = {"No video", "NTSC", "PAL"};
3099f99c7881SAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
3100f99c7881SAdrian Knoth return 0;
3101f99c7881SAdrian Knoth }
3102f99c7881SAdrian Knoth
snd_hdspm_get_tco_video_input_format(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3103f99c7881SAdrian Knoth static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol,
3104f99c7881SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
3105f99c7881SAdrian Knoth {
3106f99c7881SAdrian Knoth u32 status;
3107f99c7881SAdrian Knoth int ret = 0;
3108f99c7881SAdrian Knoth
3109f99c7881SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3110f99c7881SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
3111f99c7881SAdrian Knoth switch (status & (HDSPM_TCO1_Video_Input_Format_NTSC |
3112f99c7881SAdrian Knoth HDSPM_TCO1_Video_Input_Format_PAL)) {
3113f99c7881SAdrian Knoth case HDSPM_TCO1_Video_Input_Format_NTSC:
3114f99c7881SAdrian Knoth /* ntsc */
3115f99c7881SAdrian Knoth ret = 1;
3116f99c7881SAdrian Knoth break;
3117f99c7881SAdrian Knoth case HDSPM_TCO1_Video_Input_Format_PAL:
3118f99c7881SAdrian Knoth /* pal */
3119f99c7881SAdrian Knoth ret = 2;
3120f99c7881SAdrian Knoth break;
3121f99c7881SAdrian Knoth default:
3122f99c7881SAdrian Knoth /* no video */
3123f99c7881SAdrian Knoth ret = 0;
3124f99c7881SAdrian Knoth break;
3125f99c7881SAdrian Knoth }
3126f99c7881SAdrian Knoth ucontrol->value.enumerated.item[0] = ret;
3127f99c7881SAdrian Knoth return 0;
3128f99c7881SAdrian Knoth }
3129f99c7881SAdrian Knoth
3130f99c7881SAdrian Knoth
3131f99c7881SAdrian Knoth
3132f99c7881SAdrian Knoth #define HDSPM_TCO_LTC_FRAMES(xname, xindex) \
3133f99c7881SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3134f99c7881SAdrian Knoth .name = xname, \
3135f99c7881SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READ |\
3136f99c7881SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3137f99c7881SAdrian Knoth .info = snd_hdspm_info_tco_ltc_frames, \
3138f99c7881SAdrian Knoth .get = snd_hdspm_get_tco_ltc_frames, \
3139f99c7881SAdrian Knoth }
3140f99c7881SAdrian Knoth
snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3141f99c7881SAdrian Knoth static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol,
3142f99c7881SAdrian Knoth struct snd_ctl_elem_info *uinfo)
3143f99c7881SAdrian Knoth {
314438816545SAdrian Knoth static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps",
3145f99c7881SAdrian Knoth "30 fps"};
3146f99c7881SAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
3147f99c7881SAdrian Knoth return 0;
3148f99c7881SAdrian Knoth }
3149f99c7881SAdrian Knoth
hdspm_tco_ltc_frames(struct hdspm * hdspm)3150f99c7881SAdrian Knoth static int hdspm_tco_ltc_frames(struct hdspm *hdspm)
3151f99c7881SAdrian Knoth {
3152f99c7881SAdrian Knoth u32 status;
3153f99c7881SAdrian Knoth int ret = 0;
3154f99c7881SAdrian Knoth
3155f99c7881SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
3156f99c7881SAdrian Knoth if (status & HDSPM_TCO1_LTC_Input_valid) {
3157f99c7881SAdrian Knoth switch (status & (HDSPM_TCO1_LTC_Format_LSB |
3158f99c7881SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB)) {
3159f99c7881SAdrian Knoth case 0:
3160f99c7881SAdrian Knoth /* 24 fps */
31611568b880SAdrian Knoth ret = fps_24;
3162f99c7881SAdrian Knoth break;
3163f99c7881SAdrian Knoth case HDSPM_TCO1_LTC_Format_LSB:
3164f99c7881SAdrian Knoth /* 25 fps */
31651568b880SAdrian Knoth ret = fps_25;
3166f99c7881SAdrian Knoth break;
3167f99c7881SAdrian Knoth case HDSPM_TCO1_LTC_Format_MSB:
31681568b880SAdrian Knoth /* 29.97 fps */
31691568b880SAdrian Knoth ret = fps_2997;
3170f99c7881SAdrian Knoth break;
3171f99c7881SAdrian Knoth default:
3172f99c7881SAdrian Knoth /* 30 fps */
31731568b880SAdrian Knoth ret = fps_30;
3174f99c7881SAdrian Knoth break;
3175f99c7881SAdrian Knoth }
3176f99c7881SAdrian Knoth }
3177f99c7881SAdrian Knoth
3178f99c7881SAdrian Knoth return ret;
3179f99c7881SAdrian Knoth }
3180f99c7881SAdrian Knoth
snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3181f99c7881SAdrian Knoth static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol,
3182f99c7881SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
3183f99c7881SAdrian Knoth {
3184f99c7881SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3185f99c7881SAdrian Knoth
3186f99c7881SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm_tco_ltc_frames(hdspm);
3187f99c7881SAdrian Knoth return 0;
3188f99c7881SAdrian Knoth }
3189f99c7881SAdrian Knoth
3190bf0ff87bSAdrian Knoth #define HDSPM_TOGGLE_SETTING(xname, xindex) \
3191bf0ff87bSAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3192bf0ff87bSAdrian Knoth .name = xname, \
3193bf0ff87bSAdrian Knoth .private_value = xindex, \
3194bf0ff87bSAdrian Knoth .info = snd_hdspm_info_toggle_setting, \
3195bf0ff87bSAdrian Knoth .get = snd_hdspm_get_toggle_setting, \
3196bf0ff87bSAdrian Knoth .put = snd_hdspm_put_toggle_setting \
3197bf0ff87bSAdrian Knoth }
3198bf0ff87bSAdrian Knoth
hdspm_toggle_setting(struct hdspm * hdspm,u32 regmask)3199bf0ff87bSAdrian Knoth static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask)
3200bf0ff87bSAdrian Knoth {
3201ce13f3f3SAdrian Knoth u32 reg;
3202ce13f3f3SAdrian Knoth
3203ce13f3f3SAdrian Knoth if (hdspm_is_raydat_or_aio(hdspm))
3204ce13f3f3SAdrian Knoth reg = hdspm->settings_register;
3205ce13f3f3SAdrian Knoth else
3206ce13f3f3SAdrian Knoth reg = hdspm->control_register;
3207ce13f3f3SAdrian Knoth
3208ce13f3f3SAdrian Knoth return (reg & regmask) ? 1 : 0;
3209bf0ff87bSAdrian Knoth }
3210bf0ff87bSAdrian Knoth
hdspm_set_toggle_setting(struct hdspm * hdspm,u32 regmask,int out)3211bf0ff87bSAdrian Knoth static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out)
3212bf0ff87bSAdrian Knoth {
3213ce13f3f3SAdrian Knoth u32 *reg;
3214ce13f3f3SAdrian Knoth u32 target_reg;
3215ce13f3f3SAdrian Knoth
3216ce13f3f3SAdrian Knoth if (hdspm_is_raydat_or_aio(hdspm)) {
3217ce13f3f3SAdrian Knoth reg = &(hdspm->settings_register);
3218ce13f3f3SAdrian Knoth target_reg = HDSPM_WR_SETTINGS;
3219ce13f3f3SAdrian Knoth } else {
3220ce13f3f3SAdrian Knoth reg = &(hdspm->control_register);
3221ce13f3f3SAdrian Knoth target_reg = HDSPM_controlRegister;
3222ce13f3f3SAdrian Knoth }
3223ce13f3f3SAdrian Knoth
3224bf0ff87bSAdrian Knoth if (out)
3225ce13f3f3SAdrian Knoth *reg |= regmask;
3226bf0ff87bSAdrian Knoth else
3227ce13f3f3SAdrian Knoth *reg &= ~regmask;
3228ce13f3f3SAdrian Knoth
3229ce13f3f3SAdrian Knoth hdspm_write(hdspm, target_reg, *reg);
3230bf0ff87bSAdrian Knoth
3231bf0ff87bSAdrian Knoth return 0;
3232bf0ff87bSAdrian Knoth }
3233bf0ff87bSAdrian Knoth
3234bf0ff87bSAdrian Knoth #define snd_hdspm_info_toggle_setting snd_ctl_boolean_mono_info
3235bf0ff87bSAdrian Knoth
snd_hdspm_get_toggle_setting(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3236bf0ff87bSAdrian Knoth static int snd_hdspm_get_toggle_setting(struct snd_kcontrol *kcontrol,
3237bf0ff87bSAdrian Knoth struct snd_ctl_elem_value *ucontrol)
3238bf0ff87bSAdrian Knoth {
3239bf0ff87bSAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3240bf0ff87bSAdrian Knoth u32 regmask = kcontrol->private_value;
3241bf0ff87bSAdrian Knoth
3242bf0ff87bSAdrian Knoth spin_lock_irq(&hdspm->lock);
3243bf0ff87bSAdrian Knoth ucontrol->value.integer.value[0] = hdspm_toggle_setting(hdspm, regmask);
3244bf0ff87bSAdrian Knoth spin_unlock_irq(&hdspm->lock);
3245bf0ff87bSAdrian Knoth return 0;
3246bf0ff87bSAdrian Knoth }
3247bf0ff87bSAdrian Knoth
snd_hdspm_put_toggle_setting(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3248bf0ff87bSAdrian Knoth static int snd_hdspm_put_toggle_setting(struct snd_kcontrol *kcontrol,
3249bf0ff87bSAdrian Knoth struct snd_ctl_elem_value *ucontrol)
3250bf0ff87bSAdrian Knoth {
3251bf0ff87bSAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3252bf0ff87bSAdrian Knoth u32 regmask = kcontrol->private_value;
3253bf0ff87bSAdrian Knoth int change;
3254bf0ff87bSAdrian Knoth unsigned int val;
3255bf0ff87bSAdrian Knoth
3256bf0ff87bSAdrian Knoth if (!snd_hdspm_use_is_exclusive(hdspm))
3257bf0ff87bSAdrian Knoth return -EBUSY;
3258bf0ff87bSAdrian Knoth val = ucontrol->value.integer.value[0] & 1;
3259bf0ff87bSAdrian Knoth spin_lock_irq(&hdspm->lock);
3260bf0ff87bSAdrian Knoth change = (int) val != hdspm_toggle_setting(hdspm, regmask);
3261bf0ff87bSAdrian Knoth hdspm_set_toggle_setting(hdspm, regmask, val);
3262bf0ff87bSAdrian Knoth spin_unlock_irq(&hdspm->lock);
3263bf0ff87bSAdrian Knoth return change;
3264bf0ff87bSAdrian Knoth }
3265bf0ff87bSAdrian Knoth
3266763f356cSTakashi Iwai #define HDSPM_INPUT_SELECT(xname, xindex) \
326767ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3268763f356cSTakashi Iwai .name = xname, \
3269763f356cSTakashi Iwai .index = xindex, \
3270763f356cSTakashi Iwai .info = snd_hdspm_info_input_select, \
3271763f356cSTakashi Iwai .get = snd_hdspm_get_input_select, \
3272763f356cSTakashi Iwai .put = snd_hdspm_put_input_select \
3273763f356cSTakashi Iwai }
3274763f356cSTakashi Iwai
hdspm_input_select(struct hdspm * hdspm)327598274f07STakashi Iwai static int hdspm_input_select(struct hdspm * hdspm)
3276763f356cSTakashi Iwai {
3277763f356cSTakashi Iwai return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0;
3278763f356cSTakashi Iwai }
3279763f356cSTakashi Iwai
hdspm_set_input_select(struct hdspm * hdspm,int out)328098274f07STakashi Iwai static int hdspm_set_input_select(struct hdspm * hdspm, int out)
3281763f356cSTakashi Iwai {
3282763f356cSTakashi Iwai if (out)
3283763f356cSTakashi Iwai hdspm->control_register |= HDSPM_InputSelect0;
3284763f356cSTakashi Iwai else
3285763f356cSTakashi Iwai hdspm->control_register &= ~HDSPM_InputSelect0;
3286763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
3287763f356cSTakashi Iwai
3288763f356cSTakashi Iwai return 0;
3289763f356cSTakashi Iwai }
3290763f356cSTakashi Iwai
snd_hdspm_info_input_select(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)329198274f07STakashi Iwai static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol,
329298274f07STakashi Iwai struct snd_ctl_elem_info *uinfo)
3293763f356cSTakashi Iwai {
329438816545SAdrian Knoth static const char *const texts[] = { "optical", "coaxial" };
3295e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
3296763f356cSTakashi Iwai return 0;
3297763f356cSTakashi Iwai }
3298763f356cSTakashi Iwai
snd_hdspm_get_input_select(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)329998274f07STakashi Iwai static int snd_hdspm_get_input_select(struct snd_kcontrol *kcontrol,
330098274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3301763f356cSTakashi Iwai {
330298274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3303763f356cSTakashi Iwai
3304763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
3305763f356cSTakashi Iwai ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm);
3306763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
3307763f356cSTakashi Iwai return 0;
3308763f356cSTakashi Iwai }
3309763f356cSTakashi Iwai
snd_hdspm_put_input_select(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)331098274f07STakashi Iwai static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol,
331198274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3312763f356cSTakashi Iwai {
331398274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3314763f356cSTakashi Iwai int change;
3315763f356cSTakashi Iwai unsigned int val;
3316763f356cSTakashi Iwai
3317763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm))
3318763f356cSTakashi Iwai return -EBUSY;
3319763f356cSTakashi Iwai val = ucontrol->value.integer.value[0] & 1;
3320763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
3321763f356cSTakashi Iwai change = (int) val != hdspm_input_select(hdspm);
3322763f356cSTakashi Iwai hdspm_set_input_select(hdspm, val);
3323763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
3324763f356cSTakashi Iwai return change;
3325763f356cSTakashi Iwai }
3326763f356cSTakashi Iwai
33270dca1793SAdrian Knoth
33283cee5a60SRemy Bruno #define HDSPM_DS_WIRE(xname, xindex) \
33293cee5a60SRemy Bruno { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
33303cee5a60SRemy Bruno .name = xname, \
33313cee5a60SRemy Bruno .index = xindex, \
33323cee5a60SRemy Bruno .info = snd_hdspm_info_ds_wire, \
33333cee5a60SRemy Bruno .get = snd_hdspm_get_ds_wire, \
33343cee5a60SRemy Bruno .put = snd_hdspm_put_ds_wire \
33353cee5a60SRemy Bruno }
33363cee5a60SRemy Bruno
hdspm_ds_wire(struct hdspm * hdspm)33373cee5a60SRemy Bruno static int hdspm_ds_wire(struct hdspm * hdspm)
33383cee5a60SRemy Bruno {
33393cee5a60SRemy Bruno return (hdspm->control_register & HDSPM_DS_DoubleWire) ? 1 : 0;
33403cee5a60SRemy Bruno }
33413cee5a60SRemy Bruno
hdspm_set_ds_wire(struct hdspm * hdspm,int ds)33423cee5a60SRemy Bruno static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds)
33433cee5a60SRemy Bruno {
33443cee5a60SRemy Bruno if (ds)
33453cee5a60SRemy Bruno hdspm->control_register |= HDSPM_DS_DoubleWire;
33463cee5a60SRemy Bruno else
33473cee5a60SRemy Bruno hdspm->control_register &= ~HDSPM_DS_DoubleWire;
33483cee5a60SRemy Bruno hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
33493cee5a60SRemy Bruno
33503cee5a60SRemy Bruno return 0;
33513cee5a60SRemy Bruno }
33523cee5a60SRemy Bruno
snd_hdspm_info_ds_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)33533cee5a60SRemy Bruno static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol,
33543cee5a60SRemy Bruno struct snd_ctl_elem_info *uinfo)
33553cee5a60SRemy Bruno {
335638816545SAdrian Knoth static const char *const texts[] = { "Single", "Double" };
3357e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
33583cee5a60SRemy Bruno return 0;
33593cee5a60SRemy Bruno }
33603cee5a60SRemy Bruno
snd_hdspm_get_ds_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)33613cee5a60SRemy Bruno static int snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol,
33623cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol)
33633cee5a60SRemy Bruno {
33643cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
33653cee5a60SRemy Bruno
33663cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock);
33673cee5a60SRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm);
33683cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock);
33693cee5a60SRemy Bruno return 0;
33703cee5a60SRemy Bruno }
33713cee5a60SRemy Bruno
snd_hdspm_put_ds_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)33723cee5a60SRemy Bruno static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol,
33733cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol)
33743cee5a60SRemy Bruno {
33753cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
33763cee5a60SRemy Bruno int change;
33773cee5a60SRemy Bruno unsigned int val;
33783cee5a60SRemy Bruno
33793cee5a60SRemy Bruno if (!snd_hdspm_use_is_exclusive(hdspm))
33803cee5a60SRemy Bruno return -EBUSY;
33813cee5a60SRemy Bruno val = ucontrol->value.integer.value[0] & 1;
33823cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock);
33833cee5a60SRemy Bruno change = (int) val != hdspm_ds_wire(hdspm);
33843cee5a60SRemy Bruno hdspm_set_ds_wire(hdspm, val);
33853cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock);
33863cee5a60SRemy Bruno return change;
33873cee5a60SRemy Bruno }
33883cee5a60SRemy Bruno
33890dca1793SAdrian Knoth
33903cee5a60SRemy Bruno #define HDSPM_QS_WIRE(xname, xindex) \
33913cee5a60SRemy Bruno { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
33923cee5a60SRemy Bruno .name = xname, \
33933cee5a60SRemy Bruno .index = xindex, \
33943cee5a60SRemy Bruno .info = snd_hdspm_info_qs_wire, \
33953cee5a60SRemy Bruno .get = snd_hdspm_get_qs_wire, \
33963cee5a60SRemy Bruno .put = snd_hdspm_put_qs_wire \
33973cee5a60SRemy Bruno }
33983cee5a60SRemy Bruno
hdspm_qs_wire(struct hdspm * hdspm)33993cee5a60SRemy Bruno static int hdspm_qs_wire(struct hdspm * hdspm)
34003cee5a60SRemy Bruno {
34013cee5a60SRemy Bruno if (hdspm->control_register & HDSPM_QS_DoubleWire)
34023cee5a60SRemy Bruno return 1;
34033cee5a60SRemy Bruno if (hdspm->control_register & HDSPM_QS_QuadWire)
34043cee5a60SRemy Bruno return 2;
34053cee5a60SRemy Bruno return 0;
34063cee5a60SRemy Bruno }
34073cee5a60SRemy Bruno
hdspm_set_qs_wire(struct hdspm * hdspm,int mode)34083cee5a60SRemy Bruno static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode)
34093cee5a60SRemy Bruno {
34103cee5a60SRemy Bruno hdspm->control_register &= ~(HDSPM_QS_DoubleWire | HDSPM_QS_QuadWire);
34113cee5a60SRemy Bruno switch (mode) {
34123cee5a60SRemy Bruno case 0:
34133cee5a60SRemy Bruno break;
34143cee5a60SRemy Bruno case 1:
34153cee5a60SRemy Bruno hdspm->control_register |= HDSPM_QS_DoubleWire;
34163cee5a60SRemy Bruno break;
34173cee5a60SRemy Bruno case 2:
34183cee5a60SRemy Bruno hdspm->control_register |= HDSPM_QS_QuadWire;
34193cee5a60SRemy Bruno break;
34203cee5a60SRemy Bruno }
34213cee5a60SRemy Bruno hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
34223cee5a60SRemy Bruno
34233cee5a60SRemy Bruno return 0;
34243cee5a60SRemy Bruno }
34253cee5a60SRemy Bruno
snd_hdspm_info_qs_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)34263cee5a60SRemy Bruno static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol,
34273cee5a60SRemy Bruno struct snd_ctl_elem_info *uinfo)
34283cee5a60SRemy Bruno {
342938816545SAdrian Knoth static const char *const texts[] = { "Single", "Double", "Quad" };
3430e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
34313cee5a60SRemy Bruno return 0;
34323cee5a60SRemy Bruno }
34333cee5a60SRemy Bruno
snd_hdspm_get_qs_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)34343cee5a60SRemy Bruno static int snd_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol,
34353cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol)
34363cee5a60SRemy Bruno {
34373cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
34383cee5a60SRemy Bruno
34393cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock);
34403cee5a60SRemy Bruno ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm);
34413cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock);
34423cee5a60SRemy Bruno return 0;
34433cee5a60SRemy Bruno }
34443cee5a60SRemy Bruno
snd_hdspm_put_qs_wire(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)34453cee5a60SRemy Bruno static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
34463cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol)
34473cee5a60SRemy Bruno {
34483cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
34493cee5a60SRemy Bruno int change;
34503cee5a60SRemy Bruno int val;
34513cee5a60SRemy Bruno
34523cee5a60SRemy Bruno if (!snd_hdspm_use_is_exclusive(hdspm))
34533cee5a60SRemy Bruno return -EBUSY;
34543cee5a60SRemy Bruno val = ucontrol->value.integer.value[0];
34553cee5a60SRemy Bruno if (val < 0)
34563cee5a60SRemy Bruno val = 0;
34573cee5a60SRemy Bruno if (val > 2)
34583cee5a60SRemy Bruno val = 2;
34593cee5a60SRemy Bruno spin_lock_irq(&hdspm->lock);
3460ef5fa1a4STakashi Iwai change = val != hdspm_qs_wire(hdspm);
34613cee5a60SRemy Bruno hdspm_set_qs_wire(hdspm, val);
34623cee5a60SRemy Bruno spin_unlock_irq(&hdspm->lock);
34633cee5a60SRemy Bruno return change;
34643cee5a60SRemy Bruno }
34653cee5a60SRemy Bruno
3466acf14767SAdrian Knoth #define HDSPM_CONTROL_TRISTATE(xname, xindex) \
3467acf14767SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3468acf14767SAdrian Knoth .name = xname, \
3469acf14767SAdrian Knoth .private_value = xindex, \
3470acf14767SAdrian Knoth .info = snd_hdspm_info_tristate, \
3471acf14767SAdrian Knoth .get = snd_hdspm_get_tristate, \
3472acf14767SAdrian Knoth .put = snd_hdspm_put_tristate \
3473acf14767SAdrian Knoth }
3474acf14767SAdrian Knoth
hdspm_tristate(struct hdspm * hdspm,u32 regmask)3475acf14767SAdrian Knoth static int hdspm_tristate(struct hdspm *hdspm, u32 regmask)
3476acf14767SAdrian Knoth {
3477acf14767SAdrian Knoth u32 reg = hdspm->settings_register & (regmask * 3);
3478acf14767SAdrian Knoth return reg / regmask;
3479acf14767SAdrian Knoth }
3480acf14767SAdrian Knoth
hdspm_set_tristate(struct hdspm * hdspm,int mode,u32 regmask)3481acf14767SAdrian Knoth static int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask)
3482acf14767SAdrian Knoth {
3483acf14767SAdrian Knoth hdspm->settings_register &= ~(regmask * 3);
3484acf14767SAdrian Knoth hdspm->settings_register |= (regmask * mode);
3485acf14767SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
3486acf14767SAdrian Knoth
3487acf14767SAdrian Knoth return 0;
3488acf14767SAdrian Knoth }
3489acf14767SAdrian Knoth
snd_hdspm_info_tristate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3490acf14767SAdrian Knoth static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol,
3491acf14767SAdrian Knoth struct snd_ctl_elem_info *uinfo)
3492acf14767SAdrian Knoth {
3493acf14767SAdrian Knoth u32 regmask = kcontrol->private_value;
3494acf14767SAdrian Knoth
349538816545SAdrian Knoth static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" };
349638816545SAdrian Knoth static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" };
3497acf14767SAdrian Knoth
3498acf14767SAdrian Knoth switch (regmask) {
3499acf14767SAdrian Knoth case HDSPM_c0_Input0:
3500acf14767SAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts_spdif);
3501acf14767SAdrian Knoth break;
3502acf14767SAdrian Knoth default:
3503acf14767SAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts_levels);
3504acf14767SAdrian Knoth break;
3505acf14767SAdrian Knoth }
3506acf14767SAdrian Knoth return 0;
3507acf14767SAdrian Knoth }
3508acf14767SAdrian Knoth
snd_hdspm_get_tristate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3509acf14767SAdrian Knoth static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol,
3510acf14767SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
3511acf14767SAdrian Knoth {
3512acf14767SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3513acf14767SAdrian Knoth u32 regmask = kcontrol->private_value;
3514acf14767SAdrian Knoth
3515acf14767SAdrian Knoth spin_lock_irq(&hdspm->lock);
3516acf14767SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask);
3517acf14767SAdrian Knoth spin_unlock_irq(&hdspm->lock);
3518acf14767SAdrian Knoth return 0;
3519acf14767SAdrian Knoth }
3520acf14767SAdrian Knoth
snd_hdspm_put_tristate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3521acf14767SAdrian Knoth static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol,
3522acf14767SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
3523acf14767SAdrian Knoth {
3524acf14767SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3525acf14767SAdrian Knoth u32 regmask = kcontrol->private_value;
3526acf14767SAdrian Knoth int change;
3527acf14767SAdrian Knoth int val;
3528acf14767SAdrian Knoth
3529acf14767SAdrian Knoth if (!snd_hdspm_use_is_exclusive(hdspm))
3530acf14767SAdrian Knoth return -EBUSY;
3531acf14767SAdrian Knoth val = ucontrol->value.integer.value[0];
3532acf14767SAdrian Knoth if (val < 0)
3533acf14767SAdrian Knoth val = 0;
3534acf14767SAdrian Knoth if (val > 2)
3535acf14767SAdrian Knoth val = 2;
3536acf14767SAdrian Knoth
3537acf14767SAdrian Knoth spin_lock_irq(&hdspm->lock);
3538acf14767SAdrian Knoth change = val != hdspm_tristate(hdspm, regmask);
3539acf14767SAdrian Knoth hdspm_set_tristate(hdspm, val, regmask);
3540acf14767SAdrian Knoth spin_unlock_irq(&hdspm->lock);
3541acf14767SAdrian Knoth return change;
3542acf14767SAdrian Knoth }
3543acf14767SAdrian Knoth
3544700d1ef3SAdrian Knoth #define HDSPM_MADI_SPEEDMODE(xname, xindex) \
3545700d1ef3SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3546700d1ef3SAdrian Knoth .name = xname, \
3547700d1ef3SAdrian Knoth .index = xindex, \
3548700d1ef3SAdrian Knoth .info = snd_hdspm_info_madi_speedmode, \
3549700d1ef3SAdrian Knoth .get = snd_hdspm_get_madi_speedmode, \
3550700d1ef3SAdrian Knoth .put = snd_hdspm_put_madi_speedmode \
3551700d1ef3SAdrian Knoth }
3552700d1ef3SAdrian Knoth
hdspm_madi_speedmode(struct hdspm * hdspm)3553700d1ef3SAdrian Knoth static int hdspm_madi_speedmode(struct hdspm *hdspm)
3554700d1ef3SAdrian Knoth {
3555700d1ef3SAdrian Knoth if (hdspm->control_register & HDSPM_QuadSpeed)
3556700d1ef3SAdrian Knoth return 2;
3557700d1ef3SAdrian Knoth if (hdspm->control_register & HDSPM_DoubleSpeed)
3558700d1ef3SAdrian Knoth return 1;
3559700d1ef3SAdrian Knoth return 0;
3560700d1ef3SAdrian Knoth }
3561700d1ef3SAdrian Knoth
hdspm_set_madi_speedmode(struct hdspm * hdspm,int mode)3562700d1ef3SAdrian Knoth static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode)
3563700d1ef3SAdrian Knoth {
3564700d1ef3SAdrian Knoth hdspm->control_register &= ~(HDSPM_DoubleSpeed | HDSPM_QuadSpeed);
3565700d1ef3SAdrian Knoth switch (mode) {
3566700d1ef3SAdrian Knoth case 0:
3567700d1ef3SAdrian Knoth break;
3568700d1ef3SAdrian Knoth case 1:
3569700d1ef3SAdrian Knoth hdspm->control_register |= HDSPM_DoubleSpeed;
3570700d1ef3SAdrian Knoth break;
3571700d1ef3SAdrian Knoth case 2:
3572700d1ef3SAdrian Knoth hdspm->control_register |= HDSPM_QuadSpeed;
3573700d1ef3SAdrian Knoth break;
3574700d1ef3SAdrian Knoth }
3575700d1ef3SAdrian Knoth hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
3576700d1ef3SAdrian Knoth
3577700d1ef3SAdrian Knoth return 0;
3578700d1ef3SAdrian Knoth }
3579700d1ef3SAdrian Knoth
snd_hdspm_info_madi_speedmode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3580700d1ef3SAdrian Knoth static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol,
3581700d1ef3SAdrian Knoth struct snd_ctl_elem_info *uinfo)
3582700d1ef3SAdrian Knoth {
358338816545SAdrian Knoth static const char *const texts[] = { "Single", "Double", "Quad" };
3584e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
3585700d1ef3SAdrian Knoth return 0;
3586700d1ef3SAdrian Knoth }
3587700d1ef3SAdrian Knoth
snd_hdspm_get_madi_speedmode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3588700d1ef3SAdrian Knoth static int snd_hdspm_get_madi_speedmode(struct snd_kcontrol *kcontrol,
3589700d1ef3SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
3590700d1ef3SAdrian Knoth {
3591700d1ef3SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3592700d1ef3SAdrian Knoth
3593700d1ef3SAdrian Knoth spin_lock_irq(&hdspm->lock);
3594700d1ef3SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm_madi_speedmode(hdspm);
3595700d1ef3SAdrian Knoth spin_unlock_irq(&hdspm->lock);
3596700d1ef3SAdrian Knoth return 0;
3597700d1ef3SAdrian Knoth }
3598700d1ef3SAdrian Knoth
snd_hdspm_put_madi_speedmode(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3599700d1ef3SAdrian Knoth static int snd_hdspm_put_madi_speedmode(struct snd_kcontrol *kcontrol,
3600700d1ef3SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
3601700d1ef3SAdrian Knoth {
3602700d1ef3SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3603700d1ef3SAdrian Knoth int change;
3604700d1ef3SAdrian Knoth int val;
3605700d1ef3SAdrian Knoth
3606700d1ef3SAdrian Knoth if (!snd_hdspm_use_is_exclusive(hdspm))
3607700d1ef3SAdrian Knoth return -EBUSY;
3608700d1ef3SAdrian Knoth val = ucontrol->value.integer.value[0];
3609700d1ef3SAdrian Knoth if (val < 0)
3610700d1ef3SAdrian Knoth val = 0;
3611700d1ef3SAdrian Knoth if (val > 2)
3612700d1ef3SAdrian Knoth val = 2;
3613700d1ef3SAdrian Knoth spin_lock_irq(&hdspm->lock);
3614700d1ef3SAdrian Knoth change = val != hdspm_madi_speedmode(hdspm);
3615700d1ef3SAdrian Knoth hdspm_set_madi_speedmode(hdspm, val);
3616700d1ef3SAdrian Knoth spin_unlock_irq(&hdspm->lock);
3617700d1ef3SAdrian Knoth return change;
3618700d1ef3SAdrian Knoth }
3619763f356cSTakashi Iwai
3620763f356cSTakashi Iwai #define HDSPM_MIXER(xname, xindex) \
3621763f356cSTakashi Iwai { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
3622763f356cSTakashi Iwai .name = xname, \
3623763f356cSTakashi Iwai .index = xindex, \
362467ed4161SClemens Ladisch .device = 0, \
3625763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
3626763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3627763f356cSTakashi Iwai .info = snd_hdspm_info_mixer, \
3628763f356cSTakashi Iwai .get = snd_hdspm_get_mixer, \
3629763f356cSTakashi Iwai .put = snd_hdspm_put_mixer \
3630763f356cSTakashi Iwai }
3631763f356cSTakashi Iwai
snd_hdspm_info_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)363298274f07STakashi Iwai static int snd_hdspm_info_mixer(struct snd_kcontrol *kcontrol,
363398274f07STakashi Iwai struct snd_ctl_elem_info *uinfo)
3634763f356cSTakashi Iwai {
3635763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3636763f356cSTakashi Iwai uinfo->count = 3;
3637763f356cSTakashi Iwai uinfo->value.integer.min = 0;
3638763f356cSTakashi Iwai uinfo->value.integer.max = 65535;
3639763f356cSTakashi Iwai uinfo->value.integer.step = 1;
3640763f356cSTakashi Iwai return 0;
3641763f356cSTakashi Iwai }
3642763f356cSTakashi Iwai
snd_hdspm_get_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)364398274f07STakashi Iwai static int snd_hdspm_get_mixer(struct snd_kcontrol *kcontrol,
364498274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3645763f356cSTakashi Iwai {
364698274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3647763f356cSTakashi Iwai int source;
3648763f356cSTakashi Iwai int destination;
3649763f356cSTakashi Iwai
3650763f356cSTakashi Iwai source = ucontrol->value.integer.value[0];
3651763f356cSTakashi Iwai if (source < 0)
3652763f356cSTakashi Iwai source = 0;
3653763f356cSTakashi Iwai else if (source >= 2 * HDSPM_MAX_CHANNELS)
3654763f356cSTakashi Iwai source = 2 * HDSPM_MAX_CHANNELS - 1;
3655763f356cSTakashi Iwai
3656763f356cSTakashi Iwai destination = ucontrol->value.integer.value[1];
3657763f356cSTakashi Iwai if (destination < 0)
3658763f356cSTakashi Iwai destination = 0;
3659763f356cSTakashi Iwai else if (destination >= HDSPM_MAX_CHANNELS)
3660763f356cSTakashi Iwai destination = HDSPM_MAX_CHANNELS - 1;
3661763f356cSTakashi Iwai
3662763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
3663763f356cSTakashi Iwai if (source >= HDSPM_MAX_CHANNELS)
3664763f356cSTakashi Iwai ucontrol->value.integer.value[2] =
3665763f356cSTakashi Iwai hdspm_read_pb_gain(hdspm, destination,
3666763f356cSTakashi Iwai source - HDSPM_MAX_CHANNELS);
3667763f356cSTakashi Iwai else
3668763f356cSTakashi Iwai ucontrol->value.integer.value[2] =
3669763f356cSTakashi Iwai hdspm_read_in_gain(hdspm, destination, source);
3670763f356cSTakashi Iwai
3671763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
3672763f356cSTakashi Iwai
3673763f356cSTakashi Iwai return 0;
3674763f356cSTakashi Iwai }
3675763f356cSTakashi Iwai
snd_hdspm_put_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)367698274f07STakashi Iwai static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol,
367798274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3678763f356cSTakashi Iwai {
367998274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3680763f356cSTakashi Iwai int change;
3681763f356cSTakashi Iwai int source;
3682763f356cSTakashi Iwai int destination;
3683763f356cSTakashi Iwai int gain;
3684763f356cSTakashi Iwai
3685763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm))
3686763f356cSTakashi Iwai return -EBUSY;
3687763f356cSTakashi Iwai
3688763f356cSTakashi Iwai source = ucontrol->value.integer.value[0];
3689763f356cSTakashi Iwai destination = ucontrol->value.integer.value[1];
3690763f356cSTakashi Iwai
3691763f356cSTakashi Iwai if (source < 0 || source >= 2 * HDSPM_MAX_CHANNELS)
3692763f356cSTakashi Iwai return -1;
3693763f356cSTakashi Iwai if (destination < 0 || destination >= HDSPM_MAX_CHANNELS)
3694763f356cSTakashi Iwai return -1;
3695763f356cSTakashi Iwai
3696763f356cSTakashi Iwai gain = ucontrol->value.integer.value[2];
3697763f356cSTakashi Iwai
3698763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
3699763f356cSTakashi Iwai
3700763f356cSTakashi Iwai if (source >= HDSPM_MAX_CHANNELS)
3701763f356cSTakashi Iwai change = gain != hdspm_read_pb_gain(hdspm, destination,
3702763f356cSTakashi Iwai source -
3703763f356cSTakashi Iwai HDSPM_MAX_CHANNELS);
3704763f356cSTakashi Iwai else
3705ef5fa1a4STakashi Iwai change = gain != hdspm_read_in_gain(hdspm, destination,
3706ef5fa1a4STakashi Iwai source);
3707763f356cSTakashi Iwai
3708763f356cSTakashi Iwai if (change) {
3709763f356cSTakashi Iwai if (source >= HDSPM_MAX_CHANNELS)
3710763f356cSTakashi Iwai hdspm_write_pb_gain(hdspm, destination,
3711763f356cSTakashi Iwai source - HDSPM_MAX_CHANNELS,
3712763f356cSTakashi Iwai gain);
3713763f356cSTakashi Iwai else
3714763f356cSTakashi Iwai hdspm_write_in_gain(hdspm, destination, source,
3715763f356cSTakashi Iwai gain);
3716763f356cSTakashi Iwai }
3717763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
3718763f356cSTakashi Iwai
3719763f356cSTakashi Iwai return change;
3720763f356cSTakashi Iwai }
3721763f356cSTakashi Iwai
3722763f356cSTakashi Iwai /* The simple mixer control(s) provide gain control for the
3723763f356cSTakashi Iwai basic 1:1 mappings of playback streams to output
3724763f356cSTakashi Iwai streams.
3725763f356cSTakashi Iwai */
3726763f356cSTakashi Iwai
3727763f356cSTakashi Iwai #define HDSPM_PLAYBACK_MIXER \
3728763f356cSTakashi Iwai { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3729763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \
3730763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3731763f356cSTakashi Iwai .info = snd_hdspm_info_playback_mixer, \
3732763f356cSTakashi Iwai .get = snd_hdspm_get_playback_mixer, \
3733763f356cSTakashi Iwai .put = snd_hdspm_put_playback_mixer \
3734763f356cSTakashi Iwai }
3735763f356cSTakashi Iwai
snd_hdspm_info_playback_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)373698274f07STakashi Iwai static int snd_hdspm_info_playback_mixer(struct snd_kcontrol *kcontrol,
373798274f07STakashi Iwai struct snd_ctl_elem_info *uinfo)
3738763f356cSTakashi Iwai {
3739763f356cSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3740763f356cSTakashi Iwai uinfo->count = 1;
3741763f356cSTakashi Iwai uinfo->value.integer.min = 0;
37420dca1793SAdrian Knoth uinfo->value.integer.max = 64;
3743763f356cSTakashi Iwai uinfo->value.integer.step = 1;
3744763f356cSTakashi Iwai return 0;
3745763f356cSTakashi Iwai }
3746763f356cSTakashi Iwai
snd_hdspm_get_playback_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)374798274f07STakashi Iwai static int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol,
374898274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3749763f356cSTakashi Iwai {
375098274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3751763f356cSTakashi Iwai int channel;
3752763f356cSTakashi Iwai
3753763f356cSTakashi Iwai channel = ucontrol->id.index - 1;
3754763f356cSTakashi Iwai
3755da3cec35STakashi Iwai if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
3756da3cec35STakashi Iwai return -EINVAL;
3757763f356cSTakashi Iwai
3758763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
3759763f356cSTakashi Iwai ucontrol->value.integer.value[0] =
37600dca1793SAdrian Knoth (hdspm_read_pb_gain(hdspm, channel, channel)*64)/UNITY_GAIN;
3761763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
3762763f356cSTakashi Iwai
3763763f356cSTakashi Iwai return 0;
3764763f356cSTakashi Iwai }
3765763f356cSTakashi Iwai
snd_hdspm_put_playback_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)376698274f07STakashi Iwai static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
376798274f07STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3768763f356cSTakashi Iwai {
376998274f07STakashi Iwai struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
3770763f356cSTakashi Iwai int change;
3771763f356cSTakashi Iwai int channel;
3772763f356cSTakashi Iwai int gain;
3773763f356cSTakashi Iwai
3774763f356cSTakashi Iwai if (!snd_hdspm_use_is_exclusive(hdspm))
3775763f356cSTakashi Iwai return -EBUSY;
3776763f356cSTakashi Iwai
3777763f356cSTakashi Iwai channel = ucontrol->id.index - 1;
3778763f356cSTakashi Iwai
3779da3cec35STakashi Iwai if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
3780da3cec35STakashi Iwai return -EINVAL;
3781763f356cSTakashi Iwai
37820dca1793SAdrian Knoth gain = ucontrol->value.integer.value[0]*UNITY_GAIN/64;
3783763f356cSTakashi Iwai
3784763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
3785763f356cSTakashi Iwai change =
37860dca1793SAdrian Knoth gain != hdspm_read_pb_gain(hdspm, channel,
37870dca1793SAdrian Knoth channel);
3788763f356cSTakashi Iwai if (change)
37890dca1793SAdrian Knoth hdspm_write_pb_gain(hdspm, channel, channel,
3790763f356cSTakashi Iwai gain);
3791763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
3792763f356cSTakashi Iwai return change;
3793763f356cSTakashi Iwai }
3794763f356cSTakashi Iwai
37950dca1793SAdrian Knoth #define HDSPM_SYNC_CHECK(xname, xindex) \
379667ed4161SClemens Ladisch { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3797763f356cSTakashi Iwai .name = xname, \
37980dca1793SAdrian Knoth .private_value = xindex, \
3799763f356cSTakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3800763f356cSTakashi Iwai .info = snd_hdspm_info_sync_check, \
38010dca1793SAdrian Knoth .get = snd_hdspm_get_sync_check \
3802763f356cSTakashi Iwai }
3803763f356cSTakashi Iwai
380434542213SAdrian Knoth #define HDSPM_TCO_LOCK_CHECK(xname, xindex) \
380534542213SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
380634542213SAdrian Knoth .name = xname, \
380734542213SAdrian Knoth .private_value = xindex, \
380834542213SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
380934542213SAdrian Knoth .info = snd_hdspm_tco_info_lock_check, \
381034542213SAdrian Knoth .get = snd_hdspm_get_sync_check \
381134542213SAdrian Knoth }
381234542213SAdrian Knoth
381334542213SAdrian Knoth
38140dca1793SAdrian Knoth
snd_hdspm_info_sync_check(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)381598274f07STakashi Iwai static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
381698274f07STakashi Iwai struct snd_ctl_elem_info *uinfo)
3817763f356cSTakashi Iwai {
381838816545SAdrian Knoth static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" };
3819e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
3820763f356cSTakashi Iwai return 0;
3821763f356cSTakashi Iwai }
3822763f356cSTakashi Iwai
snd_hdspm_tco_info_lock_check(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)382334542213SAdrian Knoth static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol,
382434542213SAdrian Knoth struct snd_ctl_elem_info *uinfo)
382534542213SAdrian Knoth {
382638816545SAdrian Knoth static const char *const texts[] = { "No Lock", "Lock" };
382734542213SAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
382834542213SAdrian Knoth return 0;
382934542213SAdrian Knoth }
383034542213SAdrian Knoth
hdspm_wc_sync_check(struct hdspm * hdspm)383198274f07STakashi Iwai static int hdspm_wc_sync_check(struct hdspm *hdspm)
3832763f356cSTakashi Iwai {
38330dca1793SAdrian Knoth int status, status2;
38340dca1793SAdrian Knoth
38350dca1793SAdrian Knoth switch (hdspm->io_type) {
38360dca1793SAdrian Knoth case AES32:
38370dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister);
383856bde0f3SAndre Schramm if (status & HDSPM_AES32_wcLock) {
383956bde0f3SAndre Schramm if (status & HDSPM_AES32_wcSync)
38403cee5a60SRemy Bruno return 2;
384156bde0f3SAndre Schramm else
38420dca1793SAdrian Knoth return 1;
384356bde0f3SAndre Schramm }
38443cee5a60SRemy Bruno return 0;
38450dca1793SAdrian Knoth
38460dca1793SAdrian Knoth case MADI:
38470dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
3848763f356cSTakashi Iwai if (status2 & HDSPM_wcLock) {
3849763f356cSTakashi Iwai if (status2 & HDSPM_wcSync)
3850763f356cSTakashi Iwai return 2;
3851763f356cSTakashi Iwai else
3852763f356cSTakashi Iwai return 1;
3853763f356cSTakashi Iwai }
3854763f356cSTakashi Iwai return 0;
3855763f356cSTakashi Iwai
38560dca1793SAdrian Knoth case RayDAT:
38570dca1793SAdrian Knoth case AIO:
38580dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister);
3859763f356cSTakashi Iwai
38600dca1793SAdrian Knoth if (status & 0x2000000)
38610dca1793SAdrian Knoth return 2;
38620dca1793SAdrian Knoth else if (status & 0x1000000)
38630dca1793SAdrian Knoth return 1;
3864763f356cSTakashi Iwai return 0;
38650dca1793SAdrian Knoth
38660dca1793SAdrian Knoth case MADIface:
38670dca1793SAdrian Knoth break;
3868763f356cSTakashi Iwai }
3869763f356cSTakashi Iwai
3870763f356cSTakashi Iwai
38710dca1793SAdrian Knoth return 3;
3872763f356cSTakashi Iwai }
3873763f356cSTakashi Iwai
38740dca1793SAdrian Knoth
hdspm_madi_sync_check(struct hdspm * hdspm)38750dca1793SAdrian Knoth static int hdspm_madi_sync_check(struct hdspm *hdspm)
3876763f356cSTakashi Iwai {
3877763f356cSTakashi Iwai int status = hdspm_read(hdspm, HDSPM_statusRegister);
3878763f356cSTakashi Iwai if (status & HDSPM_madiLock) {
3879763f356cSTakashi Iwai if (status & HDSPM_madiSync)
3880763f356cSTakashi Iwai return 2;
3881763f356cSTakashi Iwai else
3882763f356cSTakashi Iwai return 1;
3883763f356cSTakashi Iwai }
3884763f356cSTakashi Iwai return 0;
3885763f356cSTakashi Iwai }
3886763f356cSTakashi Iwai
3887763f356cSTakashi Iwai
hdspm_s1_sync_check(struct hdspm * hdspm,int idx)38880dca1793SAdrian Knoth static int hdspm_s1_sync_check(struct hdspm *hdspm, int idx)
38890dca1793SAdrian Knoth {
38900dca1793SAdrian Knoth int status, lock, sync;
38910dca1793SAdrian Knoth
38920dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
38930dca1793SAdrian Knoth
38940dca1793SAdrian Knoth lock = (status & (0x1<<idx)) ? 1 : 0;
38950dca1793SAdrian Knoth sync = (status & (0x100<<idx)) ? 1 : 0;
38960dca1793SAdrian Knoth
38970dca1793SAdrian Knoth if (lock && sync)
38980dca1793SAdrian Knoth return 2;
38990dca1793SAdrian Knoth else if (lock)
39000dca1793SAdrian Knoth return 1;
3901763f356cSTakashi Iwai return 0;
3902763f356cSTakashi Iwai }
3903763f356cSTakashi Iwai
3904763f356cSTakashi Iwai
hdspm_sync_in_sync_check(struct hdspm * hdspm)39050dca1793SAdrian Knoth static int hdspm_sync_in_sync_check(struct hdspm *hdspm)
39060dca1793SAdrian Knoth {
39070dca1793SAdrian Knoth int status, lock = 0, sync = 0;
39080dca1793SAdrian Knoth
39090dca1793SAdrian Knoth switch (hdspm->io_type) {
39100dca1793SAdrian Knoth case RayDAT:
39110dca1793SAdrian Knoth case AIO:
39120dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_3);
39130dca1793SAdrian Knoth lock = (status & 0x400) ? 1 : 0;
39140dca1793SAdrian Knoth sync = (status & 0x800) ? 1 : 0;
39150dca1793SAdrian Knoth break;
39160dca1793SAdrian Knoth
39170dca1793SAdrian Knoth case MADI:
39182e0452f5SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister);
39192e0452f5SAdrian Knoth lock = (status & HDSPM_syncInLock) ? 1 : 0;
39202e0452f5SAdrian Knoth sync = (status & HDSPM_syncInSync) ? 1 : 0;
39212e0452f5SAdrian Knoth break;
39222e0452f5SAdrian Knoth
39230dca1793SAdrian Knoth case AES32:
39240dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister2);
39259a215f47SAdrian Knoth lock = (status & 0x100000) ? 1 : 0;
39269a215f47SAdrian Knoth sync = (status & 0x200000) ? 1 : 0;
39270dca1793SAdrian Knoth break;
39280dca1793SAdrian Knoth
39290dca1793SAdrian Knoth case MADIface:
39300dca1793SAdrian Knoth break;
39310dca1793SAdrian Knoth }
39320dca1793SAdrian Knoth
39330dca1793SAdrian Knoth if (lock && sync)
39340dca1793SAdrian Knoth return 2;
39350dca1793SAdrian Knoth else if (lock)
39360dca1793SAdrian Knoth return 1;
39370dca1793SAdrian Knoth
39380dca1793SAdrian Knoth return 0;
39393cee5a60SRemy Bruno }
39403cee5a60SRemy Bruno
hdspm_aes_sync_check(struct hdspm * hdspm,int idx)39413cee5a60SRemy Bruno static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx)
39423cee5a60SRemy Bruno {
39430dca1793SAdrian Knoth int status2, lock, sync;
39440dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
39450dca1793SAdrian Knoth
39460dca1793SAdrian Knoth lock = (status2 & (0x0080 >> idx)) ? 1 : 0;
39470dca1793SAdrian Knoth sync = (status2 & (0x8000 >> idx)) ? 1 : 0;
39480dca1793SAdrian Knoth
39490dca1793SAdrian Knoth if (sync)
39503cee5a60SRemy Bruno return 2;
39510dca1793SAdrian Knoth else if (lock)
39520dca1793SAdrian Knoth return 1;
39533cee5a60SRemy Bruno return 0;
39543cee5a60SRemy Bruno }
39553cee5a60SRemy Bruno
hdspm_tco_input_check(struct hdspm * hdspm,u32 mask)395634542213SAdrian Knoth static int hdspm_tco_input_check(struct hdspm *hdspm, u32 mask)
395734542213SAdrian Knoth {
395834542213SAdrian Knoth u32 status;
395934542213SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
396034542213SAdrian Knoth
396134542213SAdrian Knoth return (status & mask) ? 1 : 0;
396234542213SAdrian Knoth }
396334542213SAdrian Knoth
39640dca1793SAdrian Knoth
hdspm_tco_sync_check(struct hdspm * hdspm)39650dca1793SAdrian Knoth static int hdspm_tco_sync_check(struct hdspm *hdspm)
39660dca1793SAdrian Knoth {
39670dca1793SAdrian Knoth int status;
39680dca1793SAdrian Knoth
39690dca1793SAdrian Knoth if (hdspm->tco) {
39700dca1793SAdrian Knoth switch (hdspm->io_type) {
39710dca1793SAdrian Knoth case MADI:
3972b0bf5504SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister);
3973b0bf5504SAdrian Knoth if (status & HDSPM_tcoLockMadi) {
3974b0bf5504SAdrian Knoth if (status & HDSPM_tcoSync)
3975b0bf5504SAdrian Knoth return 2;
3976b0bf5504SAdrian Knoth else
3977b0bf5504SAdrian Knoth return 1;
3978b0bf5504SAdrian Knoth }
3979b0bf5504SAdrian Knoth return 0;
39800dca1793SAdrian Knoth case AES32:
39810dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister);
3982b0bf5504SAdrian Knoth if (status & HDSPM_tcoLockAes) {
39830dca1793SAdrian Knoth if (status & HDSPM_tcoSync)
39840dca1793SAdrian Knoth return 2;
39850dca1793SAdrian Knoth else
39860dca1793SAdrian Knoth return 1;
39870dca1793SAdrian Knoth }
39880dca1793SAdrian Knoth return 0;
39890dca1793SAdrian Knoth case RayDAT:
39900dca1793SAdrian Knoth case AIO:
39910dca1793SAdrian Knoth status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
39920dca1793SAdrian Knoth
39930dca1793SAdrian Knoth if (status & 0x8000000)
39940dca1793SAdrian Knoth return 2; /* Sync */
39950dca1793SAdrian Knoth if (status & 0x4000000)
39960dca1793SAdrian Knoth return 1; /* Lock */
39970dca1793SAdrian Knoth return 0; /* No signal */
39980dca1793SAdrian Knoth
39990dca1793SAdrian Knoth default:
40000dca1793SAdrian Knoth break;
40010dca1793SAdrian Knoth }
40020dca1793SAdrian Knoth }
40030dca1793SAdrian Knoth
40040dca1793SAdrian Knoth return 3; /* N/A */
40050dca1793SAdrian Knoth }
40060dca1793SAdrian Knoth
40070dca1793SAdrian Knoth
snd_hdspm_get_sync_check(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)40080dca1793SAdrian Knoth static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
40093cee5a60SRemy Bruno struct snd_ctl_elem_value *ucontrol)
40103cee5a60SRemy Bruno {
40113cee5a60SRemy Bruno struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
40120dca1793SAdrian Knoth int val = -1;
40133cee5a60SRemy Bruno
40140dca1793SAdrian Knoth switch (hdspm->io_type) {
40150dca1793SAdrian Knoth case RayDAT:
40160dca1793SAdrian Knoth switch (kcontrol->private_value) {
40170dca1793SAdrian Knoth case 0: /* WC */
40180dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break;
40190dca1793SAdrian Knoth case 7: /* TCO */
40200dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break;
40210dca1793SAdrian Knoth case 8: /* SYNC IN */
40220dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break;
40230dca1793SAdrian Knoth default:
4024d1a3c98dSAdrian Knoth val = hdspm_s1_sync_check(hdspm,
4025d1a3c98dSAdrian Knoth kcontrol->private_value-1);
40260dca1793SAdrian Knoth }
4027fba30fd3SAdrian Knoth break;
40283cee5a60SRemy Bruno
40290dca1793SAdrian Knoth case AIO:
40300dca1793SAdrian Knoth switch (kcontrol->private_value) {
40310dca1793SAdrian Knoth case 0: /* WC */
40320dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break;
40330dca1793SAdrian Knoth case 4: /* TCO */
40340dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break;
40350dca1793SAdrian Knoth case 5: /* SYNC IN */
40360dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break;
40370dca1793SAdrian Knoth default:
40381cb7dbf4SAdrian Knoth val = hdspm_s1_sync_check(hdspm,
40391cb7dbf4SAdrian Knoth kcontrol->private_value-1);
40400dca1793SAdrian Knoth }
4041fba30fd3SAdrian Knoth break;
40420dca1793SAdrian Knoth
40430dca1793SAdrian Knoth case MADI:
40440dca1793SAdrian Knoth switch (kcontrol->private_value) {
40450dca1793SAdrian Knoth case 0: /* WC */
40460dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break;
40470dca1793SAdrian Knoth case 1: /* MADI */
40480dca1793SAdrian Knoth val = hdspm_madi_sync_check(hdspm); break;
40490dca1793SAdrian Knoth case 2: /* TCO */
40500dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break;
40510dca1793SAdrian Knoth case 3: /* SYNC_IN */
40520dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break;
40530dca1793SAdrian Knoth }
4054fba30fd3SAdrian Knoth break;
40550dca1793SAdrian Knoth
40560dca1793SAdrian Knoth case MADIface:
40570dca1793SAdrian Knoth val = hdspm_madi_sync_check(hdspm); /* MADI */
40580dca1793SAdrian Knoth break;
40590dca1793SAdrian Knoth
40600dca1793SAdrian Knoth case AES32:
40610dca1793SAdrian Knoth switch (kcontrol->private_value) {
40620dca1793SAdrian Knoth case 0: /* WC */
40630dca1793SAdrian Knoth val = hdspm_wc_sync_check(hdspm); break;
40640dca1793SAdrian Knoth case 9: /* TCO */
40650dca1793SAdrian Knoth val = hdspm_tco_sync_check(hdspm); break;
40660dca1793SAdrian Knoth case 10 /* SYNC IN */:
40670dca1793SAdrian Knoth val = hdspm_sync_in_sync_check(hdspm); break;
40687c4a95b5SAdrian Knoth default: /* AES1 to AES8 */
40690dca1793SAdrian Knoth val = hdspm_aes_sync_check(hdspm,
40707c4a95b5SAdrian Knoth kcontrol->private_value-1);
40710dca1793SAdrian Knoth }
4072fba30fd3SAdrian Knoth break;
40730dca1793SAdrian Knoth
40740dca1793SAdrian Knoth }
40750dca1793SAdrian Knoth
407634542213SAdrian Knoth if (hdspm->tco) {
407734542213SAdrian Knoth switch (kcontrol->private_value) {
407834542213SAdrian Knoth case 11:
407934542213SAdrian Knoth /* Check TCO for lock state of its current input */
408034542213SAdrian Knoth val = hdspm_tco_input_check(hdspm, HDSPM_TCO1_TCO_lock);
408134542213SAdrian Knoth break;
408234542213SAdrian Knoth case 12:
408334542213SAdrian Knoth /* Check TCO for valid time code on LTC input. */
408434542213SAdrian Knoth val = hdspm_tco_input_check(hdspm,
408534542213SAdrian Knoth HDSPM_TCO1_LTC_Input_valid);
408634542213SAdrian Knoth break;
408734542213SAdrian Knoth default:
408834542213SAdrian Knoth break;
408934542213SAdrian Knoth }
409034542213SAdrian Knoth }
409134542213SAdrian Knoth
40920dca1793SAdrian Knoth if (-1 == val)
40930dca1793SAdrian Knoth val = 3;
40940dca1793SAdrian Knoth
40950dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = val;
40963cee5a60SRemy Bruno return 0;
40973cee5a60SRemy Bruno }
4098763f356cSTakashi Iwai
4099763f356cSTakashi Iwai
41000dca1793SAdrian Knoth
4101ddcecf6bSTakashi Iwai /*
41020dca1793SAdrian Knoth * TCO controls
4103ddcecf6bSTakashi Iwai */
hdspm_tco_write(struct hdspm * hdspm)41040dca1793SAdrian Knoth static void hdspm_tco_write(struct hdspm *hdspm)
41050dca1793SAdrian Knoth {
41060dca1793SAdrian Knoth unsigned int tc[4] = { 0, 0, 0, 0};
41070dca1793SAdrian Knoth
41080dca1793SAdrian Knoth switch (hdspm->tco->input) {
41090dca1793SAdrian Knoth case 0:
41100dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_input_MSB;
41110dca1793SAdrian Knoth break;
41120dca1793SAdrian Knoth case 1:
41130dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_input_LSB;
41140dca1793SAdrian Knoth break;
41150dca1793SAdrian Knoth default:
41160dca1793SAdrian Knoth break;
41170dca1793SAdrian Knoth }
41180dca1793SAdrian Knoth
41190dca1793SAdrian Knoth switch (hdspm->tco->framerate) {
41200dca1793SAdrian Knoth case 1:
41210dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_LSB;
41220dca1793SAdrian Knoth break;
41230dca1793SAdrian Knoth case 2:
41240dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_MSB;
41250dca1793SAdrian Knoth break;
41260dca1793SAdrian Knoth case 3:
41270dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_MSB +
41280dca1793SAdrian Knoth HDSPM_TCO1_set_drop_frame_flag;
41290dca1793SAdrian Knoth break;
41300dca1793SAdrian Knoth case 4:
41310dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_LSB +
41320dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB;
41330dca1793SAdrian Knoth break;
41340dca1793SAdrian Knoth case 5:
41350dca1793SAdrian Knoth tc[1] |= HDSPM_TCO1_LTC_Format_LSB +
41360dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB +
41370dca1793SAdrian Knoth HDSPM_TCO1_set_drop_frame_flag;
41380dca1793SAdrian Knoth break;
41390dca1793SAdrian Knoth default:
41400dca1793SAdrian Knoth break;
41410dca1793SAdrian Knoth }
41420dca1793SAdrian Knoth
41430dca1793SAdrian Knoth switch (hdspm->tco->wordclock) {
41440dca1793SAdrian Knoth case 1:
41450dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_WCK_IO_ratio_LSB;
41460dca1793SAdrian Knoth break;
41470dca1793SAdrian Knoth case 2:
41480dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_WCK_IO_ratio_MSB;
41490dca1793SAdrian Knoth break;
41500dca1793SAdrian Knoth default:
41510dca1793SAdrian Knoth break;
41520dca1793SAdrian Knoth }
41530dca1793SAdrian Knoth
41540dca1793SAdrian Knoth switch (hdspm->tco->samplerate) {
41550dca1793SAdrian Knoth case 1:
41560dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_freq;
41570dca1793SAdrian Knoth break;
41580dca1793SAdrian Knoth case 2:
41590dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_freq_from_app;
41600dca1793SAdrian Knoth break;
41610dca1793SAdrian Knoth default:
41620dca1793SAdrian Knoth break;
41630dca1793SAdrian Knoth }
41640dca1793SAdrian Knoth
41650dca1793SAdrian Knoth switch (hdspm->tco->pull) {
41660dca1793SAdrian Knoth case 1:
41670dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_up;
41680dca1793SAdrian Knoth break;
41690dca1793SAdrian Knoth case 2:
41700dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_down;
41710dca1793SAdrian Knoth break;
41720dca1793SAdrian Knoth case 3:
41730dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_up + HDSPM_TCO2_set_01_4;
41740dca1793SAdrian Knoth break;
41750dca1793SAdrian Knoth case 4:
41760dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_pull_down + HDSPM_TCO2_set_01_4;
41770dca1793SAdrian Knoth break;
41780dca1793SAdrian Knoth default:
41790dca1793SAdrian Knoth break;
41800dca1793SAdrian Knoth }
41810dca1793SAdrian Knoth
41820dca1793SAdrian Knoth if (1 == hdspm->tco->term) {
41830dca1793SAdrian Knoth tc[2] |= HDSPM_TCO2_set_term_75R;
41840dca1793SAdrian Knoth }
41850dca1793SAdrian Knoth
41860dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO, tc[0]);
41870dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO+4, tc[1]);
41880dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO+8, tc[2]);
41890dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_TCO+12, tc[3]);
41900dca1793SAdrian Knoth }
41910dca1793SAdrian Knoth
41920dca1793SAdrian Knoth
41930dca1793SAdrian Knoth #define HDSPM_TCO_SAMPLE_RATE(xname, xindex) \
41940dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
41950dca1793SAdrian Knoth .name = xname, \
41960dca1793SAdrian Knoth .index = xindex, \
41970dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
41980dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
41990dca1793SAdrian Knoth .info = snd_hdspm_info_tco_sample_rate, \
42000dca1793SAdrian Knoth .get = snd_hdspm_get_tco_sample_rate, \
42010dca1793SAdrian Knoth .put = snd_hdspm_put_tco_sample_rate \
42020dca1793SAdrian Knoth }
42030dca1793SAdrian Knoth
snd_hdspm_info_tco_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)42040dca1793SAdrian Knoth static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol,
42050dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo)
42060dca1793SAdrian Knoth {
420769358fcaSMartin Dausel /* TODO freq from app could be supported here, see tco->samplerate */
420838816545SAdrian Knoth static const char *const texts[] = { "44.1 kHz", "48 kHz" };
4209e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
42100dca1793SAdrian Knoth return 0;
42110dca1793SAdrian Knoth }
42120dca1793SAdrian Knoth
snd_hdspm_get_tco_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)42130dca1793SAdrian Knoth static int snd_hdspm_get_tco_sample_rate(struct snd_kcontrol *kcontrol,
42140dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
42150dca1793SAdrian Knoth {
42160dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
42170dca1793SAdrian Knoth
42180dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->samplerate;
42190dca1793SAdrian Knoth
42200dca1793SAdrian Knoth return 0;
42210dca1793SAdrian Knoth }
42220dca1793SAdrian Knoth
snd_hdspm_put_tco_sample_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)42230dca1793SAdrian Knoth static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol,
42240dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
42250dca1793SAdrian Knoth {
42260dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
42270dca1793SAdrian Knoth
42280dca1793SAdrian Knoth if (hdspm->tco->samplerate != ucontrol->value.enumerated.item[0]) {
42290dca1793SAdrian Knoth hdspm->tco->samplerate = ucontrol->value.enumerated.item[0];
42300dca1793SAdrian Knoth
42310dca1793SAdrian Knoth hdspm_tco_write(hdspm);
42320dca1793SAdrian Knoth
42330dca1793SAdrian Knoth return 1;
42340dca1793SAdrian Knoth }
42350dca1793SAdrian Knoth
42360dca1793SAdrian Knoth return 0;
42370dca1793SAdrian Knoth }
42380dca1793SAdrian Knoth
42390dca1793SAdrian Knoth
42400dca1793SAdrian Knoth #define HDSPM_TCO_PULL(xname, xindex) \
42410dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
42420dca1793SAdrian Knoth .name = xname, \
42430dca1793SAdrian Knoth .index = xindex, \
42440dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
42450dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
42460dca1793SAdrian Knoth .info = snd_hdspm_info_tco_pull, \
42470dca1793SAdrian Knoth .get = snd_hdspm_get_tco_pull, \
42480dca1793SAdrian Knoth .put = snd_hdspm_put_tco_pull \
42490dca1793SAdrian Knoth }
42500dca1793SAdrian Knoth
snd_hdspm_info_tco_pull(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)42510dca1793SAdrian Knoth static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol,
42520dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo)
42530dca1793SAdrian Knoth {
425438816545SAdrian Knoth static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %",
425538816545SAdrian Knoth "+ 4 %", "- 4 %" };
4256e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
42570dca1793SAdrian Knoth return 0;
42580dca1793SAdrian Knoth }
42590dca1793SAdrian Knoth
snd_hdspm_get_tco_pull(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)42600dca1793SAdrian Knoth static int snd_hdspm_get_tco_pull(struct snd_kcontrol *kcontrol,
42610dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
42620dca1793SAdrian Knoth {
42630dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
42640dca1793SAdrian Knoth
42650dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->pull;
42660dca1793SAdrian Knoth
42670dca1793SAdrian Knoth return 0;
42680dca1793SAdrian Knoth }
42690dca1793SAdrian Knoth
snd_hdspm_put_tco_pull(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)42700dca1793SAdrian Knoth static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol,
42710dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
42720dca1793SAdrian Knoth {
42730dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
42740dca1793SAdrian Knoth
42750dca1793SAdrian Knoth if (hdspm->tco->pull != ucontrol->value.enumerated.item[0]) {
42760dca1793SAdrian Knoth hdspm->tco->pull = ucontrol->value.enumerated.item[0];
42770dca1793SAdrian Knoth
42780dca1793SAdrian Knoth hdspm_tco_write(hdspm);
42790dca1793SAdrian Knoth
42800dca1793SAdrian Knoth return 1;
42810dca1793SAdrian Knoth }
42820dca1793SAdrian Knoth
42830dca1793SAdrian Knoth return 0;
42840dca1793SAdrian Knoth }
42850dca1793SAdrian Knoth
42860dca1793SAdrian Knoth #define HDSPM_TCO_WCK_CONVERSION(xname, xindex) \
42870dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
42880dca1793SAdrian Knoth .name = xname, \
42890dca1793SAdrian Knoth .index = xindex, \
42900dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
42910dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
42920dca1793SAdrian Knoth .info = snd_hdspm_info_tco_wck_conversion, \
42930dca1793SAdrian Knoth .get = snd_hdspm_get_tco_wck_conversion, \
42940dca1793SAdrian Knoth .put = snd_hdspm_put_tco_wck_conversion \
42950dca1793SAdrian Knoth }
42960dca1793SAdrian Knoth
snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)42970dca1793SAdrian Knoth static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol,
42980dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo)
42990dca1793SAdrian Knoth {
430038816545SAdrian Knoth static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" };
4301e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
43020dca1793SAdrian Knoth return 0;
43030dca1793SAdrian Knoth }
43040dca1793SAdrian Knoth
snd_hdspm_get_tco_wck_conversion(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)43050dca1793SAdrian Knoth static int snd_hdspm_get_tco_wck_conversion(struct snd_kcontrol *kcontrol,
43060dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
43070dca1793SAdrian Knoth {
43080dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
43090dca1793SAdrian Knoth
43100dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->wordclock;
43110dca1793SAdrian Knoth
43120dca1793SAdrian Knoth return 0;
43130dca1793SAdrian Knoth }
43140dca1793SAdrian Knoth
snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)43150dca1793SAdrian Knoth static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol,
43160dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
43170dca1793SAdrian Knoth {
43180dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
43190dca1793SAdrian Knoth
43200dca1793SAdrian Knoth if (hdspm->tco->wordclock != ucontrol->value.enumerated.item[0]) {
43210dca1793SAdrian Knoth hdspm->tco->wordclock = ucontrol->value.enumerated.item[0];
43220dca1793SAdrian Knoth
43230dca1793SAdrian Knoth hdspm_tco_write(hdspm);
43240dca1793SAdrian Knoth
43250dca1793SAdrian Knoth return 1;
43260dca1793SAdrian Knoth }
43270dca1793SAdrian Knoth
43280dca1793SAdrian Knoth return 0;
43290dca1793SAdrian Knoth }
43300dca1793SAdrian Knoth
43310dca1793SAdrian Knoth
43320dca1793SAdrian Knoth #define HDSPM_TCO_FRAME_RATE(xname, xindex) \
43330dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
43340dca1793SAdrian Knoth .name = xname, \
43350dca1793SAdrian Knoth .index = xindex, \
43360dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
43370dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
43380dca1793SAdrian Knoth .info = snd_hdspm_info_tco_frame_rate, \
43390dca1793SAdrian Knoth .get = snd_hdspm_get_tco_frame_rate, \
43400dca1793SAdrian Knoth .put = snd_hdspm_put_tco_frame_rate \
43410dca1793SAdrian Knoth }
43420dca1793SAdrian Knoth
snd_hdspm_info_tco_frame_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)43430dca1793SAdrian Knoth static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol,
43440dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo)
43450dca1793SAdrian Knoth {
434638816545SAdrian Knoth static const char *const texts[] = { "24 fps", "25 fps", "29.97fps",
43470dca1793SAdrian Knoth "29.97 dfps", "30 fps", "30 dfps" };
4348e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
43490dca1793SAdrian Knoth return 0;
43500dca1793SAdrian Knoth }
43510dca1793SAdrian Knoth
snd_hdspm_get_tco_frame_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)43520dca1793SAdrian Knoth static int snd_hdspm_get_tco_frame_rate(struct snd_kcontrol *kcontrol,
43530dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
43540dca1793SAdrian Knoth {
43550dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
43560dca1793SAdrian Knoth
43570dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->framerate;
43580dca1793SAdrian Knoth
43590dca1793SAdrian Knoth return 0;
43600dca1793SAdrian Knoth }
43610dca1793SAdrian Knoth
snd_hdspm_put_tco_frame_rate(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)43620dca1793SAdrian Knoth static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol,
43630dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
43640dca1793SAdrian Knoth {
43650dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
43660dca1793SAdrian Knoth
43670dca1793SAdrian Knoth if (hdspm->tco->framerate != ucontrol->value.enumerated.item[0]) {
43680dca1793SAdrian Knoth hdspm->tco->framerate = ucontrol->value.enumerated.item[0];
43690dca1793SAdrian Knoth
43700dca1793SAdrian Knoth hdspm_tco_write(hdspm);
43710dca1793SAdrian Knoth
43720dca1793SAdrian Knoth return 1;
43730dca1793SAdrian Knoth }
43740dca1793SAdrian Knoth
43750dca1793SAdrian Knoth return 0;
43760dca1793SAdrian Knoth }
43770dca1793SAdrian Knoth
43780dca1793SAdrian Knoth
43790dca1793SAdrian Knoth #define HDSPM_TCO_SYNC_SOURCE(xname, xindex) \
43800dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
43810dca1793SAdrian Knoth .name = xname, \
43820dca1793SAdrian Knoth .index = xindex, \
43830dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
43840dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
43850dca1793SAdrian Knoth .info = snd_hdspm_info_tco_sync_source, \
43860dca1793SAdrian Knoth .get = snd_hdspm_get_tco_sync_source, \
43870dca1793SAdrian Knoth .put = snd_hdspm_put_tco_sync_source \
43880dca1793SAdrian Knoth }
43890dca1793SAdrian Knoth
snd_hdspm_info_tco_sync_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)43900dca1793SAdrian Knoth static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol,
43910dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo)
43920dca1793SAdrian Knoth {
439338816545SAdrian Knoth static const char *const texts[] = { "LTC", "Video", "WCK" };
4394e5b7b1feSAdrian Knoth ENUMERATED_CTL_INFO(uinfo, texts);
43950dca1793SAdrian Knoth return 0;
43960dca1793SAdrian Knoth }
43970dca1793SAdrian Knoth
snd_hdspm_get_tco_sync_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)43980dca1793SAdrian Knoth static int snd_hdspm_get_tco_sync_source(struct snd_kcontrol *kcontrol,
43990dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
44000dca1793SAdrian Knoth {
44010dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
44020dca1793SAdrian Knoth
44030dca1793SAdrian Knoth ucontrol->value.enumerated.item[0] = hdspm->tco->input;
44040dca1793SAdrian Knoth
44050dca1793SAdrian Knoth return 0;
44060dca1793SAdrian Knoth }
44070dca1793SAdrian Knoth
snd_hdspm_put_tco_sync_source(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)44080dca1793SAdrian Knoth static int snd_hdspm_put_tco_sync_source(struct snd_kcontrol *kcontrol,
44090dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
44100dca1793SAdrian Knoth {
44110dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
44120dca1793SAdrian Knoth
44130dca1793SAdrian Knoth if (hdspm->tco->input != ucontrol->value.enumerated.item[0]) {
44140dca1793SAdrian Knoth hdspm->tco->input = ucontrol->value.enumerated.item[0];
44150dca1793SAdrian Knoth
44160dca1793SAdrian Knoth hdspm_tco_write(hdspm);
44170dca1793SAdrian Knoth
44180dca1793SAdrian Knoth return 1;
44190dca1793SAdrian Knoth }
44200dca1793SAdrian Knoth
44210dca1793SAdrian Knoth return 0;
44220dca1793SAdrian Knoth }
44230dca1793SAdrian Knoth
44240dca1793SAdrian Knoth
44250dca1793SAdrian Knoth #define HDSPM_TCO_WORD_TERM(xname, xindex) \
44260dca1793SAdrian Knoth { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
44270dca1793SAdrian Knoth .name = xname, \
44280dca1793SAdrian Knoth .index = xindex, \
44290dca1793SAdrian Knoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
44300dca1793SAdrian Knoth SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
44310dca1793SAdrian Knoth .info = snd_hdspm_info_tco_word_term, \
44320dca1793SAdrian Knoth .get = snd_hdspm_get_tco_word_term, \
44330dca1793SAdrian Knoth .put = snd_hdspm_put_tco_word_term \
44340dca1793SAdrian Knoth }
44350dca1793SAdrian Knoth
snd_hdspm_info_tco_word_term(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)44360dca1793SAdrian Knoth static int snd_hdspm_info_tco_word_term(struct snd_kcontrol *kcontrol,
44370dca1793SAdrian Knoth struct snd_ctl_elem_info *uinfo)
44380dca1793SAdrian Knoth {
44390dca1793SAdrian Knoth uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
44400dca1793SAdrian Knoth uinfo->count = 1;
44410dca1793SAdrian Knoth uinfo->value.integer.min = 0;
44420dca1793SAdrian Knoth uinfo->value.integer.max = 1;
44430dca1793SAdrian Knoth
44440dca1793SAdrian Knoth return 0;
44450dca1793SAdrian Knoth }
44460dca1793SAdrian Knoth
44470dca1793SAdrian Knoth
snd_hdspm_get_tco_word_term(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)44480dca1793SAdrian Knoth static int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol,
44490dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
44500dca1793SAdrian Knoth {
44510dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
44520dca1793SAdrian Knoth
4453537e4813STakashi Iwai ucontrol->value.integer.value[0] = hdspm->tco->term;
44540dca1793SAdrian Knoth
44550dca1793SAdrian Knoth return 0;
44560dca1793SAdrian Knoth }
44570dca1793SAdrian Knoth
44580dca1793SAdrian Knoth
snd_hdspm_put_tco_word_term(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)44590dca1793SAdrian Knoth static int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol,
44600dca1793SAdrian Knoth struct snd_ctl_elem_value *ucontrol)
44610dca1793SAdrian Knoth {
44620dca1793SAdrian Knoth struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
44630dca1793SAdrian Knoth
4464537e4813STakashi Iwai if (hdspm->tco->term != ucontrol->value.integer.value[0]) {
4465537e4813STakashi Iwai hdspm->tco->term = ucontrol->value.integer.value[0];
44660dca1793SAdrian Knoth
44670dca1793SAdrian Knoth hdspm_tco_write(hdspm);
44680dca1793SAdrian Knoth
44690dca1793SAdrian Knoth return 1;
44700dca1793SAdrian Knoth }
44710dca1793SAdrian Knoth
44720dca1793SAdrian Knoth return 0;
44730dca1793SAdrian Knoth }
44740dca1793SAdrian Knoth
44750dca1793SAdrian Knoth
44760dca1793SAdrian Knoth
44770dca1793SAdrian Knoth
4478b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_hdspm_controls_madi[] = {
4479763f356cSTakashi Iwai HDSPM_MIXER("Mixer", 0),
44800dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
4481763f356cSTakashi Iwai HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
4482763f356cSTakashi Iwai HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
4483763f356cSTakashi Iwai HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
4484763f356cSTakashi Iwai HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
4485b8812c55SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
44860dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC SyncCheck", 0),
44870dca1793SAdrian Knoth HDSPM_SYNC_CHECK("MADI SyncCheck", 1),
4488930f4ff0SAdrian Knoth HDSPM_SYNC_CHECK("TCO SyncCheck", 2),
44890dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3),
4490c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut),
4491c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch),
4492696be0fbSAdrian Knoth HDSPM_TOGGLE_SETTING("Disable 96K frames", HDSPM_SMUX),
4493c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms),
4494c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp),
4495700d1ef3SAdrian Knoth HDSPM_INPUT_SELECT("Input Select", 0),
4496700d1ef3SAdrian Knoth HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0)
44970dca1793SAdrian Knoth };
44980dca1793SAdrian Knoth
44990dca1793SAdrian Knoth
4500b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_hdspm_controls_madiface[] = {
45010dca1793SAdrian Knoth HDSPM_MIXER("Mixer", 0),
45020dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
45030dca1793SAdrian Knoth HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
45040dca1793SAdrian Knoth HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
45050dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
45060dca1793SAdrian Knoth HDSPM_SYNC_CHECK("MADI SyncCheck", 0),
4507c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch),
4508c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms),
4509c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp),
4510700d1ef3SAdrian Knoth HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0)
4511763f356cSTakashi Iwai };
4512763f356cSTakashi Iwai
4513b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
45143cee5a60SRemy Bruno HDSPM_MIXER("Mixer", 0),
45150dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
45163cee5a60SRemy Bruno HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
45173cee5a60SRemy Bruno HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
45183cee5a60SRemy Bruno HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
45193cee5a60SRemy Bruno HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
45200dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC SyncCheck", 0),
45210dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES SyncCheck", 1),
45220dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2),
45230dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT SyncCheck", 3),
45240dca1793SAdrian Knoth HDSPM_SYNC_CHECK("TCO SyncCheck", 4),
45250dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 5),
45260dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0),
45270dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1),
45280dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2),
45290dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3),
45300dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4),
4531fb0f121eSAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5),
453242f4c12dSAdrian Knoth HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0),
4533fb0f121eSAdrian Knoth HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt),
4534fb0f121eSAdrian Knoth HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro),
4535fb0f121eSAdrian Knoth HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1),
4536fb0f121eSAdrian Knoth HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db),
453742f4c12dSAdrian Knoth HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48),
453842f4c12dSAdrian Knoth HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0),
453942f4c12dSAdrian Knoth HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0),
454042f4c12dSAdrian Knoth HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0)
45410dca1793SAdrian Knoth
45420dca1793SAdrian Knoth /*
45430dca1793SAdrian Knoth HDSPM_INPUT_SELECT("Input Select", 0),
45440dca1793SAdrian Knoth HDSPM_SPDIF_OPTICAL("SPDIF Out Optical", 0),
45450dca1793SAdrian Knoth HDSPM_PROFESSIONAL("SPDIF Out Professional", 0);
45460dca1793SAdrian Knoth HDSPM_SPDIF_IN("SPDIF In", 0);
45470dca1793SAdrian Knoth HDSPM_BREAKOUT_CABLE("Breakout Cable", 0);
45480dca1793SAdrian Knoth HDSPM_INPUT_LEVEL("Input Level", 0);
45490dca1793SAdrian Knoth HDSPM_OUTPUT_LEVEL("Output Level", 0);
45500dca1793SAdrian Knoth HDSPM_PHONES("Phones", 0);
45510dca1793SAdrian Knoth */
45520dca1793SAdrian Knoth };
45530dca1793SAdrian Knoth
4554b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_hdspm_controls_raydat[] = {
45550dca1793SAdrian Knoth HDSPM_MIXER("Mixer", 0),
45560dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
45570dca1793SAdrian Knoth HDSPM_SYSTEM_CLOCK_MODE("Clock Mode", 0),
45580dca1793SAdrian Knoth HDSPM_PREF_SYNC_REF("Pref Sync Ref", 0),
45590dca1793SAdrian Knoth HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
45600dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC SyncCheck", 0),
45610dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES SyncCheck", 1),
45620dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2),
45630dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT1 SyncCheck", 3),
45640dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT2 SyncCheck", 4),
45650dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT3 SyncCheck", 5),
45660dca1793SAdrian Knoth HDSPM_SYNC_CHECK("ADAT4 SyncCheck", 6),
45670dca1793SAdrian Knoth HDSPM_SYNC_CHECK("TCO SyncCheck", 7),
45680dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 8),
45690dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0),
45700dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1),
45710dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2),
45720dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT1 Frequency", 3),
45730dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT2 Frequency", 4),
45740dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5),
45750dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6),
45760dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7),
457711a5cd3cSAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8),
457811a5cd3cSAdrian Knoth HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro),
457911a5cd3cSAdrian Knoth HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48)
45800dca1793SAdrian Knoth };
45810dca1793SAdrian Knoth
4582b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
45830dca1793SAdrian Knoth HDSPM_MIXER("Mixer", 0),
45840dca1793SAdrian Knoth HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
45850dca1793SAdrian Knoth HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
45860dca1793SAdrian Knoth HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
45870dca1793SAdrian Knoth HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
45880dca1793SAdrian Knoth HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
45892d63ec38SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11),
45900dca1793SAdrian Knoth HDSPM_SYNC_CHECK("WC Sync Check", 0),
45910dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES1 Sync Check", 1),
45920dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES2 Sync Check", 2),
45930dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES3 Sync Check", 3),
45940dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES4 Sync Check", 4),
45950dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES5 Sync Check", 5),
45960dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES6 Sync Check", 6),
45970dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES7 Sync Check", 7),
45980dca1793SAdrian Knoth HDSPM_SYNC_CHECK("AES8 Sync Check", 8),
45990dca1793SAdrian Knoth HDSPM_SYNC_CHECK("TCO Sync Check", 9),
46000dca1793SAdrian Knoth HDSPM_SYNC_CHECK("SYNC IN Sync Check", 10),
46010dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0),
46020dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES1 Frequency", 1),
46030dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES2 Frequency", 2),
46040dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES3 Frequency", 3),
46050dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES4 Frequency", 4),
46060dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES5 Frequency", 5),
46070dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES6 Frequency", 6),
46080dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES7 Frequency", 7),
46090dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("AES8 Frequency", 8),
46100dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 9),
46110dca1793SAdrian Knoth HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 10),
4612c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut),
4613c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Emphasis", HDSPM_Emphasis),
4614c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Non Audio", HDSPM_Dolby),
4615c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Professional", HDSPM_Professional),
4616c9e1668cSAdrian Knoth HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms),
46173cee5a60SRemy Bruno HDSPM_DS_WIRE("Double Speed Wire Mode", 0),
46183cee5a60SRemy Bruno HDSPM_QS_WIRE("Quad Speed Wire Mode", 0),
46193cee5a60SRemy Bruno };
46203cee5a60SRemy Bruno
46210dca1793SAdrian Knoth
46220dca1793SAdrian Knoth
46230dca1793SAdrian Knoth /* Control elements for the optional TCO module */
4624b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_hdspm_controls_tco[] = {
46250dca1793SAdrian Knoth HDSPM_TCO_SAMPLE_RATE("TCO Sample Rate", 0),
46260dca1793SAdrian Knoth HDSPM_TCO_PULL("TCO Pull", 0),
46270dca1793SAdrian Knoth HDSPM_TCO_WCK_CONVERSION("TCO WCK Conversion", 0),
46280dca1793SAdrian Knoth HDSPM_TCO_FRAME_RATE("TCO Frame Rate", 0),
46290dca1793SAdrian Knoth HDSPM_TCO_SYNC_SOURCE("TCO Sync Source", 0),
4630a817650eSAdrian Knoth HDSPM_TCO_WORD_TERM("TCO Word Term", 0),
4631a817650eSAdrian Knoth HDSPM_TCO_LOCK_CHECK("TCO Input Check", 11),
4632a817650eSAdrian Knoth HDSPM_TCO_LOCK_CHECK("TCO LTC Valid", 12),
4633a817650eSAdrian Knoth HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate", 0),
4634a817650eSAdrian Knoth HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format", 0)
46350dca1793SAdrian Knoth };
46360dca1793SAdrian Knoth
46370dca1793SAdrian Knoth
463898274f07STakashi Iwai static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER;
4639763f356cSTakashi Iwai
4640763f356cSTakashi Iwai
hdspm_update_simple_mixer_controls(struct hdspm * hdspm)464198274f07STakashi Iwai static int hdspm_update_simple_mixer_controls(struct hdspm * hdspm)
4642763f356cSTakashi Iwai {
4643763f356cSTakashi Iwai int i;
4644763f356cSTakashi Iwai
46450dca1793SAdrian Knoth for (i = hdspm->ds_out_channels; i < hdspm->ss_out_channels; ++i) {
4646763f356cSTakashi Iwai if (hdspm->system_sample_rate > 48000) {
4647763f356cSTakashi Iwai hdspm->playback_mixer_ctls[i]->vd[0].access =
4648763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_INACTIVE |
4649763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_READ |
4650763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE;
4651763f356cSTakashi Iwai } else {
4652763f356cSTakashi Iwai hdspm->playback_mixer_ctls[i]->vd[0].access =
4653763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_READWRITE |
4654763f356cSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_VOLATILE;
4655763f356cSTakashi Iwai }
4656763f356cSTakashi Iwai snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE |
4657763f356cSTakashi Iwai SNDRV_CTL_EVENT_MASK_INFO,
4658763f356cSTakashi Iwai &hdspm->playback_mixer_ctls[i]->id);
4659763f356cSTakashi Iwai }
4660763f356cSTakashi Iwai
4661763f356cSTakashi Iwai return 0;
4662763f356cSTakashi Iwai }
4663763f356cSTakashi Iwai
4664763f356cSTakashi Iwai
snd_hdspm_create_controls(struct snd_card * card,struct hdspm * hdspm)46650dca1793SAdrian Knoth static int snd_hdspm_create_controls(struct snd_card *card,
46660dca1793SAdrian Knoth struct hdspm *hdspm)
4667763f356cSTakashi Iwai {
4668763f356cSTakashi Iwai unsigned int idx, limit;
4669763f356cSTakashi Iwai int err;
467098274f07STakashi Iwai struct snd_kcontrol *kctl;
4671b4e5e707STakashi Iwai const struct snd_kcontrol_new *list = NULL;
4672763f356cSTakashi Iwai
46730dca1793SAdrian Knoth switch (hdspm->io_type) {
46740dca1793SAdrian Knoth case MADI:
46750dca1793SAdrian Knoth list = snd_hdspm_controls_madi;
46760dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_madi);
46770dca1793SAdrian Knoth break;
46780dca1793SAdrian Knoth case MADIface:
46790dca1793SAdrian Knoth list = snd_hdspm_controls_madiface;
46800dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_madiface);
46810dca1793SAdrian Knoth break;
46820dca1793SAdrian Knoth case AIO:
46830dca1793SAdrian Knoth list = snd_hdspm_controls_aio;
46840dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_aio);
46850dca1793SAdrian Knoth break;
46860dca1793SAdrian Knoth case RayDAT:
46870dca1793SAdrian Knoth list = snd_hdspm_controls_raydat;
46880dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_raydat);
46890dca1793SAdrian Knoth break;
46900dca1793SAdrian Knoth case AES32:
46910dca1793SAdrian Knoth list = snd_hdspm_controls_aes32;
46920dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_aes32);
46930dca1793SAdrian Knoth break;
46940dca1793SAdrian Knoth }
4695763f356cSTakashi Iwai
4696da2ea374SMarkus Elfring if (list) {
46970dca1793SAdrian Knoth for (idx = 0; idx < limit; idx++) {
46983cee5a60SRemy Bruno err = snd_ctl_add(card,
46990dca1793SAdrian Knoth snd_ctl_new1(&list[idx], hdspm));
47003cee5a60SRemy Bruno if (err < 0)
4701763f356cSTakashi Iwai return err;
4702763f356cSTakashi Iwai }
4703763f356cSTakashi Iwai }
4704763f356cSTakashi Iwai
4705763f356cSTakashi Iwai
47060dca1793SAdrian Knoth /* create simple 1:1 playback mixer controls */
4707763f356cSTakashi Iwai snd_hdspm_playback_mixer.name = "Chn";
47080dca1793SAdrian Knoth if (hdspm->system_sample_rate >= 128000) {
47090dca1793SAdrian Knoth limit = hdspm->qs_out_channels;
47100dca1793SAdrian Knoth } else if (hdspm->system_sample_rate >= 64000) {
47110dca1793SAdrian Knoth limit = hdspm->ds_out_channels;
47120dca1793SAdrian Knoth } else {
47130dca1793SAdrian Knoth limit = hdspm->ss_out_channels;
47140dca1793SAdrian Knoth }
4715763f356cSTakashi Iwai for (idx = 0; idx < limit; ++idx) {
4716763f356cSTakashi Iwai snd_hdspm_playback_mixer.index = idx + 1;
4717ef5fa1a4STakashi Iwai kctl = snd_ctl_new1(&snd_hdspm_playback_mixer, hdspm);
4718ef5fa1a4STakashi Iwai err = snd_ctl_add(card, kctl);
4719ef5fa1a4STakashi Iwai if (err < 0)
4720763f356cSTakashi Iwai return err;
4721763f356cSTakashi Iwai hdspm->playback_mixer_ctls[idx] = kctl;
4722763f356cSTakashi Iwai }
4723763f356cSTakashi Iwai
47240dca1793SAdrian Knoth
47250dca1793SAdrian Knoth if (hdspm->tco) {
47260dca1793SAdrian Knoth /* add tco control elements */
47270dca1793SAdrian Knoth list = snd_hdspm_controls_tco;
47280dca1793SAdrian Knoth limit = ARRAY_SIZE(snd_hdspm_controls_tco);
47290dca1793SAdrian Knoth for (idx = 0; idx < limit; idx++) {
47300dca1793SAdrian Knoth err = snd_ctl_add(card,
47310dca1793SAdrian Knoth snd_ctl_new1(&list[idx], hdspm));
47320dca1793SAdrian Knoth if (err < 0)
47330dca1793SAdrian Knoth return err;
47340dca1793SAdrian Knoth }
47350dca1793SAdrian Knoth }
47360dca1793SAdrian Knoth
4737763f356cSTakashi Iwai return 0;
4738763f356cSTakashi Iwai }
4739763f356cSTakashi Iwai
4740763f356cSTakashi Iwai /*------------------------------------------------------------
4741763f356cSTakashi Iwai /proc interface
4742763f356cSTakashi Iwai ------------------------------------------------------------*/
4743763f356cSTakashi Iwai
4744763f356cSTakashi Iwai static void
snd_hdspm_proc_read_tco(struct snd_info_entry * entry,struct snd_info_buffer * buffer)47455760107cSAdrian Knoth snd_hdspm_proc_read_tco(struct snd_info_entry *entry,
47463cee5a60SRemy Bruno struct snd_info_buffer *buffer)
4747763f356cSTakashi Iwai {
4748ef5fa1a4STakashi Iwai struct hdspm *hdspm = entry->private_data;
47495760107cSAdrian Knoth unsigned int status, control;
47500dca1793SAdrian Knoth int a, ltc, frames, seconds, minutes, hours;
47510dca1793SAdrian Knoth unsigned int period;
47520dca1793SAdrian Knoth u64 freq_const = 0;
47530dca1793SAdrian Knoth u32 rate;
47540dca1793SAdrian Knoth
47555760107cSAdrian Knoth snd_iprintf(buffer, "--- TCO ---\n");
47565760107cSAdrian Knoth
4757763f356cSTakashi Iwai status = hdspm_read(hdspm, HDSPM_statusRegister);
47580dca1793SAdrian Knoth control = hdspm->control_register;
4759763f356cSTakashi Iwai
4760763f356cSTakashi Iwai
47610dca1793SAdrian Knoth if (status & HDSPM_tco_detect) {
47620dca1793SAdrian Knoth snd_iprintf(buffer, "TCO module detected.\n");
47630dca1793SAdrian Knoth a = hdspm_read(hdspm, HDSPM_RD_TCO+4);
47640dca1793SAdrian Knoth if (a & HDSPM_TCO1_LTC_Input_valid) {
47650dca1793SAdrian Knoth snd_iprintf(buffer, " LTC valid, ");
47660dca1793SAdrian Knoth switch (a & (HDSPM_TCO1_LTC_Format_LSB |
47670dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB)) {
47680dca1793SAdrian Knoth case 0:
47690dca1793SAdrian Knoth snd_iprintf(buffer, "24 fps, ");
47700dca1793SAdrian Knoth break;
47710dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_LSB:
47720dca1793SAdrian Knoth snd_iprintf(buffer, "25 fps, ");
47730dca1793SAdrian Knoth break;
47740dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_MSB:
47750dca1793SAdrian Knoth snd_iprintf(buffer, "29.97 fps, ");
47760dca1793SAdrian Knoth break;
47770dca1793SAdrian Knoth default:
47780dca1793SAdrian Knoth snd_iprintf(buffer, "30 fps, ");
47790dca1793SAdrian Knoth break;
47800dca1793SAdrian Knoth }
47810dca1793SAdrian Knoth if (a & HDSPM_TCO1_set_drop_frame_flag) {
47820dca1793SAdrian Knoth snd_iprintf(buffer, "drop frame\n");
47830dca1793SAdrian Knoth } else {
47840dca1793SAdrian Knoth snd_iprintf(buffer, "full frame\n");
47850dca1793SAdrian Knoth }
47860dca1793SAdrian Knoth } else {
47870dca1793SAdrian Knoth snd_iprintf(buffer, " no LTC\n");
47880dca1793SAdrian Knoth }
47890dca1793SAdrian Knoth if (a & HDSPM_TCO1_Video_Input_Format_NTSC) {
47900dca1793SAdrian Knoth snd_iprintf(buffer, " Video: NTSC\n");
47910dca1793SAdrian Knoth } else if (a & HDSPM_TCO1_Video_Input_Format_PAL) {
47920dca1793SAdrian Knoth snd_iprintf(buffer, " Video: PAL\n");
47930dca1793SAdrian Knoth } else {
47940dca1793SAdrian Knoth snd_iprintf(buffer, " No video\n");
47950dca1793SAdrian Knoth }
47960dca1793SAdrian Knoth if (a & HDSPM_TCO1_TCO_lock) {
47970dca1793SAdrian Knoth snd_iprintf(buffer, " Sync: lock\n");
47980dca1793SAdrian Knoth } else {
47990dca1793SAdrian Knoth snd_iprintf(buffer, " Sync: no lock\n");
48000dca1793SAdrian Knoth }
48010dca1793SAdrian Knoth
48020dca1793SAdrian Knoth switch (hdspm->io_type) {
48030dca1793SAdrian Knoth case MADI:
48040dca1793SAdrian Knoth case AES32:
48050dca1793SAdrian Knoth freq_const = 110069313433624ULL;
48060dca1793SAdrian Knoth break;
48070dca1793SAdrian Knoth case RayDAT:
48080dca1793SAdrian Knoth case AIO:
48090dca1793SAdrian Knoth freq_const = 104857600000000ULL;
48100dca1793SAdrian Knoth break;
48110dca1793SAdrian Knoth case MADIface:
48120dca1793SAdrian Knoth break; /* no TCO possible */
48130dca1793SAdrian Knoth }
48140dca1793SAdrian Knoth
48150dca1793SAdrian Knoth period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
48160dca1793SAdrian Knoth snd_iprintf(buffer, " period: %u\n", period);
48170dca1793SAdrian Knoth
48180dca1793SAdrian Knoth
48190dca1793SAdrian Knoth /* rate = freq_const/period; */
48200dca1793SAdrian Knoth rate = div_u64(freq_const, period);
48210dca1793SAdrian Knoth
48220dca1793SAdrian Knoth if (control & HDSPM_QuadSpeed) {
48230dca1793SAdrian Knoth rate *= 4;
48240dca1793SAdrian Knoth } else if (control & HDSPM_DoubleSpeed) {
48250dca1793SAdrian Knoth rate *= 2;
48260dca1793SAdrian Knoth }
48270dca1793SAdrian Knoth
48280dca1793SAdrian Knoth snd_iprintf(buffer, " Frequency: %u Hz\n",
48290dca1793SAdrian Knoth (unsigned int) rate);
48300dca1793SAdrian Knoth
48310dca1793SAdrian Knoth ltc = hdspm_read(hdspm, HDSPM_RD_TCO);
48320dca1793SAdrian Knoth frames = ltc & 0xF;
48330dca1793SAdrian Knoth ltc >>= 4;
48340dca1793SAdrian Knoth frames += (ltc & 0x3) * 10;
48350dca1793SAdrian Knoth ltc >>= 4;
48360dca1793SAdrian Knoth seconds = ltc & 0xF;
48370dca1793SAdrian Knoth ltc >>= 4;
48380dca1793SAdrian Knoth seconds += (ltc & 0x7) * 10;
48390dca1793SAdrian Knoth ltc >>= 4;
48400dca1793SAdrian Knoth minutes = ltc & 0xF;
48410dca1793SAdrian Knoth ltc >>= 4;
48420dca1793SAdrian Knoth minutes += (ltc & 0x7) * 10;
48430dca1793SAdrian Knoth ltc >>= 4;
48440dca1793SAdrian Knoth hours = ltc & 0xF;
48450dca1793SAdrian Knoth ltc >>= 4;
48460dca1793SAdrian Knoth hours += (ltc & 0x3) * 10;
48470dca1793SAdrian Knoth snd_iprintf(buffer,
48480dca1793SAdrian Knoth " LTC In: %02d:%02d:%02d:%02d\n",
48490dca1793SAdrian Knoth hours, minutes, seconds, frames);
48500dca1793SAdrian Knoth
48510dca1793SAdrian Knoth } else {
48520dca1793SAdrian Knoth snd_iprintf(buffer, "No TCO module detected.\n");
48530dca1793SAdrian Knoth }
48545760107cSAdrian Knoth }
48555760107cSAdrian Knoth
48565760107cSAdrian Knoth static void
snd_hdspm_proc_read_madi(struct snd_info_entry * entry,struct snd_info_buffer * buffer)48575760107cSAdrian Knoth snd_hdspm_proc_read_madi(struct snd_info_entry *entry,
48585760107cSAdrian Knoth struct snd_info_buffer *buffer)
48595760107cSAdrian Knoth {
48605760107cSAdrian Knoth struct hdspm *hdspm = entry->private_data;
4861df57de17SSudip Mukherjee unsigned int status, status2;
48625760107cSAdrian Knoth
48635760107cSAdrian Knoth char *pref_sync_ref;
48645760107cSAdrian Knoth char *autosync_ref;
48655760107cSAdrian Knoth char *system_clock_mode;
48665760107cSAdrian Knoth int x, x2;
48675760107cSAdrian Knoth
48685760107cSAdrian Knoth status = hdspm_read(hdspm, HDSPM_statusRegister);
48695760107cSAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
48705760107cSAdrian Knoth
48715760107cSAdrian Knoth snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
48725760107cSAdrian Knoth hdspm->card_name, hdspm->card->number + 1,
48735760107cSAdrian Knoth hdspm->firmware_rev,
48745760107cSAdrian Knoth (status2 & HDSPM_version0) |
48755760107cSAdrian Knoth (status2 & HDSPM_version1) | (status2 &
48765760107cSAdrian Knoth HDSPM_version2));
48775760107cSAdrian Knoth
48785760107cSAdrian Knoth snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n",
48795760107cSAdrian Knoth (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF,
48805760107cSAdrian Knoth hdspm->serial);
48815760107cSAdrian Knoth
48825760107cSAdrian Knoth snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
48835760107cSAdrian Knoth hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
48845760107cSAdrian Knoth
48855760107cSAdrian Knoth snd_iprintf(buffer, "--- System ---\n");
48865760107cSAdrian Knoth
48875760107cSAdrian Knoth snd_iprintf(buffer,
48885760107cSAdrian Knoth "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
48895760107cSAdrian Knoth status & HDSPM_audioIRQPending,
48905760107cSAdrian Knoth (status & HDSPM_midi0IRQPending) ? 1 : 0,
48915760107cSAdrian Knoth (status & HDSPM_midi1IRQPending) ? 1 : 0,
48925760107cSAdrian Knoth hdspm->irq_count);
48935760107cSAdrian Knoth snd_iprintf(buffer,
48945760107cSAdrian Knoth "HW pointer: id = %d, rawptr = %d (%d->%d) "
48955760107cSAdrian Knoth "estimated= %ld (bytes)\n",
48965760107cSAdrian Knoth ((status & HDSPM_BufferID) ? 1 : 0),
48975760107cSAdrian Knoth (status & HDSPM_BufferPositionMask),
48985760107cSAdrian Knoth (status & HDSPM_BufferPositionMask) %
48995760107cSAdrian Knoth (2 * (int)hdspm->period_bytes),
49005760107cSAdrian Knoth ((status & HDSPM_BufferPositionMask) - 64) %
49015760107cSAdrian Knoth (2 * (int)hdspm->period_bytes),
49025760107cSAdrian Knoth (long) hdspm_hw_pointer(hdspm) * 4);
49035760107cSAdrian Knoth
49045760107cSAdrian Knoth snd_iprintf(buffer,
49055760107cSAdrian Knoth "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
49065760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
49075760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
49085760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
49095760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
49105760107cSAdrian Knoth snd_iprintf(buffer,
49115760107cSAdrian Knoth "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
49125760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
49135760107cSAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
49145760107cSAdrian Knoth snd_iprintf(buffer,
49155760107cSAdrian Knoth "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
49165760107cSAdrian Knoth "status2=0x%x\n",
49175760107cSAdrian Knoth hdspm->control_register, hdspm->control2_register,
49185760107cSAdrian Knoth status, status2);
49195760107cSAdrian Knoth
4920763f356cSTakashi Iwai
4921763f356cSTakashi Iwai snd_iprintf(buffer, "--- Settings ---\n");
4922763f356cSTakashi Iwai
49237cb155ffSAdrian Knoth x = hdspm_get_latency(hdspm);
4924763f356cSTakashi Iwai
4925763f356cSTakashi Iwai snd_iprintf(buffer,
4926763f356cSTakashi Iwai "Size (Latency): %d samples (2 periods of %lu bytes)\n",
4927763f356cSTakashi Iwai x, (unsigned long) hdspm->period_bytes);
4928763f356cSTakashi Iwai
49290dca1793SAdrian Knoth snd_iprintf(buffer, "Line out: %s\n",
49300dca1793SAdrian Knoth (hdspm->control_register & HDSPM_LineOut) ? "on " : "off");
4931763f356cSTakashi Iwai
4932763f356cSTakashi Iwai snd_iprintf(buffer,
4933ef5fa1a4STakashi Iwai "ClearTrackMarker = %s, Transmit in %s Channel Mode, "
4934ef5fa1a4STakashi Iwai "Auto Input %s\n",
49350dca1793SAdrian Knoth (hdspm->control_register & HDSPM_clr_tms) ? "on" : "off",
49360dca1793SAdrian Knoth (hdspm->control_register & HDSPM_TX_64ch) ? "64" : "56",
49370dca1793SAdrian Knoth (hdspm->control_register & HDSPM_AutoInp) ? "on" : "off");
4938763f356cSTakashi Iwai
49390dca1793SAdrian Knoth
49403cee5a60SRemy Bruno if (!(hdspm->control_register & HDSPM_ClockModeMaster))
49410dca1793SAdrian Knoth system_clock_mode = "AutoSync";
49423cee5a60SRemy Bruno else
4943763f356cSTakashi Iwai system_clock_mode = "Master";
49440dca1793SAdrian Knoth snd_iprintf(buffer, "AutoSync Reference: %s\n", system_clock_mode);
4945763f356cSTakashi Iwai
4946763f356cSTakashi Iwai switch (hdspm_pref_sync_ref(hdspm)) {
4947763f356cSTakashi Iwai case HDSPM_SYNC_FROM_WORD:
4948763f356cSTakashi Iwai pref_sync_ref = "Word Clock";
4949763f356cSTakashi Iwai break;
4950763f356cSTakashi Iwai case HDSPM_SYNC_FROM_MADI:
4951763f356cSTakashi Iwai pref_sync_ref = "MADI Sync";
4952763f356cSTakashi Iwai break;
49530dca1793SAdrian Knoth case HDSPM_SYNC_FROM_TCO:
49540dca1793SAdrian Knoth pref_sync_ref = "TCO";
49550dca1793SAdrian Knoth break;
49560dca1793SAdrian Knoth case HDSPM_SYNC_FROM_SYNC_IN:
49570dca1793SAdrian Knoth pref_sync_ref = "Sync In";
49580dca1793SAdrian Knoth break;
4959763f356cSTakashi Iwai default:
4960763f356cSTakashi Iwai pref_sync_ref = "XXXX Clock";
4961763f356cSTakashi Iwai break;
4962763f356cSTakashi Iwai }
4963763f356cSTakashi Iwai snd_iprintf(buffer, "Preferred Sync Reference: %s\n",
4964763f356cSTakashi Iwai pref_sync_ref);
4965763f356cSTakashi Iwai
4966763f356cSTakashi Iwai snd_iprintf(buffer, "System Clock Frequency: %d\n",
4967763f356cSTakashi Iwai hdspm->system_sample_rate);
4968763f356cSTakashi Iwai
4969763f356cSTakashi Iwai
4970763f356cSTakashi Iwai snd_iprintf(buffer, "--- Status:\n");
4971763f356cSTakashi Iwai
4972763f356cSTakashi Iwai x = status & HDSPM_madiSync;
4973763f356cSTakashi Iwai x2 = status2 & HDSPM_wcSync;
4974763f356cSTakashi Iwai
4975763f356cSTakashi Iwai snd_iprintf(buffer, "Inputs MADI=%s, WordClock=%s\n",
4976763f356cSTakashi Iwai (status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") :
4977763f356cSTakashi Iwai "NoLock",
4978763f356cSTakashi Iwai (status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") :
4979763f356cSTakashi Iwai "NoLock");
4980763f356cSTakashi Iwai
4981763f356cSTakashi Iwai switch (hdspm_autosync_ref(hdspm)) {
49820dca1793SAdrian Knoth case HDSPM_AUTOSYNC_FROM_SYNC_IN:
49830dca1793SAdrian Knoth autosync_ref = "Sync In";
49840dca1793SAdrian Knoth break;
49850dca1793SAdrian Knoth case HDSPM_AUTOSYNC_FROM_TCO:
49860dca1793SAdrian Knoth autosync_ref = "TCO";
49870dca1793SAdrian Knoth break;
4988763f356cSTakashi Iwai case HDSPM_AUTOSYNC_FROM_WORD:
4989763f356cSTakashi Iwai autosync_ref = "Word Clock";
4990763f356cSTakashi Iwai break;
4991763f356cSTakashi Iwai case HDSPM_AUTOSYNC_FROM_MADI:
4992763f356cSTakashi Iwai autosync_ref = "MADI Sync";
4993763f356cSTakashi Iwai break;
4994763f356cSTakashi Iwai case HDSPM_AUTOSYNC_FROM_NONE:
4995763f356cSTakashi Iwai autosync_ref = "Input not valid";
4996763f356cSTakashi Iwai break;
4997763f356cSTakashi Iwai default:
4998763f356cSTakashi Iwai autosync_ref = "---";
4999763f356cSTakashi Iwai break;
5000763f356cSTakashi Iwai }
5001763f356cSTakashi Iwai snd_iprintf(buffer,
5002763f356cSTakashi Iwai "AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n",
5003763f356cSTakashi Iwai autosync_ref, hdspm_external_sample_rate(hdspm),
5004763f356cSTakashi Iwai (status & HDSPM_madiFreqMask) >> 22,
5005763f356cSTakashi Iwai (status2 & HDSPM_wcFreqMask) >> 5);
5006763f356cSTakashi Iwai
5007763f356cSTakashi Iwai snd_iprintf(buffer, "Input: %s, Mode=%s\n",
5008763f356cSTakashi Iwai (status & HDSPM_AB_int) ? "Coax" : "Optical",
5009763f356cSTakashi Iwai (status & HDSPM_RX_64ch) ? "64 channels" :
5010763f356cSTakashi Iwai "56 channels");
5011763f356cSTakashi Iwai
50125760107cSAdrian Knoth /* call readout function for TCO specific status */
50135760107cSAdrian Knoth snd_hdspm_proc_read_tco(entry, buffer);
50145760107cSAdrian Knoth
5015763f356cSTakashi Iwai snd_iprintf(buffer, "\n");
5016763f356cSTakashi Iwai }
5017763f356cSTakashi Iwai
50183cee5a60SRemy Bruno static void
snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,struct snd_info_buffer * buffer)50193cee5a60SRemy Bruno snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
50203cee5a60SRemy Bruno struct snd_info_buffer *buffer)
50213cee5a60SRemy Bruno {
5022ef5fa1a4STakashi Iwai struct hdspm *hdspm = entry->private_data;
50233cee5a60SRemy Bruno unsigned int status;
50243cee5a60SRemy Bruno unsigned int status2;
50253cee5a60SRemy Bruno unsigned int timecode;
502656bde0f3SAndre Schramm unsigned int wcLock, wcSync;
50273cee5a60SRemy Bruno int pref_syncref;
50283cee5a60SRemy Bruno char *autosync_ref;
50293cee5a60SRemy Bruno int x;
50303cee5a60SRemy Bruno
50313cee5a60SRemy Bruno status = hdspm_read(hdspm, HDSPM_statusRegister);
50323cee5a60SRemy Bruno status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
50333cee5a60SRemy Bruno timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
50343cee5a60SRemy Bruno
50353cee5a60SRemy Bruno snd_iprintf(buffer, "%s (Card #%d) Rev.%x\n",
50363cee5a60SRemy Bruno hdspm->card_name, hdspm->card->number + 1,
50373cee5a60SRemy Bruno hdspm->firmware_rev);
50383cee5a60SRemy Bruno
50393cee5a60SRemy Bruno snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
50403cee5a60SRemy Bruno hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
50413cee5a60SRemy Bruno
50423cee5a60SRemy Bruno snd_iprintf(buffer, "--- System ---\n");
50433cee5a60SRemy Bruno
50443cee5a60SRemy Bruno snd_iprintf(buffer,
50453cee5a60SRemy Bruno "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
50463cee5a60SRemy Bruno status & HDSPM_audioIRQPending,
50473cee5a60SRemy Bruno (status & HDSPM_midi0IRQPending) ? 1 : 0,
50483cee5a60SRemy Bruno (status & HDSPM_midi1IRQPending) ? 1 : 0,
50493cee5a60SRemy Bruno hdspm->irq_count);
50503cee5a60SRemy Bruno snd_iprintf(buffer,
5051ef5fa1a4STakashi Iwai "HW pointer: id = %d, rawptr = %d (%d->%d) "
5052ef5fa1a4STakashi Iwai "estimated= %ld (bytes)\n",
50533cee5a60SRemy Bruno ((status & HDSPM_BufferID) ? 1 : 0),
50543cee5a60SRemy Bruno (status & HDSPM_BufferPositionMask),
5055ef5fa1a4STakashi Iwai (status & HDSPM_BufferPositionMask) %
5056ef5fa1a4STakashi Iwai (2 * (int)hdspm->period_bytes),
5057ef5fa1a4STakashi Iwai ((status & HDSPM_BufferPositionMask) - 64) %
5058ef5fa1a4STakashi Iwai (2 * (int)hdspm->period_bytes),
50593cee5a60SRemy Bruno (long) hdspm_hw_pointer(hdspm) * 4);
50603cee5a60SRemy Bruno
50613cee5a60SRemy Bruno snd_iprintf(buffer,
50623cee5a60SRemy Bruno "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
50633cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
50643cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
50653cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
50663cee5a60SRemy Bruno hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
50673cee5a60SRemy Bruno snd_iprintf(buffer,
50680dca1793SAdrian Knoth "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
50690dca1793SAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
50700dca1793SAdrian Knoth hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
50710dca1793SAdrian Knoth snd_iprintf(buffer,
50720dca1793SAdrian Knoth "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
50730dca1793SAdrian Knoth "status2=0x%x\n",
50740dca1793SAdrian Knoth hdspm->control_register, hdspm->control2_register,
50750dca1793SAdrian Knoth status, status2);
50763cee5a60SRemy Bruno
50773cee5a60SRemy Bruno snd_iprintf(buffer, "--- Settings ---\n");
50783cee5a60SRemy Bruno
50797cb155ffSAdrian Knoth x = hdspm_get_latency(hdspm);
50803cee5a60SRemy Bruno
50813cee5a60SRemy Bruno snd_iprintf(buffer,
50823cee5a60SRemy Bruno "Size (Latency): %d samples (2 periods of %lu bytes)\n",
50833cee5a60SRemy Bruno x, (unsigned long) hdspm->period_bytes);
50843cee5a60SRemy Bruno
50850dca1793SAdrian Knoth snd_iprintf(buffer, "Line out: %s\n",
50863cee5a60SRemy Bruno (hdspm->
50870dca1793SAdrian Knoth control_register & HDSPM_LineOut) ? "on " : "off");
50883cee5a60SRemy Bruno
50893cee5a60SRemy Bruno snd_iprintf(buffer,
50903cee5a60SRemy Bruno "ClearTrackMarker %s, Emphasis %s, Dolby %s\n",
50913cee5a60SRemy Bruno (hdspm->
50923cee5a60SRemy Bruno control_register & HDSPM_clr_tms) ? "on" : "off",
50933cee5a60SRemy Bruno (hdspm->
50943cee5a60SRemy Bruno control_register & HDSPM_Emphasis) ? "on" : "off",
50953cee5a60SRemy Bruno (hdspm->
50963cee5a60SRemy Bruno control_register & HDSPM_Dolby) ? "on" : "off");
50973cee5a60SRemy Bruno
50983cee5a60SRemy Bruno
50993cee5a60SRemy Bruno pref_syncref = hdspm_pref_sync_ref(hdspm);
51003cee5a60SRemy Bruno if (pref_syncref == 0)
51013cee5a60SRemy Bruno snd_iprintf(buffer, "Preferred Sync Reference: Word Clock\n");
51023cee5a60SRemy Bruno else
51033cee5a60SRemy Bruno snd_iprintf(buffer, "Preferred Sync Reference: AES%d\n",
51043cee5a60SRemy Bruno pref_syncref);
51053cee5a60SRemy Bruno
51063cee5a60SRemy Bruno snd_iprintf(buffer, "System Clock Frequency: %d\n",
51073cee5a60SRemy Bruno hdspm->system_sample_rate);
51083cee5a60SRemy Bruno
51093cee5a60SRemy Bruno snd_iprintf(buffer, "Double speed: %s\n",
51103cee5a60SRemy Bruno hdspm->control_register & HDSPM_DS_DoubleWire?
51113cee5a60SRemy Bruno "Double wire" : "Single wire");
51123cee5a60SRemy Bruno snd_iprintf(buffer, "Quad speed: %s\n",
51133cee5a60SRemy Bruno hdspm->control_register & HDSPM_QS_DoubleWire?
51143cee5a60SRemy Bruno "Double wire" :
51153cee5a60SRemy Bruno hdspm->control_register & HDSPM_QS_QuadWire?
51163cee5a60SRemy Bruno "Quad wire" : "Single wire");
51173cee5a60SRemy Bruno
51183cee5a60SRemy Bruno snd_iprintf(buffer, "--- Status:\n");
51193cee5a60SRemy Bruno
512056bde0f3SAndre Schramm wcLock = status & HDSPM_AES32_wcLock;
512156bde0f3SAndre Schramm wcSync = wcLock && (status & HDSPM_AES32_wcSync);
512256bde0f3SAndre Schramm
51233cee5a60SRemy Bruno snd_iprintf(buffer, "Word: %s Frequency: %d\n",
512456bde0f3SAndre Schramm (wcLock) ? (wcSync ? "Sync " : "Lock ") : "No Lock",
51253cee5a60SRemy Bruno HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF));
51263cee5a60SRemy Bruno
51273cee5a60SRemy Bruno for (x = 0; x < 8; x++) {
51283cee5a60SRemy Bruno snd_iprintf(buffer, "AES%d: %s Frequency: %d\n",
51293cee5a60SRemy Bruno x+1,
5130ef5fa1a4STakashi Iwai (status2 & (HDSPM_LockAES >> x)) ?
5131ef5fa1a4STakashi Iwai "Sync " : "No Lock",
51323cee5a60SRemy Bruno HDSPM_bit2freq((timecode >> (4*x)) & 0xF));
51333cee5a60SRemy Bruno }
51343cee5a60SRemy Bruno
51353cee5a60SRemy Bruno switch (hdspm_autosync_ref(hdspm)) {
51360dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_NONE:
51370dca1793SAdrian Knoth autosync_ref = "None"; break;
51380dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_WORD:
51390dca1793SAdrian Knoth autosync_ref = "Word Clock"; break;
51400dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES1:
51410dca1793SAdrian Knoth autosync_ref = "AES1"; break;
51420dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES2:
51430dca1793SAdrian Knoth autosync_ref = "AES2"; break;
51440dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES3:
51450dca1793SAdrian Knoth autosync_ref = "AES3"; break;
51460dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES4:
51470dca1793SAdrian Knoth autosync_ref = "AES4"; break;
51480dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES5:
51490dca1793SAdrian Knoth autosync_ref = "AES5"; break;
51500dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES6:
51510dca1793SAdrian Knoth autosync_ref = "AES6"; break;
51520dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES7:
51530dca1793SAdrian Knoth autosync_ref = "AES7"; break;
51540dca1793SAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_AES8:
51550dca1793SAdrian Knoth autosync_ref = "AES8"; break;
5156194062daSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_TCO:
5157194062daSAdrian Knoth autosync_ref = "TCO"; break;
5158194062daSAdrian Knoth case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN:
5159194062daSAdrian Knoth autosync_ref = "Sync In"; break;
51600dca1793SAdrian Knoth default:
51610dca1793SAdrian Knoth autosync_ref = "---"; break;
51623cee5a60SRemy Bruno }
51633cee5a60SRemy Bruno snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref);
51643cee5a60SRemy Bruno
5165194062daSAdrian Knoth /* call readout function for TCO specific status */
5166194062daSAdrian Knoth snd_hdspm_proc_read_tco(entry, buffer);
5167194062daSAdrian Knoth
51683cee5a60SRemy Bruno snd_iprintf(buffer, "\n");
51693cee5a60SRemy Bruno }
51703cee5a60SRemy Bruno
51710dca1793SAdrian Knoth static void
snd_hdspm_proc_read_raydat(struct snd_info_entry * entry,struct snd_info_buffer * buffer)51720dca1793SAdrian Knoth snd_hdspm_proc_read_raydat(struct snd_info_entry *entry,
51730dca1793SAdrian Knoth struct snd_info_buffer *buffer)
51740dca1793SAdrian Knoth {
51750dca1793SAdrian Knoth struct hdspm *hdspm = entry->private_data;
5176df57de17SSudip Mukherjee unsigned int status1, status2, status3, i;
51770dca1793SAdrian Knoth unsigned int lock, sync;
51780dca1793SAdrian Knoth
51790dca1793SAdrian Knoth status1 = hdspm_read(hdspm, HDSPM_RD_STATUS_1); /* s1 */
51800dca1793SAdrian Knoth status2 = hdspm_read(hdspm, HDSPM_RD_STATUS_2); /* freq */
51810dca1793SAdrian Knoth status3 = hdspm_read(hdspm, HDSPM_RD_STATUS_3); /* s2 */
51820dca1793SAdrian Knoth
51830dca1793SAdrian Knoth snd_iprintf(buffer, "STATUS1: 0x%08x\n", status1);
51840dca1793SAdrian Knoth snd_iprintf(buffer, "STATUS2: 0x%08x\n", status2);
51850dca1793SAdrian Knoth snd_iprintf(buffer, "STATUS3: 0x%08x\n", status3);
51860dca1793SAdrian Knoth
51870dca1793SAdrian Knoth
51880dca1793SAdrian Knoth snd_iprintf(buffer, "\n*** CLOCK MODE\n\n");
51890dca1793SAdrian Knoth
51900dca1793SAdrian Knoth snd_iprintf(buffer, "Clock mode : %s\n",
51910dca1793SAdrian Knoth (hdspm_system_clock_mode(hdspm) == 0) ? "master" : "slave");
51920dca1793SAdrian Knoth snd_iprintf(buffer, "System frequency: %d Hz\n",
51930dca1793SAdrian Knoth hdspm_get_system_sample_rate(hdspm));
51940dca1793SAdrian Knoth
51950dca1793SAdrian Knoth snd_iprintf(buffer, "\n*** INPUT STATUS\n\n");
51960dca1793SAdrian Knoth
51970dca1793SAdrian Knoth lock = 0x1;
51980dca1793SAdrian Knoth sync = 0x100;
51990dca1793SAdrian Knoth
52000dca1793SAdrian Knoth for (i = 0; i < 8; i++) {
52010dca1793SAdrian Knoth snd_iprintf(buffer, "s1_input %d: Lock %d, Sync %d, Freq %s\n",
52020dca1793SAdrian Knoth i,
52030dca1793SAdrian Knoth (status1 & lock) ? 1 : 0,
52040dca1793SAdrian Knoth (status1 & sync) ? 1 : 0,
52050dca1793SAdrian Knoth texts_freq[(status2 >> (i * 4)) & 0xF]);
52060dca1793SAdrian Knoth
52070dca1793SAdrian Knoth lock = lock<<1;
52080dca1793SAdrian Knoth sync = sync<<1;
52090dca1793SAdrian Knoth }
52100dca1793SAdrian Knoth
52110dca1793SAdrian Knoth snd_iprintf(buffer, "WC input: Lock %d, Sync %d, Freq %s\n",
52120dca1793SAdrian Knoth (status1 & 0x1000000) ? 1 : 0,
52130dca1793SAdrian Knoth (status1 & 0x2000000) ? 1 : 0,
52140dca1793SAdrian Knoth texts_freq[(status1 >> 16) & 0xF]);
52150dca1793SAdrian Knoth
52160dca1793SAdrian Knoth snd_iprintf(buffer, "TCO input: Lock %d, Sync %d, Freq %s\n",
52170dca1793SAdrian Knoth (status1 & 0x4000000) ? 1 : 0,
52180dca1793SAdrian Knoth (status1 & 0x8000000) ? 1 : 0,
52190dca1793SAdrian Knoth texts_freq[(status1 >> 20) & 0xF]);
52200dca1793SAdrian Knoth
52210dca1793SAdrian Knoth snd_iprintf(buffer, "SYNC IN: Lock %d, Sync %d, Freq %s\n",
52220dca1793SAdrian Knoth (status3 & 0x400) ? 1 : 0,
52230dca1793SAdrian Knoth (status3 & 0x800) ? 1 : 0,
52240dca1793SAdrian Knoth texts_freq[(status2 >> 12) & 0xF]);
52250dca1793SAdrian Knoth
52260dca1793SAdrian Knoth }
52270dca1793SAdrian Knoth
52283cee5a60SRemy Bruno #ifdef CONFIG_SND_DEBUG
52293cee5a60SRemy Bruno static void
snd_hdspm_proc_read_debug(struct snd_info_entry * entry,struct snd_info_buffer * buffer)52303cee5a60SRemy Bruno snd_hdspm_proc_read_debug(struct snd_info_entry *entry,
52313cee5a60SRemy Bruno struct snd_info_buffer *buffer)
52323cee5a60SRemy Bruno {
5233ef5fa1a4STakashi Iwai struct hdspm *hdspm = entry->private_data;
52343cee5a60SRemy Bruno
52353cee5a60SRemy Bruno int j,i;
52363cee5a60SRemy Bruno
5237ef5fa1a4STakashi Iwai for (i = 0; i < 256 /* 1024*64 */; i += j) {
52383cee5a60SRemy Bruno snd_iprintf(buffer, "0x%08X: ", i);
52393cee5a60SRemy Bruno for (j = 0; j < 16; j += 4)
52403cee5a60SRemy Bruno snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j));
52413cee5a60SRemy Bruno snd_iprintf(buffer, "\n");
52423cee5a60SRemy Bruno }
52433cee5a60SRemy Bruno }
52443cee5a60SRemy Bruno #endif
52453cee5a60SRemy Bruno
52463cee5a60SRemy Bruno
snd_hdspm_proc_ports_in(struct snd_info_entry * entry,struct snd_info_buffer * buffer)52470dca1793SAdrian Knoth static void snd_hdspm_proc_ports_in(struct snd_info_entry *entry,
52480dca1793SAdrian Knoth struct snd_info_buffer *buffer)
52490dca1793SAdrian Knoth {
52500dca1793SAdrian Knoth struct hdspm *hdspm = entry->private_data;
52510dca1793SAdrian Knoth int i;
52520dca1793SAdrian Knoth
52530dca1793SAdrian Knoth snd_iprintf(buffer, "# generated by hdspm\n");
52540dca1793SAdrian Knoth
52550dca1793SAdrian Knoth for (i = 0; i < hdspm->max_channels_in; i++) {
52560dca1793SAdrian Knoth snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_in[i]);
52570dca1793SAdrian Knoth }
52580dca1793SAdrian Knoth }
52590dca1793SAdrian Knoth
snd_hdspm_proc_ports_out(struct snd_info_entry * entry,struct snd_info_buffer * buffer)52600dca1793SAdrian Knoth static void snd_hdspm_proc_ports_out(struct snd_info_entry *entry,
52610dca1793SAdrian Knoth struct snd_info_buffer *buffer)
52620dca1793SAdrian Knoth {
52630dca1793SAdrian Knoth struct hdspm *hdspm = entry->private_data;
52640dca1793SAdrian Knoth int i;
52650dca1793SAdrian Knoth
52660dca1793SAdrian Knoth snd_iprintf(buffer, "# generated by hdspm\n");
52670dca1793SAdrian Knoth
52680dca1793SAdrian Knoth for (i = 0; i < hdspm->max_channels_out; i++) {
52690dca1793SAdrian Knoth snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_out[i]);
52700dca1793SAdrian Knoth }
52710dca1793SAdrian Knoth }
52720dca1793SAdrian Knoth
52733cee5a60SRemy Bruno
snd_hdspm_proc_init(struct hdspm * hdspm)5274e23e7a14SBill Pemberton static void snd_hdspm_proc_init(struct hdspm *hdspm)
5275763f356cSTakashi Iwai {
527647f2769bSTakashi Iwai void (*read)(struct snd_info_entry *, struct snd_info_buffer *) = NULL;
5277763f356cSTakashi Iwai
52780dca1793SAdrian Knoth switch (hdspm->io_type) {
52790dca1793SAdrian Knoth case AES32:
528047f2769bSTakashi Iwai read = snd_hdspm_proc_read_aes32;
52810dca1793SAdrian Knoth break;
52820dca1793SAdrian Knoth case MADI:
528347f2769bSTakashi Iwai read = snd_hdspm_proc_read_madi;
52840dca1793SAdrian Knoth break;
52850dca1793SAdrian Knoth case MADIface:
528647f2769bSTakashi Iwai /* read = snd_hdspm_proc_read_madiface; */
52870dca1793SAdrian Knoth break;
52880dca1793SAdrian Knoth case RayDAT:
528947f2769bSTakashi Iwai read = snd_hdspm_proc_read_raydat;
52900dca1793SAdrian Knoth break;
52910dca1793SAdrian Knoth case AIO:
52920dca1793SAdrian Knoth break;
52930dca1793SAdrian Knoth }
52940dca1793SAdrian Knoth
529547f2769bSTakashi Iwai snd_card_ro_proc_new(hdspm->card, "hdspm", hdspm, read);
529647f2769bSTakashi Iwai snd_card_ro_proc_new(hdspm->card, "ports.in", hdspm,
529747f2769bSTakashi Iwai snd_hdspm_proc_ports_in);
529847f2769bSTakashi Iwai snd_card_ro_proc_new(hdspm->card, "ports.out", hdspm,
529947f2769bSTakashi Iwai snd_hdspm_proc_ports_out);
53000dca1793SAdrian Knoth
53013cee5a60SRemy Bruno #ifdef CONFIG_SND_DEBUG
53023cee5a60SRemy Bruno /* debug file to read all hdspm registers */
530347f2769bSTakashi Iwai snd_card_ro_proc_new(hdspm->card, "debug", hdspm,
53043cee5a60SRemy Bruno snd_hdspm_proc_read_debug);
53053cee5a60SRemy Bruno #endif
5306763f356cSTakashi Iwai }
5307763f356cSTakashi Iwai
5308763f356cSTakashi Iwai /*------------------------------------------------------------
5309763f356cSTakashi Iwai hdspm intitialize
5310763f356cSTakashi Iwai ------------------------------------------------------------*/
5311763f356cSTakashi Iwai
snd_hdspm_set_defaults(struct hdspm * hdspm)531298274f07STakashi Iwai static int snd_hdspm_set_defaults(struct hdspm * hdspm)
5313763f356cSTakashi Iwai {
5314763f356cSTakashi Iwai /* ASSUMPTION: hdspm->lock is either held, or there is no need to
5315561de31aSJoe Perches hold it (e.g. during module initialization).
5316763f356cSTakashi Iwai */
5317763f356cSTakashi Iwai
5318763f356cSTakashi Iwai /* set defaults: */
5319763f356cSTakashi Iwai
53200dca1793SAdrian Knoth hdspm->settings_register = 0;
53210dca1793SAdrian Knoth
53220dca1793SAdrian Knoth switch (hdspm->io_type) {
53230dca1793SAdrian Knoth case MADI:
53240dca1793SAdrian Knoth case MADIface:
53250dca1793SAdrian Knoth hdspm->control_register =
53260dca1793SAdrian Knoth 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000;
53270dca1793SAdrian Knoth break;
53280dca1793SAdrian Knoth
53290dca1793SAdrian Knoth case RayDAT:
53300dca1793SAdrian Knoth case AIO:
53310dca1793SAdrian Knoth hdspm->settings_register = 0x1 + 0x1000;
53320dca1793SAdrian Knoth /* Magic values are: LAT_0, LAT_2, Master, freq1, tx64ch, inp_0,
53330dca1793SAdrian Knoth * line_out */
53340dca1793SAdrian Knoth hdspm->control_register =
53350dca1793SAdrian Knoth 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000;
53360dca1793SAdrian Knoth break;
53370dca1793SAdrian Knoth
53380dca1793SAdrian Knoth case AES32:
5339ef5fa1a4STakashi Iwai hdspm->control_register =
5340e71b95adSAdrian Knoth HDSPM_ClockModeMaster | /* Master Clock Mode on */
53410dca1793SAdrian Knoth hdspm_encode_latency(7) | /* latency max=8192samples */
53423cee5a60SRemy Bruno HDSPM_SyncRef0 | /* AES1 is syncclock */
53433cee5a60SRemy Bruno HDSPM_LineOut | /* Analog output in */
53443cee5a60SRemy Bruno HDSPM_Professional; /* Professional mode */
53450dca1793SAdrian Knoth break;
53460dca1793SAdrian Knoth }
5347763f356cSTakashi Iwai
5348763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
5349763f356cSTakashi Iwai
53500dca1793SAdrian Knoth if (AES32 == hdspm->io_type) {
5351ffb2c3c0SRemy Bruno /* No control2 register for AES32 */
5352763f356cSTakashi Iwai #ifdef SNDRV_BIG_ENDIAN
5353763f356cSTakashi Iwai hdspm->control2_register = HDSPM_BIGENDIAN_MODE;
5354763f356cSTakashi Iwai #else
5355763f356cSTakashi Iwai hdspm->control2_register = 0;
5356763f356cSTakashi Iwai #endif
5357763f356cSTakashi Iwai
5358763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register);
5359ffb2c3c0SRemy Bruno }
5360763f356cSTakashi Iwai hdspm_compute_period_size(hdspm);
5361763f356cSTakashi Iwai
5362763f356cSTakashi Iwai /* silence everything */
5363763f356cSTakashi Iwai
5364763f356cSTakashi Iwai all_in_all_mixer(hdspm, 0 * UNITY_GAIN);
5365763f356cSTakashi Iwai
5366b2ed6326SAdrian Knoth if (hdspm_is_raydat_or_aio(hdspm))
53670dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
5368763f356cSTakashi Iwai
5369763f356cSTakashi Iwai /* set a default rate so that the channel map is set up. */
53700dca1793SAdrian Knoth hdspm_set_rate(hdspm, 48000, 1);
5371763f356cSTakashi Iwai
5372763f356cSTakashi Iwai return 0;
5373763f356cSTakashi Iwai }
5374763f356cSTakashi Iwai
5375763f356cSTakashi Iwai
5376763f356cSTakashi Iwai /*------------------------------------------------------------
5377561de31aSJoe Perches interrupt
5378763f356cSTakashi Iwai ------------------------------------------------------------*/
5379763f356cSTakashi Iwai
snd_hdspm_interrupt(int irq,void * dev_id)53807d12e780SDavid Howells static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
5381763f356cSTakashi Iwai {
538298274f07STakashi Iwai struct hdspm *hdspm = (struct hdspm *) dev_id;
5383763f356cSTakashi Iwai unsigned int status;
53840dca1793SAdrian Knoth int i, audio, midi, schedule = 0;
53850dca1793SAdrian Knoth /* cycles_t now; */
5386763f356cSTakashi Iwai
5387763f356cSTakashi Iwai status = hdspm_read(hdspm, HDSPM_statusRegister);
5388763f356cSTakashi Iwai
5389763f356cSTakashi Iwai audio = status & HDSPM_audioIRQPending;
53900dca1793SAdrian Knoth midi = status & (HDSPM_midi0IRQPending | HDSPM_midi1IRQPending |
53910dca1793SAdrian Knoth HDSPM_midi2IRQPending | HDSPM_midi3IRQPending);
5392763f356cSTakashi Iwai
53930dca1793SAdrian Knoth /* now = get_cycles(); */
5394ddcecf6bSTakashi Iwai /*
53950dca1793SAdrian Knoth * LAT_2..LAT_0 period counter (win) counter (mac)
53960dca1793SAdrian Knoth * 6 4096 ~256053425 ~514672358
53970dca1793SAdrian Knoth * 5 2048 ~128024983 ~257373821
53980dca1793SAdrian Knoth * 4 1024 ~64023706 ~128718089
53990dca1793SAdrian Knoth * 3 512 ~32005945 ~64385999
54000dca1793SAdrian Knoth * 2 256 ~16003039 ~32260176
54010dca1793SAdrian Knoth * 1 128 ~7998738 ~16194507
54020dca1793SAdrian Knoth * 0 64 ~3998231 ~8191558
5403ddcecf6bSTakashi Iwai */
54040dca1793SAdrian Knoth /*
5405e3a471d6STakashi Iwai dev_info(hdspm->card->dev, "snd_hdspm_interrupt %llu @ %llx\n",
54060dca1793SAdrian Knoth now-hdspm->last_interrupt, status & 0xFFC0);
54070dca1793SAdrian Knoth hdspm->last_interrupt = now;
54080dca1793SAdrian Knoth */
54090dca1793SAdrian Knoth
54100dca1793SAdrian Knoth if (!audio && !midi)
5411763f356cSTakashi Iwai return IRQ_NONE;
5412763f356cSTakashi Iwai
5413763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_interruptConfirmation, 0);
5414763f356cSTakashi Iwai hdspm->irq_count++;
5415763f356cSTakashi Iwai
5416763f356cSTakashi Iwai
5417763f356cSTakashi Iwai if (audio) {
5418763f356cSTakashi Iwai if (hdspm->capture_substream)
5419ef5fa1a4STakashi Iwai snd_pcm_period_elapsed(hdspm->capture_substream);
5420763f356cSTakashi Iwai
5421763f356cSTakashi Iwai if (hdspm->playback_substream)
5422ef5fa1a4STakashi Iwai snd_pcm_period_elapsed(hdspm->playback_substream);
5423763f356cSTakashi Iwai }
5424763f356cSTakashi Iwai
54250dca1793SAdrian Knoth if (midi) {
54260dca1793SAdrian Knoth i = 0;
54270dca1793SAdrian Knoth while (i < hdspm->midiPorts) {
54280dca1793SAdrian Knoth if ((hdspm_read(hdspm,
54290dca1793SAdrian Knoth hdspm->midi[i].statusIn) & 0xff) &&
54300dca1793SAdrian Knoth (status & hdspm->midi[i].irq)) {
54310dca1793SAdrian Knoth /* we disable interrupts for this input until
54320dca1793SAdrian Knoth * processing is done
5433ef5fa1a4STakashi Iwai */
54340dca1793SAdrian Knoth hdspm->control_register &= ~hdspm->midi[i].ie;
5435763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister,
5436763f356cSTakashi Iwai hdspm->control_register);
54370dca1793SAdrian Knoth hdspm->midi[i].pending = 1;
5438763f356cSTakashi Iwai schedule = 1;
5439763f356cSTakashi Iwai }
54400dca1793SAdrian Knoth
54410dca1793SAdrian Knoth i++;
5442763f356cSTakashi Iwai }
54430dca1793SAdrian Knoth
5444763f356cSTakashi Iwai if (schedule)
5445a2e527c5STakashi Iwai queue_work(system_highpri_wq, &hdspm->midi_work);
54460dca1793SAdrian Knoth }
54470dca1793SAdrian Knoth
5448763f356cSTakashi Iwai return IRQ_HANDLED;
5449763f356cSTakashi Iwai }
5450763f356cSTakashi Iwai
5451763f356cSTakashi Iwai /*------------------------------------------------------------
5452763f356cSTakashi Iwai pcm interface
5453763f356cSTakashi Iwai ------------------------------------------------------------*/
5454763f356cSTakashi Iwai
5455763f356cSTakashi Iwai
snd_hdspm_hw_pointer(struct snd_pcm_substream * substream)54560dca1793SAdrian Knoth static snd_pcm_uframes_t snd_hdspm_hw_pointer(struct snd_pcm_substream
54570dca1793SAdrian Knoth *substream)
5458763f356cSTakashi Iwai {
545998274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream);
5460763f356cSTakashi Iwai return hdspm_hw_pointer(hdspm);
5461763f356cSTakashi Iwai }
5462763f356cSTakashi Iwai
5463763f356cSTakashi Iwai
snd_hdspm_reset(struct snd_pcm_substream * substream)546498274f07STakashi Iwai static int snd_hdspm_reset(struct snd_pcm_substream *substream)
5465763f356cSTakashi Iwai {
546698274f07STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
546798274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream);
546898274f07STakashi Iwai struct snd_pcm_substream *other;
5469763f356cSTakashi Iwai
5470763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
5471763f356cSTakashi Iwai other = hdspm->capture_substream;
5472763f356cSTakashi Iwai else
5473763f356cSTakashi Iwai other = hdspm->playback_substream;
5474763f356cSTakashi Iwai
5475763f356cSTakashi Iwai if (hdspm->running)
5476763f356cSTakashi Iwai runtime->status->hw_ptr = hdspm_hw_pointer(hdspm);
5477763f356cSTakashi Iwai else
5478763f356cSTakashi Iwai runtime->status->hw_ptr = 0;
5479763f356cSTakashi Iwai if (other) {
548098274f07STakashi Iwai struct snd_pcm_substream *s;
548198274f07STakashi Iwai struct snd_pcm_runtime *oruntime = other->runtime;
5482ef991b95STakashi Iwai snd_pcm_group_for_each_entry(s, substream) {
5483763f356cSTakashi Iwai if (s == other) {
5484763f356cSTakashi Iwai oruntime->status->hw_ptr =
5485763f356cSTakashi Iwai runtime->status->hw_ptr;
5486763f356cSTakashi Iwai break;
5487763f356cSTakashi Iwai }
5488763f356cSTakashi Iwai }
5489763f356cSTakashi Iwai }
5490763f356cSTakashi Iwai return 0;
5491763f356cSTakashi Iwai }
5492763f356cSTakashi Iwai
snd_hdspm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)549398274f07STakashi Iwai static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
549498274f07STakashi Iwai struct snd_pcm_hw_params *params)
5495763f356cSTakashi Iwai {
549698274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream);
5497763f356cSTakashi Iwai int err;
5498763f356cSTakashi Iwai int i;
5499763f356cSTakashi Iwai pid_t this_pid;
5500763f356cSTakashi Iwai pid_t other_pid;
5501763f356cSTakashi Iwai
5502763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
5503763f356cSTakashi Iwai
5504763f356cSTakashi Iwai if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
5505763f356cSTakashi Iwai this_pid = hdspm->playback_pid;
5506763f356cSTakashi Iwai other_pid = hdspm->capture_pid;
5507763f356cSTakashi Iwai } else {
5508763f356cSTakashi Iwai this_pid = hdspm->capture_pid;
5509763f356cSTakashi Iwai other_pid = hdspm->playback_pid;
5510763f356cSTakashi Iwai }
5511763f356cSTakashi Iwai
5512ef5fa1a4STakashi Iwai if (other_pid > 0 && this_pid != other_pid) {
5513763f356cSTakashi Iwai
5514763f356cSTakashi Iwai /* The other stream is open, and not by the same
5515763f356cSTakashi Iwai task as this one. Make sure that the parameters
5516763f356cSTakashi Iwai that matter are the same.
5517763f356cSTakashi Iwai */
5518763f356cSTakashi Iwai
5519763f356cSTakashi Iwai if (params_rate(params) != hdspm->system_sample_rate) {
5520763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
5521763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params,
5522763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_RATE);
5523763f356cSTakashi Iwai return -EBUSY;
5524763f356cSTakashi Iwai }
5525763f356cSTakashi Iwai
5526763f356cSTakashi Iwai if (params_period_size(params) != hdspm->period_bytes / 4) {
5527763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
5528763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params,
5529763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
5530763f356cSTakashi Iwai return -EBUSY;
5531763f356cSTakashi Iwai }
5532763f356cSTakashi Iwai
5533763f356cSTakashi Iwai }
5534763f356cSTakashi Iwai /* We're fine. */
5535763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
5536763f356cSTakashi Iwai
5537763f356cSTakashi Iwai /* how to make sure that the rate matches an externally-set one ? */
5538763f356cSTakashi Iwai
5539763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
5540ef5fa1a4STakashi Iwai err = hdspm_set_rate(hdspm, params_rate(params), 0);
5541ef5fa1a4STakashi Iwai if (err < 0) {
5542e3a471d6STakashi Iwai dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err);
5543763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
5544763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params,
5545763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_RATE);
5546763f356cSTakashi Iwai return err;
5547763f356cSTakashi Iwai }
5548763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
5549763f356cSTakashi Iwai
5550ef5fa1a4STakashi Iwai err = hdspm_set_interrupt_interval(hdspm,
5551ef5fa1a4STakashi Iwai params_period_size(params));
5552ef5fa1a4STakashi Iwai if (err < 0) {
5553e3a471d6STakashi Iwai dev_info(hdspm->card->dev,
5554e3a471d6STakashi Iwai "err on hdspm_set_interrupt_interval: %d\n", err);
5555763f356cSTakashi Iwai _snd_pcm_hw_param_setempty(params,
5556763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
5557763f356cSTakashi Iwai return err;
5558763f356cSTakashi Iwai }
5559763f356cSTakashi Iwai
5560ef5fa1a4STakashi Iwai /* Memory allocation, takashi's method, dont know if we should
5561ef5fa1a4STakashi Iwai * spinlock
5562ef5fa1a4STakashi Iwai */
5563763f356cSTakashi Iwai /* malloc all buffer even if not enabled to get sure */
5564ffb2c3c0SRemy Bruno /* Update for MADI rev 204: we need to allocate for all channels,
5565ffb2c3c0SRemy Bruno * otherwise it doesn't work at 96kHz */
55660dca1793SAdrian Knoth
5567763f356cSTakashi Iwai err =
5568ffb2c3c0SRemy Bruno snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES);
55690dca1793SAdrian Knoth if (err < 0) {
5570e3a471d6STakashi Iwai dev_info(hdspm->card->dev,
5571e3a471d6STakashi Iwai "err on snd_pcm_lib_malloc_pages: %d\n", err);
5572763f356cSTakashi Iwai return err;
55730dca1793SAdrian Knoth }
5574763f356cSTakashi Iwai
5575763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
5576763f356cSTakashi Iwai
5577e4e07c6cSPhilippe Bekaert for (i = 0; i < params_channels(params); ++i) {
5578e4e07c6cSPhilippe Bekaert int c = hdspm->channel_map_out[i];
5579763f356cSTakashi Iwai
5580e4e07c6cSPhilippe Bekaert if (c < 0)
5581e4e07c6cSPhilippe Bekaert continue; /* just make sure */
5582e4e07c6cSPhilippe Bekaert hdspm_set_channel_dma_addr(hdspm, substream,
5583e4e07c6cSPhilippe Bekaert HDSPM_pageAddressBufferOut,
5584e4e07c6cSPhilippe Bekaert c);
5585e4e07c6cSPhilippe Bekaert snd_hdspm_enable_out(hdspm, c, 1);
5586e4e07c6cSPhilippe Bekaert }
5587763f356cSTakashi Iwai
5588763f356cSTakashi Iwai hdspm->playback_buffer =
5589763f356cSTakashi Iwai (unsigned char *) substream->runtime->dma_area;
5590e3a471d6STakashi Iwai dev_dbg(hdspm->card->dev,
5591e3a471d6STakashi Iwai "Allocated sample buffer for playback at %p\n",
55923cee5a60SRemy Bruno hdspm->playback_buffer);
5593763f356cSTakashi Iwai } else {
5594e4e07c6cSPhilippe Bekaert for (i = 0; i < params_channels(params); ++i) {
5595e4e07c6cSPhilippe Bekaert int c = hdspm->channel_map_in[i];
5596763f356cSTakashi Iwai
5597e4e07c6cSPhilippe Bekaert if (c < 0)
5598e4e07c6cSPhilippe Bekaert continue;
5599e4e07c6cSPhilippe Bekaert hdspm_set_channel_dma_addr(hdspm, substream,
5600e4e07c6cSPhilippe Bekaert HDSPM_pageAddressBufferIn,
5601e4e07c6cSPhilippe Bekaert c);
5602e4e07c6cSPhilippe Bekaert snd_hdspm_enable_in(hdspm, c, 1);
5603e4e07c6cSPhilippe Bekaert }
5604763f356cSTakashi Iwai
5605763f356cSTakashi Iwai hdspm->capture_buffer =
5606763f356cSTakashi Iwai (unsigned char *) substream->runtime->dma_area;
5607e3a471d6STakashi Iwai dev_dbg(hdspm->card->dev,
5608e3a471d6STakashi Iwai "Allocated sample buffer for capture at %p\n",
56093cee5a60SRemy Bruno hdspm->capture_buffer);
5610763f356cSTakashi Iwai }
56110dca1793SAdrian Knoth
56123cee5a60SRemy Bruno /*
5613e3a471d6STakashi Iwai dev_dbg(hdspm->card->dev,
5614e3a471d6STakashi Iwai "Allocated sample buffer for %s at 0x%08X\n",
56153cee5a60SRemy Bruno substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
56163cee5a60SRemy Bruno "playback" : "capture",
561777a23f26STakashi Iwai snd_pcm_sgbuf_get_addr(substream, 0));
56183cee5a60SRemy Bruno */
5619ffb2c3c0SRemy Bruno /*
5620e3a471d6STakashi Iwai dev_dbg(hdspm->card->dev,
5621e3a471d6STakashi Iwai "set_hwparams: %s %d Hz, %d channels, bs = %d\n",
5622ffb2c3c0SRemy Bruno substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
5623ffb2c3c0SRemy Bruno "playback" : "capture",
5624ffb2c3c0SRemy Bruno params_rate(params), params_channels(params),
5625ffb2c3c0SRemy Bruno params_buffer_size(params));
5626ffb2c3c0SRemy Bruno */
56270dca1793SAdrian Knoth
56280dca1793SAdrian Knoth
56293ac9b0acSAdrian Knoth /* For AES cards, the float format bit is the same as the
56303ac9b0acSAdrian Knoth * preferred sync reference. Since we don't want to break
56313ac9b0acSAdrian Knoth * sync settings, we have to skip the remaining part of this
56323ac9b0acSAdrian Knoth * function.
56333ac9b0acSAdrian Knoth */
56343ac9b0acSAdrian Knoth if (hdspm->io_type == AES32) {
56353ac9b0acSAdrian Knoth return 0;
56363ac9b0acSAdrian Knoth }
56373ac9b0acSAdrian Knoth
56383ac9b0acSAdrian Knoth
56390dca1793SAdrian Knoth /* Switch to native float format if requested */
56400dca1793SAdrian Knoth if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) {
56410dca1793SAdrian Knoth if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT))
5642e3a471d6STakashi Iwai dev_info(hdspm->card->dev,
5643e3a471d6STakashi Iwai "Switching to native 32bit LE float format.\n");
56440dca1793SAdrian Knoth
56450dca1793SAdrian Knoth hdspm->control_register |= HDSPe_FLOAT_FORMAT;
56460dca1793SAdrian Knoth } else if (SNDRV_PCM_FORMAT_S32_LE == params_format(params)) {
56470dca1793SAdrian Knoth if (hdspm->control_register & HDSPe_FLOAT_FORMAT)
5648e3a471d6STakashi Iwai dev_info(hdspm->card->dev,
5649e3a471d6STakashi Iwai "Switching to native 32bit LE integer format.\n");
56500dca1793SAdrian Knoth
56510dca1793SAdrian Knoth hdspm->control_register &= ~HDSPe_FLOAT_FORMAT;
56520dca1793SAdrian Knoth }
56530dca1793SAdrian Knoth hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
56540dca1793SAdrian Knoth
5655763f356cSTakashi Iwai return 0;
5656763f356cSTakashi Iwai }
5657763f356cSTakashi Iwai
snd_hdspm_hw_free(struct snd_pcm_substream * substream)565898274f07STakashi Iwai static int snd_hdspm_hw_free(struct snd_pcm_substream *substream)
5659763f356cSTakashi Iwai {
5660763f356cSTakashi Iwai int i;
566198274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream);
5662763f356cSTakashi Iwai
5663763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
5664e4e07c6cSPhilippe Bekaert /* Just disable all channels. The saving when disabling a */
5665e4e07c6cSPhilippe Bekaert /* smaller set is not worth the trouble. */
5666e4e07c6cSPhilippe Bekaert for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
5667763f356cSTakashi Iwai snd_hdspm_enable_out(hdspm, i, 0);
5668763f356cSTakashi Iwai
5669763f356cSTakashi Iwai hdspm->playback_buffer = NULL;
5670763f356cSTakashi Iwai } else {
5671e4e07c6cSPhilippe Bekaert for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
5672763f356cSTakashi Iwai snd_hdspm_enable_in(hdspm, i, 0);
5673763f356cSTakashi Iwai
5674763f356cSTakashi Iwai hdspm->capture_buffer = NULL;
5675763f356cSTakashi Iwai }
5676763f356cSTakashi Iwai
5677763f356cSTakashi Iwai snd_pcm_lib_free_pages(substream);
5678763f356cSTakashi Iwai
5679763f356cSTakashi Iwai return 0;
5680763f356cSTakashi Iwai }
5681763f356cSTakashi Iwai
56820dca1793SAdrian Knoth
snd_hdspm_channel_info(struct snd_pcm_substream * substream,struct snd_pcm_channel_info * info)568398274f07STakashi Iwai static int snd_hdspm_channel_info(struct snd_pcm_substream *substream,
568498274f07STakashi Iwai struct snd_pcm_channel_info *info)
5685763f356cSTakashi Iwai {
568698274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream);
568710513142STakashi Iwai unsigned int channel = info->channel;
5688763f356cSTakashi Iwai
56890dca1793SAdrian Knoth if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
569010513142STakashi Iwai if (snd_BUG_ON(channel >= hdspm->max_channels_out)) {
5691e3a471d6STakashi Iwai dev_info(hdspm->card->dev,
5692e3a471d6STakashi Iwai "snd_hdspm_channel_info: output channel out of range (%d)\n",
569310513142STakashi Iwai channel);
5694da3cec35STakashi Iwai return -EINVAL;
56950dca1793SAdrian Knoth }
5696763f356cSTakashi Iwai
569710513142STakashi Iwai channel = array_index_nospec(channel, hdspm->max_channels_out);
569810513142STakashi Iwai if (hdspm->channel_map_out[channel] < 0) {
5699e3a471d6STakashi Iwai dev_info(hdspm->card->dev,
5700e3a471d6STakashi Iwai "snd_hdspm_channel_info: output channel %d mapped out\n",
570110513142STakashi Iwai channel);
5702763f356cSTakashi Iwai return -EINVAL;
57030dca1793SAdrian Knoth }
5704763f356cSTakashi Iwai
570510513142STakashi Iwai info->offset = hdspm->channel_map_out[channel] *
57060dca1793SAdrian Knoth HDSPM_CHANNEL_BUFFER_BYTES;
57070dca1793SAdrian Knoth } else {
570810513142STakashi Iwai if (snd_BUG_ON(channel >= hdspm->max_channels_in)) {
5709e3a471d6STakashi Iwai dev_info(hdspm->card->dev,
5710e3a471d6STakashi Iwai "snd_hdspm_channel_info: input channel out of range (%d)\n",
571110513142STakashi Iwai channel);
57120dca1793SAdrian Knoth return -EINVAL;
57130dca1793SAdrian Knoth }
57140dca1793SAdrian Knoth
571510513142STakashi Iwai channel = array_index_nospec(channel, hdspm->max_channels_in);
571610513142STakashi Iwai if (hdspm->channel_map_in[channel] < 0) {
5717e3a471d6STakashi Iwai dev_info(hdspm->card->dev,
5718e3a471d6STakashi Iwai "snd_hdspm_channel_info: input channel %d mapped out\n",
571910513142STakashi Iwai channel);
57200dca1793SAdrian Knoth return -EINVAL;
57210dca1793SAdrian Knoth }
57220dca1793SAdrian Knoth
572310513142STakashi Iwai info->offset = hdspm->channel_map_in[channel] *
57240dca1793SAdrian Knoth HDSPM_CHANNEL_BUFFER_BYTES;
57250dca1793SAdrian Knoth }
57260dca1793SAdrian Knoth
5727763f356cSTakashi Iwai info->first = 0;
5728763f356cSTakashi Iwai info->step = 32;
5729763f356cSTakashi Iwai return 0;
5730763f356cSTakashi Iwai }
5731763f356cSTakashi Iwai
57320dca1793SAdrian Knoth
snd_hdspm_ioctl(struct snd_pcm_substream * substream,unsigned int cmd,void * arg)573398274f07STakashi Iwai static int snd_hdspm_ioctl(struct snd_pcm_substream *substream,
5734763f356cSTakashi Iwai unsigned int cmd, void *arg)
5735763f356cSTakashi Iwai {
5736763f356cSTakashi Iwai switch (cmd) {
5737763f356cSTakashi Iwai case SNDRV_PCM_IOCTL1_RESET:
5738763f356cSTakashi Iwai return snd_hdspm_reset(substream);
5739763f356cSTakashi Iwai
5740763f356cSTakashi Iwai case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
5741763f356cSTakashi Iwai {
574298274f07STakashi Iwai struct snd_pcm_channel_info *info = arg;
5743763f356cSTakashi Iwai return snd_hdspm_channel_info(substream, info);
5744763f356cSTakashi Iwai }
5745763f356cSTakashi Iwai default:
5746763f356cSTakashi Iwai break;
5747763f356cSTakashi Iwai }
5748763f356cSTakashi Iwai
5749763f356cSTakashi Iwai return snd_pcm_lib_ioctl(substream, cmd, arg);
5750763f356cSTakashi Iwai }
5751763f356cSTakashi Iwai
snd_hdspm_trigger(struct snd_pcm_substream * substream,int cmd)575298274f07STakashi Iwai static int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd)
5753763f356cSTakashi Iwai {
575498274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream);
575598274f07STakashi Iwai struct snd_pcm_substream *other;
5756763f356cSTakashi Iwai int running;
5757763f356cSTakashi Iwai
5758763f356cSTakashi Iwai spin_lock(&hdspm->lock);
5759763f356cSTakashi Iwai running = hdspm->running;
5760763f356cSTakashi Iwai switch (cmd) {
5761763f356cSTakashi Iwai case SNDRV_PCM_TRIGGER_START:
5762763f356cSTakashi Iwai running |= 1 << substream->stream;
5763763f356cSTakashi Iwai break;
5764763f356cSTakashi Iwai case SNDRV_PCM_TRIGGER_STOP:
5765763f356cSTakashi Iwai running &= ~(1 << substream->stream);
5766763f356cSTakashi Iwai break;
5767763f356cSTakashi Iwai default:
5768763f356cSTakashi Iwai snd_BUG();
5769763f356cSTakashi Iwai spin_unlock(&hdspm->lock);
5770763f356cSTakashi Iwai return -EINVAL;
5771763f356cSTakashi Iwai }
5772763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
5773763f356cSTakashi Iwai other = hdspm->capture_substream;
5774763f356cSTakashi Iwai else
5775763f356cSTakashi Iwai other = hdspm->playback_substream;
5776763f356cSTakashi Iwai
5777763f356cSTakashi Iwai if (other) {
577898274f07STakashi Iwai struct snd_pcm_substream *s;
5779ef991b95STakashi Iwai snd_pcm_group_for_each_entry(s, substream) {
5780763f356cSTakashi Iwai if (s == other) {
5781763f356cSTakashi Iwai snd_pcm_trigger_done(s, substream);
5782763f356cSTakashi Iwai if (cmd == SNDRV_PCM_TRIGGER_START)
5783763f356cSTakashi Iwai running |= 1 << s->stream;
5784763f356cSTakashi Iwai else
5785763f356cSTakashi Iwai running &= ~(1 << s->stream);
5786763f356cSTakashi Iwai goto _ok;
5787763f356cSTakashi Iwai }
5788763f356cSTakashi Iwai }
5789763f356cSTakashi Iwai if (cmd == SNDRV_PCM_TRIGGER_START) {
5790763f356cSTakashi Iwai if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK))
5791763f356cSTakashi Iwai && substream->stream ==
5792763f356cSTakashi Iwai SNDRV_PCM_STREAM_CAPTURE)
5793763f356cSTakashi Iwai hdspm_silence_playback(hdspm);
5794763f356cSTakashi Iwai } else {
5795763f356cSTakashi Iwai if (running &&
5796763f356cSTakashi Iwai substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
5797763f356cSTakashi Iwai hdspm_silence_playback(hdspm);
5798763f356cSTakashi Iwai }
5799763f356cSTakashi Iwai } else {
5800763f356cSTakashi Iwai if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
5801763f356cSTakashi Iwai hdspm_silence_playback(hdspm);
5802763f356cSTakashi Iwai }
5803763f356cSTakashi Iwai _ok:
5804763f356cSTakashi Iwai snd_pcm_trigger_done(substream, substream);
5805763f356cSTakashi Iwai if (!hdspm->running && running)
5806763f356cSTakashi Iwai hdspm_start_audio(hdspm);
5807763f356cSTakashi Iwai else if (hdspm->running && !running)
5808763f356cSTakashi Iwai hdspm_stop_audio(hdspm);
5809763f356cSTakashi Iwai hdspm->running = running;
5810763f356cSTakashi Iwai spin_unlock(&hdspm->lock);
5811763f356cSTakashi Iwai
5812763f356cSTakashi Iwai return 0;
5813763f356cSTakashi Iwai }
5814763f356cSTakashi Iwai
snd_hdspm_prepare(struct snd_pcm_substream * substream)581598274f07STakashi Iwai static int snd_hdspm_prepare(struct snd_pcm_substream *substream)
5816763f356cSTakashi Iwai {
5817763f356cSTakashi Iwai return 0;
5818763f356cSTakashi Iwai }
5819763f356cSTakashi Iwai
5820c1c3981fSTakashi Iwai static const struct snd_pcm_hardware snd_hdspm_playback_subinfo = {
5821763f356cSTakashi Iwai .info = (SNDRV_PCM_INFO_MMAP |
5822763f356cSTakashi Iwai SNDRV_PCM_INFO_MMAP_VALID |
5823763f356cSTakashi Iwai SNDRV_PCM_INFO_NONINTERLEAVED |
5824763f356cSTakashi Iwai SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_DOUBLE),
5825763f356cSTakashi Iwai .formats = SNDRV_PCM_FMTBIT_S32_LE,
5826763f356cSTakashi Iwai .rates = (SNDRV_PCM_RATE_32000 |
5827763f356cSTakashi Iwai SNDRV_PCM_RATE_44100 |
5828763f356cSTakashi Iwai SNDRV_PCM_RATE_48000 |
5829763f356cSTakashi Iwai SNDRV_PCM_RATE_64000 |
58303cee5a60SRemy Bruno SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
58313cee5a60SRemy Bruno SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ),
5832763f356cSTakashi Iwai .rate_min = 32000,
58333cee5a60SRemy Bruno .rate_max = 192000,
5834763f356cSTakashi Iwai .channels_min = 1,
5835763f356cSTakashi Iwai .channels_max = HDSPM_MAX_CHANNELS,
5836763f356cSTakashi Iwai .buffer_bytes_max =
5837763f356cSTakashi Iwai HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS,
58381b6fa108SAdrian Knoth .period_bytes_min = (32 * 4),
583952e6fb48STakashi Iwai .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS,
5840763f356cSTakashi Iwai .periods_min = 2,
58410dca1793SAdrian Knoth .periods_max = 512,
5842763f356cSTakashi Iwai .fifo_size = 0
5843763f356cSTakashi Iwai };
5844763f356cSTakashi Iwai
5845c1c3981fSTakashi Iwai static const struct snd_pcm_hardware snd_hdspm_capture_subinfo = {
5846763f356cSTakashi Iwai .info = (SNDRV_PCM_INFO_MMAP |
5847763f356cSTakashi Iwai SNDRV_PCM_INFO_MMAP_VALID |
5848763f356cSTakashi Iwai SNDRV_PCM_INFO_NONINTERLEAVED |
5849763f356cSTakashi Iwai SNDRV_PCM_INFO_SYNC_START),
5850763f356cSTakashi Iwai .formats = SNDRV_PCM_FMTBIT_S32_LE,
5851763f356cSTakashi Iwai .rates = (SNDRV_PCM_RATE_32000 |
5852763f356cSTakashi Iwai SNDRV_PCM_RATE_44100 |
5853763f356cSTakashi Iwai SNDRV_PCM_RATE_48000 |
5854763f356cSTakashi Iwai SNDRV_PCM_RATE_64000 |
58553cee5a60SRemy Bruno SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
58563cee5a60SRemy Bruno SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000),
5857763f356cSTakashi Iwai .rate_min = 32000,
58583cee5a60SRemy Bruno .rate_max = 192000,
5859763f356cSTakashi Iwai .channels_min = 1,
5860763f356cSTakashi Iwai .channels_max = HDSPM_MAX_CHANNELS,
5861763f356cSTakashi Iwai .buffer_bytes_max =
5862763f356cSTakashi Iwai HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS,
58631b6fa108SAdrian Knoth .period_bytes_min = (32 * 4),
586452e6fb48STakashi Iwai .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS,
5865763f356cSTakashi Iwai .periods_min = 2,
58660dca1793SAdrian Knoth .periods_max = 512,
5867763f356cSTakashi Iwai .fifo_size = 0
5868763f356cSTakashi Iwai };
5869763f356cSTakashi Iwai
snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)58700dca1793SAdrian Knoth static int snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params,
587198274f07STakashi Iwai struct snd_pcm_hw_rule *rule)
5872763f356cSTakashi Iwai {
587398274f07STakashi Iwai struct hdspm *hdspm = rule->private;
587498274f07STakashi Iwai struct snd_interval *c =
5875763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
587698274f07STakashi Iwai struct snd_interval *r =
5877763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
5878763f356cSTakashi Iwai
58790dca1793SAdrian Knoth if (r->min > 96000 && r->max <= 192000) {
588098274f07STakashi Iwai struct snd_interval t = {
58810dca1793SAdrian Knoth .min = hdspm->qs_in_channels,
58820dca1793SAdrian Knoth .max = hdspm->qs_in_channels,
58830dca1793SAdrian Knoth .integer = 1,
58840dca1793SAdrian Knoth };
58850dca1793SAdrian Knoth return snd_interval_refine(c, &t);
58860dca1793SAdrian Knoth } else if (r->min > 48000 && r->max <= 96000) {
58870dca1793SAdrian Knoth struct snd_interval t = {
58880dca1793SAdrian Knoth .min = hdspm->ds_in_channels,
58890dca1793SAdrian Knoth .max = hdspm->ds_in_channels,
5890763f356cSTakashi Iwai .integer = 1,
5891763f356cSTakashi Iwai };
5892763f356cSTakashi Iwai return snd_interval_refine(c, &t);
5893763f356cSTakashi Iwai } else if (r->max < 64000) {
589498274f07STakashi Iwai struct snd_interval t = {
58950dca1793SAdrian Knoth .min = hdspm->ss_in_channels,
58960dca1793SAdrian Knoth .max = hdspm->ss_in_channels,
5897763f356cSTakashi Iwai .integer = 1,
5898763f356cSTakashi Iwai };
5899763f356cSTakashi Iwai return snd_interval_refine(c, &t);
5900763f356cSTakashi Iwai }
59010dca1793SAdrian Knoth
5902763f356cSTakashi Iwai return 0;
5903763f356cSTakashi Iwai }
5904763f356cSTakashi Iwai
snd_hdspm_hw_rule_out_channels_rate(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)59050dca1793SAdrian Knoth static int snd_hdspm_hw_rule_out_channels_rate(struct snd_pcm_hw_params *params,
590698274f07STakashi Iwai struct snd_pcm_hw_rule * rule)
5907763f356cSTakashi Iwai {
590898274f07STakashi Iwai struct hdspm *hdspm = rule->private;
590998274f07STakashi Iwai struct snd_interval *c =
5910763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
591198274f07STakashi Iwai struct snd_interval *r =
5912763f356cSTakashi Iwai hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
5913763f356cSTakashi Iwai
59140dca1793SAdrian Knoth if (r->min > 96000 && r->max <= 192000) {
59150dca1793SAdrian Knoth struct snd_interval t = {
59160dca1793SAdrian Knoth .min = hdspm->qs_out_channels,
59170dca1793SAdrian Knoth .max = hdspm->qs_out_channels,
59180dca1793SAdrian Knoth .integer = 1,
59190dca1793SAdrian Knoth };
59200dca1793SAdrian Knoth return snd_interval_refine(c, &t);
59210dca1793SAdrian Knoth } else if (r->min > 48000 && r->max <= 96000) {
59220dca1793SAdrian Knoth struct snd_interval t = {
59230dca1793SAdrian Knoth .min = hdspm->ds_out_channels,
59240dca1793SAdrian Knoth .max = hdspm->ds_out_channels,
59250dca1793SAdrian Knoth .integer = 1,
59260dca1793SAdrian Knoth };
59270dca1793SAdrian Knoth return snd_interval_refine(c, &t);
59280dca1793SAdrian Knoth } else if (r->max < 64000) {
59290dca1793SAdrian Knoth struct snd_interval t = {
59300dca1793SAdrian Knoth .min = hdspm->ss_out_channels,
59310dca1793SAdrian Knoth .max = hdspm->ss_out_channels,
59320dca1793SAdrian Knoth .integer = 1,
59330dca1793SAdrian Knoth };
59340dca1793SAdrian Knoth return snd_interval_refine(c, &t);
59350dca1793SAdrian Knoth } else {
59360dca1793SAdrian Knoth }
59370dca1793SAdrian Knoth return 0;
59380dca1793SAdrian Knoth }
59390dca1793SAdrian Knoth
snd_hdspm_hw_rule_rate_in_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)59400dca1793SAdrian Knoth static int snd_hdspm_hw_rule_rate_in_channels(struct snd_pcm_hw_params *params,
59410dca1793SAdrian Knoth struct snd_pcm_hw_rule * rule)
59420dca1793SAdrian Knoth {
59430dca1793SAdrian Knoth struct hdspm *hdspm = rule->private;
59440dca1793SAdrian Knoth struct snd_interval *c =
59450dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
59460dca1793SAdrian Knoth struct snd_interval *r =
59470dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
59480dca1793SAdrian Knoth
59490dca1793SAdrian Knoth if (c->min >= hdspm->ss_in_channels) {
595098274f07STakashi Iwai struct snd_interval t = {
5951763f356cSTakashi Iwai .min = 32000,
5952763f356cSTakashi Iwai .max = 48000,
5953763f356cSTakashi Iwai .integer = 1,
5954763f356cSTakashi Iwai };
5955763f356cSTakashi Iwai return snd_interval_refine(r, &t);
59560dca1793SAdrian Knoth } else if (c->max <= hdspm->qs_in_channels) {
59570dca1793SAdrian Knoth struct snd_interval t = {
59580dca1793SAdrian Knoth .min = 128000,
59590dca1793SAdrian Knoth .max = 192000,
59600dca1793SAdrian Knoth .integer = 1,
59610dca1793SAdrian Knoth };
59620dca1793SAdrian Knoth return snd_interval_refine(r, &t);
59630dca1793SAdrian Knoth } else if (c->max <= hdspm->ds_in_channels) {
596498274f07STakashi Iwai struct snd_interval t = {
5965763f356cSTakashi Iwai .min = 64000,
5966763f356cSTakashi Iwai .max = 96000,
5967763f356cSTakashi Iwai .integer = 1,
5968763f356cSTakashi Iwai };
5969763f356cSTakashi Iwai return snd_interval_refine(r, &t);
5970763f356cSTakashi Iwai }
59710dca1793SAdrian Knoth
59720dca1793SAdrian Knoth return 0;
59730dca1793SAdrian Knoth }
snd_hdspm_hw_rule_rate_out_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)59740dca1793SAdrian Knoth static int snd_hdspm_hw_rule_rate_out_channels(struct snd_pcm_hw_params *params,
59750dca1793SAdrian Knoth struct snd_pcm_hw_rule *rule)
59760dca1793SAdrian Knoth {
59770dca1793SAdrian Knoth struct hdspm *hdspm = rule->private;
59780dca1793SAdrian Knoth struct snd_interval *c =
59790dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
59800dca1793SAdrian Knoth struct snd_interval *r =
59810dca1793SAdrian Knoth hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
59820dca1793SAdrian Knoth
59830dca1793SAdrian Knoth if (c->min >= hdspm->ss_out_channels) {
59840dca1793SAdrian Knoth struct snd_interval t = {
59850dca1793SAdrian Knoth .min = 32000,
59860dca1793SAdrian Knoth .max = 48000,
59870dca1793SAdrian Knoth .integer = 1,
59880dca1793SAdrian Knoth };
59890dca1793SAdrian Knoth return snd_interval_refine(r, &t);
59900dca1793SAdrian Knoth } else if (c->max <= hdspm->qs_out_channels) {
59910dca1793SAdrian Knoth struct snd_interval t = {
59920dca1793SAdrian Knoth .min = 128000,
59930dca1793SAdrian Knoth .max = 192000,
59940dca1793SAdrian Knoth .integer = 1,
59950dca1793SAdrian Knoth };
59960dca1793SAdrian Knoth return snd_interval_refine(r, &t);
59970dca1793SAdrian Knoth } else if (c->max <= hdspm->ds_out_channels) {
59980dca1793SAdrian Knoth struct snd_interval t = {
59990dca1793SAdrian Knoth .min = 64000,
60000dca1793SAdrian Knoth .max = 96000,
60010dca1793SAdrian Knoth .integer = 1,
60020dca1793SAdrian Knoth };
60030dca1793SAdrian Knoth return snd_interval_refine(r, &t);
60040dca1793SAdrian Knoth }
60050dca1793SAdrian Knoth
6006763f356cSTakashi Iwai return 0;
6007763f356cSTakashi Iwai }
6008763f356cSTakashi Iwai
snd_hdspm_hw_rule_in_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)60090dca1793SAdrian Knoth static int snd_hdspm_hw_rule_in_channels(struct snd_pcm_hw_params *params,
6010ffb2c3c0SRemy Bruno struct snd_pcm_hw_rule *rule)
6011ffb2c3c0SRemy Bruno {
6012ffb2c3c0SRemy Bruno unsigned int list[3];
6013ffb2c3c0SRemy Bruno struct hdspm *hdspm = rule->private;
6014ffb2c3c0SRemy Bruno struct snd_interval *c = hw_param_interval(params,
6015ffb2c3c0SRemy Bruno SNDRV_PCM_HW_PARAM_CHANNELS);
60160dca1793SAdrian Knoth
60170dca1793SAdrian Knoth list[0] = hdspm->qs_in_channels;
60180dca1793SAdrian Knoth list[1] = hdspm->ds_in_channels;
60190dca1793SAdrian Knoth list[2] = hdspm->ss_in_channels;
6020ffb2c3c0SRemy Bruno return snd_interval_list(c, 3, list, 0);
6021ffb2c3c0SRemy Bruno }
60220dca1793SAdrian Knoth
snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)60230dca1793SAdrian Knoth static int snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params *params,
60240dca1793SAdrian Knoth struct snd_pcm_hw_rule *rule)
60250dca1793SAdrian Knoth {
60260dca1793SAdrian Knoth unsigned int list[3];
60270dca1793SAdrian Knoth struct hdspm *hdspm = rule->private;
60280dca1793SAdrian Knoth struct snd_interval *c = hw_param_interval(params,
60290dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_CHANNELS);
60300dca1793SAdrian Knoth
60310dca1793SAdrian Knoth list[0] = hdspm->qs_out_channels;
60320dca1793SAdrian Knoth list[1] = hdspm->ds_out_channels;
60330dca1793SAdrian Knoth list[2] = hdspm->ss_out_channels;
60340dca1793SAdrian Knoth return snd_interval_list(c, 3, list, 0);
6035ffb2c3c0SRemy Bruno }
6036ffb2c3c0SRemy Bruno
6037ffb2c3c0SRemy Bruno
6038bdf84db7STakashi Iwai static const unsigned int hdspm_aes32_sample_rates[] = {
6039ef5fa1a4STakashi Iwai 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000
6040ef5fa1a4STakashi Iwai };
6041ffb2c3c0SRemy Bruno
6042bdf84db7STakashi Iwai static const struct snd_pcm_hw_constraint_list
6043ef5fa1a4STakashi Iwai hdspm_hw_constraints_aes32_sample_rates = {
6044ffb2c3c0SRemy Bruno .count = ARRAY_SIZE(hdspm_aes32_sample_rates),
6045ffb2c3c0SRemy Bruno .list = hdspm_aes32_sample_rates,
6046ffb2c3c0SRemy Bruno .mask = 0
6047ffb2c3c0SRemy Bruno };
6048ffb2c3c0SRemy Bruno
snd_hdspm_open(struct snd_pcm_substream * substream)60495ecc5dc7SAdrian Knoth static int snd_hdspm_open(struct snd_pcm_substream *substream)
6050763f356cSTakashi Iwai {
605198274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream);
605298274f07STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime;
60535ecc5dc7SAdrian Knoth bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
6054763f356cSTakashi Iwai
6055763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
6056763f356cSTakashi Iwai snd_pcm_set_sync(substream);
60575ecc5dc7SAdrian Knoth runtime->hw = (playback) ? snd_hdspm_playback_subinfo :
60585ecc5dc7SAdrian Knoth snd_hdspm_capture_subinfo;
6059763f356cSTakashi Iwai
60605ecc5dc7SAdrian Knoth if (playback) {
6061da2ea374SMarkus Elfring if (!hdspm->capture_substream)
6062763f356cSTakashi Iwai hdspm_stop_audio(hdspm);
6063763f356cSTakashi Iwai
6064763f356cSTakashi Iwai hdspm->playback_pid = current->pid;
6065763f356cSTakashi Iwai hdspm->playback_substream = substream;
60665ecc5dc7SAdrian Knoth } else {
6067da2ea374SMarkus Elfring if (!hdspm->playback_substream)
60685ecc5dc7SAdrian Knoth hdspm_stop_audio(hdspm);
60695ecc5dc7SAdrian Knoth
60705ecc5dc7SAdrian Knoth hdspm->capture_pid = current->pid;
60715ecc5dc7SAdrian Knoth hdspm->capture_substream = substream;
60725ecc5dc7SAdrian Knoth }
6073763f356cSTakashi Iwai
6074763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
6075763f356cSTakashi Iwai
6076763f356cSTakashi Iwai snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
6077d877681dSTakashi Iwai snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
6078763f356cSTakashi Iwai
60790dca1793SAdrian Knoth switch (hdspm->io_type) {
60800dca1793SAdrian Knoth case AIO:
60810dca1793SAdrian Knoth case RayDAT:
6082d877681dSTakashi Iwai snd_pcm_hw_constraint_minmax(runtime,
6083763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
6084d877681dSTakashi Iwai 32, 4096);
6085d877681dSTakashi Iwai /* RayDAT & AIO have a fixed buffer of 16384 samples per channel */
6086b4ffc1beSLars-Peter Clausen snd_pcm_hw_constraint_single(runtime,
60870dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
6088b4ffc1beSLars-Peter Clausen 16384);
60890dca1793SAdrian Knoth break;
60900dca1793SAdrian Knoth
60910dca1793SAdrian Knoth default:
6092d877681dSTakashi Iwai snd_pcm_hw_constraint_minmax(runtime,
60930dca1793SAdrian Knoth SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
6094d877681dSTakashi Iwai 64, 8192);
6095b4ffc1beSLars-Peter Clausen snd_pcm_hw_constraint_single(runtime,
6096b4ffc1beSLars-Peter Clausen SNDRV_PCM_HW_PARAM_PERIODS, 2);
6097d877681dSTakashi Iwai break;
60980dca1793SAdrian Knoth }
60990dca1793SAdrian Knoth
61000dca1793SAdrian Knoth if (AES32 == hdspm->io_type) {
61013fa9e3d2STakashi Iwai runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
6102ffb2c3c0SRemy Bruno snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
6103ffb2c3c0SRemy Bruno &hdspm_hw_constraints_aes32_sample_rates);
6104ffb2c3c0SRemy Bruno } else {
6105763f356cSTakashi Iwai snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
61065ecc5dc7SAdrian Knoth (playback ?
61075ecc5dc7SAdrian Knoth snd_hdspm_hw_rule_rate_out_channels :
61085ecc5dc7SAdrian Knoth snd_hdspm_hw_rule_rate_in_channels), hdspm,
6109763f356cSTakashi Iwai SNDRV_PCM_HW_PARAM_CHANNELS, -1);
6110ffb2c3c0SRemy Bruno }
611188fabbfcSAdrian Knoth
611288fabbfcSAdrian Knoth snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
61135ecc5dc7SAdrian Knoth (playback ? snd_hdspm_hw_rule_out_channels :
61145ecc5dc7SAdrian Knoth snd_hdspm_hw_rule_in_channels), hdspm,
611588fabbfcSAdrian Knoth SNDRV_PCM_HW_PARAM_CHANNELS, -1);
611688fabbfcSAdrian Knoth
611788fabbfcSAdrian Knoth snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
61185ecc5dc7SAdrian Knoth (playback ? snd_hdspm_hw_rule_out_channels_rate :
61195ecc5dc7SAdrian Knoth snd_hdspm_hw_rule_in_channels_rate), hdspm,
612088fabbfcSAdrian Knoth SNDRV_PCM_HW_PARAM_RATE, -1);
612188fabbfcSAdrian Knoth
6122763f356cSTakashi Iwai return 0;
6123763f356cSTakashi Iwai }
6124763f356cSTakashi Iwai
snd_hdspm_release(struct snd_pcm_substream * substream)61258b73b867SAdrian Knoth static int snd_hdspm_release(struct snd_pcm_substream *substream)
6126763f356cSTakashi Iwai {
612798274f07STakashi Iwai struct hdspm *hdspm = snd_pcm_substream_chip(substream);
61288b73b867SAdrian Knoth bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
6129763f356cSTakashi Iwai
6130763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
6131763f356cSTakashi Iwai
61328b73b867SAdrian Knoth if (playback) {
6133763f356cSTakashi Iwai hdspm->playback_pid = -1;
6134763f356cSTakashi Iwai hdspm->playback_substream = NULL;
61358b73b867SAdrian Knoth } else {
6136763f356cSTakashi Iwai hdspm->capture_pid = -1;
6137763f356cSTakashi Iwai hdspm->capture_substream = NULL;
61388b73b867SAdrian Knoth }
6139763f356cSTakashi Iwai
6140763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
61418b73b867SAdrian Knoth
6142763f356cSTakashi Iwai return 0;
6143763f356cSTakashi Iwai }
6144763f356cSTakashi Iwai
snd_hdspm_hwdep_dummy_op(struct snd_hwdep * hw,struct file * file)61450dca1793SAdrian Knoth static int snd_hdspm_hwdep_dummy_op(struct snd_hwdep *hw, struct file *file)
6146763f356cSTakashi Iwai {
61470dca1793SAdrian Knoth /* we have nothing to initialize but the call is required */
61480dca1793SAdrian Knoth return 0;
61490dca1793SAdrian Knoth }
61500dca1793SAdrian Knoth
snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw,struct file * file,unsigned int cmd,unsigned long arg)61510dca1793SAdrian Knoth static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
61522ca595abSDan Carpenter unsigned int cmd, unsigned long arg)
61530dca1793SAdrian Knoth {
61540dca1793SAdrian Knoth void __user *argp = (void __user *)arg;
6155ef5fa1a4STakashi Iwai struct hdspm *hdspm = hw->private_data;
615698274f07STakashi Iwai struct hdspm_mixer_ioctl mixer;
61570dca1793SAdrian Knoth struct hdspm_config info;
61580dca1793SAdrian Knoth struct hdspm_status status;
615998274f07STakashi Iwai struct hdspm_version hdspm_version;
6160730a5865SJaroslav Kysela struct hdspm_peak_rms *levels;
61610dca1793SAdrian Knoth struct hdspm_ltc ltc;
61620dca1793SAdrian Knoth unsigned int statusregister;
61630dca1793SAdrian Knoth long unsigned int s;
61640dca1793SAdrian Knoth int i = 0;
6165763f356cSTakashi Iwai
6166763f356cSTakashi Iwai switch (cmd) {
6167763f356cSTakashi Iwai
6168763f356cSTakashi Iwai case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS:
6169730a5865SJaroslav Kysela levels = &hdspm->peak_rms;
61700dca1793SAdrian Knoth for (i = 0; i < HDSPM_MAX_CHANNELS; i++) {
6171730a5865SJaroslav Kysela levels->input_peaks[i] =
61720dca1793SAdrian Knoth readl(hdspm->iobase +
61730dca1793SAdrian Knoth HDSPM_MADI_INPUT_PEAK + i*4);
6174730a5865SJaroslav Kysela levels->playback_peaks[i] =
61750dca1793SAdrian Knoth readl(hdspm->iobase +
61760dca1793SAdrian Knoth HDSPM_MADI_PLAYBACK_PEAK + i*4);
6177730a5865SJaroslav Kysela levels->output_peaks[i] =
61780dca1793SAdrian Knoth readl(hdspm->iobase +
61790dca1793SAdrian Knoth HDSPM_MADI_OUTPUT_PEAK + i*4);
61800dca1793SAdrian Knoth
6181730a5865SJaroslav Kysela levels->input_rms[i] =
61820dca1793SAdrian Knoth ((uint64_t) readl(hdspm->iobase +
61830dca1793SAdrian Knoth HDSPM_MADI_INPUT_RMS_H + i*4) << 32) |
61840dca1793SAdrian Knoth (uint64_t) readl(hdspm->iobase +
61850dca1793SAdrian Knoth HDSPM_MADI_INPUT_RMS_L + i*4);
6186730a5865SJaroslav Kysela levels->playback_rms[i] =
61870dca1793SAdrian Knoth ((uint64_t)readl(hdspm->iobase +
61880dca1793SAdrian Knoth HDSPM_MADI_PLAYBACK_RMS_H+i*4) << 32) |
61890dca1793SAdrian Knoth (uint64_t)readl(hdspm->iobase +
61900dca1793SAdrian Knoth HDSPM_MADI_PLAYBACK_RMS_L + i*4);
6191730a5865SJaroslav Kysela levels->output_rms[i] =
61920dca1793SAdrian Knoth ((uint64_t)readl(hdspm->iobase +
61930dca1793SAdrian Knoth HDSPM_MADI_OUTPUT_RMS_H + i*4) << 32) |
61940dca1793SAdrian Knoth (uint64_t)readl(hdspm->iobase +
61950dca1793SAdrian Knoth HDSPM_MADI_OUTPUT_RMS_L + i*4);
61960dca1793SAdrian Knoth }
61970dca1793SAdrian Knoth
61980dca1793SAdrian Knoth if (hdspm->system_sample_rate > 96000) {
6199730a5865SJaroslav Kysela levels->speed = qs;
62000dca1793SAdrian Knoth } else if (hdspm->system_sample_rate > 48000) {
6201730a5865SJaroslav Kysela levels->speed = ds;
62020dca1793SAdrian Knoth } else {
6203730a5865SJaroslav Kysela levels->speed = ss;
62040dca1793SAdrian Knoth }
6205730a5865SJaroslav Kysela levels->status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
62060dca1793SAdrian Knoth
62077dfec507SMarkus Elfring s = copy_to_user(argp, levels, sizeof(*levels));
62080dca1793SAdrian Knoth if (0 != s) {
6209e3a471d6STakashi Iwai /* dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu
62100dca1793SAdrian Knoth [Levels]\n", sizeof(struct hdspm_peak_rms), s);
6211ef5fa1a4STakashi Iwai */
6212763f356cSTakashi Iwai return -EFAULT;
62130dca1793SAdrian Knoth }
62140dca1793SAdrian Knoth break;
62150dca1793SAdrian Knoth
62160dca1793SAdrian Knoth case SNDRV_HDSPM_IOCTL_GET_LTC:
62170dca1793SAdrian Knoth ltc.ltc = hdspm_read(hdspm, HDSPM_RD_TCO);
62180dca1793SAdrian Knoth i = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
62190dca1793SAdrian Knoth if (i & HDSPM_TCO1_LTC_Input_valid) {
62200dca1793SAdrian Knoth switch (i & (HDSPM_TCO1_LTC_Format_LSB |
62210dca1793SAdrian Knoth HDSPM_TCO1_LTC_Format_MSB)) {
62220dca1793SAdrian Knoth case 0:
62230dca1793SAdrian Knoth ltc.format = fps_24;
62240dca1793SAdrian Knoth break;
62250dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_LSB:
62260dca1793SAdrian Knoth ltc.format = fps_25;
62270dca1793SAdrian Knoth break;
62280dca1793SAdrian Knoth case HDSPM_TCO1_LTC_Format_MSB:
62290dca1793SAdrian Knoth ltc.format = fps_2997;
62300dca1793SAdrian Knoth break;
62310dca1793SAdrian Knoth default:
623217d2f008SAdrian Knoth ltc.format = fps_30;
62330dca1793SAdrian Knoth break;
62340dca1793SAdrian Knoth }
62350dca1793SAdrian Knoth if (i & HDSPM_TCO1_set_drop_frame_flag) {
62360dca1793SAdrian Knoth ltc.frame = drop_frame;
62370dca1793SAdrian Knoth } else {
62380dca1793SAdrian Knoth ltc.frame = full_frame;
62390dca1793SAdrian Knoth }
62400dca1793SAdrian Knoth } else {
62410dca1793SAdrian Knoth ltc.format = format_invalid;
62420dca1793SAdrian Knoth ltc.frame = frame_invalid;
62430dca1793SAdrian Knoth }
62440dca1793SAdrian Knoth if (i & HDSPM_TCO1_Video_Input_Format_NTSC) {
62450dca1793SAdrian Knoth ltc.input_format = ntsc;
62460dca1793SAdrian Knoth } else if (i & HDSPM_TCO1_Video_Input_Format_PAL) {
62470dca1793SAdrian Knoth ltc.input_format = pal;
62480dca1793SAdrian Knoth } else {
62490dca1793SAdrian Knoth ltc.input_format = no_video;
62500dca1793SAdrian Knoth }
62510dca1793SAdrian Knoth
62527dfec507SMarkus Elfring s = copy_to_user(argp, <c, sizeof(ltc));
62530dca1793SAdrian Knoth if (0 != s) {
62540dca1793SAdrian Knoth /*
6255e3a471d6STakashi Iwai dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */
62560dca1793SAdrian Knoth return -EFAULT;
62570dca1793SAdrian Knoth }
6258763f356cSTakashi Iwai
6259763f356cSTakashi Iwai break;
6260763f356cSTakashi Iwai
62610dca1793SAdrian Knoth case SNDRV_HDSPM_IOCTL_GET_CONFIG:
6262763f356cSTakashi Iwai
62634ab69a2bSAdrian Knoth memset(&info, 0, sizeof(info));
6264763f356cSTakashi Iwai spin_lock_irq(&hdspm->lock);
6265ef5fa1a4STakashi Iwai info.pref_sync_ref = hdspm_pref_sync_ref(hdspm);
6266ef5fa1a4STakashi Iwai info.wordclock_sync_check = hdspm_wc_sync_check(hdspm);
6267763f356cSTakashi Iwai
6268763f356cSTakashi Iwai info.system_sample_rate = hdspm->system_sample_rate;
6269763f356cSTakashi Iwai info.autosync_sample_rate =
6270763f356cSTakashi Iwai hdspm_external_sample_rate(hdspm);
6271ef5fa1a4STakashi Iwai info.system_clock_mode = hdspm_system_clock_mode(hdspm);
6272ef5fa1a4STakashi Iwai info.clock_source = hdspm_clock_source(hdspm);
6273ef5fa1a4STakashi Iwai info.autosync_ref = hdspm_autosync_ref(hdspm);
6274c9e1668cSAdrian Knoth info.line_out = hdspm_toggle_setting(hdspm, HDSPM_LineOut);
6275763f356cSTakashi Iwai info.passthru = 0;
6276763f356cSTakashi Iwai spin_unlock_irq(&hdspm->lock);
62772ca595abSDan Carpenter if (copy_to_user(argp, &info, sizeof(info)))
6278763f356cSTakashi Iwai return -EFAULT;
6279763f356cSTakashi Iwai break;
6280763f356cSTakashi Iwai
62810dca1793SAdrian Knoth case SNDRV_HDSPM_IOCTL_GET_STATUS:
6282643d6bbbSDan Carpenter memset(&status, 0, sizeof(status));
6283643d6bbbSDan Carpenter
62840dca1793SAdrian Knoth status.card_type = hdspm->io_type;
62850dca1793SAdrian Knoth
62860dca1793SAdrian Knoth status.autosync_source = hdspm_autosync_ref(hdspm);
62870dca1793SAdrian Knoth
62880dca1793SAdrian Knoth status.card_clock = 110069313433624ULL;
62890dca1793SAdrian Knoth status.master_period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
62900dca1793SAdrian Knoth
62910dca1793SAdrian Knoth switch (hdspm->io_type) {
62920dca1793SAdrian Knoth case MADI:
62930dca1793SAdrian Knoth case MADIface:
62940dca1793SAdrian Knoth status.card_specific.madi.sync_wc =
62950dca1793SAdrian Knoth hdspm_wc_sync_check(hdspm);
62960dca1793SAdrian Knoth status.card_specific.madi.sync_madi =
62970dca1793SAdrian Knoth hdspm_madi_sync_check(hdspm);
62980dca1793SAdrian Knoth status.card_specific.madi.sync_tco =
62990dca1793SAdrian Knoth hdspm_tco_sync_check(hdspm);
63000dca1793SAdrian Knoth status.card_specific.madi.sync_in =
63010dca1793SAdrian Knoth hdspm_sync_in_sync_check(hdspm);
63020dca1793SAdrian Knoth
63030dca1793SAdrian Knoth statusregister =
63040dca1793SAdrian Knoth hdspm_read(hdspm, HDSPM_statusRegister);
63050dca1793SAdrian Knoth status.card_specific.madi.madi_input =
63060dca1793SAdrian Knoth (statusregister & HDSPM_AB_int) ? 1 : 0;
63070dca1793SAdrian Knoth status.card_specific.madi.channel_format =
63089e6ff520SAdrian Knoth (statusregister & HDSPM_RX_64ch) ? 1 : 0;
63090dca1793SAdrian Knoth /* TODO: Mac driver sets it when f_s>48kHz */
63100dca1793SAdrian Knoth status.card_specific.madi.frame_format = 0;
6311704cbc4eSGustavo A. R. Silva break;
63120dca1793SAdrian Knoth
63130dca1793SAdrian Knoth default:
63140dca1793SAdrian Knoth break;
63150dca1793SAdrian Knoth }
63160dca1793SAdrian Knoth
63172ca595abSDan Carpenter if (copy_to_user(argp, &status, sizeof(status)))
63180dca1793SAdrian Knoth return -EFAULT;
63190dca1793SAdrian Knoth
63200dca1793SAdrian Knoth
63210dca1793SAdrian Knoth break;
63220dca1793SAdrian Knoth
6323763f356cSTakashi Iwai case SNDRV_HDSPM_IOCTL_GET_VERSION:
6324643d6bbbSDan Carpenter memset(&hdspm_version, 0, sizeof(hdspm_version));
6325643d6bbbSDan Carpenter
63260dca1793SAdrian Knoth hdspm_version.card_type = hdspm->io_type;
632775b1a8f9SJoe Perches strscpy(hdspm_version.cardname, hdspm->card_name,
63280dca1793SAdrian Knoth sizeof(hdspm_version.cardname));
63297d53a631SAdrian Knoth hdspm_version.serial = hdspm->serial;
6330763f356cSTakashi Iwai hdspm_version.firmware_rev = hdspm->firmware_rev;
63310dca1793SAdrian Knoth hdspm_version.addons = 0;
63320dca1793SAdrian Knoth if (hdspm->tco)
63330dca1793SAdrian Knoth hdspm_version.addons |= HDSPM_ADDON_TCO;
63340dca1793SAdrian Knoth
63352ca595abSDan Carpenter if (copy_to_user(argp, &hdspm_version,
6336763f356cSTakashi Iwai sizeof(hdspm_version)))
6337763f356cSTakashi Iwai return -EFAULT;
6338763f356cSTakashi Iwai break;
6339763f356cSTakashi Iwai
6340763f356cSTakashi Iwai case SNDRV_HDSPM_IOCTL_GET_MIXER:
63412ca595abSDan Carpenter if (copy_from_user(&mixer, argp, sizeof(mixer)))
6342763f356cSTakashi Iwai return -EFAULT;
6343ef5fa1a4STakashi Iwai if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer,
63447dfec507SMarkus Elfring sizeof(*mixer.mixer)))
6345763f356cSTakashi Iwai return -EFAULT;
6346763f356cSTakashi Iwai break;
6347763f356cSTakashi Iwai
6348763f356cSTakashi Iwai default:
6349763f356cSTakashi Iwai return -EINVAL;
6350763f356cSTakashi Iwai }
6351763f356cSTakashi Iwai return 0;
6352763f356cSTakashi Iwai }
6353763f356cSTakashi Iwai
63546769e988SJulia Lawall static const struct snd_pcm_ops snd_hdspm_ops = {
63555ecc5dc7SAdrian Knoth .open = snd_hdspm_open,
63568b73b867SAdrian Knoth .close = snd_hdspm_release,
6357763f356cSTakashi Iwai .ioctl = snd_hdspm_ioctl,
6358763f356cSTakashi Iwai .hw_params = snd_hdspm_hw_params,
6359763f356cSTakashi Iwai .hw_free = snd_hdspm_hw_free,
6360763f356cSTakashi Iwai .prepare = snd_hdspm_prepare,
6361763f356cSTakashi Iwai .trigger = snd_hdspm_trigger,
6362763f356cSTakashi Iwai .pointer = snd_hdspm_hw_pointer,
6363763f356cSTakashi Iwai };
6364763f356cSTakashi Iwai
snd_hdspm_create_hwdep(struct snd_card * card,struct hdspm * hdspm)6365e23e7a14SBill Pemberton static int snd_hdspm_create_hwdep(struct snd_card *card,
636698274f07STakashi Iwai struct hdspm *hdspm)
6367763f356cSTakashi Iwai {
636898274f07STakashi Iwai struct snd_hwdep *hw;
6369763f356cSTakashi Iwai int err;
6370763f356cSTakashi Iwai
6371ef5fa1a4STakashi Iwai err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw);
6372ef5fa1a4STakashi Iwai if (err < 0)
6373763f356cSTakashi Iwai return err;
6374763f356cSTakashi Iwai
6375763f356cSTakashi Iwai hdspm->hwdep = hw;
6376763f356cSTakashi Iwai hw->private_data = hdspm;
6377763f356cSTakashi Iwai strcpy(hw->name, "HDSPM hwdep interface");
6378763f356cSTakashi Iwai
63790dca1793SAdrian Knoth hw->ops.open = snd_hdspm_hwdep_dummy_op;
6380763f356cSTakashi Iwai hw->ops.ioctl = snd_hdspm_hwdep_ioctl;
63818de5d6f1SAdrian Knoth hw->ops.ioctl_compat = snd_hdspm_hwdep_ioctl;
63820dca1793SAdrian Knoth hw->ops.release = snd_hdspm_hwdep_dummy_op;
6383763f356cSTakashi Iwai
6384763f356cSTakashi Iwai return 0;
6385763f356cSTakashi Iwai }
6386763f356cSTakashi Iwai
6387763f356cSTakashi Iwai
6388763f356cSTakashi Iwai /*------------------------------------------------------------
6389763f356cSTakashi Iwai memory interface
6390763f356cSTakashi Iwai ------------------------------------------------------------*/
snd_hdspm_preallocate_memory(struct hdspm * hdspm)6391e23e7a14SBill Pemberton static int snd_hdspm_preallocate_memory(struct hdspm *hdspm)
6392763f356cSTakashi Iwai {
639398274f07STakashi Iwai struct snd_pcm *pcm;
6394763f356cSTakashi Iwai size_t wanted;
6395763f356cSTakashi Iwai
6396763f356cSTakashi Iwai pcm = hdspm->pcm;
6397763f356cSTakashi Iwai
63983cee5a60SRemy Bruno wanted = HDSPM_DMA_AREA_BYTES;
6399763f356cSTakashi Iwai
64005116b94aSTakashi Iwai snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
64011a810436STakashi Iwai &hdspm->pci->dev,
64025116b94aSTakashi Iwai wanted, wanted);
64035116b94aSTakashi Iwai dev_dbg(hdspm->card->dev, " Preallocated %zd Bytes\n", wanted);
6404763f356cSTakashi Iwai return 0;
6405763f356cSTakashi Iwai }
6406763f356cSTakashi Iwai
6407e4e07c6cSPhilippe Bekaert /* Inform the card what DMA addresses to use for the indicated channel. */
6408e4e07c6cSPhilippe Bekaert /* 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)6409e4e07c6cSPhilippe Bekaert static void hdspm_set_channel_dma_addr(struct hdspm *hdspm,
641077a23f26STakashi Iwai struct snd_pcm_substream *substream,
6411e4e07c6cSPhilippe Bekaert unsigned int reg, int channel)
6412763f356cSTakashi Iwai {
6413763f356cSTakashi Iwai int i;
64140dca1793SAdrian Knoth
6415e4e07c6cSPhilippe Bekaert for (i = channel * 16; i < channel * 16 + 16; i++)
6416763f356cSTakashi Iwai hdspm_write(hdspm, reg + 4 * i,
641777a23f26STakashi Iwai snd_pcm_sgbuf_get_addr(substream, 4096 * i));
6418763f356cSTakashi Iwai }
6419763f356cSTakashi Iwai
64200dca1793SAdrian Knoth
6421763f356cSTakashi Iwai /* ------------- ALSA Devices ---------------------------- */
snd_hdspm_create_pcm(struct snd_card * card,struct hdspm * hdspm)6422e23e7a14SBill Pemberton static int snd_hdspm_create_pcm(struct snd_card *card,
642398274f07STakashi Iwai struct hdspm *hdspm)
6424763f356cSTakashi Iwai {
642598274f07STakashi Iwai struct snd_pcm *pcm;
6426763f356cSTakashi Iwai int err;
6427763f356cSTakashi Iwai
6428ef5fa1a4STakashi Iwai err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm);
6429ef5fa1a4STakashi Iwai if (err < 0)
6430763f356cSTakashi Iwai return err;
6431763f356cSTakashi Iwai
6432763f356cSTakashi Iwai hdspm->pcm = pcm;
6433763f356cSTakashi Iwai pcm->private_data = hdspm;
6434763f356cSTakashi Iwai strcpy(pcm->name, hdspm->card_name);
6435763f356cSTakashi Iwai
6436763f356cSTakashi Iwai snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
64370c8d9485SAdrian Knoth &snd_hdspm_ops);
6438763f356cSTakashi Iwai snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
64390c8d9485SAdrian Knoth &snd_hdspm_ops);
6440763f356cSTakashi Iwai
6441763f356cSTakashi Iwai pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
6442763f356cSTakashi Iwai
6443ef5fa1a4STakashi Iwai err = snd_hdspm_preallocate_memory(hdspm);
6444ef5fa1a4STakashi Iwai if (err < 0)
6445763f356cSTakashi Iwai return err;
6446763f356cSTakashi Iwai
6447763f356cSTakashi Iwai return 0;
6448763f356cSTakashi Iwai }
6449763f356cSTakashi Iwai
snd_hdspm_initialize_midi_flush(struct hdspm * hdspm)645098274f07STakashi Iwai static inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm)
6451763f356cSTakashi Iwai {
64527c7102b7SAdrian Knoth int i;
64537c7102b7SAdrian Knoth
64547c7102b7SAdrian Knoth for (i = 0; i < hdspm->midiPorts; i++)
64557c7102b7SAdrian Knoth snd_hdspm_flush_midi_input(hdspm, i);
6456763f356cSTakashi Iwai }
6457763f356cSTakashi Iwai
snd_hdspm_create_alsa_devices(struct snd_card * card,struct hdspm * hdspm)6458e23e7a14SBill Pemberton static int snd_hdspm_create_alsa_devices(struct snd_card *card,
645998274f07STakashi Iwai struct hdspm *hdspm)
6460763f356cSTakashi Iwai {
64610dca1793SAdrian Knoth int err, i;
6462763f356cSTakashi Iwai
6463e3a471d6STakashi Iwai dev_dbg(card->dev, "Create card...\n");
6464ef5fa1a4STakashi Iwai err = snd_hdspm_create_pcm(card, hdspm);
6465ef5fa1a4STakashi Iwai if (err < 0)
6466763f356cSTakashi Iwai return err;
6467763f356cSTakashi Iwai
64680dca1793SAdrian Knoth i = 0;
64690dca1793SAdrian Knoth while (i < hdspm->midiPorts) {
64700dca1793SAdrian Knoth err = snd_hdspm_create_midi(card, hdspm, i);
64710dca1793SAdrian Knoth if (err < 0) {
6472763f356cSTakashi Iwai return err;
64730dca1793SAdrian Knoth }
64740dca1793SAdrian Knoth i++;
64750dca1793SAdrian Knoth }
6476763f356cSTakashi Iwai
6477ef5fa1a4STakashi Iwai err = snd_hdspm_create_controls(card, hdspm);
6478ef5fa1a4STakashi Iwai if (err < 0)
6479763f356cSTakashi Iwai return err;
6480763f356cSTakashi Iwai
6481ef5fa1a4STakashi Iwai err = snd_hdspm_create_hwdep(card, hdspm);
6482ef5fa1a4STakashi Iwai if (err < 0)
6483763f356cSTakashi Iwai return err;
6484763f356cSTakashi Iwai
6485e3a471d6STakashi Iwai dev_dbg(card->dev, "proc init...\n");
6486763f356cSTakashi Iwai snd_hdspm_proc_init(hdspm);
6487763f356cSTakashi Iwai
6488763f356cSTakashi Iwai hdspm->system_sample_rate = -1;
6489763f356cSTakashi Iwai hdspm->last_external_sample_rate = -1;
6490763f356cSTakashi Iwai hdspm->last_internal_sample_rate = -1;
6491763f356cSTakashi Iwai hdspm->playback_pid = -1;
6492763f356cSTakashi Iwai hdspm->capture_pid = -1;
6493763f356cSTakashi Iwai hdspm->capture_substream = NULL;
6494763f356cSTakashi Iwai hdspm->playback_substream = NULL;
6495763f356cSTakashi Iwai
6496e3a471d6STakashi Iwai dev_dbg(card->dev, "Set defaults...\n");
6497ef5fa1a4STakashi Iwai err = snd_hdspm_set_defaults(hdspm);
6498ef5fa1a4STakashi Iwai if (err < 0)
6499763f356cSTakashi Iwai return err;
6500763f356cSTakashi Iwai
6501e3a471d6STakashi Iwai dev_dbg(card->dev, "Update mixer controls...\n");
6502763f356cSTakashi Iwai hdspm_update_simple_mixer_controls(hdspm);
6503763f356cSTakashi Iwai
65041bb6d9e2SColin Ian King dev_dbg(card->dev, "Initializing complete?\n");
6505763f356cSTakashi Iwai
6506ef5fa1a4STakashi Iwai err = snd_card_register(card);
6507ef5fa1a4STakashi Iwai if (err < 0) {
6508e3a471d6STakashi Iwai dev_err(card->dev, "error registering card\n");
6509763f356cSTakashi Iwai return err;
6510763f356cSTakashi Iwai }
6511763f356cSTakashi Iwai
6512e3a471d6STakashi Iwai dev_dbg(card->dev, "... yes now\n");
6513763f356cSTakashi Iwai
6514763f356cSTakashi Iwai return 0;
6515763f356cSTakashi Iwai }
6516763f356cSTakashi Iwai
snd_hdspm_create(struct snd_card * card,struct hdspm * hdspm)6517e23e7a14SBill Pemberton static int snd_hdspm_create(struct snd_card *card,
6518e23e7a14SBill Pemberton struct hdspm *hdspm)
6519e23e7a14SBill Pemberton {
65200dca1793SAdrian Knoth
6521763f356cSTakashi Iwai struct pci_dev *pci = hdspm->pci;
6522763f356cSTakashi Iwai int err;
6523763f356cSTakashi Iwai unsigned long io_extent;
6524763f356cSTakashi Iwai
6525763f356cSTakashi Iwai hdspm->irq = -1;
6526763f356cSTakashi Iwai hdspm->card = card;
6527763f356cSTakashi Iwai
6528763f356cSTakashi Iwai spin_lock_init(&hdspm->lock);
6529a2e527c5STakashi Iwai INIT_WORK(&hdspm->midi_work, hdspm_midi_work);
6530763f356cSTakashi Iwai
6531763f356cSTakashi Iwai pci_read_config_word(hdspm->pci,
6532763f356cSTakashi Iwai PCI_CLASS_REVISION, &hdspm->firmware_rev);
6533763f356cSTakashi Iwai
6534763f356cSTakashi Iwai strcpy(card->mixername, "Xilinx FPGA");
65353cee5a60SRemy Bruno strcpy(card->driver, "HDSPM");
65360dca1793SAdrian Knoth
65370dca1793SAdrian Knoth switch (hdspm->firmware_rev) {
65380dca1793SAdrian Knoth case HDSPM_RAYDAT_REV:
65390dca1793SAdrian Knoth hdspm->io_type = RayDAT;
65400dca1793SAdrian Knoth hdspm->card_name = "RME RayDAT";
65410dca1793SAdrian Knoth hdspm->midiPorts = 2;
65420dca1793SAdrian Knoth break;
65430dca1793SAdrian Knoth case HDSPM_AIO_REV:
65440dca1793SAdrian Knoth hdspm->io_type = AIO;
65450dca1793SAdrian Knoth hdspm->card_name = "RME AIO";
65460dca1793SAdrian Knoth hdspm->midiPorts = 1;
65470dca1793SAdrian Knoth break;
65480dca1793SAdrian Knoth case HDSPM_MADIFACE_REV:
65490dca1793SAdrian Knoth hdspm->io_type = MADIface;
65500dca1793SAdrian Knoth hdspm->card_name = "RME MADIface";
65510dca1793SAdrian Knoth hdspm->midiPorts = 1;
65520dca1793SAdrian Knoth break;
6553c09403dcSAdrian Knoth default:
6554c09403dcSAdrian Knoth if ((hdspm->firmware_rev == 0xf0) ||
6555c09403dcSAdrian Knoth ((hdspm->firmware_rev >= 0xe6) &&
6556c09403dcSAdrian Knoth (hdspm->firmware_rev <= 0xea))) {
65570dca1793SAdrian Knoth hdspm->io_type = AES32;
65580dca1793SAdrian Knoth hdspm->card_name = "RME AES32";
65590dca1793SAdrian Knoth hdspm->midiPorts = 2;
656005c7cc9cSAdrian Knoth } else if ((hdspm->firmware_rev == 0xd2) ||
6561c09403dcSAdrian Knoth ((hdspm->firmware_rev >= 0xc8) &&
6562c09403dcSAdrian Knoth (hdspm->firmware_rev <= 0xcf))) {
6563c09403dcSAdrian Knoth hdspm->io_type = MADI;
6564c09403dcSAdrian Knoth hdspm->card_name = "RME MADI";
6565c09403dcSAdrian Knoth hdspm->midiPorts = 3;
6566c09403dcSAdrian Knoth } else {
6567e3a471d6STakashi Iwai dev_err(card->dev,
6568e3a471d6STakashi Iwai "unknown firmware revision %x\n",
65695027f347SAdrian Knoth hdspm->firmware_rev);
65705027f347SAdrian Knoth return -ENODEV;
65713cee5a60SRemy Bruno }
6572c09403dcSAdrian Knoth }
6573763f356cSTakashi Iwai
65740195ca5fSTakashi Iwai err = pcim_enable_device(pci);
6575ef5fa1a4STakashi Iwai if (err < 0)
6576763f356cSTakashi Iwai return err;
6577763f356cSTakashi Iwai
6578763f356cSTakashi Iwai pci_set_master(hdspm->pci);
6579763f356cSTakashi Iwai
65800195ca5fSTakashi Iwai err = pcim_iomap_regions(pci, 1 << 0, "hdspm");
6581ef5fa1a4STakashi Iwai if (err < 0)
6582763f356cSTakashi Iwai return err;
6583763f356cSTakashi Iwai
6584763f356cSTakashi Iwai hdspm->port = pci_resource_start(pci, 0);
6585763f356cSTakashi Iwai io_extent = pci_resource_len(pci, 0);
65860195ca5fSTakashi Iwai hdspm->iobase = pcim_iomap_table(pci)[0];
6587e3a471d6STakashi Iwai dev_dbg(card->dev, "remapped region (0x%lx) 0x%lx-0x%lx\n",
6588763f356cSTakashi Iwai (unsigned long)hdspm->iobase, hdspm->port,
6589763f356cSTakashi Iwai hdspm->port + io_extent - 1);
6590763f356cSTakashi Iwai
65910195ca5fSTakashi Iwai if (devm_request_irq(&pci->dev, pci->irq, snd_hdspm_interrupt,
6592934c2b6dSTakashi Iwai IRQF_SHARED, KBUILD_MODNAME, hdspm)) {
6593e3a471d6STakashi Iwai dev_err(card->dev, "unable to use IRQ %d\n", pci->irq);
6594763f356cSTakashi Iwai return -EBUSY;
6595763f356cSTakashi Iwai }
6596763f356cSTakashi Iwai
6597e3a471d6STakashi Iwai dev_dbg(card->dev, "use IRQ %d\n", pci->irq);
6598763f356cSTakashi Iwai
6599763f356cSTakashi Iwai hdspm->irq = pci->irq;
660039cccf45STakashi Iwai card->sync_irq = hdspm->irq;
6601763f356cSTakashi Iwai
6602e3a471d6STakashi Iwai dev_dbg(card->dev, "kmalloc Mixer memory of %zd Bytes\n",
66037dfec507SMarkus Elfring sizeof(*hdspm->mixer));
66040195ca5fSTakashi Iwai hdspm->mixer = devm_kzalloc(&pci->dev, sizeof(*hdspm->mixer), GFP_KERNEL);
66059dba5429SMarkus Elfring if (!hdspm->mixer)
6606b17cbdd8SJulia Lawall return -ENOMEM;
6607763f356cSTakashi Iwai
66080dca1793SAdrian Knoth hdspm->port_names_in = NULL;
66090dca1793SAdrian Knoth hdspm->port_names_out = NULL;
66100dca1793SAdrian Knoth
66110dca1793SAdrian Knoth switch (hdspm->io_type) {
66120dca1793SAdrian Knoth case AES32:
6613d2d10a21SAdrian Knoth hdspm->ss_in_channels = hdspm->ss_out_channels = AES32_CHANNELS;
6614d2d10a21SAdrian Knoth hdspm->ds_in_channels = hdspm->ds_out_channels = AES32_CHANNELS;
6615d2d10a21SAdrian Knoth hdspm->qs_in_channels = hdspm->qs_out_channels = AES32_CHANNELS;
6616432d2500SAdrian Knoth
6617432d2500SAdrian Knoth hdspm->channel_map_in_ss = hdspm->channel_map_out_ss =
6618432d2500SAdrian Knoth channel_map_aes32;
6619432d2500SAdrian Knoth hdspm->channel_map_in_ds = hdspm->channel_map_out_ds =
6620432d2500SAdrian Knoth channel_map_aes32;
6621432d2500SAdrian Knoth hdspm->channel_map_in_qs = hdspm->channel_map_out_qs =
6622432d2500SAdrian Knoth channel_map_aes32;
6623432d2500SAdrian Knoth hdspm->port_names_in_ss = hdspm->port_names_out_ss =
6624432d2500SAdrian Knoth texts_ports_aes32;
6625432d2500SAdrian Knoth hdspm->port_names_in_ds = hdspm->port_names_out_ds =
6626432d2500SAdrian Knoth texts_ports_aes32;
6627432d2500SAdrian Knoth hdspm->port_names_in_qs = hdspm->port_names_out_qs =
6628432d2500SAdrian Knoth texts_ports_aes32;
6629432d2500SAdrian Knoth
6630d2d10a21SAdrian Knoth hdspm->max_channels_out = hdspm->max_channels_in =
6631d2d10a21SAdrian Knoth AES32_CHANNELS;
6632432d2500SAdrian Knoth hdspm->port_names_in = hdspm->port_names_out =
6633432d2500SAdrian Knoth texts_ports_aes32;
6634432d2500SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_out =
6635432d2500SAdrian Knoth channel_map_aes32;
6636432d2500SAdrian Knoth
66370dca1793SAdrian Knoth break;
66380dca1793SAdrian Knoth
66390dca1793SAdrian Knoth case MADI:
66400dca1793SAdrian Knoth case MADIface:
66410dca1793SAdrian Knoth hdspm->ss_in_channels = hdspm->ss_out_channels =
66420dca1793SAdrian Knoth MADI_SS_CHANNELS;
66430dca1793SAdrian Knoth hdspm->ds_in_channels = hdspm->ds_out_channels =
66440dca1793SAdrian Knoth MADI_DS_CHANNELS;
66450dca1793SAdrian Knoth hdspm->qs_in_channels = hdspm->qs_out_channels =
66460dca1793SAdrian Knoth MADI_QS_CHANNELS;
66470dca1793SAdrian Knoth
66480dca1793SAdrian Knoth hdspm->channel_map_in_ss = hdspm->channel_map_out_ss =
66490dca1793SAdrian Knoth channel_map_unity_ss;
665001e96078SAdrian Knoth hdspm->channel_map_in_ds = hdspm->channel_map_out_ds =
66510dca1793SAdrian Knoth channel_map_unity_ss;
665201e96078SAdrian Knoth hdspm->channel_map_in_qs = hdspm->channel_map_out_qs =
66530dca1793SAdrian Knoth channel_map_unity_ss;
66540dca1793SAdrian Knoth
66550dca1793SAdrian Knoth hdspm->port_names_in_ss = hdspm->port_names_out_ss =
66560dca1793SAdrian Knoth texts_ports_madi;
66570dca1793SAdrian Knoth hdspm->port_names_in_ds = hdspm->port_names_out_ds =
66580dca1793SAdrian Knoth texts_ports_madi;
66590dca1793SAdrian Knoth hdspm->port_names_in_qs = hdspm->port_names_out_qs =
66600dca1793SAdrian Knoth texts_ports_madi;
66610dca1793SAdrian Knoth break;
66620dca1793SAdrian Knoth
66630dca1793SAdrian Knoth case AIO:
66640dca1793SAdrian Knoth hdspm->ss_in_channels = AIO_IN_SS_CHANNELS;
66650dca1793SAdrian Knoth hdspm->ds_in_channels = AIO_IN_DS_CHANNELS;
66660dca1793SAdrian Knoth hdspm->qs_in_channels = AIO_IN_QS_CHANNELS;
66670dca1793SAdrian Knoth hdspm->ss_out_channels = AIO_OUT_SS_CHANNELS;
66680dca1793SAdrian Knoth hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS;
66690dca1793SAdrian Knoth hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS;
66700dca1793SAdrian Knoth
66713de9db26SAdrian Knoth if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) {
6672e3a471d6STakashi Iwai dev_info(card->dev, "AEB input board found\n");
66733de9db26SAdrian Knoth hdspm->ss_in_channels += 4;
66743de9db26SAdrian Knoth hdspm->ds_in_channels += 4;
66753de9db26SAdrian Knoth hdspm->qs_in_channels += 4;
66763de9db26SAdrian Knoth }
66773de9db26SAdrian Knoth
66783de9db26SAdrian Knoth if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) {
6679e3a471d6STakashi Iwai dev_info(card->dev, "AEB output board found\n");
66803de9db26SAdrian Knoth hdspm->ss_out_channels += 4;
66813de9db26SAdrian Knoth hdspm->ds_out_channels += 4;
66823de9db26SAdrian Knoth hdspm->qs_out_channels += 4;
66833de9db26SAdrian Knoth }
66843de9db26SAdrian Knoth
66850dca1793SAdrian Knoth hdspm->channel_map_out_ss = channel_map_aio_out_ss;
66860dca1793SAdrian Knoth hdspm->channel_map_out_ds = channel_map_aio_out_ds;
66870dca1793SAdrian Knoth hdspm->channel_map_out_qs = channel_map_aio_out_qs;
66880dca1793SAdrian Knoth
66890dca1793SAdrian Knoth hdspm->channel_map_in_ss = channel_map_aio_in_ss;
66900dca1793SAdrian Knoth hdspm->channel_map_in_ds = channel_map_aio_in_ds;
66910dca1793SAdrian Knoth hdspm->channel_map_in_qs = channel_map_aio_in_qs;
66920dca1793SAdrian Knoth
66930dca1793SAdrian Knoth hdspm->port_names_in_ss = texts_ports_aio_in_ss;
66940dca1793SAdrian Knoth hdspm->port_names_out_ss = texts_ports_aio_out_ss;
66950dca1793SAdrian Knoth hdspm->port_names_in_ds = texts_ports_aio_in_ds;
66960dca1793SAdrian Knoth hdspm->port_names_out_ds = texts_ports_aio_out_ds;
66970dca1793SAdrian Knoth hdspm->port_names_in_qs = texts_ports_aio_in_qs;
66980dca1793SAdrian Knoth hdspm->port_names_out_qs = texts_ports_aio_out_qs;
66990dca1793SAdrian Knoth
67000dca1793SAdrian Knoth break;
67010dca1793SAdrian Knoth
67020dca1793SAdrian Knoth case RayDAT:
67030dca1793SAdrian Knoth hdspm->ss_in_channels = hdspm->ss_out_channels =
67040dca1793SAdrian Knoth RAYDAT_SS_CHANNELS;
67050dca1793SAdrian Knoth hdspm->ds_in_channels = hdspm->ds_out_channels =
67060dca1793SAdrian Knoth RAYDAT_DS_CHANNELS;
67070dca1793SAdrian Knoth hdspm->qs_in_channels = hdspm->qs_out_channels =
67080dca1793SAdrian Knoth RAYDAT_QS_CHANNELS;
67090dca1793SAdrian Knoth
67100dca1793SAdrian Knoth hdspm->max_channels_in = RAYDAT_SS_CHANNELS;
67110dca1793SAdrian Knoth hdspm->max_channels_out = RAYDAT_SS_CHANNELS;
67120dca1793SAdrian Knoth
67130dca1793SAdrian Knoth hdspm->channel_map_in_ss = hdspm->channel_map_out_ss =
67140dca1793SAdrian Knoth channel_map_raydat_ss;
67150dca1793SAdrian Knoth hdspm->channel_map_in_ds = hdspm->channel_map_out_ds =
67160dca1793SAdrian Knoth channel_map_raydat_ds;
67170dca1793SAdrian Knoth hdspm->channel_map_in_qs = hdspm->channel_map_out_qs =
67180dca1793SAdrian Knoth channel_map_raydat_qs;
67190dca1793SAdrian Knoth hdspm->channel_map_in = hdspm->channel_map_out =
67200dca1793SAdrian Knoth channel_map_raydat_ss;
67210dca1793SAdrian Knoth
67220dca1793SAdrian Knoth hdspm->port_names_in_ss = hdspm->port_names_out_ss =
67230dca1793SAdrian Knoth texts_ports_raydat_ss;
67240dca1793SAdrian Knoth hdspm->port_names_in_ds = hdspm->port_names_out_ds =
67250dca1793SAdrian Knoth texts_ports_raydat_ds;
67260dca1793SAdrian Knoth hdspm->port_names_in_qs = hdspm->port_names_out_qs =
67270dca1793SAdrian Knoth texts_ports_raydat_qs;
67280dca1793SAdrian Knoth
67290dca1793SAdrian Knoth
67300dca1793SAdrian Knoth break;
67310dca1793SAdrian Knoth
67320dca1793SAdrian Knoth }
67330dca1793SAdrian Knoth
67340dca1793SAdrian Knoth /* TCO detection */
67350dca1793SAdrian Knoth switch (hdspm->io_type) {
67360dca1793SAdrian Knoth case AIO:
67370dca1793SAdrian Knoth case RayDAT:
67380dca1793SAdrian Knoth if (hdspm_read(hdspm, HDSPM_statusRegister2) &
67390dca1793SAdrian Knoth HDSPM_s2_tco_detect) {
67400dca1793SAdrian Knoth hdspm->midiPorts++;
67417dfec507SMarkus Elfring hdspm->tco = kzalloc(sizeof(*hdspm->tco), GFP_KERNEL);
6742da2ea374SMarkus Elfring if (hdspm->tco)
67430dca1793SAdrian Knoth hdspm_tco_write(hdspm);
6744da2ea374SMarkus Elfring
6745e3a471d6STakashi Iwai dev_info(card->dev, "AIO/RayDAT TCO module found\n");
67460dca1793SAdrian Knoth } else {
67470dca1793SAdrian Knoth hdspm->tco = NULL;
67480dca1793SAdrian Knoth }
67490dca1793SAdrian Knoth break;
67500dca1793SAdrian Knoth
67510dca1793SAdrian Knoth case MADI:
67520dc831b9SAdrian Knoth case AES32:
67530dca1793SAdrian Knoth if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) {
67540dca1793SAdrian Knoth hdspm->midiPorts++;
67557dfec507SMarkus Elfring hdspm->tco = kzalloc(sizeof(*hdspm->tco), GFP_KERNEL);
6756da2ea374SMarkus Elfring if (hdspm->tco)
67570dca1793SAdrian Knoth hdspm_tco_write(hdspm);
6758da2ea374SMarkus Elfring
6759e3a471d6STakashi Iwai dev_info(card->dev, "MADI/AES TCO module found\n");
67600dca1793SAdrian Knoth } else {
67610dca1793SAdrian Knoth hdspm->tco = NULL;
67620dca1793SAdrian Knoth }
67630dca1793SAdrian Knoth break;
67640dca1793SAdrian Knoth
67650dca1793SAdrian Knoth default:
67660dca1793SAdrian Knoth hdspm->tco = NULL;
67670dca1793SAdrian Knoth }
67680dca1793SAdrian Knoth
67690dca1793SAdrian Knoth /* texts */
67700dca1793SAdrian Knoth switch (hdspm->io_type) {
67710dca1793SAdrian Knoth case AES32:
67720dca1793SAdrian Knoth if (hdspm->tco) {
67730dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aes_tco;
6774e71b95adSAdrian Knoth hdspm->texts_autosync_items =
6775e71b95adSAdrian Knoth ARRAY_SIZE(texts_autosync_aes_tco);
67760dca1793SAdrian Knoth } else {
67770dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aes;
6778e71b95adSAdrian Knoth hdspm->texts_autosync_items =
6779e71b95adSAdrian Knoth ARRAY_SIZE(texts_autosync_aes);
67800dca1793SAdrian Knoth }
67810dca1793SAdrian Knoth break;
67820dca1793SAdrian Knoth
67830dca1793SAdrian Knoth case MADI:
67840dca1793SAdrian Knoth if (hdspm->tco) {
67850dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_madi_tco;
67860dca1793SAdrian Knoth hdspm->texts_autosync_items = 4;
67870dca1793SAdrian Knoth } else {
67880dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_madi;
67890dca1793SAdrian Knoth hdspm->texts_autosync_items = 3;
67900dca1793SAdrian Knoth }
67910dca1793SAdrian Knoth break;
67920dca1793SAdrian Knoth
67930dca1793SAdrian Knoth case MADIface:
67940dca1793SAdrian Knoth
67950dca1793SAdrian Knoth break;
67960dca1793SAdrian Knoth
67970dca1793SAdrian Knoth case RayDAT:
67980dca1793SAdrian Knoth if (hdspm->tco) {
67990dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_raydat_tco;
68000dca1793SAdrian Knoth hdspm->texts_autosync_items = 9;
68010dca1793SAdrian Knoth } else {
68020dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_raydat;
68030dca1793SAdrian Knoth hdspm->texts_autosync_items = 8;
68040dca1793SAdrian Knoth }
68050dca1793SAdrian Knoth break;
68060dca1793SAdrian Knoth
68070dca1793SAdrian Knoth case AIO:
68080dca1793SAdrian Knoth if (hdspm->tco) {
68090dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aio_tco;
68100dca1793SAdrian Knoth hdspm->texts_autosync_items = 6;
68110dca1793SAdrian Knoth } else {
68120dca1793SAdrian Knoth hdspm->texts_autosync = texts_autosync_aio;
68130dca1793SAdrian Knoth hdspm->texts_autosync_items = 5;
68140dca1793SAdrian Knoth }
68150dca1793SAdrian Knoth break;
68160dca1793SAdrian Knoth
68170dca1793SAdrian Knoth }
68180dca1793SAdrian Knoth
6819f7de8ba3SAdrian Knoth if (hdspm->io_type != MADIface) {
6820f7de8ba3SAdrian Knoth hdspm->serial = (hdspm_read(hdspm,
6821f7de8ba3SAdrian Knoth HDSPM_midiStatusIn0)>>8) & 0xFFFFFF;
6822f7de8ba3SAdrian Knoth /* id contains either a user-provided value or the default
6823f7de8ba3SAdrian Knoth * NULL. If it's the default, we're safe to
6824f7de8ba3SAdrian Knoth * fill card->id with the serial number.
6825f7de8ba3SAdrian Knoth *
6826f7de8ba3SAdrian Knoth * If the serial number is 0xFFFFFF, then we're dealing with
6827f7de8ba3SAdrian Knoth * an old PCI revision that comes without a sane number. In
6828f7de8ba3SAdrian Knoth * this case, we don't set card->id to avoid collisions
6829f7de8ba3SAdrian Knoth * when running with multiple cards.
6830f7de8ba3SAdrian Knoth */
6831da2ea374SMarkus Elfring if (!id[hdspm->dev] && hdspm->serial != 0xFFFFFF) {
68327ad210acSArnd Bergmann snprintf(card->id, sizeof(card->id),
68337ad210acSArnd Bergmann "HDSPMx%06x", hdspm->serial);
6834f7de8ba3SAdrian Knoth snd_card_set_id(card, card->id);
6835f7de8ba3SAdrian Knoth }
6836f7de8ba3SAdrian Knoth }
6837f7de8ba3SAdrian Knoth
6838e3a471d6STakashi Iwai dev_dbg(card->dev, "create alsa devices.\n");
6839ef5fa1a4STakashi Iwai err = snd_hdspm_create_alsa_devices(card, hdspm);
6840ef5fa1a4STakashi Iwai if (err < 0)
6841763f356cSTakashi Iwai return err;
6842763f356cSTakashi Iwai
6843763f356cSTakashi Iwai snd_hdspm_initialize_midi_flush(hdspm);
6844763f356cSTakashi Iwai
6845763f356cSTakashi Iwai return 0;
6846763f356cSTakashi Iwai }
6847763f356cSTakashi Iwai
68480dca1793SAdrian Knoth
snd_hdspm_card_free(struct snd_card * card)68490195ca5fSTakashi Iwai static void snd_hdspm_card_free(struct snd_card *card)
6850763f356cSTakashi Iwai {
68510195ca5fSTakashi Iwai struct hdspm *hdspm = card->private_data;
6852763f356cSTakashi Iwai
6853763f356cSTakashi Iwai if (hdspm->port) {
6854a2e527c5STakashi Iwai cancel_work_sync(&hdspm->midi_work);
6855763f356cSTakashi Iwai
6856763f356cSTakashi Iwai /* stop th audio, and cancel all interrupts */
6857763f356cSTakashi Iwai hdspm->control_register &=
6858ef5fa1a4STakashi Iwai ~(HDSPM_Start | HDSPM_AudioInterruptEnable |
68590dca1793SAdrian Knoth HDSPM_Midi0InterruptEnable | HDSPM_Midi1InterruptEnable |
68600dca1793SAdrian Knoth HDSPM_Midi2InterruptEnable | HDSPM_Midi3InterruptEnable);
6861763f356cSTakashi Iwai hdspm_write(hdspm, HDSPM_controlRegister,
6862763f356cSTakashi Iwai hdspm->control_register);
6863763f356cSTakashi Iwai }
6864763f356cSTakashi Iwai }
6865763f356cSTakashi Iwai
68660dca1793SAdrian Knoth
snd_hdspm_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)6867e23e7a14SBill Pemberton static int snd_hdspm_probe(struct pci_dev *pci,
6868763f356cSTakashi Iwai const struct pci_device_id *pci_id)
6869763f356cSTakashi Iwai {
6870763f356cSTakashi Iwai static int dev;
687198274f07STakashi Iwai struct hdspm *hdspm;
687298274f07STakashi Iwai struct snd_card *card;
6873763f356cSTakashi Iwai int err;
6874763f356cSTakashi Iwai
6875763f356cSTakashi Iwai if (dev >= SNDRV_CARDS)
6876763f356cSTakashi Iwai return -ENODEV;
6877763f356cSTakashi Iwai if (!enable[dev]) {
6878763f356cSTakashi Iwai dev++;
6879763f356cSTakashi Iwai return -ENOENT;
6880763f356cSTakashi Iwai }
6881763f356cSTakashi Iwai
68820195ca5fSTakashi Iwai err = snd_devm_card_new(&pci->dev, index[dev], id[dev],
68837dfec507SMarkus Elfring THIS_MODULE, sizeof(*hdspm), &card);
6884e58de7baSTakashi Iwai if (err < 0)
6885e58de7baSTakashi Iwai return err;
6886763f356cSTakashi Iwai
6887ef5fa1a4STakashi Iwai hdspm = card->private_data;
6888763f356cSTakashi Iwai card->private_free = snd_hdspm_card_free;
6889763f356cSTakashi Iwai hdspm->dev = dev;
6890763f356cSTakashi Iwai hdspm->pci = pci;
6891763f356cSTakashi Iwai
68920dca1793SAdrian Knoth err = snd_hdspm_create(card, hdspm);
6893e35e9ddfSMarkus Elfring if (err < 0)
6894eab521aeSTakashi Iwai goto error;
6895763f356cSTakashi Iwai
68960dca1793SAdrian Knoth if (hdspm->io_type != MADIface) {
68977ad210acSArnd Bergmann snprintf(card->shortname, sizeof(card->shortname), "%s_%x",
68987ad210acSArnd Bergmann hdspm->card_name, hdspm->serial);
68997ad210acSArnd Bergmann snprintf(card->longname, sizeof(card->longname),
69007ad210acSArnd Bergmann "%s S/N 0x%x at 0x%lx, irq %d",
69017ad210acSArnd Bergmann hdspm->card_name, hdspm->serial,
6902763f356cSTakashi Iwai hdspm->port, hdspm->irq);
69030dca1793SAdrian Knoth } else {
69047ad210acSArnd Bergmann snprintf(card->shortname, sizeof(card->shortname), "%s",
69057ad210acSArnd Bergmann hdspm->card_name);
69067ad210acSArnd Bergmann snprintf(card->longname, sizeof(card->longname),
69077ad210acSArnd Bergmann "%s at 0x%lx, irq %d",
69080dca1793SAdrian Knoth hdspm->card_name, hdspm->port, hdspm->irq);
69090dca1793SAdrian Knoth }
6910763f356cSTakashi Iwai
6911ef5fa1a4STakashi Iwai err = snd_card_register(card);
6912e35e9ddfSMarkus Elfring if (err < 0)
6913eab521aeSTakashi Iwai goto error;
6914763f356cSTakashi Iwai
6915763f356cSTakashi Iwai pci_set_drvdata(pci, card);
6916763f356cSTakashi Iwai
6917763f356cSTakashi Iwai dev++;
6918763f356cSTakashi Iwai return 0;
6919eab521aeSTakashi Iwai
6920eab521aeSTakashi Iwai error:
6921eab521aeSTakashi Iwai snd_card_free(card);
6922eab521aeSTakashi Iwai return err;
6923763f356cSTakashi Iwai }
6924763f356cSTakashi Iwai
6925e9f66d9bSTakashi Iwai static struct pci_driver hdspm_driver = {
69263733e424STakashi Iwai .name = KBUILD_MODNAME,
6927763f356cSTakashi Iwai .id_table = snd_hdspm_ids,
6928763f356cSTakashi Iwai .probe = snd_hdspm_probe,
6929763f356cSTakashi Iwai };
6930763f356cSTakashi Iwai
6931e9f66d9bSTakashi Iwai module_pci_driver(hdspm_driver);
6932