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