162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   ALSA driver for RME Hammerfall DSP audio interface(s)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *      Copyright (c) 2002  Paul Davis
662306a36Sopenharmony_ci *                          Marcus Andersson
762306a36Sopenharmony_ci *                          Thomas Charbonnel
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/pci.h>
1462306a36Sopenharmony_ci#include <linux/firmware.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/math64.h>
1762306a36Sopenharmony_ci#include <linux/vmalloc.h>
1862306a36Sopenharmony_ci#include <linux/io.h>
1962306a36Sopenharmony_ci#include <linux/nospec.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <sound/core.h>
2262306a36Sopenharmony_ci#include <sound/control.h>
2362306a36Sopenharmony_ci#include <sound/pcm.h>
2462306a36Sopenharmony_ci#include <sound/info.h>
2562306a36Sopenharmony_ci#include <sound/asoundef.h>
2662306a36Sopenharmony_ci#include <sound/rawmidi.h>
2762306a36Sopenharmony_ci#include <sound/hwdep.h>
2862306a36Sopenharmony_ci#include <sound/initval.h>
2962306a36Sopenharmony_ci#include <sound/hdsp.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <asm/byteorder.h>
3262306a36Sopenharmony_ci#include <asm/current.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
3562306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
3662306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444);
3962306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for RME Hammerfall DSP interface.");
4062306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444);
4162306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for RME Hammerfall DSP interface.");
4262306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444);
4362306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable/disable specific Hammerfall DSP soundcards.");
4462306a36Sopenharmony_ciMODULE_AUTHOR("Paul Davis <paul@linuxaudiosystems.com>, Marcus Andersson, Thomas Charbonnel <thomas@undata.org>");
4562306a36Sopenharmony_ciMODULE_DESCRIPTION("RME Hammerfall DSP");
4662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
4762306a36Sopenharmony_ciMODULE_FIRMWARE("rpm_firmware.bin");
4862306a36Sopenharmony_ciMODULE_FIRMWARE("multiface_firmware.bin");
4962306a36Sopenharmony_ciMODULE_FIRMWARE("multiface_firmware_rev11.bin");
5062306a36Sopenharmony_ciMODULE_FIRMWARE("digiface_firmware.bin");
5162306a36Sopenharmony_ciMODULE_FIRMWARE("digiface_firmware_rev11.bin");
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define HDSP_MAX_CHANNELS        26
5462306a36Sopenharmony_ci#define HDSP_MAX_DS_CHANNELS     14
5562306a36Sopenharmony_ci#define HDSP_MAX_QS_CHANNELS     8
5662306a36Sopenharmony_ci#define DIGIFACE_SS_CHANNELS     26
5762306a36Sopenharmony_ci#define DIGIFACE_DS_CHANNELS     14
5862306a36Sopenharmony_ci#define MULTIFACE_SS_CHANNELS    18
5962306a36Sopenharmony_ci#define MULTIFACE_DS_CHANNELS    14
6062306a36Sopenharmony_ci#define H9652_SS_CHANNELS        26
6162306a36Sopenharmony_ci#define H9652_DS_CHANNELS        14
6262306a36Sopenharmony_ci/* This does not include possible Analog Extension Boards
6362306a36Sopenharmony_ci   AEBs are detected at card initialization
6462306a36Sopenharmony_ci*/
6562306a36Sopenharmony_ci#define H9632_SS_CHANNELS	 12
6662306a36Sopenharmony_ci#define H9632_DS_CHANNELS	 8
6762306a36Sopenharmony_ci#define H9632_QS_CHANNELS	 4
6862306a36Sopenharmony_ci#define RPM_CHANNELS             6
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* Write registers. These are defined as byte-offsets from the iobase value.
7162306a36Sopenharmony_ci */
7262306a36Sopenharmony_ci#define HDSP_resetPointer               0
7362306a36Sopenharmony_ci#define HDSP_freqReg			0
7462306a36Sopenharmony_ci#define HDSP_outputBufferAddress	32
7562306a36Sopenharmony_ci#define HDSP_inputBufferAddress		36
7662306a36Sopenharmony_ci#define HDSP_controlRegister		64
7762306a36Sopenharmony_ci#define HDSP_interruptConfirmation	96
7862306a36Sopenharmony_ci#define HDSP_outputEnable	  	128
7962306a36Sopenharmony_ci#define HDSP_control2Reg		256
8062306a36Sopenharmony_ci#define HDSP_midiDataOut0  		352
8162306a36Sopenharmony_ci#define HDSP_midiDataOut1  		356
8262306a36Sopenharmony_ci#define HDSP_fifoData  			368
8362306a36Sopenharmony_ci#define HDSP_inputEnable	 	384
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/* Read registers. These are defined as byte-offsets from the iobase value
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define HDSP_statusRegister    0
8962306a36Sopenharmony_ci#define HDSP_timecode        128
9062306a36Sopenharmony_ci#define HDSP_status2Register 192
9162306a36Sopenharmony_ci#define HDSP_midiDataIn0     360
9262306a36Sopenharmony_ci#define HDSP_midiDataIn1     364
9362306a36Sopenharmony_ci#define HDSP_midiStatusOut0  384
9462306a36Sopenharmony_ci#define HDSP_midiStatusOut1  388
9562306a36Sopenharmony_ci#define HDSP_midiStatusIn0   392
9662306a36Sopenharmony_ci#define HDSP_midiStatusIn1   396
9762306a36Sopenharmony_ci#define HDSP_fifoStatus      400
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/* the meters are regular i/o-mapped registers, but offset
10062306a36Sopenharmony_ci   considerably from the rest. the peak registers are reset
10162306a36Sopenharmony_ci   when read; the least-significant 4 bits are full-scale counters;
10262306a36Sopenharmony_ci   the actual peak value is in the most-significant 24 bits.
10362306a36Sopenharmony_ci*/
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define HDSP_playbackPeakLevel  4096  /* 26 * 32 bit values */
10662306a36Sopenharmony_ci#define HDSP_inputPeakLevel     4224  /* 26 * 32 bit values */
10762306a36Sopenharmony_ci#define HDSP_outputPeakLevel    4352  /* (26+2) * 32 bit values */
10862306a36Sopenharmony_ci#define HDSP_playbackRmsLevel   4612  /* 26 * 64 bit values */
10962306a36Sopenharmony_ci#define HDSP_inputRmsLevel      4868  /* 26 * 64 bit values */
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/* This is for H9652 cards
11362306a36Sopenharmony_ci   Peak values are read downward from the base
11462306a36Sopenharmony_ci   Rms values are read upward
11562306a36Sopenharmony_ci   There are rms values for the outputs too
11662306a36Sopenharmony_ci   26*3 values are read in ss mode
11762306a36Sopenharmony_ci   14*3 in ds mode, with no gap between values
11862306a36Sopenharmony_ci*/
11962306a36Sopenharmony_ci#define HDSP_9652_peakBase	7164
12062306a36Sopenharmony_ci#define HDSP_9652_rmsBase	4096
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* c.f. the hdsp_9632_meters_t struct */
12362306a36Sopenharmony_ci#define HDSP_9632_metersBase	4096
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#define HDSP_IO_EXTENT     7168
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/* control2 register bits */
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#define HDSP_TMS                0x01
13062306a36Sopenharmony_ci#define HDSP_TCK                0x02
13162306a36Sopenharmony_ci#define HDSP_TDI                0x04
13262306a36Sopenharmony_ci#define HDSP_JTAG               0x08
13362306a36Sopenharmony_ci#define HDSP_PWDN               0x10
13462306a36Sopenharmony_ci#define HDSP_PROGRAM	        0x020
13562306a36Sopenharmony_ci#define HDSP_CONFIG_MODE_0	0x040
13662306a36Sopenharmony_ci#define HDSP_CONFIG_MODE_1	0x080
13762306a36Sopenharmony_ci#define HDSP_VERSION_BIT	(0x100 | HDSP_S_LOAD)
13862306a36Sopenharmony_ci#define HDSP_BIGENDIAN_MODE     0x200
13962306a36Sopenharmony_ci#define HDSP_RD_MULTIPLE        0x400
14062306a36Sopenharmony_ci#define HDSP_9652_ENABLE_MIXER  0x800
14162306a36Sopenharmony_ci#define HDSP_S200		0x800
14262306a36Sopenharmony_ci#define HDSP_S300		(0x100 | HDSP_S200) /* dummy, purpose of 0x100 unknown */
14362306a36Sopenharmony_ci#define HDSP_CYCLIC_MODE	0x1000
14462306a36Sopenharmony_ci#define HDSP_TDO                0x10000000
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#define HDSP_S_PROGRAM	    (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_0)
14762306a36Sopenharmony_ci#define HDSP_S_LOAD	    (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_1)
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/* Control Register bits */
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci#define HDSP_Start                (1<<0)  /* start engine */
15262306a36Sopenharmony_ci#define HDSP_Latency0             (1<<1)  /* buffer size = 2^n where n is defined by Latency{2,1,0} */
15362306a36Sopenharmony_ci#define HDSP_Latency1             (1<<2)  /* [ see above ] */
15462306a36Sopenharmony_ci#define HDSP_Latency2             (1<<3)  /* [ see above ] */
15562306a36Sopenharmony_ci#define HDSP_ClockModeMaster      (1<<4)  /* 1=Master, 0=Slave/Autosync */
15662306a36Sopenharmony_ci#define HDSP_AudioInterruptEnable (1<<5)  /* what do you think ? */
15762306a36Sopenharmony_ci#define HDSP_Frequency0           (1<<6)  /* 0=44.1kHz/88.2kHz/176.4kHz 1=48kHz/96kHz/192kHz */
15862306a36Sopenharmony_ci#define HDSP_Frequency1           (1<<7)  /* 0=32kHz/64kHz/128kHz */
15962306a36Sopenharmony_ci#define HDSP_DoubleSpeed          (1<<8)  /* 0=normal speed, 1=double speed */
16062306a36Sopenharmony_ci#define HDSP_SPDIFProfessional    (1<<9)  /* 0=consumer, 1=professional */
16162306a36Sopenharmony_ci#define HDSP_SPDIFEmphasis        (1<<10) /* 0=none, 1=on */
16262306a36Sopenharmony_ci#define HDSP_SPDIFNonAudio        (1<<11) /* 0=off, 1=on */
16362306a36Sopenharmony_ci#define HDSP_SPDIFOpticalOut      (1<<12) /* 1=use 1st ADAT connector for SPDIF, 0=do not */
16462306a36Sopenharmony_ci#define HDSP_SyncRef2             (1<<13)
16562306a36Sopenharmony_ci#define HDSP_SPDIFInputSelect0    (1<<14)
16662306a36Sopenharmony_ci#define HDSP_SPDIFInputSelect1    (1<<15)
16762306a36Sopenharmony_ci#define HDSP_SyncRef0             (1<<16)
16862306a36Sopenharmony_ci#define HDSP_SyncRef1             (1<<17)
16962306a36Sopenharmony_ci#define HDSP_AnalogExtensionBoard (1<<18) /* For H9632 cards */
17062306a36Sopenharmony_ci#define HDSP_XLRBreakoutCable     (1<<20) /* For H9632 cards */
17162306a36Sopenharmony_ci#define HDSP_Midi0InterruptEnable (1<<22)
17262306a36Sopenharmony_ci#define HDSP_Midi1InterruptEnable (1<<23)
17362306a36Sopenharmony_ci#define HDSP_LineOut              (1<<24)
17462306a36Sopenharmony_ci#define HDSP_ADGain0		  (1<<25) /* From here : H9632 specific */
17562306a36Sopenharmony_ci#define HDSP_ADGain1		  (1<<26)
17662306a36Sopenharmony_ci#define HDSP_DAGain0		  (1<<27)
17762306a36Sopenharmony_ci#define HDSP_DAGain1		  (1<<28)
17862306a36Sopenharmony_ci#define HDSP_PhoneGain0		  (1<<29)
17962306a36Sopenharmony_ci#define HDSP_PhoneGain1		  (1<<30)
18062306a36Sopenharmony_ci#define HDSP_QuadSpeed	  	  (1<<31)
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/* RPM uses some of the registers for special purposes */
18362306a36Sopenharmony_ci#define HDSP_RPM_Inp12            0x04A00
18462306a36Sopenharmony_ci#define HDSP_RPM_Inp12_Phon_6dB   0x00800  /* Dolby */
18562306a36Sopenharmony_ci#define HDSP_RPM_Inp12_Phon_0dB   0x00000  /* .. */
18662306a36Sopenharmony_ci#define HDSP_RPM_Inp12_Phon_n6dB  0x04000  /* inp_0 */
18762306a36Sopenharmony_ci#define HDSP_RPM_Inp12_Line_0dB   0x04200  /* Dolby+PRO */
18862306a36Sopenharmony_ci#define HDSP_RPM_Inp12_Line_n6dB  0x00200  /* PRO */
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci#define HDSP_RPM_Inp34            0x32000
19162306a36Sopenharmony_ci#define HDSP_RPM_Inp34_Phon_6dB   0x20000  /* SyncRef1 */
19262306a36Sopenharmony_ci#define HDSP_RPM_Inp34_Phon_0dB   0x00000  /* .. */
19362306a36Sopenharmony_ci#define HDSP_RPM_Inp34_Phon_n6dB  0x02000  /* SyncRef2 */
19462306a36Sopenharmony_ci#define HDSP_RPM_Inp34_Line_0dB   0x30000  /* SyncRef1+SyncRef0 */
19562306a36Sopenharmony_ci#define HDSP_RPM_Inp34_Line_n6dB  0x10000  /* SyncRef0 */
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci#define HDSP_RPM_Bypass           0x01000
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci#define HDSP_RPM_Disconnect       0x00001
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci#define HDSP_ADGainMask       (HDSP_ADGain0|HDSP_ADGain1)
20262306a36Sopenharmony_ci#define HDSP_ADGainMinus10dBV  HDSP_ADGainMask
20362306a36Sopenharmony_ci#define HDSP_ADGainPlus4dBu   (HDSP_ADGain0)
20462306a36Sopenharmony_ci#define HDSP_ADGainLowGain     0
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci#define HDSP_DAGainMask         (HDSP_DAGain0|HDSP_DAGain1)
20762306a36Sopenharmony_ci#define HDSP_DAGainHighGain      HDSP_DAGainMask
20862306a36Sopenharmony_ci#define HDSP_DAGainPlus4dBu     (HDSP_DAGain0)
20962306a36Sopenharmony_ci#define HDSP_DAGainMinus10dBV    0
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci#define HDSP_PhoneGainMask      (HDSP_PhoneGain0|HDSP_PhoneGain1)
21262306a36Sopenharmony_ci#define HDSP_PhoneGain0dB        HDSP_PhoneGainMask
21362306a36Sopenharmony_ci#define HDSP_PhoneGainMinus6dB  (HDSP_PhoneGain0)
21462306a36Sopenharmony_ci#define HDSP_PhoneGainMinus12dB  0
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci#define HDSP_LatencyMask    (HDSP_Latency0|HDSP_Latency1|HDSP_Latency2)
21762306a36Sopenharmony_ci#define HDSP_FrequencyMask  (HDSP_Frequency0|HDSP_Frequency1|HDSP_DoubleSpeed|HDSP_QuadSpeed)
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci#define HDSP_SPDIFInputMask    (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1)
22062306a36Sopenharmony_ci#define HDSP_SPDIFInputADAT1    0
22162306a36Sopenharmony_ci#define HDSP_SPDIFInputCoaxial (HDSP_SPDIFInputSelect0)
22262306a36Sopenharmony_ci#define HDSP_SPDIFInputCdrom   (HDSP_SPDIFInputSelect1)
22362306a36Sopenharmony_ci#define HDSP_SPDIFInputAES     (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1)
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci#define HDSP_SyncRefMask        (HDSP_SyncRef0|HDSP_SyncRef1|HDSP_SyncRef2)
22662306a36Sopenharmony_ci#define HDSP_SyncRef_ADAT1       0
22762306a36Sopenharmony_ci#define HDSP_SyncRef_ADAT2      (HDSP_SyncRef0)
22862306a36Sopenharmony_ci#define HDSP_SyncRef_ADAT3      (HDSP_SyncRef1)
22962306a36Sopenharmony_ci#define HDSP_SyncRef_SPDIF      (HDSP_SyncRef0|HDSP_SyncRef1)
23062306a36Sopenharmony_ci#define HDSP_SyncRef_WORD       (HDSP_SyncRef2)
23162306a36Sopenharmony_ci#define HDSP_SyncRef_ADAT_SYNC  (HDSP_SyncRef0|HDSP_SyncRef2)
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/* Sample Clock Sources */
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci#define HDSP_CLOCK_SOURCE_AUTOSYNC           0
23662306a36Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_32KHZ     1
23762306a36Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ   2
23862306a36Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_48KHZ     3
23962306a36Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_64KHZ     4
24062306a36Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ   5
24162306a36Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_96KHZ     6
24262306a36Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_128KHZ    7
24362306a36Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ  8
24462306a36Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_192KHZ    9
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci/* Preferred sync reference choices - used by "pref_sync_ref" control switch */
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci#define HDSP_SYNC_FROM_WORD      0
24962306a36Sopenharmony_ci#define HDSP_SYNC_FROM_SPDIF     1
25062306a36Sopenharmony_ci#define HDSP_SYNC_FROM_ADAT1     2
25162306a36Sopenharmony_ci#define HDSP_SYNC_FROM_ADAT_SYNC 3
25262306a36Sopenharmony_ci#define HDSP_SYNC_FROM_ADAT2     4
25362306a36Sopenharmony_ci#define HDSP_SYNC_FROM_ADAT3     5
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/* SyncCheck status */
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci#define HDSP_SYNC_CHECK_NO_LOCK 0
25862306a36Sopenharmony_ci#define HDSP_SYNC_CHECK_LOCK    1
25962306a36Sopenharmony_ci#define HDSP_SYNC_CHECK_SYNC	2
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/* AutoSync references - used by "autosync_ref" control switch */
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_WORD      0
26462306a36Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_ADAT_SYNC 1
26562306a36Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_SPDIF     2
26662306a36Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_NONE	     3
26762306a36Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_ADAT1     4
26862306a36Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_ADAT2     5
26962306a36Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_ADAT3     6
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/* Possible sources of S/PDIF input */
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci#define HDSP_SPDIFIN_OPTICAL  0	/* optical  (ADAT1) */
27462306a36Sopenharmony_ci#define HDSP_SPDIFIN_COAXIAL  1	/* coaxial (RCA) */
27562306a36Sopenharmony_ci#define HDSP_SPDIFIN_INTERNAL 2	/* internal (CDROM) */
27662306a36Sopenharmony_ci#define HDSP_SPDIFIN_AES      3 /* xlr for H9632 (AES)*/
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci#define HDSP_Frequency32KHz    HDSP_Frequency0
27962306a36Sopenharmony_ci#define HDSP_Frequency44_1KHz  HDSP_Frequency1
28062306a36Sopenharmony_ci#define HDSP_Frequency48KHz    (HDSP_Frequency1|HDSP_Frequency0)
28162306a36Sopenharmony_ci#define HDSP_Frequency64KHz    (HDSP_DoubleSpeed|HDSP_Frequency0)
28262306a36Sopenharmony_ci#define HDSP_Frequency88_2KHz  (HDSP_DoubleSpeed|HDSP_Frequency1)
28362306a36Sopenharmony_ci#define HDSP_Frequency96KHz    (HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0)
28462306a36Sopenharmony_ci/* For H9632 cards */
28562306a36Sopenharmony_ci#define HDSP_Frequency128KHz   (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency0)
28662306a36Sopenharmony_ci#define HDSP_Frequency176_4KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1)
28762306a36Sopenharmony_ci#define HDSP_Frequency192KHz   (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0)
28862306a36Sopenharmony_ci/* RME says n = 104857600000000, but in the windows MADI driver, I see:
28962306a36Sopenharmony_ci	return 104857600000000 / rate; // 100 MHz
29062306a36Sopenharmony_ci	return 110100480000000 / rate; // 105 MHz
29162306a36Sopenharmony_ci*/
29262306a36Sopenharmony_ci#define DDS_NUMERATOR 104857600000000ULL  /*  =  2^20 * 10^8 */
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci#define hdsp_encode_latency(x)       (((x)<<1) & HDSP_LatencyMask)
29562306a36Sopenharmony_ci#define hdsp_decode_latency(x)       (((x) & HDSP_LatencyMask)>>1)
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci#define hdsp_encode_spdif_in(x) (((x)&0x3)<<14)
29862306a36Sopenharmony_ci#define hdsp_decode_spdif_in(x) (((x)>>14)&0x3)
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci/* Status Register bits */
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci#define HDSP_audioIRQPending    (1<<0)
30362306a36Sopenharmony_ci#define HDSP_Lock2              (1<<1)     /* this is for Digiface and H9652 */
30462306a36Sopenharmony_ci#define HDSP_spdifFrequency3	HDSP_Lock2 /* this is for H9632 only */
30562306a36Sopenharmony_ci#define HDSP_Lock1              (1<<2)
30662306a36Sopenharmony_ci#define HDSP_Lock0              (1<<3)
30762306a36Sopenharmony_ci#define HDSP_SPDIFSync          (1<<4)
30862306a36Sopenharmony_ci#define HDSP_TimecodeLock       (1<<5)
30962306a36Sopenharmony_ci#define HDSP_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */
31062306a36Sopenharmony_ci#define HDSP_Sync2              (1<<16)
31162306a36Sopenharmony_ci#define HDSP_Sync1              (1<<17)
31262306a36Sopenharmony_ci#define HDSP_Sync0              (1<<18)
31362306a36Sopenharmony_ci#define HDSP_DoubleSpeedStatus  (1<<19)
31462306a36Sopenharmony_ci#define HDSP_ConfigError        (1<<20)
31562306a36Sopenharmony_ci#define HDSP_DllError           (1<<21)
31662306a36Sopenharmony_ci#define HDSP_spdifFrequency0    (1<<22)
31762306a36Sopenharmony_ci#define HDSP_spdifFrequency1    (1<<23)
31862306a36Sopenharmony_ci#define HDSP_spdifFrequency2    (1<<24)
31962306a36Sopenharmony_ci#define HDSP_SPDIFErrorFlag     (1<<25)
32062306a36Sopenharmony_ci#define HDSP_BufferID           (1<<26)
32162306a36Sopenharmony_ci#define HDSP_TimecodeSync       (1<<27)
32262306a36Sopenharmony_ci#define HDSP_AEBO          	(1<<28) /* H9632 specific Analog Extension Boards */
32362306a36Sopenharmony_ci#define HDSP_AEBI		(1<<29) /* 0 = present, 1 = absent */
32462306a36Sopenharmony_ci#define HDSP_midi0IRQPending    (1<<30)
32562306a36Sopenharmony_ci#define HDSP_midi1IRQPending    (1<<31)
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci#define HDSP_spdifFrequencyMask    (HDSP_spdifFrequency0|HDSP_spdifFrequency1|HDSP_spdifFrequency2)
32862306a36Sopenharmony_ci#define HDSP_spdifFrequencyMask_9632 (HDSP_spdifFrequency0|\
32962306a36Sopenharmony_ci				      HDSP_spdifFrequency1|\
33062306a36Sopenharmony_ci				      HDSP_spdifFrequency2|\
33162306a36Sopenharmony_ci				      HDSP_spdifFrequency3)
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci#define HDSP_spdifFrequency32KHz   (HDSP_spdifFrequency0)
33462306a36Sopenharmony_ci#define HDSP_spdifFrequency44_1KHz (HDSP_spdifFrequency1)
33562306a36Sopenharmony_ci#define HDSP_spdifFrequency48KHz   (HDSP_spdifFrequency0|HDSP_spdifFrequency1)
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci#define HDSP_spdifFrequency64KHz   (HDSP_spdifFrequency2)
33862306a36Sopenharmony_ci#define HDSP_spdifFrequency88_2KHz (HDSP_spdifFrequency0|HDSP_spdifFrequency2)
33962306a36Sopenharmony_ci#define HDSP_spdifFrequency96KHz   (HDSP_spdifFrequency2|HDSP_spdifFrequency1)
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci/* This is for H9632 cards */
34262306a36Sopenharmony_ci#define HDSP_spdifFrequency128KHz   (HDSP_spdifFrequency0|\
34362306a36Sopenharmony_ci				     HDSP_spdifFrequency1|\
34462306a36Sopenharmony_ci				     HDSP_spdifFrequency2)
34562306a36Sopenharmony_ci#define HDSP_spdifFrequency176_4KHz HDSP_spdifFrequency3
34662306a36Sopenharmony_ci#define HDSP_spdifFrequency192KHz   (HDSP_spdifFrequency3|HDSP_spdifFrequency0)
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/* Status2 Register bits */
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci#define HDSP_version0     (1<<0)
35162306a36Sopenharmony_ci#define HDSP_version1     (1<<1)
35262306a36Sopenharmony_ci#define HDSP_version2     (1<<2)
35362306a36Sopenharmony_ci#define HDSP_wc_lock      (1<<3)
35462306a36Sopenharmony_ci#define HDSP_wc_sync      (1<<4)
35562306a36Sopenharmony_ci#define HDSP_inp_freq0    (1<<5)
35662306a36Sopenharmony_ci#define HDSP_inp_freq1    (1<<6)
35762306a36Sopenharmony_ci#define HDSP_inp_freq2    (1<<7)
35862306a36Sopenharmony_ci#define HDSP_SelSyncRef0  (1<<8)
35962306a36Sopenharmony_ci#define HDSP_SelSyncRef1  (1<<9)
36062306a36Sopenharmony_ci#define HDSP_SelSyncRef2  (1<<10)
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci#define HDSP_wc_valid (HDSP_wc_lock|HDSP_wc_sync)
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci#define HDSP_systemFrequencyMask (HDSP_inp_freq0|HDSP_inp_freq1|HDSP_inp_freq2)
36562306a36Sopenharmony_ci#define HDSP_systemFrequency32   (HDSP_inp_freq0)
36662306a36Sopenharmony_ci#define HDSP_systemFrequency44_1 (HDSP_inp_freq1)
36762306a36Sopenharmony_ci#define HDSP_systemFrequency48   (HDSP_inp_freq0|HDSP_inp_freq1)
36862306a36Sopenharmony_ci#define HDSP_systemFrequency64   (HDSP_inp_freq2)
36962306a36Sopenharmony_ci#define HDSP_systemFrequency88_2 (HDSP_inp_freq0|HDSP_inp_freq2)
37062306a36Sopenharmony_ci#define HDSP_systemFrequency96   (HDSP_inp_freq1|HDSP_inp_freq2)
37162306a36Sopenharmony_ci/* FIXME : more values for 9632 cards ? */
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci#define HDSP_SelSyncRefMask        (HDSP_SelSyncRef0|HDSP_SelSyncRef1|HDSP_SelSyncRef2)
37462306a36Sopenharmony_ci#define HDSP_SelSyncRef_ADAT1      0
37562306a36Sopenharmony_ci#define HDSP_SelSyncRef_ADAT2      (HDSP_SelSyncRef0)
37662306a36Sopenharmony_ci#define HDSP_SelSyncRef_ADAT3      (HDSP_SelSyncRef1)
37762306a36Sopenharmony_ci#define HDSP_SelSyncRef_SPDIF      (HDSP_SelSyncRef0|HDSP_SelSyncRef1)
37862306a36Sopenharmony_ci#define HDSP_SelSyncRef_WORD       (HDSP_SelSyncRef2)
37962306a36Sopenharmony_ci#define HDSP_SelSyncRef_ADAT_SYNC  (HDSP_SelSyncRef0|HDSP_SelSyncRef2)
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci/* Card state flags */
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci#define HDSP_InitializationComplete  (1<<0)
38462306a36Sopenharmony_ci#define HDSP_FirmwareLoaded	     (1<<1)
38562306a36Sopenharmony_ci#define HDSP_FirmwareCached	     (1<<2)
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/* FIFO wait times, defined in terms of 1/10ths of msecs */
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci#define HDSP_LONG_WAIT	 5000
39062306a36Sopenharmony_ci#define HDSP_SHORT_WAIT  30
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci#define UNITY_GAIN                       32768
39362306a36Sopenharmony_ci#define MINUS_INFINITY_GAIN              0
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci/* the size of a substream (1 mono data stream) */
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci#define HDSP_CHANNEL_BUFFER_SAMPLES  (16*1024)
39862306a36Sopenharmony_ci#define HDSP_CHANNEL_BUFFER_BYTES    (4*HDSP_CHANNEL_BUFFER_SAMPLES)
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci/* the size of the area we need to allocate for DMA transfers. the
40162306a36Sopenharmony_ci   size is the same regardless of the number of channels - the
40262306a36Sopenharmony_ci   Multiface still uses the same memory area.
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci   Note that we allocate 1 more channel than is apparently needed
40562306a36Sopenharmony_ci   because the h/w seems to write 1 byte beyond the end of the last
40662306a36Sopenharmony_ci   page. Sigh.
40762306a36Sopenharmony_ci*/
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci#define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES)
41062306a36Sopenharmony_ci#define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024)
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci#define HDSP_FIRMWARE_SIZE	(24413 * 4)
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistruct hdsp_9632_meters {
41562306a36Sopenharmony_ci    u32 input_peak[16];
41662306a36Sopenharmony_ci    u32 playback_peak[16];
41762306a36Sopenharmony_ci    u32 output_peak[16];
41862306a36Sopenharmony_ci    u32 xxx_peak[16];
41962306a36Sopenharmony_ci    u32 padding[64];
42062306a36Sopenharmony_ci    u32 input_rms_low[16];
42162306a36Sopenharmony_ci    u32 playback_rms_low[16];
42262306a36Sopenharmony_ci    u32 output_rms_low[16];
42362306a36Sopenharmony_ci    u32 xxx_rms_low[16];
42462306a36Sopenharmony_ci    u32 input_rms_high[16];
42562306a36Sopenharmony_ci    u32 playback_rms_high[16];
42662306a36Sopenharmony_ci    u32 output_rms_high[16];
42762306a36Sopenharmony_ci    u32 xxx_rms_high[16];
42862306a36Sopenharmony_ci};
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistruct hdsp_midi {
43162306a36Sopenharmony_ci    struct hdsp             *hdsp;
43262306a36Sopenharmony_ci    int                      id;
43362306a36Sopenharmony_ci    struct snd_rawmidi           *rmidi;
43462306a36Sopenharmony_ci    struct snd_rawmidi_substream *input;
43562306a36Sopenharmony_ci    struct snd_rawmidi_substream *output;
43662306a36Sopenharmony_ci    signed char		     istimer; /* timer in use */
43762306a36Sopenharmony_ci    struct timer_list	     timer;
43862306a36Sopenharmony_ci    spinlock_t               lock;
43962306a36Sopenharmony_ci    int			     pending;
44062306a36Sopenharmony_ci};
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistruct hdsp {
44362306a36Sopenharmony_ci	spinlock_t            lock;
44462306a36Sopenharmony_ci	struct snd_pcm_substream *capture_substream;
44562306a36Sopenharmony_ci	struct snd_pcm_substream *playback_substream;
44662306a36Sopenharmony_ci        struct hdsp_midi      midi[2];
44762306a36Sopenharmony_ci	struct work_struct    midi_work;
44862306a36Sopenharmony_ci	int		      use_midi_work;
44962306a36Sopenharmony_ci	int                   precise_ptr;
45062306a36Sopenharmony_ci	u32                   control_register;	     /* cached value */
45162306a36Sopenharmony_ci	u32                   control2_register;     /* cached value */
45262306a36Sopenharmony_ci	u32                   creg_spdif;
45362306a36Sopenharmony_ci	u32                   creg_spdif_stream;
45462306a36Sopenharmony_ci	int                   clock_source_locked;
45562306a36Sopenharmony_ci	char                 *card_name;	 /* digiface/multiface/rpm */
45662306a36Sopenharmony_ci	enum HDSP_IO_Type     io_type;               /* ditto, but for code use */
45762306a36Sopenharmony_ci        unsigned short        firmware_rev;
45862306a36Sopenharmony_ci	unsigned short	      state;		     /* stores state bits */
45962306a36Sopenharmony_ci	const struct firmware *firmware;
46062306a36Sopenharmony_ci	u32                  *fw_uploaded;
46162306a36Sopenharmony_ci	size_t                period_bytes; 	     /* guess what this is */
46262306a36Sopenharmony_ci	unsigned char	      max_channels;
46362306a36Sopenharmony_ci	unsigned char	      qs_in_channels;	     /* quad speed mode for H9632 */
46462306a36Sopenharmony_ci	unsigned char         ds_in_channels;
46562306a36Sopenharmony_ci	unsigned char         ss_in_channels;	    /* different for multiface/digiface */
46662306a36Sopenharmony_ci	unsigned char	      qs_out_channels;
46762306a36Sopenharmony_ci	unsigned char         ds_out_channels;
46862306a36Sopenharmony_ci	unsigned char         ss_out_channels;
46962306a36Sopenharmony_ci	u32                   io_loopback;          /* output loopback channel states*/
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* DMA buffers; those are copied instances from the original snd_dma_buf
47262306a36Sopenharmony_ci	 * objects (which are managed via devres) for the address alignments
47362306a36Sopenharmony_ci	 */
47462306a36Sopenharmony_ci	struct snd_dma_buffer capture_dma_buf;
47562306a36Sopenharmony_ci	struct snd_dma_buffer playback_dma_buf;
47662306a36Sopenharmony_ci	unsigned char        *capture_buffer;	    /* suitably aligned address */
47762306a36Sopenharmony_ci	unsigned char        *playback_buffer;	    /* suitably aligned address */
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	pid_t                 capture_pid;
48062306a36Sopenharmony_ci	pid_t                 playback_pid;
48162306a36Sopenharmony_ci	int                   running;
48262306a36Sopenharmony_ci	int                   system_sample_rate;
48362306a36Sopenharmony_ci	const signed char    *channel_map;
48462306a36Sopenharmony_ci	int                   dev;
48562306a36Sopenharmony_ci	int                   irq;
48662306a36Sopenharmony_ci	unsigned long         port;
48762306a36Sopenharmony_ci        void __iomem         *iobase;
48862306a36Sopenharmony_ci	struct snd_card *card;
48962306a36Sopenharmony_ci	struct snd_pcm *pcm;
49062306a36Sopenharmony_ci	struct snd_hwdep          *hwdep;
49162306a36Sopenharmony_ci	struct pci_dev       *pci;
49262306a36Sopenharmony_ci	struct snd_kcontrol *spdif_ctl;
49362306a36Sopenharmony_ci        unsigned short        mixer_matrix[HDSP_MATRIX_MIXER_SIZE];
49462306a36Sopenharmony_ci	unsigned int          dds_value; /* last value written to freq register */
49562306a36Sopenharmony_ci};
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci/* These tables map the ALSA channels 1..N to the channels that we
49862306a36Sopenharmony_ci   need to use in order to find the relevant channel buffer. RME
49962306a36Sopenharmony_ci   refer to this kind of mapping as between "the ADAT channel and
50062306a36Sopenharmony_ci   the DMA channel." We index it using the logical audio channel,
50162306a36Sopenharmony_ci   and the value is the DMA channel (i.e. channel buffer number)
50262306a36Sopenharmony_ci   where the data for that channel can be read/written from/to.
50362306a36Sopenharmony_ci*/
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic const signed char channel_map_df_ss[HDSP_MAX_CHANNELS] = {
50662306a36Sopenharmony_ci	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
50762306a36Sopenharmony_ci	18, 19, 20, 21, 22, 23, 24, 25
50862306a36Sopenharmony_ci};
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic const char channel_map_mf_ss[HDSP_MAX_CHANNELS] = { /* Multiface */
51162306a36Sopenharmony_ci	/* Analog */
51262306a36Sopenharmony_ci	0, 1, 2, 3, 4, 5, 6, 7,
51362306a36Sopenharmony_ci	/* ADAT 2 */
51462306a36Sopenharmony_ci	16, 17, 18, 19, 20, 21, 22, 23,
51562306a36Sopenharmony_ci	/* SPDIF */
51662306a36Sopenharmony_ci	24, 25,
51762306a36Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1
51862306a36Sopenharmony_ci};
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic const signed char channel_map_ds[HDSP_MAX_CHANNELS] = {
52162306a36Sopenharmony_ci	/* ADAT channels are remapped */
52262306a36Sopenharmony_ci	1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23,
52362306a36Sopenharmony_ci	/* channels 12 and 13 are S/PDIF */
52462306a36Sopenharmony_ci	24, 25,
52562306a36Sopenharmony_ci	/* others don't exist */
52662306a36Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
52762306a36Sopenharmony_ci};
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic const signed char channel_map_H9632_ss[HDSP_MAX_CHANNELS] = {
53062306a36Sopenharmony_ci	/* ADAT channels */
53162306a36Sopenharmony_ci	0, 1, 2, 3, 4, 5, 6, 7,
53262306a36Sopenharmony_ci	/* SPDIF */
53362306a36Sopenharmony_ci	8, 9,
53462306a36Sopenharmony_ci	/* Analog */
53562306a36Sopenharmony_ci	10, 11,
53662306a36Sopenharmony_ci	/* AO4S-192 and AI4S-192 extension boards */
53762306a36Sopenharmony_ci	12, 13, 14, 15,
53862306a36Sopenharmony_ci	/* others don't exist */
53962306a36Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1,
54062306a36Sopenharmony_ci	-1, -1
54162306a36Sopenharmony_ci};
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic const signed char channel_map_H9632_ds[HDSP_MAX_CHANNELS] = {
54462306a36Sopenharmony_ci	/* ADAT */
54562306a36Sopenharmony_ci	1, 3, 5, 7,
54662306a36Sopenharmony_ci	/* SPDIF */
54762306a36Sopenharmony_ci	8, 9,
54862306a36Sopenharmony_ci	/* Analog */
54962306a36Sopenharmony_ci	10, 11,
55062306a36Sopenharmony_ci	/* AO4S-192 and AI4S-192 extension boards */
55162306a36Sopenharmony_ci	12, 13, 14, 15,
55262306a36Sopenharmony_ci	/* others don't exist */
55362306a36Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1,
55462306a36Sopenharmony_ci	-1, -1, -1, -1, -1, -1
55562306a36Sopenharmony_ci};
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic const signed char channel_map_H9632_qs[HDSP_MAX_CHANNELS] = {
55862306a36Sopenharmony_ci	/* ADAT is disabled in this mode */
55962306a36Sopenharmony_ci	/* SPDIF */
56062306a36Sopenharmony_ci	8, 9,
56162306a36Sopenharmony_ci	/* Analog */
56262306a36Sopenharmony_ci	10, 11,
56362306a36Sopenharmony_ci	/* AO4S-192 and AI4S-192 extension boards */
56462306a36Sopenharmony_ci	12, 13, 14, 15,
56562306a36Sopenharmony_ci	/* others don't exist */
56662306a36Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1,
56762306a36Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1,
56862306a36Sopenharmony_ci	-1, -1
56962306a36Sopenharmony_ci};
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cistatic struct snd_dma_buffer *
57262306a36Sopenharmony_cisnd_hammerfall_get_buffer(struct pci_dev *pci, size_t size)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	return snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV, size);
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic const struct pci_device_id snd_hdsp_ids[] = {
57862306a36Sopenharmony_ci	{
57962306a36Sopenharmony_ci		.vendor = PCI_VENDOR_ID_XILINX,
58062306a36Sopenharmony_ci		.device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP,
58162306a36Sopenharmony_ci		.subvendor = PCI_ANY_ID,
58262306a36Sopenharmony_ci		.subdevice = PCI_ANY_ID,
58362306a36Sopenharmony_ci	}, /* RME Hammerfall-DSP */
58462306a36Sopenharmony_ci	{ 0, },
58562306a36Sopenharmony_ci};
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_hdsp_ids);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci/* prototypes */
59062306a36Sopenharmony_cistatic int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp);
59162306a36Sopenharmony_cistatic int snd_hdsp_create_pcm(struct snd_card *card, struct hdsp *hdsp);
59262306a36Sopenharmony_cistatic int snd_hdsp_enable_io (struct hdsp *hdsp);
59362306a36Sopenharmony_cistatic void snd_hdsp_initialize_midi_flush (struct hdsp *hdsp);
59462306a36Sopenharmony_cistatic void snd_hdsp_initialize_channels (struct hdsp *hdsp);
59562306a36Sopenharmony_cistatic int hdsp_fifo_wait(struct hdsp *hdsp, int count, int timeout);
59662306a36Sopenharmony_cistatic int hdsp_autosync_ref(struct hdsp *hdsp);
59762306a36Sopenharmony_cistatic int snd_hdsp_set_defaults(struct hdsp *hdsp);
59862306a36Sopenharmony_cistatic void snd_hdsp_9652_enable_mixer (struct hdsp *hdsp);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	switch (hdsp->io_type) {
60362306a36Sopenharmony_ci	case Multiface:
60462306a36Sopenharmony_ci	case Digiface:
60562306a36Sopenharmony_ci	case RPM:
60662306a36Sopenharmony_ci	default:
60762306a36Sopenharmony_ci		if (hdsp->firmware_rev == 0xa)
60862306a36Sopenharmony_ci			return (64 * out) + (32 + (in));
60962306a36Sopenharmony_ci		else
61062306a36Sopenharmony_ci			return (52 * out) + (26 + (in));
61162306a36Sopenharmony_ci	case H9632:
61262306a36Sopenharmony_ci		return (32 * out) + (16 + (in));
61362306a36Sopenharmony_ci	case H9652:
61462306a36Sopenharmony_ci		return (52 * out) + (26 + (in));
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_cistatic int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	switch (hdsp->io_type) {
62162306a36Sopenharmony_ci	case Multiface:
62262306a36Sopenharmony_ci	case Digiface:
62362306a36Sopenharmony_ci	case RPM:
62462306a36Sopenharmony_ci	default:
62562306a36Sopenharmony_ci		if (hdsp->firmware_rev == 0xa)
62662306a36Sopenharmony_ci			return (64 * out) + in;
62762306a36Sopenharmony_ci		else
62862306a36Sopenharmony_ci			return (52 * out) + in;
62962306a36Sopenharmony_ci	case H9632:
63062306a36Sopenharmony_ci		return (32 * out) + in;
63162306a36Sopenharmony_ci	case H9652:
63262306a36Sopenharmony_ci		return (52 * out) + in;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic void hdsp_write(struct hdsp *hdsp, int reg, int val)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	writel(val, hdsp->iobase + reg);
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic unsigned int hdsp_read(struct hdsp *hdsp, int reg)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	return readl (hdsp->iobase + reg);
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic int hdsp_check_for_iobox (struct hdsp *hdsp)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	int i;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
65162306a36Sopenharmony_ci	for (i = 0; i < 500; i++) {
65262306a36Sopenharmony_ci		if (0 == (hdsp_read(hdsp, HDSP_statusRegister) &
65362306a36Sopenharmony_ci					HDSP_ConfigError)) {
65462306a36Sopenharmony_ci			if (i) {
65562306a36Sopenharmony_ci				dev_dbg(hdsp->card->dev,
65662306a36Sopenharmony_ci					"IO box found after %d ms\n",
65762306a36Sopenharmony_ci						(20 * i));
65862306a36Sopenharmony_ci			}
65962306a36Sopenharmony_ci			return 0;
66062306a36Sopenharmony_ci		}
66162306a36Sopenharmony_ci		msleep(20);
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci	dev_err(hdsp->card->dev, "no IO box connected!\n");
66462306a36Sopenharmony_ci	hdsp->state &= ~HDSP_FirmwareLoaded;
66562306a36Sopenharmony_ci	return -EIO;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
66962306a36Sopenharmony_ci			       unsigned int delay)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	unsigned int i;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
67462306a36Sopenharmony_ci		return 0;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	for (i = 0; i != loops; ++i) {
67762306a36Sopenharmony_ci		if (hdsp_read(hdsp, HDSP_statusRegister) & HDSP_ConfigError)
67862306a36Sopenharmony_ci			msleep(delay);
67962306a36Sopenharmony_ci		else {
68062306a36Sopenharmony_ci			dev_dbg(hdsp->card->dev, "iobox found after %ums!\n",
68162306a36Sopenharmony_ci				   i * delay);
68262306a36Sopenharmony_ci			return 0;
68362306a36Sopenharmony_ci		}
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	dev_info(hdsp->card->dev, "no IO box connected!\n");
68762306a36Sopenharmony_ci	hdsp->state &= ~HDSP_FirmwareLoaded;
68862306a36Sopenharmony_ci	return -EIO;
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	int i;
69462306a36Sopenharmony_ci	unsigned long flags;
69562306a36Sopenharmony_ci	const u32 *cache;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (hdsp->fw_uploaded)
69862306a36Sopenharmony_ci		cache = hdsp->fw_uploaded;
69962306a36Sopenharmony_ci	else {
70062306a36Sopenharmony_ci		if (!hdsp->firmware)
70162306a36Sopenharmony_ci			return -ENODEV;
70262306a36Sopenharmony_ci		cache = (u32 *)hdsp->firmware->data;
70362306a36Sopenharmony_ci		if (!cache)
70462306a36Sopenharmony_ci			return -ENODEV;
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		dev_info(hdsp->card->dev, "loading firmware\n");
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci		hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_PROGRAM);
71262306a36Sopenharmony_ci		hdsp_write (hdsp, HDSP_fifoData, 0);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci		if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
71562306a36Sopenharmony_ci			dev_info(hdsp->card->dev,
71662306a36Sopenharmony_ci				 "timeout waiting for download preparation\n");
71762306a36Sopenharmony_ci			hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
71862306a36Sopenharmony_ci			return -EIO;
71962306a36Sopenharmony_ci		}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		for (i = 0; i < HDSP_FIRMWARE_SIZE / 4; ++i) {
72462306a36Sopenharmony_ci			hdsp_write(hdsp, HDSP_fifoData, cache[i]);
72562306a36Sopenharmony_ci			if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) {
72662306a36Sopenharmony_ci				dev_info(hdsp->card->dev,
72762306a36Sopenharmony_ci					 "timeout during firmware loading\n");
72862306a36Sopenharmony_ci				hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
72962306a36Sopenharmony_ci				return -EIO;
73062306a36Sopenharmony_ci			}
73162306a36Sopenharmony_ci		}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		hdsp_fifo_wait(hdsp, 3, HDSP_LONG_WAIT);
73462306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		ssleep(3);
73762306a36Sopenharmony_ci#ifdef SNDRV_BIG_ENDIAN
73862306a36Sopenharmony_ci		hdsp->control2_register = HDSP_BIGENDIAN_MODE;
73962306a36Sopenharmony_ci#else
74062306a36Sopenharmony_ci		hdsp->control2_register = 0;
74162306a36Sopenharmony_ci#endif
74262306a36Sopenharmony_ci		hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
74362306a36Sopenharmony_ci		dev_info(hdsp->card->dev, "finished firmware loading\n");
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci	if (hdsp->state & HDSP_InitializationComplete) {
74762306a36Sopenharmony_ci		dev_info(hdsp->card->dev,
74862306a36Sopenharmony_ci			 "firmware loaded from cache, restoring defaults\n");
74962306a36Sopenharmony_ci		spin_lock_irqsave(&hdsp->lock, flags);
75062306a36Sopenharmony_ci		snd_hdsp_set_defaults(hdsp);
75162306a36Sopenharmony_ci		spin_unlock_irqrestore(&hdsp->lock, flags);
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	hdsp->state |= HDSP_FirmwareLoaded;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	return 0;
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_cistatic int hdsp_get_iobox_version (struct hdsp *hdsp)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
76462306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_fifoData, 0);
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
76762306a36Sopenharmony_ci			hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
76862306a36Sopenharmony_ci			hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
76962306a36Sopenharmony_ci		}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200 | HDSP_PROGRAM);
77262306a36Sopenharmony_ci		hdsp_write (hdsp, HDSP_fifoData, 0);
77362306a36Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0)
77462306a36Sopenharmony_ci			goto set_multi;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
77762306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_fifoData, 0);
77862306a36Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
77962306a36Sopenharmony_ci			hdsp->io_type = Digiface;
78062306a36Sopenharmony_ci			dev_info(hdsp->card->dev, "Digiface found\n");
78162306a36Sopenharmony_ci			return 0;
78262306a36Sopenharmony_ci		}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
78562306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
78662306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_fifoData, 0);
78762306a36Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0)
78862306a36Sopenharmony_ci			goto set_multi;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
79162306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
79262306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_fifoData, 0);
79362306a36Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0)
79462306a36Sopenharmony_ci			goto set_multi;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci		hdsp->io_type = RPM;
79762306a36Sopenharmony_ci		dev_info(hdsp->card->dev, "RPM found\n");
79862306a36Sopenharmony_ci		return 0;
79962306a36Sopenharmony_ci	} else {
80062306a36Sopenharmony_ci		/* firmware was already loaded, get iobox type */
80162306a36Sopenharmony_ci		if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
80262306a36Sopenharmony_ci			hdsp->io_type = RPM;
80362306a36Sopenharmony_ci		else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
80462306a36Sopenharmony_ci			hdsp->io_type = Multiface;
80562306a36Sopenharmony_ci		else
80662306a36Sopenharmony_ci			hdsp->io_type = Digiface;
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci	return 0;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ciset_multi:
81162306a36Sopenharmony_ci	hdsp->io_type = Multiface;
81262306a36Sopenharmony_ci	dev_info(hdsp->card->dev, "Multiface found\n");
81362306a36Sopenharmony_ci	return 0;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic int hdsp_request_fw_loader(struct hdsp *hdsp);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
82262306a36Sopenharmony_ci		return 0;
82362306a36Sopenharmony_ci	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
82462306a36Sopenharmony_ci		hdsp->state &= ~HDSP_FirmwareLoaded;
82562306a36Sopenharmony_ci		if (! load_on_demand)
82662306a36Sopenharmony_ci			return -EIO;
82762306a36Sopenharmony_ci		dev_err(hdsp->card->dev, "firmware not present.\n");
82862306a36Sopenharmony_ci		/* try to load firmware */
82962306a36Sopenharmony_ci		if (! (hdsp->state & HDSP_FirmwareCached)) {
83062306a36Sopenharmony_ci			if (! hdsp_request_fw_loader(hdsp))
83162306a36Sopenharmony_ci				return 0;
83262306a36Sopenharmony_ci			dev_err(hdsp->card->dev,
83362306a36Sopenharmony_ci				   "No firmware loaded nor cached, please upload firmware.\n");
83462306a36Sopenharmony_ci			return -EIO;
83562306a36Sopenharmony_ci		}
83662306a36Sopenharmony_ci		if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
83762306a36Sopenharmony_ci			dev_err(hdsp->card->dev,
83862306a36Sopenharmony_ci				   "Firmware loading from cache failed, please upload manually.\n");
83962306a36Sopenharmony_ci			return -EIO;
84062306a36Sopenharmony_ci		}
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci	return 0;
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_cistatic int hdsp_fifo_wait(struct hdsp *hdsp, int count, int timeout)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	int i;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	/* the fifoStatus registers reports on how many words
85162306a36Sopenharmony_ci	   are available in the command FIFO.
85262306a36Sopenharmony_ci	*/
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	for (i = 0; i < timeout; i++) {
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci		if ((int)(hdsp_read (hdsp, HDSP_fifoStatus) & 0xff) <= count)
85762306a36Sopenharmony_ci			return 0;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci		/* not very friendly, but we only do this during a firmware
86062306a36Sopenharmony_ci		   load and changing the mixer, so we just put up with it.
86162306a36Sopenharmony_ci		*/
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		udelay (100);
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	dev_warn(hdsp->card->dev,
86762306a36Sopenharmony_ci		 "wait for FIFO status <= %d failed after %d iterations\n",
86862306a36Sopenharmony_ci		    count, timeout);
86962306a36Sopenharmony_ci	return -1;
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_cistatic int hdsp_read_gain (struct hdsp *hdsp, unsigned int addr)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	if (addr >= HDSP_MATRIX_MIXER_SIZE)
87562306a36Sopenharmony_ci		return 0;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	return hdsp->mixer_matrix[addr];
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic int hdsp_write_gain(struct hdsp *hdsp, unsigned int addr, unsigned short data)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	unsigned int ad;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	if (addr >= HDSP_MATRIX_MIXER_SIZE)
88562306a36Sopenharmony_ci		return -1;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	if (hdsp->io_type == H9652 || hdsp->io_type == H9632) {
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci		/* from martin bjornsen:
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci		   "You can only write dwords to the
89262306a36Sopenharmony_ci		   mixer memory which contain two
89362306a36Sopenharmony_ci		   mixer values in the low and high
89462306a36Sopenharmony_ci		   word. So if you want to change
89562306a36Sopenharmony_ci		   value 0 you have to read value 1
89662306a36Sopenharmony_ci		   from the cache and write both to
89762306a36Sopenharmony_ci		   the first dword in the mixer
89862306a36Sopenharmony_ci		   memory."
89962306a36Sopenharmony_ci		*/
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		if (hdsp->io_type == H9632 && addr >= 512)
90262306a36Sopenharmony_ci			return 0;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci		if (hdsp->io_type == H9652 && addr >= 1352)
90562306a36Sopenharmony_ci			return 0;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci		hdsp->mixer_matrix[addr] = data;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci		/* `addr' addresses a 16-bit wide address, but
91162306a36Sopenharmony_ci		   the address space accessed via hdsp_write
91262306a36Sopenharmony_ci		   uses byte offsets. put another way, addr
91362306a36Sopenharmony_ci		   varies from 0 to 1351, but to access the
91462306a36Sopenharmony_ci		   corresponding memory location, we need
91562306a36Sopenharmony_ci		   to access 0 to 2703 ...
91662306a36Sopenharmony_ci		*/
91762306a36Sopenharmony_ci		ad = addr/2;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci		hdsp_write (hdsp, 4096 + (ad*4),
92062306a36Sopenharmony_ci			    (hdsp->mixer_matrix[(addr&0x7fe)+1] << 16) +
92162306a36Sopenharmony_ci			    hdsp->mixer_matrix[addr&0x7fe]);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci		return 0;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	} else {
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci		ad = (addr << 16) + data;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT))
93062306a36Sopenharmony_ci			return -1;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci		hdsp_write (hdsp, HDSP_fifoData, ad);
93362306a36Sopenharmony_ci		hdsp->mixer_matrix[addr] = data;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	return 0;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic int snd_hdsp_use_is_exclusive(struct hdsp *hdsp)
94162306a36Sopenharmony_ci{
94262306a36Sopenharmony_ci	unsigned long flags;
94362306a36Sopenharmony_ci	int ret = 1;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	spin_lock_irqsave(&hdsp->lock, flags);
94662306a36Sopenharmony_ci	if ((hdsp->playback_pid != hdsp->capture_pid) &&
94762306a36Sopenharmony_ci	    (hdsp->playback_pid >= 0) && (hdsp->capture_pid >= 0))
94862306a36Sopenharmony_ci		ret = 0;
94962306a36Sopenharmony_ci	spin_unlock_irqrestore(&hdsp->lock, flags);
95062306a36Sopenharmony_ci	return ret;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_cistatic int hdsp_spdif_sample_rate(struct hdsp *hdsp)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	unsigned int status = hdsp_read(hdsp, HDSP_statusRegister);
95662306a36Sopenharmony_ci	unsigned int rate_bits = (status & HDSP_spdifFrequencyMask);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	/* For the 9632, the mask is different */
95962306a36Sopenharmony_ci	if (hdsp->io_type == H9632)
96062306a36Sopenharmony_ci		 rate_bits = (status & HDSP_spdifFrequencyMask_9632);
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	if (status & HDSP_SPDIFErrorFlag)
96362306a36Sopenharmony_ci		return 0;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	switch (rate_bits) {
96662306a36Sopenharmony_ci	case HDSP_spdifFrequency32KHz: return 32000;
96762306a36Sopenharmony_ci	case HDSP_spdifFrequency44_1KHz: return 44100;
96862306a36Sopenharmony_ci	case HDSP_spdifFrequency48KHz: return 48000;
96962306a36Sopenharmony_ci	case HDSP_spdifFrequency64KHz: return 64000;
97062306a36Sopenharmony_ci	case HDSP_spdifFrequency88_2KHz: return 88200;
97162306a36Sopenharmony_ci	case HDSP_spdifFrequency96KHz: return 96000;
97262306a36Sopenharmony_ci	case HDSP_spdifFrequency128KHz:
97362306a36Sopenharmony_ci		if (hdsp->io_type == H9632) return 128000;
97462306a36Sopenharmony_ci		break;
97562306a36Sopenharmony_ci	case HDSP_spdifFrequency176_4KHz:
97662306a36Sopenharmony_ci		if (hdsp->io_type == H9632) return 176400;
97762306a36Sopenharmony_ci		break;
97862306a36Sopenharmony_ci	case HDSP_spdifFrequency192KHz:
97962306a36Sopenharmony_ci		if (hdsp->io_type == H9632) return 192000;
98062306a36Sopenharmony_ci		break;
98162306a36Sopenharmony_ci	default:
98262306a36Sopenharmony_ci		break;
98362306a36Sopenharmony_ci	}
98462306a36Sopenharmony_ci	dev_warn(hdsp->card->dev,
98562306a36Sopenharmony_ci		 "unknown spdif frequency status; bits = 0x%x, status = 0x%x\n",
98662306a36Sopenharmony_ci		 rate_bits, status);
98762306a36Sopenharmony_ci	return 0;
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic int hdsp_external_sample_rate(struct hdsp *hdsp)
99162306a36Sopenharmony_ci{
99262306a36Sopenharmony_ci	unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register);
99362306a36Sopenharmony_ci	unsigned int rate_bits = status2 & HDSP_systemFrequencyMask;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	/* For the 9632 card, there seems to be no bit for indicating external
99662306a36Sopenharmony_ci	 * sample rate greater than 96kHz. The card reports the corresponding
99762306a36Sopenharmony_ci	 * single speed. So the best means seems to get spdif rate when
99862306a36Sopenharmony_ci	 * autosync reference is spdif */
99962306a36Sopenharmony_ci	if (hdsp->io_type == H9632 &&
100062306a36Sopenharmony_ci	    hdsp_autosync_ref(hdsp) == HDSP_AUTOSYNC_FROM_SPDIF)
100162306a36Sopenharmony_ci		 return hdsp_spdif_sample_rate(hdsp);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	switch (rate_bits) {
100462306a36Sopenharmony_ci	case HDSP_systemFrequency32:   return 32000;
100562306a36Sopenharmony_ci	case HDSP_systemFrequency44_1: return 44100;
100662306a36Sopenharmony_ci	case HDSP_systemFrequency48:   return 48000;
100762306a36Sopenharmony_ci	case HDSP_systemFrequency64:   return 64000;
100862306a36Sopenharmony_ci	case HDSP_systemFrequency88_2: return 88200;
100962306a36Sopenharmony_ci	case HDSP_systemFrequency96:   return 96000;
101062306a36Sopenharmony_ci	default:
101162306a36Sopenharmony_ci		return 0;
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic void hdsp_compute_period_size(struct hdsp *hdsp)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	hdsp->period_bytes = 1 << ((hdsp_decode_latency(hdsp->control_register) + 8));
101862306a36Sopenharmony_ci}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_cistatic snd_pcm_uframes_t hdsp_hw_pointer(struct hdsp *hdsp)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	int position;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	position = hdsp_read(hdsp, HDSP_statusRegister);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	if (!hdsp->precise_ptr)
102762306a36Sopenharmony_ci		return (position & HDSP_BufferID) ? (hdsp->period_bytes / 4) : 0;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	position &= HDSP_BufferPositionMask;
103062306a36Sopenharmony_ci	position /= 4;
103162306a36Sopenharmony_ci	position &= (hdsp->period_bytes/2) - 1;
103262306a36Sopenharmony_ci	return position;
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cistatic void hdsp_reset_hw_pointer(struct hdsp *hdsp)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	hdsp_write (hdsp, HDSP_resetPointer, 0);
103862306a36Sopenharmony_ci	if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
103962306a36Sopenharmony_ci		/* HDSP_resetPointer = HDSP_freqReg, which is strange and
104062306a36Sopenharmony_ci		 * requires (?) to write again DDS value after a reset pointer
104162306a36Sopenharmony_ci		 * (at least, it works like this) */
104262306a36Sopenharmony_ci		hdsp_write (hdsp, HDSP_freqReg, hdsp->dds_value);
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic void hdsp_start_audio(struct hdsp *s)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	s->control_register |= (HDSP_AudioInterruptEnable | HDSP_Start);
104862306a36Sopenharmony_ci	hdsp_write(s, HDSP_controlRegister, s->control_register);
104962306a36Sopenharmony_ci}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_cistatic void hdsp_stop_audio(struct hdsp *s)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	s->control_register &= ~(HDSP_Start | HDSP_AudioInterruptEnable);
105462306a36Sopenharmony_ci	hdsp_write(s, HDSP_controlRegister, s->control_register);
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cistatic void hdsp_silence_playback(struct hdsp *hdsp)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	memset(hdsp->playback_buffer, 0, HDSP_DMA_AREA_BYTES);
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cistatic int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	int n;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	spin_lock_irq(&s->lock);
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	frames >>= 7;
106962306a36Sopenharmony_ci	n = 0;
107062306a36Sopenharmony_ci	while (frames) {
107162306a36Sopenharmony_ci		n++;
107262306a36Sopenharmony_ci		frames >>= 1;
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	s->control_register &= ~HDSP_LatencyMask;
107662306a36Sopenharmony_ci	s->control_register |= hdsp_encode_latency(n);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	hdsp_write(s, HDSP_controlRegister, s->control_register);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	hdsp_compute_period_size(s);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	spin_unlock_irq(&s->lock);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	return 0;
108562306a36Sopenharmony_ci}
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_cistatic void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
108862306a36Sopenharmony_ci{
108962306a36Sopenharmony_ci	u64 n;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	if (rate >= 112000)
109262306a36Sopenharmony_ci		rate /= 4;
109362306a36Sopenharmony_ci	else if (rate >= 56000)
109462306a36Sopenharmony_ci		rate /= 2;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	n = DDS_NUMERATOR;
109762306a36Sopenharmony_ci	n = div_u64(n, rate);
109862306a36Sopenharmony_ci	/* n should be less than 2^32 for being written to FREQ register */
109962306a36Sopenharmony_ci	snd_BUG_ON(n >> 32);
110062306a36Sopenharmony_ci	/* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS
110162306a36Sopenharmony_ci	   value to write it after a reset */
110262306a36Sopenharmony_ci	hdsp->dds_value = n;
110362306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_freqReg, hdsp->dds_value);
110462306a36Sopenharmony_ci}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_cistatic int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
110762306a36Sopenharmony_ci{
110862306a36Sopenharmony_ci	int reject_if_open = 0;
110962306a36Sopenharmony_ci	int current_rate;
111062306a36Sopenharmony_ci	int rate_bits;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	/* ASSUMPTION: hdsp->lock is either held, or
111362306a36Sopenharmony_ci	   there is no need for it (e.g. during module
111462306a36Sopenharmony_ci	   initialization).
111562306a36Sopenharmony_ci	*/
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (!(hdsp->control_register & HDSP_ClockModeMaster)) {
111862306a36Sopenharmony_ci		if (called_internally) {
111962306a36Sopenharmony_ci			/* request from ctl or card initialization */
112062306a36Sopenharmony_ci			dev_err(hdsp->card->dev,
112162306a36Sopenharmony_ci				"device is not running as a clock master: cannot set sample rate.\n");
112262306a36Sopenharmony_ci			return -1;
112362306a36Sopenharmony_ci		} else {
112462306a36Sopenharmony_ci			/* hw_param request while in AutoSync mode */
112562306a36Sopenharmony_ci			int external_freq = hdsp_external_sample_rate(hdsp);
112662306a36Sopenharmony_ci			int spdif_freq = hdsp_spdif_sample_rate(hdsp);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci			if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
112962306a36Sopenharmony_ci				dev_info(hdsp->card->dev,
113062306a36Sopenharmony_ci					 "Detected ADAT in double speed mode\n");
113162306a36Sopenharmony_ci			else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
113262306a36Sopenharmony_ci				dev_info(hdsp->card->dev,
113362306a36Sopenharmony_ci					 "Detected ADAT in quad speed mode\n");
113462306a36Sopenharmony_ci			else if (rate != external_freq) {
113562306a36Sopenharmony_ci				dev_info(hdsp->card->dev,
113662306a36Sopenharmony_ci					 "No AutoSync source for requested rate\n");
113762306a36Sopenharmony_ci				return -1;
113862306a36Sopenharmony_ci			}
113962306a36Sopenharmony_ci		}
114062306a36Sopenharmony_ci	}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	current_rate = hdsp->system_sample_rate;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	/* Changing from a "single speed" to a "double speed" rate is
114562306a36Sopenharmony_ci	   not allowed if any substreams are open. This is because
114662306a36Sopenharmony_ci	   such a change causes a shift in the location of
114762306a36Sopenharmony_ci	   the DMA buffers and a reduction in the number of available
114862306a36Sopenharmony_ci	   buffers.
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	   Note that a similar but essentially insoluble problem
115162306a36Sopenharmony_ci	   exists for externally-driven rate changes. All we can do
115262306a36Sopenharmony_ci	   is to flag rate changes in the read/write routines.  */
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	if (rate > 96000 && hdsp->io_type != H9632)
115562306a36Sopenharmony_ci		return -EINVAL;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	switch (rate) {
115862306a36Sopenharmony_ci	case 32000:
115962306a36Sopenharmony_ci		if (current_rate > 48000)
116062306a36Sopenharmony_ci			reject_if_open = 1;
116162306a36Sopenharmony_ci		rate_bits = HDSP_Frequency32KHz;
116262306a36Sopenharmony_ci		break;
116362306a36Sopenharmony_ci	case 44100:
116462306a36Sopenharmony_ci		if (current_rate > 48000)
116562306a36Sopenharmony_ci			reject_if_open = 1;
116662306a36Sopenharmony_ci		rate_bits = HDSP_Frequency44_1KHz;
116762306a36Sopenharmony_ci		break;
116862306a36Sopenharmony_ci	case 48000:
116962306a36Sopenharmony_ci		if (current_rate > 48000)
117062306a36Sopenharmony_ci			reject_if_open = 1;
117162306a36Sopenharmony_ci		rate_bits = HDSP_Frequency48KHz;
117262306a36Sopenharmony_ci		break;
117362306a36Sopenharmony_ci	case 64000:
117462306a36Sopenharmony_ci		if (current_rate <= 48000 || current_rate > 96000)
117562306a36Sopenharmony_ci			reject_if_open = 1;
117662306a36Sopenharmony_ci		rate_bits = HDSP_Frequency64KHz;
117762306a36Sopenharmony_ci		break;
117862306a36Sopenharmony_ci	case 88200:
117962306a36Sopenharmony_ci		if (current_rate <= 48000 || current_rate > 96000)
118062306a36Sopenharmony_ci			reject_if_open = 1;
118162306a36Sopenharmony_ci		rate_bits = HDSP_Frequency88_2KHz;
118262306a36Sopenharmony_ci		break;
118362306a36Sopenharmony_ci	case 96000:
118462306a36Sopenharmony_ci		if (current_rate <= 48000 || current_rate > 96000)
118562306a36Sopenharmony_ci			reject_if_open = 1;
118662306a36Sopenharmony_ci		rate_bits = HDSP_Frequency96KHz;
118762306a36Sopenharmony_ci		break;
118862306a36Sopenharmony_ci	case 128000:
118962306a36Sopenharmony_ci		if (current_rate < 128000)
119062306a36Sopenharmony_ci			reject_if_open = 1;
119162306a36Sopenharmony_ci		rate_bits = HDSP_Frequency128KHz;
119262306a36Sopenharmony_ci		break;
119362306a36Sopenharmony_ci	case 176400:
119462306a36Sopenharmony_ci		if (current_rate < 128000)
119562306a36Sopenharmony_ci			reject_if_open = 1;
119662306a36Sopenharmony_ci		rate_bits = HDSP_Frequency176_4KHz;
119762306a36Sopenharmony_ci		break;
119862306a36Sopenharmony_ci	case 192000:
119962306a36Sopenharmony_ci		if (current_rate < 128000)
120062306a36Sopenharmony_ci			reject_if_open = 1;
120162306a36Sopenharmony_ci		rate_bits = HDSP_Frequency192KHz;
120262306a36Sopenharmony_ci		break;
120362306a36Sopenharmony_ci	default:
120462306a36Sopenharmony_ci		return -EINVAL;
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	if (reject_if_open && (hdsp->capture_pid >= 0 || hdsp->playback_pid >= 0)) {
120862306a36Sopenharmony_ci		dev_warn(hdsp->card->dev,
120962306a36Sopenharmony_ci			 "cannot change speed mode (capture PID = %d, playback PID = %d)\n",
121062306a36Sopenharmony_ci			    hdsp->capture_pid,
121162306a36Sopenharmony_ci			    hdsp->playback_pid);
121262306a36Sopenharmony_ci		return -EBUSY;
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	hdsp->control_register &= ~HDSP_FrequencyMask;
121662306a36Sopenharmony_ci	hdsp->control_register |= rate_bits;
121762306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	/* For HDSP9632 rev 152, need to set DDS value in FREQ register */
122062306a36Sopenharmony_ci	if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
122162306a36Sopenharmony_ci		hdsp_set_dds_value(hdsp, rate);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	if (rate >= 128000) {
122462306a36Sopenharmony_ci		hdsp->channel_map = channel_map_H9632_qs;
122562306a36Sopenharmony_ci	} else if (rate > 48000) {
122662306a36Sopenharmony_ci		if (hdsp->io_type == H9632)
122762306a36Sopenharmony_ci			hdsp->channel_map = channel_map_H9632_ds;
122862306a36Sopenharmony_ci		else
122962306a36Sopenharmony_ci			hdsp->channel_map = channel_map_ds;
123062306a36Sopenharmony_ci	} else {
123162306a36Sopenharmony_ci		switch (hdsp->io_type) {
123262306a36Sopenharmony_ci		case RPM:
123362306a36Sopenharmony_ci		case Multiface:
123462306a36Sopenharmony_ci			hdsp->channel_map = channel_map_mf_ss;
123562306a36Sopenharmony_ci			break;
123662306a36Sopenharmony_ci		case Digiface:
123762306a36Sopenharmony_ci		case H9652:
123862306a36Sopenharmony_ci			hdsp->channel_map = channel_map_df_ss;
123962306a36Sopenharmony_ci			break;
124062306a36Sopenharmony_ci		case H9632:
124162306a36Sopenharmony_ci			hdsp->channel_map = channel_map_H9632_ss;
124262306a36Sopenharmony_ci			break;
124362306a36Sopenharmony_ci		default:
124462306a36Sopenharmony_ci			/* should never happen */
124562306a36Sopenharmony_ci			break;
124662306a36Sopenharmony_ci		}
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	hdsp->system_sample_rate = rate;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	return 0;
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci/*----------------------------------------------------------------------------
125562306a36Sopenharmony_ci   MIDI
125662306a36Sopenharmony_ci  ----------------------------------------------------------------------------*/
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_cistatic unsigned char snd_hdsp_midi_read_byte (struct hdsp *hdsp, int id)
125962306a36Sopenharmony_ci{
126062306a36Sopenharmony_ci	/* the hardware already does the relevant bit-mask with 0xff */
126162306a36Sopenharmony_ci	if (id)
126262306a36Sopenharmony_ci		return hdsp_read(hdsp, HDSP_midiDataIn1);
126362306a36Sopenharmony_ci	else
126462306a36Sopenharmony_ci		return hdsp_read(hdsp, HDSP_midiDataIn0);
126562306a36Sopenharmony_ci}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_cistatic void snd_hdsp_midi_write_byte (struct hdsp *hdsp, int id, int val)
126862306a36Sopenharmony_ci{
126962306a36Sopenharmony_ci	/* the hardware already does the relevant bit-mask with 0xff */
127062306a36Sopenharmony_ci	if (id)
127162306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_midiDataOut1, val);
127262306a36Sopenharmony_ci	else
127362306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_midiDataOut0, val);
127462306a36Sopenharmony_ci}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_cistatic int snd_hdsp_midi_input_available (struct hdsp *hdsp, int id)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	if (id)
127962306a36Sopenharmony_ci		return (hdsp_read(hdsp, HDSP_midiStatusIn1) & 0xff);
128062306a36Sopenharmony_ci	else
128162306a36Sopenharmony_ci		return (hdsp_read(hdsp, HDSP_midiStatusIn0) & 0xff);
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic int snd_hdsp_midi_output_possible (struct hdsp *hdsp, int id)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	int fifo_bytes_used;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if (id)
128962306a36Sopenharmony_ci		fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut1) & 0xff;
129062306a36Sopenharmony_ci	else
129162306a36Sopenharmony_ci		fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut0) & 0xff;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	if (fifo_bytes_used < 128)
129462306a36Sopenharmony_ci		return  128 - fifo_bytes_used;
129562306a36Sopenharmony_ci	else
129662306a36Sopenharmony_ci		return 0;
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_cistatic void snd_hdsp_flush_midi_input (struct hdsp *hdsp, int id)
130062306a36Sopenharmony_ci{
130162306a36Sopenharmony_ci	while (snd_hdsp_midi_input_available (hdsp, id))
130262306a36Sopenharmony_ci		snd_hdsp_midi_read_byte (hdsp, id);
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_cistatic int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi)
130662306a36Sopenharmony_ci{
130762306a36Sopenharmony_ci	unsigned long flags;
130862306a36Sopenharmony_ci	int n_pending;
130962306a36Sopenharmony_ci	int to_write;
131062306a36Sopenharmony_ci	int i;
131162306a36Sopenharmony_ci	unsigned char buf[128];
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	/* Output is not interrupt driven */
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	spin_lock_irqsave (&hmidi->lock, flags);
131662306a36Sopenharmony_ci	if (hmidi->output) {
131762306a36Sopenharmony_ci		if (!snd_rawmidi_transmit_empty (hmidi->output)) {
131862306a36Sopenharmony_ci			n_pending = snd_hdsp_midi_output_possible(hmidi->hdsp, hmidi->id);
131962306a36Sopenharmony_ci			if (n_pending > 0) {
132062306a36Sopenharmony_ci				if (n_pending > (int)sizeof (buf))
132162306a36Sopenharmony_ci					n_pending = sizeof (buf);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci				to_write = snd_rawmidi_transmit(hmidi->output, buf, n_pending);
132462306a36Sopenharmony_ci				if (to_write > 0) {
132562306a36Sopenharmony_ci					for (i = 0; i < to_write; ++i)
132662306a36Sopenharmony_ci						snd_hdsp_midi_write_byte (hmidi->hdsp, hmidi->id, buf[i]);
132762306a36Sopenharmony_ci				}
132862306a36Sopenharmony_ci			}
132962306a36Sopenharmony_ci		}
133062306a36Sopenharmony_ci	}
133162306a36Sopenharmony_ci	spin_unlock_irqrestore (&hmidi->lock, flags);
133262306a36Sopenharmony_ci	return 0;
133362306a36Sopenharmony_ci}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_cistatic int snd_hdsp_midi_input_read (struct hdsp_midi *hmidi)
133662306a36Sopenharmony_ci{
133762306a36Sopenharmony_ci	unsigned char buf[128]; /* this buffer is designed to match the MIDI input FIFO size */
133862306a36Sopenharmony_ci	unsigned long flags;
133962306a36Sopenharmony_ci	int n_pending;
134062306a36Sopenharmony_ci	int i;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	spin_lock_irqsave (&hmidi->lock, flags);
134362306a36Sopenharmony_ci	n_pending = snd_hdsp_midi_input_available(hmidi->hdsp, hmidi->id);
134462306a36Sopenharmony_ci	if (n_pending > 0) {
134562306a36Sopenharmony_ci		if (hmidi->input) {
134662306a36Sopenharmony_ci			if (n_pending > (int)sizeof (buf))
134762306a36Sopenharmony_ci				n_pending = sizeof (buf);
134862306a36Sopenharmony_ci			for (i = 0; i < n_pending; ++i)
134962306a36Sopenharmony_ci				buf[i] = snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id);
135062306a36Sopenharmony_ci			if (n_pending)
135162306a36Sopenharmony_ci				snd_rawmidi_receive (hmidi->input, buf, n_pending);
135262306a36Sopenharmony_ci		} else {
135362306a36Sopenharmony_ci			/* flush the MIDI input FIFO */
135462306a36Sopenharmony_ci			while (--n_pending)
135562306a36Sopenharmony_ci				snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id);
135662306a36Sopenharmony_ci		}
135762306a36Sopenharmony_ci	}
135862306a36Sopenharmony_ci	hmidi->pending = 0;
135962306a36Sopenharmony_ci	if (hmidi->id)
136062306a36Sopenharmony_ci		hmidi->hdsp->control_register |= HDSP_Midi1InterruptEnable;
136162306a36Sopenharmony_ci	else
136262306a36Sopenharmony_ci		hmidi->hdsp->control_register |= HDSP_Midi0InterruptEnable;
136362306a36Sopenharmony_ci	hdsp_write(hmidi->hdsp, HDSP_controlRegister, hmidi->hdsp->control_register);
136462306a36Sopenharmony_ci	spin_unlock_irqrestore (&hmidi->lock, flags);
136562306a36Sopenharmony_ci	return snd_hdsp_midi_output_write (hmidi);
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
136962306a36Sopenharmony_ci{
137062306a36Sopenharmony_ci	struct hdsp *hdsp;
137162306a36Sopenharmony_ci	struct hdsp_midi *hmidi;
137262306a36Sopenharmony_ci	unsigned long flags;
137362306a36Sopenharmony_ci	u32 ie;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
137662306a36Sopenharmony_ci	hdsp = hmidi->hdsp;
137762306a36Sopenharmony_ci	ie = hmidi->id ? HDSP_Midi1InterruptEnable : HDSP_Midi0InterruptEnable;
137862306a36Sopenharmony_ci	spin_lock_irqsave (&hdsp->lock, flags);
137962306a36Sopenharmony_ci	if (up) {
138062306a36Sopenharmony_ci		if (!(hdsp->control_register & ie)) {
138162306a36Sopenharmony_ci			snd_hdsp_flush_midi_input (hdsp, hmidi->id);
138262306a36Sopenharmony_ci			hdsp->control_register |= ie;
138362306a36Sopenharmony_ci		}
138462306a36Sopenharmony_ci	} else {
138562306a36Sopenharmony_ci		hdsp->control_register &= ~ie;
138662306a36Sopenharmony_ci	}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
138962306a36Sopenharmony_ci	spin_unlock_irqrestore (&hdsp->lock, flags);
139062306a36Sopenharmony_ci}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_cistatic void snd_hdsp_midi_output_timer(struct timer_list *t)
139362306a36Sopenharmony_ci{
139462306a36Sopenharmony_ci	struct hdsp_midi *hmidi = from_timer(hmidi, t, timer);
139562306a36Sopenharmony_ci	unsigned long flags;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	snd_hdsp_midi_output_write(hmidi);
139862306a36Sopenharmony_ci	spin_lock_irqsave (&hmidi->lock, flags);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	/* this does not bump hmidi->istimer, because the
140162306a36Sopenharmony_ci	   kernel automatically removed the timer when it
140262306a36Sopenharmony_ci	   expired, and we are now adding it back, thus
140362306a36Sopenharmony_ci	   leaving istimer wherever it was set before.
140462306a36Sopenharmony_ci	*/
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	if (hmidi->istimer)
140762306a36Sopenharmony_ci		mod_timer(&hmidi->timer, 1 + jiffies);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	spin_unlock_irqrestore (&hmidi->lock, flags);
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_cistatic void snd_hdsp_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
141362306a36Sopenharmony_ci{
141462306a36Sopenharmony_ci	struct hdsp_midi *hmidi;
141562306a36Sopenharmony_ci	unsigned long flags;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
141862306a36Sopenharmony_ci	spin_lock_irqsave (&hmidi->lock, flags);
141962306a36Sopenharmony_ci	if (up) {
142062306a36Sopenharmony_ci		if (!hmidi->istimer) {
142162306a36Sopenharmony_ci			timer_setup(&hmidi->timer, snd_hdsp_midi_output_timer,
142262306a36Sopenharmony_ci				    0);
142362306a36Sopenharmony_ci			mod_timer(&hmidi->timer, 1 + jiffies);
142462306a36Sopenharmony_ci			hmidi->istimer++;
142562306a36Sopenharmony_ci		}
142662306a36Sopenharmony_ci	} else {
142762306a36Sopenharmony_ci		if (hmidi->istimer && --hmidi->istimer <= 0)
142862306a36Sopenharmony_ci			del_timer (&hmidi->timer);
142962306a36Sopenharmony_ci	}
143062306a36Sopenharmony_ci	spin_unlock_irqrestore (&hmidi->lock, flags);
143162306a36Sopenharmony_ci	if (up)
143262306a36Sopenharmony_ci		snd_hdsp_midi_output_write(hmidi);
143362306a36Sopenharmony_ci}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_cistatic int snd_hdsp_midi_input_open(struct snd_rawmidi_substream *substream)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct hdsp_midi *hmidi;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
144062306a36Sopenharmony_ci	spin_lock_irq (&hmidi->lock);
144162306a36Sopenharmony_ci	snd_hdsp_flush_midi_input (hmidi->hdsp, hmidi->id);
144262306a36Sopenharmony_ci	hmidi->input = substream;
144362306a36Sopenharmony_ci	spin_unlock_irq (&hmidi->lock);
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	return 0;
144662306a36Sopenharmony_ci}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_cistatic int snd_hdsp_midi_output_open(struct snd_rawmidi_substream *substream)
144962306a36Sopenharmony_ci{
145062306a36Sopenharmony_ci	struct hdsp_midi *hmidi;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
145362306a36Sopenharmony_ci	spin_lock_irq (&hmidi->lock);
145462306a36Sopenharmony_ci	hmidi->output = substream;
145562306a36Sopenharmony_ci	spin_unlock_irq (&hmidi->lock);
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	return 0;
145862306a36Sopenharmony_ci}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_cistatic int snd_hdsp_midi_input_close(struct snd_rawmidi_substream *substream)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	struct hdsp_midi *hmidi;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	snd_hdsp_midi_input_trigger (substream, 0);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
146762306a36Sopenharmony_ci	spin_lock_irq (&hmidi->lock);
146862306a36Sopenharmony_ci	hmidi->input = NULL;
146962306a36Sopenharmony_ci	spin_unlock_irq (&hmidi->lock);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	return 0;
147262306a36Sopenharmony_ci}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cistatic int snd_hdsp_midi_output_close(struct snd_rawmidi_substream *substream)
147562306a36Sopenharmony_ci{
147662306a36Sopenharmony_ci	struct hdsp_midi *hmidi;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	snd_hdsp_midi_output_trigger (substream, 0);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
148162306a36Sopenharmony_ci	spin_lock_irq (&hmidi->lock);
148262306a36Sopenharmony_ci	hmidi->output = NULL;
148362306a36Sopenharmony_ci	spin_unlock_irq (&hmidi->lock);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	return 0;
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_cistatic const struct snd_rawmidi_ops snd_hdsp_midi_output =
148962306a36Sopenharmony_ci{
149062306a36Sopenharmony_ci	.open =		snd_hdsp_midi_output_open,
149162306a36Sopenharmony_ci	.close =	snd_hdsp_midi_output_close,
149262306a36Sopenharmony_ci	.trigger =	snd_hdsp_midi_output_trigger,
149362306a36Sopenharmony_ci};
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_cistatic const struct snd_rawmidi_ops snd_hdsp_midi_input =
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	.open =		snd_hdsp_midi_input_open,
149862306a36Sopenharmony_ci	.close =	snd_hdsp_midi_input_close,
149962306a36Sopenharmony_ci	.trigger =	snd_hdsp_midi_input_trigger,
150062306a36Sopenharmony_ci};
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_cistatic int snd_hdsp_create_midi (struct snd_card *card, struct hdsp *hdsp, int id)
150362306a36Sopenharmony_ci{
150462306a36Sopenharmony_ci	char buf[40];
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	hdsp->midi[id].id = id;
150762306a36Sopenharmony_ci	hdsp->midi[id].rmidi = NULL;
150862306a36Sopenharmony_ci	hdsp->midi[id].input = NULL;
150962306a36Sopenharmony_ci	hdsp->midi[id].output = NULL;
151062306a36Sopenharmony_ci	hdsp->midi[id].hdsp = hdsp;
151162306a36Sopenharmony_ci	hdsp->midi[id].istimer = 0;
151262306a36Sopenharmony_ci	hdsp->midi[id].pending = 0;
151362306a36Sopenharmony_ci	spin_lock_init (&hdsp->midi[id].lock);
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "%s MIDI %d", card->shortname, id + 1);
151662306a36Sopenharmony_ci	if (snd_rawmidi_new (card, buf, id, 1, 1, &hdsp->midi[id].rmidi) < 0)
151762306a36Sopenharmony_ci		return -1;
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	sprintf(hdsp->midi[id].rmidi->name, "HDSP MIDI %d", id+1);
152062306a36Sopenharmony_ci	hdsp->midi[id].rmidi->private_data = &hdsp->midi[id];
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	snd_rawmidi_set_ops (hdsp->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdsp_midi_output);
152362306a36Sopenharmony_ci	snd_rawmidi_set_ops (hdsp->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_hdsp_midi_input);
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	hdsp->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
152662306a36Sopenharmony_ci		SNDRV_RAWMIDI_INFO_INPUT |
152762306a36Sopenharmony_ci		SNDRV_RAWMIDI_INFO_DUPLEX;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	return 0;
153062306a36Sopenharmony_ci}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci/*-----------------------------------------------------------------------------
153362306a36Sopenharmony_ci  Control Interface
153462306a36Sopenharmony_ci  ----------------------------------------------------------------------------*/
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_cistatic u32 snd_hdsp_convert_from_aes(struct snd_aes_iec958 *aes)
153762306a36Sopenharmony_ci{
153862306a36Sopenharmony_ci	u32 val = 0;
153962306a36Sopenharmony_ci	val |= (aes->status[0] & IEC958_AES0_PROFESSIONAL) ? HDSP_SPDIFProfessional : 0;
154062306a36Sopenharmony_ci	val |= (aes->status[0] & IEC958_AES0_NONAUDIO) ? HDSP_SPDIFNonAudio : 0;
154162306a36Sopenharmony_ci	if (val & HDSP_SPDIFProfessional)
154262306a36Sopenharmony_ci		val |= (aes->status[0] & IEC958_AES0_PRO_EMPHASIS_5015) ? HDSP_SPDIFEmphasis : 0;
154362306a36Sopenharmony_ci	else
154462306a36Sopenharmony_ci		val |= (aes->status[0] & IEC958_AES0_CON_EMPHASIS_5015) ? HDSP_SPDIFEmphasis : 0;
154562306a36Sopenharmony_ci	return val;
154662306a36Sopenharmony_ci}
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_cistatic void snd_hdsp_convert_to_aes(struct snd_aes_iec958 *aes, u32 val)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	aes->status[0] = ((val & HDSP_SPDIFProfessional) ? IEC958_AES0_PROFESSIONAL : 0) |
155162306a36Sopenharmony_ci			 ((val & HDSP_SPDIFNonAudio) ? IEC958_AES0_NONAUDIO : 0);
155262306a36Sopenharmony_ci	if (val & HDSP_SPDIFProfessional)
155362306a36Sopenharmony_ci		aes->status[0] |= (val & HDSP_SPDIFEmphasis) ? IEC958_AES0_PRO_EMPHASIS_5015 : 0;
155462306a36Sopenharmony_ci	else
155562306a36Sopenharmony_ci		aes->status[0] |= (val & HDSP_SPDIFEmphasis) ? IEC958_AES0_CON_EMPHASIS_5015 : 0;
155662306a36Sopenharmony_ci}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_cistatic int snd_hdsp_control_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
155962306a36Sopenharmony_ci{
156062306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
156162306a36Sopenharmony_ci	uinfo->count = 1;
156262306a36Sopenharmony_ci	return 0;
156362306a36Sopenharmony_ci}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_cistatic int snd_hdsp_control_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	snd_hdsp_convert_to_aes(&ucontrol->value.iec958, hdsp->creg_spdif);
157062306a36Sopenharmony_ci	return 0;
157162306a36Sopenharmony_ci}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_cistatic int snd_hdsp_control_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
157462306a36Sopenharmony_ci{
157562306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
157662306a36Sopenharmony_ci	int change;
157762306a36Sopenharmony_ci	u32 val;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958);
158062306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
158162306a36Sopenharmony_ci	change = val != hdsp->creg_spdif;
158262306a36Sopenharmony_ci	hdsp->creg_spdif = val;
158362306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
158462306a36Sopenharmony_ci	return change;
158562306a36Sopenharmony_ci}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_cistatic int snd_hdsp_control_spdif_stream_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
159062306a36Sopenharmony_ci	uinfo->count = 1;
159162306a36Sopenharmony_ci	return 0;
159262306a36Sopenharmony_ci}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_cistatic int snd_hdsp_control_spdif_stream_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
159562306a36Sopenharmony_ci{
159662306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	snd_hdsp_convert_to_aes(&ucontrol->value.iec958, hdsp->creg_spdif_stream);
159962306a36Sopenharmony_ci	return 0;
160062306a36Sopenharmony_ci}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_cistatic int snd_hdsp_control_spdif_stream_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
160362306a36Sopenharmony_ci{
160462306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
160562306a36Sopenharmony_ci	int change;
160662306a36Sopenharmony_ci	u32 val;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958);
160962306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
161062306a36Sopenharmony_ci	change = val != hdsp->creg_spdif_stream;
161162306a36Sopenharmony_ci	hdsp->creg_spdif_stream = val;
161262306a36Sopenharmony_ci	hdsp->control_register &= ~(HDSP_SPDIFProfessional | HDSP_SPDIFNonAudio | HDSP_SPDIFEmphasis);
161362306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register |= val);
161462306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
161562306a36Sopenharmony_ci	return change;
161662306a36Sopenharmony_ci}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_cistatic int snd_hdsp_control_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
161962306a36Sopenharmony_ci{
162062306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
162162306a36Sopenharmony_ci	uinfo->count = 1;
162262306a36Sopenharmony_ci	return 0;
162362306a36Sopenharmony_ci}
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_cistatic int snd_hdsp_control_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
162662306a36Sopenharmony_ci{
162762306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = kcontrol->private_value;
162862306a36Sopenharmony_ci	return 0;
162962306a36Sopenharmony_ci}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci#define HDSP_SPDIF_IN(xname, xindex) \
163262306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
163362306a36Sopenharmony_ci  .name = xname, \
163462306a36Sopenharmony_ci  .index = xindex, \
163562306a36Sopenharmony_ci  .info = snd_hdsp_info_spdif_in, \
163662306a36Sopenharmony_ci  .get = snd_hdsp_get_spdif_in, \
163762306a36Sopenharmony_ci  .put = snd_hdsp_put_spdif_in }
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_cistatic unsigned int hdsp_spdif_in(struct hdsp *hdsp)
164062306a36Sopenharmony_ci{
164162306a36Sopenharmony_ci	return hdsp_decode_spdif_in(hdsp->control_register & HDSP_SPDIFInputMask);
164262306a36Sopenharmony_ci}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_cistatic int hdsp_set_spdif_input(struct hdsp *hdsp, int in)
164562306a36Sopenharmony_ci{
164662306a36Sopenharmony_ci	hdsp->control_register &= ~HDSP_SPDIFInputMask;
164762306a36Sopenharmony_ci	hdsp->control_register |= hdsp_encode_spdif_in(in);
164862306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
164962306a36Sopenharmony_ci	return 0;
165062306a36Sopenharmony_ci}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_cistatic int snd_hdsp_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
165362306a36Sopenharmony_ci{
165462306a36Sopenharmony_ci	static const char * const texts[4] = {
165562306a36Sopenharmony_ci		"Optical", "Coaxial", "Internal", "AES"
165662306a36Sopenharmony_ci	};
165762306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 4 : 3,
166062306a36Sopenharmony_ci				 texts);
166162306a36Sopenharmony_ci}
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_cistatic int snd_hdsp_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
166462306a36Sopenharmony_ci{
166562306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_spdif_in(hdsp);
166862306a36Sopenharmony_ci	return 0;
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_cistatic int snd_hdsp_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
167262306a36Sopenharmony_ci{
167362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
167462306a36Sopenharmony_ci	int change;
167562306a36Sopenharmony_ci	unsigned int val;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
167862306a36Sopenharmony_ci		return -EBUSY;
167962306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0] % ((hdsp->io_type == H9632) ? 4 : 3);
168062306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
168162306a36Sopenharmony_ci	change = val != hdsp_spdif_in(hdsp);
168262306a36Sopenharmony_ci	if (change)
168362306a36Sopenharmony_ci		hdsp_set_spdif_input(hdsp, val);
168462306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
168562306a36Sopenharmony_ci	return change;
168662306a36Sopenharmony_ci}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci#define HDSP_TOGGLE_SETTING(xname, xindex) \
168962306a36Sopenharmony_ci{   .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
169062306a36Sopenharmony_ci	.name = xname, \
169162306a36Sopenharmony_ci	.private_value = xindex, \
169262306a36Sopenharmony_ci	.info = snd_hdsp_info_toggle_setting, \
169362306a36Sopenharmony_ci	.get = snd_hdsp_get_toggle_setting, \
169462306a36Sopenharmony_ci	.put = snd_hdsp_put_toggle_setting \
169562306a36Sopenharmony_ci}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_cistatic int hdsp_toggle_setting(struct hdsp *hdsp, u32 regmask)
169862306a36Sopenharmony_ci{
169962306a36Sopenharmony_ci	return (hdsp->control_register & regmask) ? 1 : 0;
170062306a36Sopenharmony_ci}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_cistatic int hdsp_set_toggle_setting(struct hdsp *hdsp, u32 regmask, int out)
170362306a36Sopenharmony_ci{
170462306a36Sopenharmony_ci	if (out)
170562306a36Sopenharmony_ci		hdsp->control_register |= regmask;
170662306a36Sopenharmony_ci	else
170762306a36Sopenharmony_ci		hdsp->control_register &= ~regmask;
170862306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	return 0;
171162306a36Sopenharmony_ci}
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci#define snd_hdsp_info_toggle_setting		   snd_ctl_boolean_mono_info
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_cistatic int snd_hdsp_get_toggle_setting(struct snd_kcontrol *kcontrol,
171662306a36Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
171762306a36Sopenharmony_ci{
171862306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
171962306a36Sopenharmony_ci	u32 regmask = kcontrol->private_value;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
172262306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp_toggle_setting(hdsp, regmask);
172362306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
172462306a36Sopenharmony_ci	return 0;
172562306a36Sopenharmony_ci}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_cistatic int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol,
172862306a36Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
173162306a36Sopenharmony_ci	u32 regmask = kcontrol->private_value;
173262306a36Sopenharmony_ci	int change;
173362306a36Sopenharmony_ci	unsigned int val;
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
173662306a36Sopenharmony_ci		return -EBUSY;
173762306a36Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
173862306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
173962306a36Sopenharmony_ci	change = (int) val != hdsp_toggle_setting(hdsp, regmask);
174062306a36Sopenharmony_ci	if (change)
174162306a36Sopenharmony_ci		hdsp_set_toggle_setting(hdsp, regmask, val);
174262306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
174362306a36Sopenharmony_ci	return change;
174462306a36Sopenharmony_ci}
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci#define HDSP_SPDIF_SAMPLE_RATE(xname, xindex) \
174762306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
174862306a36Sopenharmony_ci  .name = xname, \
174962306a36Sopenharmony_ci  .index = xindex, \
175062306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ, \
175162306a36Sopenharmony_ci  .info = snd_hdsp_info_spdif_sample_rate, \
175262306a36Sopenharmony_ci  .get = snd_hdsp_get_spdif_sample_rate \
175362306a36Sopenharmony_ci}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_cistatic int snd_hdsp_info_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
175662306a36Sopenharmony_ci{
175762306a36Sopenharmony_ci	static const char * const texts[] = {
175862306a36Sopenharmony_ci		"32000", "44100", "48000", "64000", "88200", "96000",
175962306a36Sopenharmony_ci		"None", "128000", "176400", "192000"
176062306a36Sopenharmony_ci	};
176162306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
176462306a36Sopenharmony_ci				 texts);
176562306a36Sopenharmony_ci}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_cistatic int snd_hdsp_get_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	switch (hdsp_spdif_sample_rate(hdsp)) {
177262306a36Sopenharmony_ci	case 32000:
177362306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 0;
177462306a36Sopenharmony_ci		break;
177562306a36Sopenharmony_ci	case 44100:
177662306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 1;
177762306a36Sopenharmony_ci		break;
177862306a36Sopenharmony_ci	case 48000:
177962306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 2;
178062306a36Sopenharmony_ci		break;
178162306a36Sopenharmony_ci	case 64000:
178262306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 3;
178362306a36Sopenharmony_ci		break;
178462306a36Sopenharmony_ci	case 88200:
178562306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 4;
178662306a36Sopenharmony_ci		break;
178762306a36Sopenharmony_ci	case 96000:
178862306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 5;
178962306a36Sopenharmony_ci		break;
179062306a36Sopenharmony_ci	case 128000:
179162306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 7;
179262306a36Sopenharmony_ci		break;
179362306a36Sopenharmony_ci	case 176400:
179462306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 8;
179562306a36Sopenharmony_ci		break;
179662306a36Sopenharmony_ci	case 192000:
179762306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 9;
179862306a36Sopenharmony_ci		break;
179962306a36Sopenharmony_ci	default:
180062306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 6;
180162306a36Sopenharmony_ci	}
180262306a36Sopenharmony_ci	return 0;
180362306a36Sopenharmony_ci}
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci#define HDSP_SYSTEM_SAMPLE_RATE(xname, xindex) \
180662306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
180762306a36Sopenharmony_ci  .name = xname, \
180862306a36Sopenharmony_ci  .index = xindex, \
180962306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ, \
181062306a36Sopenharmony_ci  .info = snd_hdsp_info_system_sample_rate, \
181162306a36Sopenharmony_ci  .get = snd_hdsp_get_system_sample_rate \
181262306a36Sopenharmony_ci}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_cistatic int snd_hdsp_info_system_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
181562306a36Sopenharmony_ci{
181662306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
181762306a36Sopenharmony_ci	uinfo->count = 1;
181862306a36Sopenharmony_ci	return 0;
181962306a36Sopenharmony_ci}
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_cistatic int snd_hdsp_get_system_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
182262306a36Sopenharmony_ci{
182362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp->system_sample_rate;
182662306a36Sopenharmony_ci	return 0;
182762306a36Sopenharmony_ci}
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci#define HDSP_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
183062306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
183162306a36Sopenharmony_ci  .name = xname, \
183262306a36Sopenharmony_ci  .index = xindex, \
183362306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ, \
183462306a36Sopenharmony_ci  .info = snd_hdsp_info_autosync_sample_rate, \
183562306a36Sopenharmony_ci  .get = snd_hdsp_get_autosync_sample_rate \
183662306a36Sopenharmony_ci}
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_cistatic int snd_hdsp_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
183962306a36Sopenharmony_ci{
184062306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
184162306a36Sopenharmony_ci	static const char * const texts[] = {
184262306a36Sopenharmony_ci		"32000", "44100", "48000", "64000", "88200", "96000",
184362306a36Sopenharmony_ci		"None", "128000", "176400", "192000"
184462306a36Sopenharmony_ci	};
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
184762306a36Sopenharmony_ci				 texts);
184862306a36Sopenharmony_ci}
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_cistatic int snd_hdsp_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
185162306a36Sopenharmony_ci{
185262306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	switch (hdsp_external_sample_rate(hdsp)) {
185562306a36Sopenharmony_ci	case 32000:
185662306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 0;
185762306a36Sopenharmony_ci		break;
185862306a36Sopenharmony_ci	case 44100:
185962306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 1;
186062306a36Sopenharmony_ci		break;
186162306a36Sopenharmony_ci	case 48000:
186262306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 2;
186362306a36Sopenharmony_ci		break;
186462306a36Sopenharmony_ci	case 64000:
186562306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 3;
186662306a36Sopenharmony_ci		break;
186762306a36Sopenharmony_ci	case 88200:
186862306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 4;
186962306a36Sopenharmony_ci		break;
187062306a36Sopenharmony_ci	case 96000:
187162306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 5;
187262306a36Sopenharmony_ci		break;
187362306a36Sopenharmony_ci	case 128000:
187462306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 7;
187562306a36Sopenharmony_ci		break;
187662306a36Sopenharmony_ci	case 176400:
187762306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 8;
187862306a36Sopenharmony_ci		break;
187962306a36Sopenharmony_ci	case 192000:
188062306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 9;
188162306a36Sopenharmony_ci		break;
188262306a36Sopenharmony_ci	default:
188362306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 6;
188462306a36Sopenharmony_ci	}
188562306a36Sopenharmony_ci	return 0;
188662306a36Sopenharmony_ci}
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci#define HDSP_SYSTEM_CLOCK_MODE(xname, xindex) \
188962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
189062306a36Sopenharmony_ci  .name = xname, \
189162306a36Sopenharmony_ci  .index = xindex, \
189262306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ, \
189362306a36Sopenharmony_ci  .info = snd_hdsp_info_system_clock_mode, \
189462306a36Sopenharmony_ci  .get = snd_hdsp_get_system_clock_mode \
189562306a36Sopenharmony_ci}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_cistatic int hdsp_system_clock_mode(struct hdsp *hdsp)
189862306a36Sopenharmony_ci{
189962306a36Sopenharmony_ci	if (hdsp->control_register & HDSP_ClockModeMaster)
190062306a36Sopenharmony_ci		return 0;
190162306a36Sopenharmony_ci	else if (hdsp_external_sample_rate(hdsp) != hdsp->system_sample_rate)
190262306a36Sopenharmony_ci			return 0;
190362306a36Sopenharmony_ci	return 1;
190462306a36Sopenharmony_ci}
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_cistatic int snd_hdsp_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
190762306a36Sopenharmony_ci{
190862306a36Sopenharmony_ci	static const char * const texts[] = {"Master", "Slave" };
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 2, texts);
191162306a36Sopenharmony_ci}
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_cistatic int snd_hdsp_get_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
191462306a36Sopenharmony_ci{
191562306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_system_clock_mode(hdsp);
191862306a36Sopenharmony_ci	return 0;
191962306a36Sopenharmony_ci}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci#define HDSP_CLOCK_SOURCE(xname, xindex) \
192262306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
192362306a36Sopenharmony_ci  .name = xname, \
192462306a36Sopenharmony_ci  .index = xindex, \
192562306a36Sopenharmony_ci  .info = snd_hdsp_info_clock_source, \
192662306a36Sopenharmony_ci  .get = snd_hdsp_get_clock_source, \
192762306a36Sopenharmony_ci  .put = snd_hdsp_put_clock_source \
192862306a36Sopenharmony_ci}
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_cistatic int hdsp_clock_source(struct hdsp *hdsp)
193162306a36Sopenharmony_ci{
193262306a36Sopenharmony_ci	if (hdsp->control_register & HDSP_ClockModeMaster) {
193362306a36Sopenharmony_ci		switch (hdsp->system_sample_rate) {
193462306a36Sopenharmony_ci		case 32000:
193562306a36Sopenharmony_ci			return 1;
193662306a36Sopenharmony_ci		case 44100:
193762306a36Sopenharmony_ci			return 2;
193862306a36Sopenharmony_ci		case 48000:
193962306a36Sopenharmony_ci			return 3;
194062306a36Sopenharmony_ci		case 64000:
194162306a36Sopenharmony_ci			return 4;
194262306a36Sopenharmony_ci		case 88200:
194362306a36Sopenharmony_ci			return 5;
194462306a36Sopenharmony_ci		case 96000:
194562306a36Sopenharmony_ci			return 6;
194662306a36Sopenharmony_ci		case 128000:
194762306a36Sopenharmony_ci			return 7;
194862306a36Sopenharmony_ci		case 176400:
194962306a36Sopenharmony_ci			return 8;
195062306a36Sopenharmony_ci		case 192000:
195162306a36Sopenharmony_ci			return 9;
195262306a36Sopenharmony_ci		default:
195362306a36Sopenharmony_ci			return 3;
195462306a36Sopenharmony_ci		}
195562306a36Sopenharmony_ci	} else {
195662306a36Sopenharmony_ci		return 0;
195762306a36Sopenharmony_ci	}
195862306a36Sopenharmony_ci}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_cistatic int hdsp_set_clock_source(struct hdsp *hdsp, int mode)
196162306a36Sopenharmony_ci{
196262306a36Sopenharmony_ci	int rate;
196362306a36Sopenharmony_ci	switch (mode) {
196462306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_AUTOSYNC:
196562306a36Sopenharmony_ci		if (hdsp_external_sample_rate(hdsp) != 0) {
196662306a36Sopenharmony_ci		    if (!hdsp_set_rate(hdsp, hdsp_external_sample_rate(hdsp), 1)) {
196762306a36Sopenharmony_ci			hdsp->control_register &= ~HDSP_ClockModeMaster;
196862306a36Sopenharmony_ci			hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
196962306a36Sopenharmony_ci			return 0;
197062306a36Sopenharmony_ci		    }
197162306a36Sopenharmony_ci		}
197262306a36Sopenharmony_ci		return -1;
197362306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_32KHZ:
197462306a36Sopenharmony_ci		rate = 32000;
197562306a36Sopenharmony_ci		break;
197662306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ:
197762306a36Sopenharmony_ci		rate = 44100;
197862306a36Sopenharmony_ci		break;
197962306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_48KHZ:
198062306a36Sopenharmony_ci		rate = 48000;
198162306a36Sopenharmony_ci		break;
198262306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_64KHZ:
198362306a36Sopenharmony_ci		rate = 64000;
198462306a36Sopenharmony_ci		break;
198562306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ:
198662306a36Sopenharmony_ci		rate = 88200;
198762306a36Sopenharmony_ci		break;
198862306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_96KHZ:
198962306a36Sopenharmony_ci		rate = 96000;
199062306a36Sopenharmony_ci		break;
199162306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_128KHZ:
199262306a36Sopenharmony_ci		rate = 128000;
199362306a36Sopenharmony_ci		break;
199462306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ:
199562306a36Sopenharmony_ci		rate = 176400;
199662306a36Sopenharmony_ci		break;
199762306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_192KHZ:
199862306a36Sopenharmony_ci		rate = 192000;
199962306a36Sopenharmony_ci		break;
200062306a36Sopenharmony_ci	default:
200162306a36Sopenharmony_ci		rate = 48000;
200262306a36Sopenharmony_ci	}
200362306a36Sopenharmony_ci	hdsp->control_register |= HDSP_ClockModeMaster;
200462306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
200562306a36Sopenharmony_ci	hdsp_set_rate(hdsp, rate, 1);
200662306a36Sopenharmony_ci	return 0;
200762306a36Sopenharmony_ci}
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_cistatic int snd_hdsp_info_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
201062306a36Sopenharmony_ci{
201162306a36Sopenharmony_ci	static const char * const texts[] = {
201262306a36Sopenharmony_ci		"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz",
201362306a36Sopenharmony_ci		"Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz",
201462306a36Sopenharmony_ci		"Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz",
201562306a36Sopenharmony_ci		"Internal 192.0 KHz"
201662306a36Sopenharmony_ci	};
201762306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
202062306a36Sopenharmony_ci				 texts);
202162306a36Sopenharmony_ci}
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_cistatic int snd_hdsp_get_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
202462306a36Sopenharmony_ci{
202562306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_clock_source(hdsp);
202862306a36Sopenharmony_ci	return 0;
202962306a36Sopenharmony_ci}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_cistatic int snd_hdsp_put_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
203262306a36Sopenharmony_ci{
203362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
203462306a36Sopenharmony_ci	int change;
203562306a36Sopenharmony_ci	int val;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
203862306a36Sopenharmony_ci		return -EBUSY;
203962306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
204062306a36Sopenharmony_ci	if (val < 0) val = 0;
204162306a36Sopenharmony_ci	if (hdsp->io_type == H9632) {
204262306a36Sopenharmony_ci		if (val > 9)
204362306a36Sopenharmony_ci			val = 9;
204462306a36Sopenharmony_ci	} else {
204562306a36Sopenharmony_ci		if (val > 6)
204662306a36Sopenharmony_ci			val = 6;
204762306a36Sopenharmony_ci	}
204862306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
204962306a36Sopenharmony_ci	if (val != hdsp_clock_source(hdsp))
205062306a36Sopenharmony_ci		change = (hdsp_set_clock_source(hdsp, val) == 0) ? 1 : 0;
205162306a36Sopenharmony_ci	else
205262306a36Sopenharmony_ci		change = 0;
205362306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
205462306a36Sopenharmony_ci	return change;
205562306a36Sopenharmony_ci}
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci#define snd_hdsp_info_clock_source_lock		snd_ctl_boolean_mono_info
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_cistatic int snd_hdsp_get_clock_source_lock(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
206062306a36Sopenharmony_ci{
206162306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp->clock_source_locked;
206462306a36Sopenharmony_ci	return 0;
206562306a36Sopenharmony_ci}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_cistatic int snd_hdsp_put_clock_source_lock(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
206862306a36Sopenharmony_ci{
206962306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
207062306a36Sopenharmony_ci	int change;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	change = (int)ucontrol->value.integer.value[0] != hdsp->clock_source_locked;
207362306a36Sopenharmony_ci	if (change)
207462306a36Sopenharmony_ci		hdsp->clock_source_locked = !!ucontrol->value.integer.value[0];
207562306a36Sopenharmony_ci	return change;
207662306a36Sopenharmony_ci}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci#define HDSP_DA_GAIN(xname, xindex) \
207962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
208062306a36Sopenharmony_ci  .name = xname, \
208162306a36Sopenharmony_ci  .index = xindex, \
208262306a36Sopenharmony_ci  .info = snd_hdsp_info_da_gain, \
208362306a36Sopenharmony_ci  .get = snd_hdsp_get_da_gain, \
208462306a36Sopenharmony_ci  .put = snd_hdsp_put_da_gain \
208562306a36Sopenharmony_ci}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_cistatic int hdsp_da_gain(struct hdsp *hdsp)
208862306a36Sopenharmony_ci{
208962306a36Sopenharmony_ci	switch (hdsp->control_register & HDSP_DAGainMask) {
209062306a36Sopenharmony_ci	case HDSP_DAGainHighGain:
209162306a36Sopenharmony_ci		return 0;
209262306a36Sopenharmony_ci	case HDSP_DAGainPlus4dBu:
209362306a36Sopenharmony_ci		return 1;
209462306a36Sopenharmony_ci	case HDSP_DAGainMinus10dBV:
209562306a36Sopenharmony_ci		return 2;
209662306a36Sopenharmony_ci	default:
209762306a36Sopenharmony_ci		return 1;
209862306a36Sopenharmony_ci	}
209962306a36Sopenharmony_ci}
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_cistatic int hdsp_set_da_gain(struct hdsp *hdsp, int mode)
210262306a36Sopenharmony_ci{
210362306a36Sopenharmony_ci	hdsp->control_register &= ~HDSP_DAGainMask;
210462306a36Sopenharmony_ci	switch (mode) {
210562306a36Sopenharmony_ci	case 0:
210662306a36Sopenharmony_ci		hdsp->control_register |= HDSP_DAGainHighGain;
210762306a36Sopenharmony_ci		break;
210862306a36Sopenharmony_ci	case 1:
210962306a36Sopenharmony_ci		hdsp->control_register |= HDSP_DAGainPlus4dBu;
211062306a36Sopenharmony_ci		break;
211162306a36Sopenharmony_ci	case 2:
211262306a36Sopenharmony_ci		hdsp->control_register |= HDSP_DAGainMinus10dBV;
211362306a36Sopenharmony_ci		break;
211462306a36Sopenharmony_ci	default:
211562306a36Sopenharmony_ci		return -1;
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	}
211862306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
211962306a36Sopenharmony_ci	return 0;
212062306a36Sopenharmony_ci}
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_cistatic int snd_hdsp_info_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
212362306a36Sopenharmony_ci{
212462306a36Sopenharmony_ci	static const char * const texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"};
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
212762306a36Sopenharmony_ci}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_cistatic int snd_hdsp_get_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
213062306a36Sopenharmony_ci{
213162306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_da_gain(hdsp);
213462306a36Sopenharmony_ci	return 0;
213562306a36Sopenharmony_ci}
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_cistatic int snd_hdsp_put_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
213862306a36Sopenharmony_ci{
213962306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
214062306a36Sopenharmony_ci	int change;
214162306a36Sopenharmony_ci	int val;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
214462306a36Sopenharmony_ci		return -EBUSY;
214562306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
214662306a36Sopenharmony_ci	if (val < 0) val = 0;
214762306a36Sopenharmony_ci	if (val > 2) val = 2;
214862306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
214962306a36Sopenharmony_ci	if (val != hdsp_da_gain(hdsp))
215062306a36Sopenharmony_ci		change = (hdsp_set_da_gain(hdsp, val) == 0) ? 1 : 0;
215162306a36Sopenharmony_ci	else
215262306a36Sopenharmony_ci		change = 0;
215362306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
215462306a36Sopenharmony_ci	return change;
215562306a36Sopenharmony_ci}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci#define HDSP_AD_GAIN(xname, xindex) \
215862306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
215962306a36Sopenharmony_ci  .name = xname, \
216062306a36Sopenharmony_ci  .index = xindex, \
216162306a36Sopenharmony_ci  .info = snd_hdsp_info_ad_gain, \
216262306a36Sopenharmony_ci  .get = snd_hdsp_get_ad_gain, \
216362306a36Sopenharmony_ci  .put = snd_hdsp_put_ad_gain \
216462306a36Sopenharmony_ci}
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_cistatic int hdsp_ad_gain(struct hdsp *hdsp)
216762306a36Sopenharmony_ci{
216862306a36Sopenharmony_ci	switch (hdsp->control_register & HDSP_ADGainMask) {
216962306a36Sopenharmony_ci	case HDSP_ADGainMinus10dBV:
217062306a36Sopenharmony_ci		return 0;
217162306a36Sopenharmony_ci	case HDSP_ADGainPlus4dBu:
217262306a36Sopenharmony_ci		return 1;
217362306a36Sopenharmony_ci	case HDSP_ADGainLowGain:
217462306a36Sopenharmony_ci		return 2;
217562306a36Sopenharmony_ci	default:
217662306a36Sopenharmony_ci		return 1;
217762306a36Sopenharmony_ci	}
217862306a36Sopenharmony_ci}
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_cistatic int hdsp_set_ad_gain(struct hdsp *hdsp, int mode)
218162306a36Sopenharmony_ci{
218262306a36Sopenharmony_ci	hdsp->control_register &= ~HDSP_ADGainMask;
218362306a36Sopenharmony_ci	switch (mode) {
218462306a36Sopenharmony_ci	case 0:
218562306a36Sopenharmony_ci		hdsp->control_register |= HDSP_ADGainMinus10dBV;
218662306a36Sopenharmony_ci		break;
218762306a36Sopenharmony_ci	case 1:
218862306a36Sopenharmony_ci		hdsp->control_register |= HDSP_ADGainPlus4dBu;
218962306a36Sopenharmony_ci		break;
219062306a36Sopenharmony_ci	case 2:
219162306a36Sopenharmony_ci		hdsp->control_register |= HDSP_ADGainLowGain;
219262306a36Sopenharmony_ci		break;
219362306a36Sopenharmony_ci	default:
219462306a36Sopenharmony_ci		return -1;
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	}
219762306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
219862306a36Sopenharmony_ci	return 0;
219962306a36Sopenharmony_ci}
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_cistatic int snd_hdsp_info_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
220262306a36Sopenharmony_ci{
220362306a36Sopenharmony_ci	static const char * const texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"};
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
220662306a36Sopenharmony_ci}
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_cistatic int snd_hdsp_get_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
220962306a36Sopenharmony_ci{
221062306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_ad_gain(hdsp);
221362306a36Sopenharmony_ci	return 0;
221462306a36Sopenharmony_ci}
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_cistatic int snd_hdsp_put_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
221762306a36Sopenharmony_ci{
221862306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
221962306a36Sopenharmony_ci	int change;
222062306a36Sopenharmony_ci	int val;
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
222362306a36Sopenharmony_ci		return -EBUSY;
222462306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
222562306a36Sopenharmony_ci	if (val < 0) val = 0;
222662306a36Sopenharmony_ci	if (val > 2) val = 2;
222762306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
222862306a36Sopenharmony_ci	if (val != hdsp_ad_gain(hdsp))
222962306a36Sopenharmony_ci		change = (hdsp_set_ad_gain(hdsp, val) == 0) ? 1 : 0;
223062306a36Sopenharmony_ci	else
223162306a36Sopenharmony_ci		change = 0;
223262306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
223362306a36Sopenharmony_ci	return change;
223462306a36Sopenharmony_ci}
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci#define HDSP_PHONE_GAIN(xname, xindex) \
223762306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
223862306a36Sopenharmony_ci  .name = xname, \
223962306a36Sopenharmony_ci  .index = xindex, \
224062306a36Sopenharmony_ci  .info = snd_hdsp_info_phone_gain, \
224162306a36Sopenharmony_ci  .get = snd_hdsp_get_phone_gain, \
224262306a36Sopenharmony_ci  .put = snd_hdsp_put_phone_gain \
224362306a36Sopenharmony_ci}
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_cistatic int hdsp_phone_gain(struct hdsp *hdsp)
224662306a36Sopenharmony_ci{
224762306a36Sopenharmony_ci	switch (hdsp->control_register & HDSP_PhoneGainMask) {
224862306a36Sopenharmony_ci	case HDSP_PhoneGain0dB:
224962306a36Sopenharmony_ci		return 0;
225062306a36Sopenharmony_ci	case HDSP_PhoneGainMinus6dB:
225162306a36Sopenharmony_ci		return 1;
225262306a36Sopenharmony_ci	case HDSP_PhoneGainMinus12dB:
225362306a36Sopenharmony_ci		return 2;
225462306a36Sopenharmony_ci	default:
225562306a36Sopenharmony_ci		return 0;
225662306a36Sopenharmony_ci	}
225762306a36Sopenharmony_ci}
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_cistatic int hdsp_set_phone_gain(struct hdsp *hdsp, int mode)
226062306a36Sopenharmony_ci{
226162306a36Sopenharmony_ci	hdsp->control_register &= ~HDSP_PhoneGainMask;
226262306a36Sopenharmony_ci	switch (mode) {
226362306a36Sopenharmony_ci	case 0:
226462306a36Sopenharmony_ci		hdsp->control_register |= HDSP_PhoneGain0dB;
226562306a36Sopenharmony_ci		break;
226662306a36Sopenharmony_ci	case 1:
226762306a36Sopenharmony_ci		hdsp->control_register |= HDSP_PhoneGainMinus6dB;
226862306a36Sopenharmony_ci		break;
226962306a36Sopenharmony_ci	case 2:
227062306a36Sopenharmony_ci		hdsp->control_register |= HDSP_PhoneGainMinus12dB;
227162306a36Sopenharmony_ci		break;
227262306a36Sopenharmony_ci	default:
227362306a36Sopenharmony_ci		return -1;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	}
227662306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
227762306a36Sopenharmony_ci	return 0;
227862306a36Sopenharmony_ci}
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_cistatic int snd_hdsp_info_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
228162306a36Sopenharmony_ci{
228262306a36Sopenharmony_ci	static const char * const texts[] = {"0 dB", "-6 dB", "-12 dB"};
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
228562306a36Sopenharmony_ci}
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_cistatic int snd_hdsp_get_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
228862306a36Sopenharmony_ci{
228962306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_phone_gain(hdsp);
229262306a36Sopenharmony_ci	return 0;
229362306a36Sopenharmony_ci}
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_cistatic int snd_hdsp_put_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
229662306a36Sopenharmony_ci{
229762306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
229862306a36Sopenharmony_ci	int change;
229962306a36Sopenharmony_ci	int val;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
230262306a36Sopenharmony_ci		return -EBUSY;
230362306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
230462306a36Sopenharmony_ci	if (val < 0) val = 0;
230562306a36Sopenharmony_ci	if (val > 2) val = 2;
230662306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
230762306a36Sopenharmony_ci	if (val != hdsp_phone_gain(hdsp))
230862306a36Sopenharmony_ci		change = (hdsp_set_phone_gain(hdsp, val) == 0) ? 1 : 0;
230962306a36Sopenharmony_ci	else
231062306a36Sopenharmony_ci		change = 0;
231162306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
231262306a36Sopenharmony_ci	return change;
231362306a36Sopenharmony_ci}
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci#define HDSP_PREF_SYNC_REF(xname, xindex) \
231662306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
231762306a36Sopenharmony_ci  .name = xname, \
231862306a36Sopenharmony_ci  .index = xindex, \
231962306a36Sopenharmony_ci  .info = snd_hdsp_info_pref_sync_ref, \
232062306a36Sopenharmony_ci  .get = snd_hdsp_get_pref_sync_ref, \
232162306a36Sopenharmony_ci  .put = snd_hdsp_put_pref_sync_ref \
232262306a36Sopenharmony_ci}
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_cistatic int hdsp_pref_sync_ref(struct hdsp *hdsp)
232562306a36Sopenharmony_ci{
232662306a36Sopenharmony_ci	/* Notice that this looks at the requested sync source,
232762306a36Sopenharmony_ci	   not the one actually in use.
232862306a36Sopenharmony_ci	*/
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	switch (hdsp->control_register & HDSP_SyncRefMask) {
233162306a36Sopenharmony_ci	case HDSP_SyncRef_ADAT1:
233262306a36Sopenharmony_ci		return HDSP_SYNC_FROM_ADAT1;
233362306a36Sopenharmony_ci	case HDSP_SyncRef_ADAT2:
233462306a36Sopenharmony_ci		return HDSP_SYNC_FROM_ADAT2;
233562306a36Sopenharmony_ci	case HDSP_SyncRef_ADAT3:
233662306a36Sopenharmony_ci		return HDSP_SYNC_FROM_ADAT3;
233762306a36Sopenharmony_ci	case HDSP_SyncRef_SPDIF:
233862306a36Sopenharmony_ci		return HDSP_SYNC_FROM_SPDIF;
233962306a36Sopenharmony_ci	case HDSP_SyncRef_WORD:
234062306a36Sopenharmony_ci		return HDSP_SYNC_FROM_WORD;
234162306a36Sopenharmony_ci	case HDSP_SyncRef_ADAT_SYNC:
234262306a36Sopenharmony_ci		return HDSP_SYNC_FROM_ADAT_SYNC;
234362306a36Sopenharmony_ci	default:
234462306a36Sopenharmony_ci		return HDSP_SYNC_FROM_WORD;
234562306a36Sopenharmony_ci	}
234662306a36Sopenharmony_ci	return 0;
234762306a36Sopenharmony_ci}
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_cistatic int hdsp_set_pref_sync_ref(struct hdsp *hdsp, int pref)
235062306a36Sopenharmony_ci{
235162306a36Sopenharmony_ci	hdsp->control_register &= ~HDSP_SyncRefMask;
235262306a36Sopenharmony_ci	switch (pref) {
235362306a36Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT1:
235462306a36Sopenharmony_ci		hdsp->control_register &= ~HDSP_SyncRefMask; /* clear SyncRef bits */
235562306a36Sopenharmony_ci		break;
235662306a36Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT2:
235762306a36Sopenharmony_ci		hdsp->control_register |= HDSP_SyncRef_ADAT2;
235862306a36Sopenharmony_ci		break;
235962306a36Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT3:
236062306a36Sopenharmony_ci		hdsp->control_register |= HDSP_SyncRef_ADAT3;
236162306a36Sopenharmony_ci		break;
236262306a36Sopenharmony_ci	case HDSP_SYNC_FROM_SPDIF:
236362306a36Sopenharmony_ci		hdsp->control_register |= HDSP_SyncRef_SPDIF;
236462306a36Sopenharmony_ci		break;
236562306a36Sopenharmony_ci	case HDSP_SYNC_FROM_WORD:
236662306a36Sopenharmony_ci		hdsp->control_register |= HDSP_SyncRef_WORD;
236762306a36Sopenharmony_ci		break;
236862306a36Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT_SYNC:
236962306a36Sopenharmony_ci		hdsp->control_register |= HDSP_SyncRef_ADAT_SYNC;
237062306a36Sopenharmony_ci		break;
237162306a36Sopenharmony_ci	default:
237262306a36Sopenharmony_ci		return -1;
237362306a36Sopenharmony_ci	}
237462306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
237562306a36Sopenharmony_ci	return 0;
237662306a36Sopenharmony_ci}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_cistatic int snd_hdsp_info_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
237962306a36Sopenharmony_ci{
238062306a36Sopenharmony_ci	static const char * const texts[] = {
238162306a36Sopenharmony_ci		"Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3"
238262306a36Sopenharmony_ci	};
238362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
238462306a36Sopenharmony_ci	int num_items;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	switch (hdsp->io_type) {
238762306a36Sopenharmony_ci	case Digiface:
238862306a36Sopenharmony_ci	case H9652:
238962306a36Sopenharmony_ci		num_items = 6;
239062306a36Sopenharmony_ci		break;
239162306a36Sopenharmony_ci	case Multiface:
239262306a36Sopenharmony_ci		num_items = 4;
239362306a36Sopenharmony_ci		break;
239462306a36Sopenharmony_ci	case H9632:
239562306a36Sopenharmony_ci		num_items = 3;
239662306a36Sopenharmony_ci		break;
239762306a36Sopenharmony_ci	default:
239862306a36Sopenharmony_ci		return -EINVAL;
239962306a36Sopenharmony_ci	}
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, num_items, texts);
240262306a36Sopenharmony_ci}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_cistatic int snd_hdsp_get_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
240562306a36Sopenharmony_ci{
240662306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp);
240962306a36Sopenharmony_ci	return 0;
241062306a36Sopenharmony_ci}
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_cistatic int snd_hdsp_put_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
241362306a36Sopenharmony_ci{
241462306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
241562306a36Sopenharmony_ci	int change, max;
241662306a36Sopenharmony_ci	unsigned int val;
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
241962306a36Sopenharmony_ci		return -EBUSY;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	switch (hdsp->io_type) {
242262306a36Sopenharmony_ci	case Digiface:
242362306a36Sopenharmony_ci	case H9652:
242462306a36Sopenharmony_ci		max = 6;
242562306a36Sopenharmony_ci		break;
242662306a36Sopenharmony_ci	case Multiface:
242762306a36Sopenharmony_ci		max = 4;
242862306a36Sopenharmony_ci		break;
242962306a36Sopenharmony_ci	case H9632:
243062306a36Sopenharmony_ci		max = 3;
243162306a36Sopenharmony_ci		break;
243262306a36Sopenharmony_ci	default:
243362306a36Sopenharmony_ci		return -EIO;
243462306a36Sopenharmony_ci	}
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0] % max;
243762306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
243862306a36Sopenharmony_ci	change = (int)val != hdsp_pref_sync_ref(hdsp);
243962306a36Sopenharmony_ci	hdsp_set_pref_sync_ref(hdsp, val);
244062306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
244162306a36Sopenharmony_ci	return change;
244262306a36Sopenharmony_ci}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci#define HDSP_AUTOSYNC_REF(xname, xindex) \
244562306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
244662306a36Sopenharmony_ci  .name = xname, \
244762306a36Sopenharmony_ci  .index = xindex, \
244862306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ, \
244962306a36Sopenharmony_ci  .info = snd_hdsp_info_autosync_ref, \
245062306a36Sopenharmony_ci  .get = snd_hdsp_get_autosync_ref, \
245162306a36Sopenharmony_ci}
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_cistatic int hdsp_autosync_ref(struct hdsp *hdsp)
245462306a36Sopenharmony_ci{
245562306a36Sopenharmony_ci	/* This looks at the autosync selected sync reference */
245662306a36Sopenharmony_ci	unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register);
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	switch (status2 & HDSP_SelSyncRefMask) {
245962306a36Sopenharmony_ci	case HDSP_SelSyncRef_WORD:
246062306a36Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_WORD;
246162306a36Sopenharmony_ci	case HDSP_SelSyncRef_ADAT_SYNC:
246262306a36Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_ADAT_SYNC;
246362306a36Sopenharmony_ci	case HDSP_SelSyncRef_SPDIF:
246462306a36Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_SPDIF;
246562306a36Sopenharmony_ci	case HDSP_SelSyncRefMask:
246662306a36Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_NONE;
246762306a36Sopenharmony_ci	case HDSP_SelSyncRef_ADAT1:
246862306a36Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_ADAT1;
246962306a36Sopenharmony_ci	case HDSP_SelSyncRef_ADAT2:
247062306a36Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_ADAT2;
247162306a36Sopenharmony_ci	case HDSP_SelSyncRef_ADAT3:
247262306a36Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_ADAT3;
247362306a36Sopenharmony_ci	default:
247462306a36Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_WORD;
247562306a36Sopenharmony_ci	}
247662306a36Sopenharmony_ci	return 0;
247762306a36Sopenharmony_ci}
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_cistatic int snd_hdsp_info_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
248062306a36Sopenharmony_ci{
248162306a36Sopenharmony_ci	static const char * const texts[] = {
248262306a36Sopenharmony_ci		"Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3"
248362306a36Sopenharmony_ci	};
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 7, texts);
248662306a36Sopenharmony_ci}
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_cistatic int snd_hdsp_get_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
248962306a36Sopenharmony_ci{
249062306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_autosync_ref(hdsp);
249362306a36Sopenharmony_ci	return 0;
249462306a36Sopenharmony_ci}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci#define HDSP_PRECISE_POINTER(xname, xindex) \
249762306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
249862306a36Sopenharmony_ci  .name = xname, \
249962306a36Sopenharmony_ci  .index = xindex, \
250062306a36Sopenharmony_ci  .info = snd_hdsp_info_precise_pointer, \
250162306a36Sopenharmony_ci  .get = snd_hdsp_get_precise_pointer, \
250262306a36Sopenharmony_ci  .put = snd_hdsp_put_precise_pointer \
250362306a36Sopenharmony_ci}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_cistatic int hdsp_set_precise_pointer(struct hdsp *hdsp, int precise)
250662306a36Sopenharmony_ci{
250762306a36Sopenharmony_ci	if (precise)
250862306a36Sopenharmony_ci		hdsp->precise_ptr = 1;
250962306a36Sopenharmony_ci	else
251062306a36Sopenharmony_ci		hdsp->precise_ptr = 0;
251162306a36Sopenharmony_ci	return 0;
251262306a36Sopenharmony_ci}
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci#define snd_hdsp_info_precise_pointer		snd_ctl_boolean_mono_info
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_cistatic int snd_hdsp_get_precise_pointer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
251762306a36Sopenharmony_ci{
251862306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
252162306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp->precise_ptr;
252262306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
252362306a36Sopenharmony_ci	return 0;
252462306a36Sopenharmony_ci}
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_cistatic int snd_hdsp_put_precise_pointer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
252762306a36Sopenharmony_ci{
252862306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
252962306a36Sopenharmony_ci	int change;
253062306a36Sopenharmony_ci	unsigned int val;
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
253362306a36Sopenharmony_ci		return -EBUSY;
253462306a36Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
253562306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
253662306a36Sopenharmony_ci	change = (int)val != hdsp->precise_ptr;
253762306a36Sopenharmony_ci	hdsp_set_precise_pointer(hdsp, val);
253862306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
253962306a36Sopenharmony_ci	return change;
254062306a36Sopenharmony_ci}
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci#define HDSP_USE_MIDI_WORK(xname, xindex) \
254362306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
254462306a36Sopenharmony_ci  .name = xname, \
254562306a36Sopenharmony_ci  .index = xindex, \
254662306a36Sopenharmony_ci  .info = snd_hdsp_info_use_midi_work, \
254762306a36Sopenharmony_ci  .get = snd_hdsp_get_use_midi_work, \
254862306a36Sopenharmony_ci  .put = snd_hdsp_put_use_midi_work \
254962306a36Sopenharmony_ci}
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_cistatic int hdsp_set_use_midi_work(struct hdsp *hdsp, int use_work)
255262306a36Sopenharmony_ci{
255362306a36Sopenharmony_ci	if (use_work)
255462306a36Sopenharmony_ci		hdsp->use_midi_work = 1;
255562306a36Sopenharmony_ci	else
255662306a36Sopenharmony_ci		hdsp->use_midi_work = 0;
255762306a36Sopenharmony_ci	return 0;
255862306a36Sopenharmony_ci}
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ci#define snd_hdsp_info_use_midi_work		snd_ctl_boolean_mono_info
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_cistatic int snd_hdsp_get_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
256362306a36Sopenharmony_ci{
256462306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
256762306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp->use_midi_work;
256862306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
256962306a36Sopenharmony_ci	return 0;
257062306a36Sopenharmony_ci}
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_cistatic int snd_hdsp_put_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
257362306a36Sopenharmony_ci{
257462306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
257562306a36Sopenharmony_ci	int change;
257662306a36Sopenharmony_ci	unsigned int val;
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
257962306a36Sopenharmony_ci		return -EBUSY;
258062306a36Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
258162306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
258262306a36Sopenharmony_ci	change = (int)val != hdsp->use_midi_work;
258362306a36Sopenharmony_ci	hdsp_set_use_midi_work(hdsp, val);
258462306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
258562306a36Sopenharmony_ci	return change;
258662306a36Sopenharmony_ci}
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci#define HDSP_MIXER(xname, xindex) \
258962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
259062306a36Sopenharmony_ci  .name = xname, \
259162306a36Sopenharmony_ci  .index = xindex, \
259262306a36Sopenharmony_ci  .device = 0, \
259362306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
259462306a36Sopenharmony_ci		 SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
259562306a36Sopenharmony_ci  .info = snd_hdsp_info_mixer, \
259662306a36Sopenharmony_ci  .get = snd_hdsp_get_mixer, \
259762306a36Sopenharmony_ci  .put = snd_hdsp_put_mixer \
259862306a36Sopenharmony_ci}
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_cistatic int snd_hdsp_info_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
260162306a36Sopenharmony_ci{
260262306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
260362306a36Sopenharmony_ci	uinfo->count = 3;
260462306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
260562306a36Sopenharmony_ci	uinfo->value.integer.max = 65536;
260662306a36Sopenharmony_ci	uinfo->value.integer.step = 1;
260762306a36Sopenharmony_ci	return 0;
260862306a36Sopenharmony_ci}
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_cistatic int snd_hdsp_get_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
261162306a36Sopenharmony_ci{
261262306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
261362306a36Sopenharmony_ci	int source;
261462306a36Sopenharmony_ci	int destination;
261562306a36Sopenharmony_ci	int addr;
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	source = ucontrol->value.integer.value[0];
261862306a36Sopenharmony_ci	destination = ucontrol->value.integer.value[1];
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	if (source >= hdsp->max_channels)
262162306a36Sopenharmony_ci		addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels,destination);
262262306a36Sopenharmony_ci	else
262362306a36Sopenharmony_ci		addr = hdsp_input_to_output_key(hdsp,source, destination);
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
262662306a36Sopenharmony_ci	ucontrol->value.integer.value[2] = hdsp_read_gain (hdsp, addr);
262762306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
262862306a36Sopenharmony_ci	return 0;
262962306a36Sopenharmony_ci}
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_cistatic int snd_hdsp_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
263262306a36Sopenharmony_ci{
263362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
263462306a36Sopenharmony_ci	int change;
263562306a36Sopenharmony_ci	int source;
263662306a36Sopenharmony_ci	int destination;
263762306a36Sopenharmony_ci	int gain;
263862306a36Sopenharmony_ci	int addr;
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
264162306a36Sopenharmony_ci		return -EBUSY;
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	source = ucontrol->value.integer.value[0];
264462306a36Sopenharmony_ci	destination = ucontrol->value.integer.value[1];
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	if (source >= hdsp->max_channels)
264762306a36Sopenharmony_ci		addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels, destination);
264862306a36Sopenharmony_ci	else
264962306a36Sopenharmony_ci		addr = hdsp_input_to_output_key(hdsp,source, destination);
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	gain = ucontrol->value.integer.value[2];
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
265462306a36Sopenharmony_ci	change = gain != hdsp_read_gain(hdsp, addr);
265562306a36Sopenharmony_ci	if (change)
265662306a36Sopenharmony_ci		hdsp_write_gain(hdsp, addr, gain);
265762306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
265862306a36Sopenharmony_ci	return change;
265962306a36Sopenharmony_ci}
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci#define HDSP_WC_SYNC_CHECK(xname, xindex) \
266262306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
266362306a36Sopenharmony_ci  .name = xname, \
266462306a36Sopenharmony_ci  .index = xindex, \
266562306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
266662306a36Sopenharmony_ci  .info = snd_hdsp_info_sync_check, \
266762306a36Sopenharmony_ci  .get = snd_hdsp_get_wc_sync_check \
266862306a36Sopenharmony_ci}
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_cistatic int snd_hdsp_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
267162306a36Sopenharmony_ci{
267262306a36Sopenharmony_ci	static const char * const texts[] = {"No Lock", "Lock", "Sync" };
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
267562306a36Sopenharmony_ci}
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_cistatic int hdsp_wc_sync_check(struct hdsp *hdsp)
267862306a36Sopenharmony_ci{
267962306a36Sopenharmony_ci	int status2 = hdsp_read(hdsp, HDSP_status2Register);
268062306a36Sopenharmony_ci	if (status2 & HDSP_wc_lock) {
268162306a36Sopenharmony_ci		if (status2 & HDSP_wc_sync)
268262306a36Sopenharmony_ci			return 2;
268362306a36Sopenharmony_ci		else
268462306a36Sopenharmony_ci			 return 1;
268562306a36Sopenharmony_ci	} else
268662306a36Sopenharmony_ci		return 0;
268762306a36Sopenharmony_ci	return 0;
268862306a36Sopenharmony_ci}
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_cistatic int snd_hdsp_get_wc_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
269162306a36Sopenharmony_ci{
269262306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_wc_sync_check(hdsp);
269562306a36Sopenharmony_ci	return 0;
269662306a36Sopenharmony_ci}
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci#define HDSP_SPDIF_SYNC_CHECK(xname, xindex) \
269962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
270062306a36Sopenharmony_ci  .name = xname, \
270162306a36Sopenharmony_ci  .index = xindex, \
270262306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
270362306a36Sopenharmony_ci  .info = snd_hdsp_info_sync_check, \
270462306a36Sopenharmony_ci  .get = snd_hdsp_get_spdif_sync_check \
270562306a36Sopenharmony_ci}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_cistatic int hdsp_spdif_sync_check(struct hdsp *hdsp)
270862306a36Sopenharmony_ci{
270962306a36Sopenharmony_ci	int status = hdsp_read(hdsp, HDSP_statusRegister);
271062306a36Sopenharmony_ci	if (status & HDSP_SPDIFErrorFlag)
271162306a36Sopenharmony_ci		return 0;
271262306a36Sopenharmony_ci	else {
271362306a36Sopenharmony_ci		if (status & HDSP_SPDIFSync)
271462306a36Sopenharmony_ci			return 2;
271562306a36Sopenharmony_ci		else
271662306a36Sopenharmony_ci			return 1;
271762306a36Sopenharmony_ci	}
271862306a36Sopenharmony_ci	return 0;
271962306a36Sopenharmony_ci}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_cistatic int snd_hdsp_get_spdif_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
272262306a36Sopenharmony_ci{
272362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_spdif_sync_check(hdsp);
272662306a36Sopenharmony_ci	return 0;
272762306a36Sopenharmony_ci}
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci#define HDSP_ADATSYNC_SYNC_CHECK(xname, xindex) \
273062306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
273162306a36Sopenharmony_ci  .name = xname, \
273262306a36Sopenharmony_ci  .index = xindex, \
273362306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
273462306a36Sopenharmony_ci  .info = snd_hdsp_info_sync_check, \
273562306a36Sopenharmony_ci  .get = snd_hdsp_get_adatsync_sync_check \
273662306a36Sopenharmony_ci}
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_cistatic int hdsp_adatsync_sync_check(struct hdsp *hdsp)
273962306a36Sopenharmony_ci{
274062306a36Sopenharmony_ci	int status = hdsp_read(hdsp, HDSP_statusRegister);
274162306a36Sopenharmony_ci	if (status & HDSP_TimecodeLock) {
274262306a36Sopenharmony_ci		if (status & HDSP_TimecodeSync)
274362306a36Sopenharmony_ci			return 2;
274462306a36Sopenharmony_ci		else
274562306a36Sopenharmony_ci			return 1;
274662306a36Sopenharmony_ci	} else
274762306a36Sopenharmony_ci		return 0;
274862306a36Sopenharmony_ci}
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_cistatic int snd_hdsp_get_adatsync_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
275162306a36Sopenharmony_ci{
275262306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_adatsync_sync_check(hdsp);
275562306a36Sopenharmony_ci	return 0;
275662306a36Sopenharmony_ci}
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci#define HDSP_ADAT_SYNC_CHECK \
275962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
276062306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
276162306a36Sopenharmony_ci  .info = snd_hdsp_info_sync_check, \
276262306a36Sopenharmony_ci  .get = snd_hdsp_get_adat_sync_check \
276362306a36Sopenharmony_ci}
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_cistatic int hdsp_adat_sync_check(struct hdsp *hdsp, int idx)
276662306a36Sopenharmony_ci{
276762306a36Sopenharmony_ci	int status = hdsp_read(hdsp, HDSP_statusRegister);
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci	if (status & (HDSP_Lock0>>idx)) {
277062306a36Sopenharmony_ci		if (status & (HDSP_Sync0>>idx))
277162306a36Sopenharmony_ci			return 2;
277262306a36Sopenharmony_ci		else
277362306a36Sopenharmony_ci			return 1;
277462306a36Sopenharmony_ci	} else
277562306a36Sopenharmony_ci		return 0;
277662306a36Sopenharmony_ci}
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_cistatic int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
277962306a36Sopenharmony_ci{
278062306a36Sopenharmony_ci	int offset;
278162306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	offset = ucontrol->id.index - 1;
278462306a36Sopenharmony_ci	if (snd_BUG_ON(offset < 0))
278562306a36Sopenharmony_ci		return -EINVAL;
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	switch (hdsp->io_type) {
278862306a36Sopenharmony_ci	case Digiface:
278962306a36Sopenharmony_ci	case H9652:
279062306a36Sopenharmony_ci		if (offset >= 3)
279162306a36Sopenharmony_ci			return -EINVAL;
279262306a36Sopenharmony_ci		break;
279362306a36Sopenharmony_ci	case Multiface:
279462306a36Sopenharmony_ci	case H9632:
279562306a36Sopenharmony_ci		if (offset >= 1)
279662306a36Sopenharmony_ci			return -EINVAL;
279762306a36Sopenharmony_ci		break;
279862306a36Sopenharmony_ci	default:
279962306a36Sopenharmony_ci		return -EIO;
280062306a36Sopenharmony_ci	}
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_adat_sync_check(hdsp, offset);
280362306a36Sopenharmony_ci	return 0;
280462306a36Sopenharmony_ci}
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci#define HDSP_DDS_OFFSET(xname, xindex) \
280762306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
280862306a36Sopenharmony_ci  .name = xname, \
280962306a36Sopenharmony_ci  .index = xindex, \
281062306a36Sopenharmony_ci  .info = snd_hdsp_info_dds_offset, \
281162306a36Sopenharmony_ci  .get = snd_hdsp_get_dds_offset, \
281262306a36Sopenharmony_ci  .put = snd_hdsp_put_dds_offset \
281362306a36Sopenharmony_ci}
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_cistatic int hdsp_dds_offset(struct hdsp *hdsp)
281662306a36Sopenharmony_ci{
281762306a36Sopenharmony_ci	u64 n;
281862306a36Sopenharmony_ci	unsigned int dds_value = hdsp->dds_value;
281962306a36Sopenharmony_ci	int system_sample_rate = hdsp->system_sample_rate;
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci	if (!dds_value)
282262306a36Sopenharmony_ci		return 0;
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	n = DDS_NUMERATOR;
282562306a36Sopenharmony_ci	/*
282662306a36Sopenharmony_ci	 * dds_value = n / rate
282762306a36Sopenharmony_ci	 * rate = n / dds_value
282862306a36Sopenharmony_ci	 */
282962306a36Sopenharmony_ci	n = div_u64(n, dds_value);
283062306a36Sopenharmony_ci	if (system_sample_rate >= 112000)
283162306a36Sopenharmony_ci		n *= 4;
283262306a36Sopenharmony_ci	else if (system_sample_rate >= 56000)
283362306a36Sopenharmony_ci		n *= 2;
283462306a36Sopenharmony_ci	return ((int)n) - system_sample_rate;
283562306a36Sopenharmony_ci}
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_cistatic int hdsp_set_dds_offset(struct hdsp *hdsp, int offset_hz)
283862306a36Sopenharmony_ci{
283962306a36Sopenharmony_ci	int rate = hdsp->system_sample_rate + offset_hz;
284062306a36Sopenharmony_ci	hdsp_set_dds_value(hdsp, rate);
284162306a36Sopenharmony_ci	return 0;
284262306a36Sopenharmony_ci}
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_cistatic int snd_hdsp_info_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
284562306a36Sopenharmony_ci{
284662306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
284762306a36Sopenharmony_ci	uinfo->count = 1;
284862306a36Sopenharmony_ci	uinfo->value.integer.min = -5000;
284962306a36Sopenharmony_ci	uinfo->value.integer.max = 5000;
285062306a36Sopenharmony_ci	return 0;
285162306a36Sopenharmony_ci}
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_cistatic int snd_hdsp_get_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
285462306a36Sopenharmony_ci{
285562306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp_dds_offset(hdsp);
285862306a36Sopenharmony_ci	return 0;
285962306a36Sopenharmony_ci}
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_cistatic int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
286262306a36Sopenharmony_ci{
286362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
286462306a36Sopenharmony_ci	int change;
286562306a36Sopenharmony_ci	int val;
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
286862306a36Sopenharmony_ci		return -EBUSY;
286962306a36Sopenharmony_ci	val = ucontrol->value.integer.value[0];
287062306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
287162306a36Sopenharmony_ci	if (val != hdsp_dds_offset(hdsp))
287262306a36Sopenharmony_ci		change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0;
287362306a36Sopenharmony_ci	else
287462306a36Sopenharmony_ci		change = 0;
287562306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
287662306a36Sopenharmony_ci	return change;
287762306a36Sopenharmony_ci}
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdsp_9632_controls[] = {
288062306a36Sopenharmony_ciHDSP_DA_GAIN("DA Gain", 0),
288162306a36Sopenharmony_ciHDSP_AD_GAIN("AD Gain", 0),
288262306a36Sopenharmony_ciHDSP_PHONE_GAIN("Phones Gain", 0),
288362306a36Sopenharmony_ciHDSP_TOGGLE_SETTING("XLR Breakout Cable", HDSP_XLRBreakoutCable),
288462306a36Sopenharmony_ciHDSP_DDS_OFFSET("DDS Sample Rate Offset", 0)
288562306a36Sopenharmony_ci};
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdsp_controls[] = {
288862306a36Sopenharmony_ci{
288962306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
289062306a36Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
289162306a36Sopenharmony_ci	.info =		snd_hdsp_control_spdif_info,
289262306a36Sopenharmony_ci	.get =		snd_hdsp_control_spdif_get,
289362306a36Sopenharmony_ci	.put =		snd_hdsp_control_spdif_put,
289462306a36Sopenharmony_ci},
289562306a36Sopenharmony_ci{
289662306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
289762306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
289862306a36Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
289962306a36Sopenharmony_ci	.info =		snd_hdsp_control_spdif_stream_info,
290062306a36Sopenharmony_ci	.get =		snd_hdsp_control_spdif_stream_get,
290162306a36Sopenharmony_ci	.put =		snd_hdsp_control_spdif_stream_put,
290262306a36Sopenharmony_ci},
290362306a36Sopenharmony_ci{
290462306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
290562306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
290662306a36Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
290762306a36Sopenharmony_ci	.info =		snd_hdsp_control_spdif_mask_info,
290862306a36Sopenharmony_ci	.get =		snd_hdsp_control_spdif_mask_get,
290962306a36Sopenharmony_ci	.private_value = IEC958_AES0_NONAUDIO |
291062306a36Sopenharmony_ci  			 IEC958_AES0_PROFESSIONAL |
291162306a36Sopenharmony_ci			 IEC958_AES0_CON_EMPHASIS,
291262306a36Sopenharmony_ci},
291362306a36Sopenharmony_ci{
291462306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
291562306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
291662306a36Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
291762306a36Sopenharmony_ci	.info =		snd_hdsp_control_spdif_mask_info,
291862306a36Sopenharmony_ci	.get =		snd_hdsp_control_spdif_mask_get,
291962306a36Sopenharmony_ci	.private_value = IEC958_AES0_NONAUDIO |
292062306a36Sopenharmony_ci			 IEC958_AES0_PROFESSIONAL |
292162306a36Sopenharmony_ci			 IEC958_AES0_PRO_EMPHASIS,
292262306a36Sopenharmony_ci},
292362306a36Sopenharmony_ciHDSP_MIXER("Mixer", 0),
292462306a36Sopenharmony_ciHDSP_SPDIF_IN("IEC958 Input Connector", 0),
292562306a36Sopenharmony_ciHDSP_TOGGLE_SETTING("IEC958 Output also on ADAT1", HDSP_SPDIFOpticalOut),
292662306a36Sopenharmony_ciHDSP_TOGGLE_SETTING("IEC958 Professional Bit", HDSP_SPDIFProfessional),
292762306a36Sopenharmony_ciHDSP_TOGGLE_SETTING("IEC958 Emphasis Bit", HDSP_SPDIFEmphasis),
292862306a36Sopenharmony_ciHDSP_TOGGLE_SETTING("IEC958 Non-audio Bit", HDSP_SPDIFNonAudio),
292962306a36Sopenharmony_ci/* 'Sample Clock Source' complies with the alsa control naming scheme */
293062306a36Sopenharmony_ciHDSP_CLOCK_SOURCE("Sample Clock Source", 0),
293162306a36Sopenharmony_ci{
293262306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
293362306a36Sopenharmony_ci	.name = "Sample Clock Source Locking",
293462306a36Sopenharmony_ci	.info = snd_hdsp_info_clock_source_lock,
293562306a36Sopenharmony_ci	.get = snd_hdsp_get_clock_source_lock,
293662306a36Sopenharmony_ci	.put = snd_hdsp_put_clock_source_lock,
293762306a36Sopenharmony_ci},
293862306a36Sopenharmony_ciHDSP_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
293962306a36Sopenharmony_ciHDSP_PREF_SYNC_REF("Preferred Sync Reference", 0),
294062306a36Sopenharmony_ciHDSP_AUTOSYNC_REF("AutoSync Reference", 0),
294162306a36Sopenharmony_ciHDSP_SPDIF_SAMPLE_RATE("SPDIF Sample Rate", 0),
294262306a36Sopenharmony_ciHDSP_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
294362306a36Sopenharmony_ci/* 'External Rate' complies with the alsa control naming scheme */
294462306a36Sopenharmony_ciHDSP_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
294562306a36Sopenharmony_ciHDSP_WC_SYNC_CHECK("Word Clock Lock Status", 0),
294662306a36Sopenharmony_ciHDSP_SPDIF_SYNC_CHECK("SPDIF Lock Status", 0),
294762306a36Sopenharmony_ciHDSP_ADATSYNC_SYNC_CHECK("ADAT Sync Lock Status", 0),
294862306a36Sopenharmony_ciHDSP_TOGGLE_SETTING("Line Out", HDSP_LineOut),
294962306a36Sopenharmony_ciHDSP_PRECISE_POINTER("Precise Pointer", 0),
295062306a36Sopenharmony_ciHDSP_USE_MIDI_WORK("Use Midi Tasklet", 0),
295162306a36Sopenharmony_ci};
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_cistatic int hdsp_rpm_input12(struct hdsp *hdsp)
295562306a36Sopenharmony_ci{
295662306a36Sopenharmony_ci	switch (hdsp->control_register & HDSP_RPM_Inp12) {
295762306a36Sopenharmony_ci	case HDSP_RPM_Inp12_Phon_6dB:
295862306a36Sopenharmony_ci		return 0;
295962306a36Sopenharmony_ci	case HDSP_RPM_Inp12_Phon_n6dB:
296062306a36Sopenharmony_ci		return 2;
296162306a36Sopenharmony_ci	case HDSP_RPM_Inp12_Line_0dB:
296262306a36Sopenharmony_ci		return 3;
296362306a36Sopenharmony_ci	case HDSP_RPM_Inp12_Line_n6dB:
296462306a36Sopenharmony_ci		return 4;
296562306a36Sopenharmony_ci	}
296662306a36Sopenharmony_ci	return 1;
296762306a36Sopenharmony_ci}
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci
297062306a36Sopenharmony_cistatic int snd_hdsp_get_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
297162306a36Sopenharmony_ci{
297262306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_rpm_input12(hdsp);
297562306a36Sopenharmony_ci	return 0;
297662306a36Sopenharmony_ci}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_cistatic int hdsp_set_rpm_input12(struct hdsp *hdsp, int mode)
298062306a36Sopenharmony_ci{
298162306a36Sopenharmony_ci	hdsp->control_register &= ~HDSP_RPM_Inp12;
298262306a36Sopenharmony_ci	switch (mode) {
298362306a36Sopenharmony_ci	case 0:
298462306a36Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp12_Phon_6dB;
298562306a36Sopenharmony_ci		break;
298662306a36Sopenharmony_ci	case 1:
298762306a36Sopenharmony_ci		break;
298862306a36Sopenharmony_ci	case 2:
298962306a36Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp12_Phon_n6dB;
299062306a36Sopenharmony_ci		break;
299162306a36Sopenharmony_ci	case 3:
299262306a36Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp12_Line_0dB;
299362306a36Sopenharmony_ci		break;
299462306a36Sopenharmony_ci	case 4:
299562306a36Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp12_Line_n6dB;
299662306a36Sopenharmony_ci		break;
299762306a36Sopenharmony_ci	default:
299862306a36Sopenharmony_ci		return -1;
299962306a36Sopenharmony_ci	}
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
300262306a36Sopenharmony_ci	return 0;
300362306a36Sopenharmony_ci}
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci
300662306a36Sopenharmony_cistatic int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
300762306a36Sopenharmony_ci{
300862306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
300962306a36Sopenharmony_ci	int change;
301062306a36Sopenharmony_ci	int val;
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
301362306a36Sopenharmony_ci		return -EBUSY;
301462306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
301562306a36Sopenharmony_ci	if (val < 0)
301662306a36Sopenharmony_ci		val = 0;
301762306a36Sopenharmony_ci	if (val > 4)
301862306a36Sopenharmony_ci		val = 4;
301962306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
302062306a36Sopenharmony_ci	if (val != hdsp_rpm_input12(hdsp))
302162306a36Sopenharmony_ci		change = (hdsp_set_rpm_input12(hdsp, val) == 0) ? 1 : 0;
302262306a36Sopenharmony_ci	else
302362306a36Sopenharmony_ci		change = 0;
302462306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
302562306a36Sopenharmony_ci	return change;
302662306a36Sopenharmony_ci}
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_cistatic int snd_hdsp_info_rpm_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
303062306a36Sopenharmony_ci{
303162306a36Sopenharmony_ci	static const char * const texts[] = {
303262306a36Sopenharmony_ci		"Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"
303362306a36Sopenharmony_ci	};
303462306a36Sopenharmony_ci
303562306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 5, texts);
303662306a36Sopenharmony_ci}
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_cistatic int hdsp_rpm_input34(struct hdsp *hdsp)
304062306a36Sopenharmony_ci{
304162306a36Sopenharmony_ci	switch (hdsp->control_register & HDSP_RPM_Inp34) {
304262306a36Sopenharmony_ci	case HDSP_RPM_Inp34_Phon_6dB:
304362306a36Sopenharmony_ci		return 0;
304462306a36Sopenharmony_ci	case HDSP_RPM_Inp34_Phon_n6dB:
304562306a36Sopenharmony_ci		return 2;
304662306a36Sopenharmony_ci	case HDSP_RPM_Inp34_Line_0dB:
304762306a36Sopenharmony_ci		return 3;
304862306a36Sopenharmony_ci	case HDSP_RPM_Inp34_Line_n6dB:
304962306a36Sopenharmony_ci		return 4;
305062306a36Sopenharmony_ci	}
305162306a36Sopenharmony_ci	return 1;
305262306a36Sopenharmony_ci}
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_cistatic int snd_hdsp_get_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
305662306a36Sopenharmony_ci{
305762306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_rpm_input34(hdsp);
306062306a36Sopenharmony_ci	return 0;
306162306a36Sopenharmony_ci}
306262306a36Sopenharmony_ci
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_cistatic int hdsp_set_rpm_input34(struct hdsp *hdsp, int mode)
306562306a36Sopenharmony_ci{
306662306a36Sopenharmony_ci	hdsp->control_register &= ~HDSP_RPM_Inp34;
306762306a36Sopenharmony_ci	switch (mode) {
306862306a36Sopenharmony_ci	case 0:
306962306a36Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp34_Phon_6dB;
307062306a36Sopenharmony_ci		break;
307162306a36Sopenharmony_ci	case 1:
307262306a36Sopenharmony_ci		break;
307362306a36Sopenharmony_ci	case 2:
307462306a36Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp34_Phon_n6dB;
307562306a36Sopenharmony_ci		break;
307662306a36Sopenharmony_ci	case 3:
307762306a36Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp34_Line_0dB;
307862306a36Sopenharmony_ci		break;
307962306a36Sopenharmony_ci	case 4:
308062306a36Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp34_Line_n6dB;
308162306a36Sopenharmony_ci		break;
308262306a36Sopenharmony_ci	default:
308362306a36Sopenharmony_ci		return -1;
308462306a36Sopenharmony_ci	}
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
308762306a36Sopenharmony_ci	return 0;
308862306a36Sopenharmony_ci}
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_cistatic int snd_hdsp_put_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
309262306a36Sopenharmony_ci{
309362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
309462306a36Sopenharmony_ci	int change;
309562306a36Sopenharmony_ci	int val;
309662306a36Sopenharmony_ci
309762306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
309862306a36Sopenharmony_ci		return -EBUSY;
309962306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
310062306a36Sopenharmony_ci	if (val < 0)
310162306a36Sopenharmony_ci		val = 0;
310262306a36Sopenharmony_ci	if (val > 4)
310362306a36Sopenharmony_ci		val = 4;
310462306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
310562306a36Sopenharmony_ci	if (val != hdsp_rpm_input34(hdsp))
310662306a36Sopenharmony_ci		change = (hdsp_set_rpm_input34(hdsp, val) == 0) ? 1 : 0;
310762306a36Sopenharmony_ci	else
310862306a36Sopenharmony_ci		change = 0;
310962306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
311062306a36Sopenharmony_ci	return change;
311162306a36Sopenharmony_ci}
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci/* RPM Bypass switch */
311562306a36Sopenharmony_cistatic int hdsp_rpm_bypass(struct hdsp *hdsp)
311662306a36Sopenharmony_ci{
311762306a36Sopenharmony_ci	return (hdsp->control_register & HDSP_RPM_Bypass) ? 1 : 0;
311862306a36Sopenharmony_ci}
311962306a36Sopenharmony_ci
312062306a36Sopenharmony_ci
312162306a36Sopenharmony_cistatic int snd_hdsp_get_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
312262306a36Sopenharmony_ci{
312362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp_rpm_bypass(hdsp);
312662306a36Sopenharmony_ci	return 0;
312762306a36Sopenharmony_ci}
312862306a36Sopenharmony_ci
312962306a36Sopenharmony_ci
313062306a36Sopenharmony_cistatic int hdsp_set_rpm_bypass(struct hdsp *hdsp, int on)
313162306a36Sopenharmony_ci{
313262306a36Sopenharmony_ci	if (on)
313362306a36Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Bypass;
313462306a36Sopenharmony_ci	else
313562306a36Sopenharmony_ci		hdsp->control_register &= ~HDSP_RPM_Bypass;
313662306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
313762306a36Sopenharmony_ci	return 0;
313862306a36Sopenharmony_ci}
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_cistatic int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
314262306a36Sopenharmony_ci{
314362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
314462306a36Sopenharmony_ci	int change;
314562306a36Sopenharmony_ci	unsigned int val;
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
314862306a36Sopenharmony_ci		return -EBUSY;
314962306a36Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
315062306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
315162306a36Sopenharmony_ci	change = (int)val != hdsp_rpm_bypass(hdsp);
315262306a36Sopenharmony_ci	hdsp_set_rpm_bypass(hdsp, val);
315362306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
315462306a36Sopenharmony_ci	return change;
315562306a36Sopenharmony_ci}
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_cistatic int snd_hdsp_info_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
315962306a36Sopenharmony_ci{
316062306a36Sopenharmony_ci	static const char * const texts[] = {"On", "Off"};
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 2, texts);
316362306a36Sopenharmony_ci}
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_ci/* RPM Disconnect switch */
316762306a36Sopenharmony_cistatic int hdsp_rpm_disconnect(struct hdsp *hdsp)
316862306a36Sopenharmony_ci{
316962306a36Sopenharmony_ci	return (hdsp->control_register & HDSP_RPM_Disconnect) ? 1 : 0;
317062306a36Sopenharmony_ci}
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_cistatic int snd_hdsp_get_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
317462306a36Sopenharmony_ci{
317562306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp_rpm_disconnect(hdsp);
317862306a36Sopenharmony_ci	return 0;
317962306a36Sopenharmony_ci}
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_cistatic int hdsp_set_rpm_disconnect(struct hdsp *hdsp, int on)
318362306a36Sopenharmony_ci{
318462306a36Sopenharmony_ci	if (on)
318562306a36Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Disconnect;
318662306a36Sopenharmony_ci	else
318762306a36Sopenharmony_ci		hdsp->control_register &= ~HDSP_RPM_Disconnect;
318862306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
318962306a36Sopenharmony_ci	return 0;
319062306a36Sopenharmony_ci}
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_cistatic int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
319462306a36Sopenharmony_ci{
319562306a36Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
319662306a36Sopenharmony_ci	int change;
319762306a36Sopenharmony_ci	unsigned int val;
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
320062306a36Sopenharmony_ci		return -EBUSY;
320162306a36Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
320262306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
320362306a36Sopenharmony_ci	change = (int)val != hdsp_rpm_disconnect(hdsp);
320462306a36Sopenharmony_ci	hdsp_set_rpm_disconnect(hdsp, val);
320562306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
320662306a36Sopenharmony_ci	return change;
320762306a36Sopenharmony_ci}
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_cistatic int snd_hdsp_info_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
321062306a36Sopenharmony_ci{
321162306a36Sopenharmony_ci	static const char * const texts[] = {"On", "Off"};
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 2, texts);
321462306a36Sopenharmony_ci}
321562306a36Sopenharmony_ci
321662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdsp_rpm_controls[] = {
321762306a36Sopenharmony_ci	{
321862306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
321962306a36Sopenharmony_ci		.name = "RPM Bypass",
322062306a36Sopenharmony_ci		.get = snd_hdsp_get_rpm_bypass,
322162306a36Sopenharmony_ci		.put = snd_hdsp_put_rpm_bypass,
322262306a36Sopenharmony_ci		.info = snd_hdsp_info_rpm_bypass
322362306a36Sopenharmony_ci	},
322462306a36Sopenharmony_ci	{
322562306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
322662306a36Sopenharmony_ci		.name = "RPM Disconnect",
322762306a36Sopenharmony_ci		.get = snd_hdsp_get_rpm_disconnect,
322862306a36Sopenharmony_ci		.put = snd_hdsp_put_rpm_disconnect,
322962306a36Sopenharmony_ci		.info = snd_hdsp_info_rpm_disconnect
323062306a36Sopenharmony_ci	},
323162306a36Sopenharmony_ci	{
323262306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
323362306a36Sopenharmony_ci		.name = "Input 1/2",
323462306a36Sopenharmony_ci		.get = snd_hdsp_get_rpm_input12,
323562306a36Sopenharmony_ci		.put = snd_hdsp_put_rpm_input12,
323662306a36Sopenharmony_ci		.info = snd_hdsp_info_rpm_input
323762306a36Sopenharmony_ci	},
323862306a36Sopenharmony_ci	{
323962306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
324062306a36Sopenharmony_ci		.name = "Input 3/4",
324162306a36Sopenharmony_ci		.get = snd_hdsp_get_rpm_input34,
324262306a36Sopenharmony_ci		.put = snd_hdsp_put_rpm_input34,
324362306a36Sopenharmony_ci		.info = snd_hdsp_info_rpm_input
324462306a36Sopenharmony_ci	},
324562306a36Sopenharmony_ci	HDSP_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
324662306a36Sopenharmony_ci	HDSP_MIXER("Mixer", 0)
324762306a36Sopenharmony_ci};
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdsp_96xx_aeb =
325062306a36Sopenharmony_ci	HDSP_TOGGLE_SETTING("Analog Extension Board",
325162306a36Sopenharmony_ci			HDSP_AnalogExtensionBoard);
325262306a36Sopenharmony_cistatic struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK;
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_cistatic bool hdsp_loopback_get(struct hdsp *const hdsp, const u8 channel)
325662306a36Sopenharmony_ci{
325762306a36Sopenharmony_ci	return hdsp->io_loopback & (1 << channel);
325862306a36Sopenharmony_ci}
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_cistatic int hdsp_loopback_set(struct hdsp *const hdsp, const u8 channel, const bool enable)
326162306a36Sopenharmony_ci{
326262306a36Sopenharmony_ci	if (hdsp_loopback_get(hdsp, channel) == enable)
326362306a36Sopenharmony_ci		return 0;
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	hdsp->io_loopback ^= (1 << channel);
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_inputEnable + (4 * (hdsp->max_channels + channel)), enable);
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci	return 1;
327062306a36Sopenharmony_ci}
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_cistatic int snd_hdsp_loopback_get(struct snd_kcontrol *const kcontrol,
327362306a36Sopenharmony_ci				 struct snd_ctl_elem_value *const ucontrol)
327462306a36Sopenharmony_ci{
327562306a36Sopenharmony_ci	struct hdsp *const hdsp = snd_kcontrol_chip(kcontrol);
327662306a36Sopenharmony_ci	const u8 channel = snd_ctl_get_ioff(kcontrol, &ucontrol->id);
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci	if (channel >= hdsp->max_channels)
327962306a36Sopenharmony_ci		return -ENOENT;
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp_loopback_get(hdsp, channel);
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci	return 0;
328462306a36Sopenharmony_ci}
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_cistatic int snd_hdsp_loopback_put(struct snd_kcontrol *const kcontrol,
328762306a36Sopenharmony_ci				 struct snd_ctl_elem_value *const ucontrol)
328862306a36Sopenharmony_ci{
328962306a36Sopenharmony_ci	struct hdsp *const hdsp = snd_kcontrol_chip(kcontrol);
329062306a36Sopenharmony_ci	const u8 channel = snd_ctl_get_ioff(kcontrol, &ucontrol->id);
329162306a36Sopenharmony_ci	const bool enable = ucontrol->value.integer.value[0] & 1;
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_ci	if (channel >= hdsp->max_channels)
329462306a36Sopenharmony_ci		return -ENOENT;
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_ci	return hdsp_loopback_set(hdsp, channel, enable);
329762306a36Sopenharmony_ci}
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_cistatic struct snd_kcontrol_new snd_hdsp_loopback_control = {
330062306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_HWDEP,
330162306a36Sopenharmony_ci	.name = "Output Loopback",
330262306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
330362306a36Sopenharmony_ci	.info = snd_ctl_boolean_mono_info,
330462306a36Sopenharmony_ci	.get = snd_hdsp_loopback_get,
330562306a36Sopenharmony_ci	.put = snd_hdsp_loopback_put
330662306a36Sopenharmony_ci};
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_cistatic int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
330962306a36Sopenharmony_ci{
331062306a36Sopenharmony_ci	unsigned int idx;
331162306a36Sopenharmony_ci	int err;
331262306a36Sopenharmony_ci	struct snd_kcontrol *kctl;
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci	if (hdsp->io_type == RPM) {
331562306a36Sopenharmony_ci		/* RPM Bypass, Disconnect and Input switches */
331662306a36Sopenharmony_ci		for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_rpm_controls); idx++) {
331762306a36Sopenharmony_ci			err = snd_ctl_add(card, snd_ctl_new1(&snd_hdsp_rpm_controls[idx], hdsp));
331862306a36Sopenharmony_ci			if (err < 0)
331962306a36Sopenharmony_ci				return err;
332062306a36Sopenharmony_ci		}
332162306a36Sopenharmony_ci		return 0;
332262306a36Sopenharmony_ci	}
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci	for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_controls); idx++) {
332562306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp);
332662306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
332762306a36Sopenharmony_ci		if (err < 0)
332862306a36Sopenharmony_ci			return err;
332962306a36Sopenharmony_ci		if (idx == 1)	/* IEC958 (S/PDIF) Stream */
333062306a36Sopenharmony_ci			hdsp->spdif_ctl = kctl;
333162306a36Sopenharmony_ci	}
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	/* ADAT SyncCheck status */
333462306a36Sopenharmony_ci	snd_hdsp_adat_sync_check.name = "ADAT Lock Status";
333562306a36Sopenharmony_ci	snd_hdsp_adat_sync_check.index = 1;
333662306a36Sopenharmony_ci	kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp);
333762306a36Sopenharmony_ci	err = snd_ctl_add(card, kctl);
333862306a36Sopenharmony_ci	if (err < 0)
333962306a36Sopenharmony_ci		return err;
334062306a36Sopenharmony_ci	if (hdsp->io_type == Digiface || hdsp->io_type == H9652) {
334162306a36Sopenharmony_ci		for (idx = 1; idx < 3; ++idx) {
334262306a36Sopenharmony_ci			snd_hdsp_adat_sync_check.index = idx+1;
334362306a36Sopenharmony_ci			kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp);
334462306a36Sopenharmony_ci			err = snd_ctl_add(card, kctl);
334562306a36Sopenharmony_ci			if (err < 0)
334662306a36Sopenharmony_ci				return err;
334762306a36Sopenharmony_ci		}
334862306a36Sopenharmony_ci	}
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci	/* DA, AD and Phone gain and XLR breakout cable controls for H9632 cards */
335162306a36Sopenharmony_ci	if (hdsp->io_type == H9632) {
335262306a36Sopenharmony_ci		for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_9632_controls); idx++) {
335362306a36Sopenharmony_ci			kctl = snd_ctl_new1(&snd_hdsp_9632_controls[idx], hdsp);
335462306a36Sopenharmony_ci			err = snd_ctl_add(card, kctl);
335562306a36Sopenharmony_ci			if (err < 0)
335662306a36Sopenharmony_ci				return err;
335762306a36Sopenharmony_ci		}
335862306a36Sopenharmony_ci	}
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	/* Output loopback controls for H9632 cards */
336162306a36Sopenharmony_ci	if (hdsp->io_type == H9632) {
336262306a36Sopenharmony_ci		snd_hdsp_loopback_control.count = hdsp->max_channels;
336362306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_hdsp_loopback_control, hdsp);
336462306a36Sopenharmony_ci		if (kctl == NULL)
336562306a36Sopenharmony_ci			return -ENOMEM;
336662306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
336762306a36Sopenharmony_ci		if (err < 0)
336862306a36Sopenharmony_ci			return err;
336962306a36Sopenharmony_ci	}
337062306a36Sopenharmony_ci
337162306a36Sopenharmony_ci	/* AEB control for H96xx card */
337262306a36Sopenharmony_ci	if (hdsp->io_type == H9632 || hdsp->io_type == H9652) {
337362306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_hdsp_96xx_aeb, hdsp);
337462306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
337562306a36Sopenharmony_ci		if (err < 0)
337662306a36Sopenharmony_ci			return err;
337762306a36Sopenharmony_ci	}
337862306a36Sopenharmony_ci
337962306a36Sopenharmony_ci	return 0;
338062306a36Sopenharmony_ci}
338162306a36Sopenharmony_ci
338262306a36Sopenharmony_ci/*------------------------------------------------------------
338362306a36Sopenharmony_ci   /proc interface
338462306a36Sopenharmony_ci ------------------------------------------------------------*/
338562306a36Sopenharmony_ci
338662306a36Sopenharmony_cistatic void
338762306a36Sopenharmony_cisnd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
338862306a36Sopenharmony_ci{
338962306a36Sopenharmony_ci	struct hdsp *hdsp = entry->private_data;
339062306a36Sopenharmony_ci	unsigned int status;
339162306a36Sopenharmony_ci	unsigned int status2;
339262306a36Sopenharmony_ci	char *pref_sync_ref;
339362306a36Sopenharmony_ci	char *autosync_ref;
339462306a36Sopenharmony_ci	char *system_clock_mode;
339562306a36Sopenharmony_ci	char *clock_source;
339662306a36Sopenharmony_ci	int x;
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci	status = hdsp_read(hdsp, HDSP_statusRegister);
339962306a36Sopenharmony_ci	status2 = hdsp_read(hdsp, HDSP_status2Register);
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci	snd_iprintf(buffer, "%s (Card #%d)\n", hdsp->card_name,
340262306a36Sopenharmony_ci		    hdsp->card->number + 1);
340362306a36Sopenharmony_ci	snd_iprintf(buffer, "Buffers: capture %p playback %p\n",
340462306a36Sopenharmony_ci		    hdsp->capture_buffer, hdsp->playback_buffer);
340562306a36Sopenharmony_ci	snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
340662306a36Sopenharmony_ci		    hdsp->irq, hdsp->port, (unsigned long)hdsp->iobase);
340762306a36Sopenharmony_ci	snd_iprintf(buffer, "Control register: 0x%x\n", hdsp->control_register);
340862306a36Sopenharmony_ci	snd_iprintf(buffer, "Control2 register: 0x%x\n",
340962306a36Sopenharmony_ci		    hdsp->control2_register);
341062306a36Sopenharmony_ci	snd_iprintf(buffer, "Status register: 0x%x\n", status);
341162306a36Sopenharmony_ci	snd_iprintf(buffer, "Status2 register: 0x%x\n", status2);
341262306a36Sopenharmony_ci
341362306a36Sopenharmony_ci	if (hdsp_check_for_iobox(hdsp)) {
341462306a36Sopenharmony_ci		snd_iprintf(buffer, "No I/O box connected.\n"
341562306a36Sopenharmony_ci			    "Please connect one and upload firmware.\n");
341662306a36Sopenharmony_ci		return;
341762306a36Sopenharmony_ci	}
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 0)) {
342062306a36Sopenharmony_ci		if (hdsp->state & HDSP_FirmwareCached) {
342162306a36Sopenharmony_ci			if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
342262306a36Sopenharmony_ci				snd_iprintf(buffer, "Firmware loading from "
342362306a36Sopenharmony_ci					    "cache failed, "
342462306a36Sopenharmony_ci					    "please upload manually.\n");
342562306a36Sopenharmony_ci				return;
342662306a36Sopenharmony_ci			}
342762306a36Sopenharmony_ci		} else {
342862306a36Sopenharmony_ci			int err;
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_ci			err = hdsp_request_fw_loader(hdsp);
343162306a36Sopenharmony_ci			if (err < 0) {
343262306a36Sopenharmony_ci				snd_iprintf(buffer,
343362306a36Sopenharmony_ci					    "No firmware loaded nor cached, "
343462306a36Sopenharmony_ci					    "please upload firmware.\n");
343562306a36Sopenharmony_ci				return;
343662306a36Sopenharmony_ci			}
343762306a36Sopenharmony_ci		}
343862306a36Sopenharmony_ci	}
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	snd_iprintf(buffer, "FIFO status: %d\n", hdsp_read(hdsp, HDSP_fifoStatus) & 0xff);
344162306a36Sopenharmony_ci	snd_iprintf(buffer, "MIDI1 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut0));
344262306a36Sopenharmony_ci	snd_iprintf(buffer, "MIDI1 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn0));
344362306a36Sopenharmony_ci	snd_iprintf(buffer, "MIDI2 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut1));
344462306a36Sopenharmony_ci	snd_iprintf(buffer, "MIDI2 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn1));
344562306a36Sopenharmony_ci	snd_iprintf(buffer, "Use Midi Tasklet: %s\n", hdsp->use_midi_work ? "on" : "off");
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_ci	snd_iprintf(buffer, "\n");
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci	x = 1 << (6 + hdsp_decode_latency(hdsp->control_register & HDSP_LatencyMask));
345062306a36Sopenharmony_ci
345162306a36Sopenharmony_ci	snd_iprintf(buffer, "Buffer Size (Latency): %d samples (2 periods of %lu bytes)\n", x, (unsigned long) hdsp->period_bytes);
345262306a36Sopenharmony_ci	snd_iprintf(buffer, "Hardware pointer (frames): %ld\n", hdsp_hw_pointer(hdsp));
345362306a36Sopenharmony_ci	snd_iprintf(buffer, "Precise pointer: %s\n", hdsp->precise_ptr ? "on" : "off");
345462306a36Sopenharmony_ci	snd_iprintf(buffer, "Line out: %s\n", (hdsp->control_register & HDSP_LineOut) ? "on" : "off");
345562306a36Sopenharmony_ci
345662306a36Sopenharmony_ci	snd_iprintf(buffer, "Firmware version: %d\n", (status2&HDSP_version0)|(status2&HDSP_version1)<<1|(status2&HDSP_version2)<<2);
345762306a36Sopenharmony_ci
345862306a36Sopenharmony_ci	snd_iprintf(buffer, "\n");
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci	switch (hdsp_clock_source(hdsp)) {
346162306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_AUTOSYNC:
346262306a36Sopenharmony_ci		clock_source = "AutoSync";
346362306a36Sopenharmony_ci		break;
346462306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_32KHZ:
346562306a36Sopenharmony_ci		clock_source = "Internal 32 kHz";
346662306a36Sopenharmony_ci		break;
346762306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ:
346862306a36Sopenharmony_ci		clock_source = "Internal 44.1 kHz";
346962306a36Sopenharmony_ci		break;
347062306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_48KHZ:
347162306a36Sopenharmony_ci		clock_source = "Internal 48 kHz";
347262306a36Sopenharmony_ci		break;
347362306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_64KHZ:
347462306a36Sopenharmony_ci		clock_source = "Internal 64 kHz";
347562306a36Sopenharmony_ci		break;
347662306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ:
347762306a36Sopenharmony_ci		clock_source = "Internal 88.2 kHz";
347862306a36Sopenharmony_ci		break;
347962306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_96KHZ:
348062306a36Sopenharmony_ci		clock_source = "Internal 96 kHz";
348162306a36Sopenharmony_ci		break;
348262306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_128KHZ:
348362306a36Sopenharmony_ci		clock_source = "Internal 128 kHz";
348462306a36Sopenharmony_ci		break;
348562306a36Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ:
348662306a36Sopenharmony_ci		clock_source = "Internal 176.4 kHz";
348762306a36Sopenharmony_ci		break;
348862306a36Sopenharmony_ci		case HDSP_CLOCK_SOURCE_INTERNAL_192KHZ:
348962306a36Sopenharmony_ci		clock_source = "Internal 192 kHz";
349062306a36Sopenharmony_ci		break;
349162306a36Sopenharmony_ci	default:
349262306a36Sopenharmony_ci		clock_source = "Error";
349362306a36Sopenharmony_ci	}
349462306a36Sopenharmony_ci	snd_iprintf (buffer, "Sample Clock Source: %s\n", clock_source);
349562306a36Sopenharmony_ci
349662306a36Sopenharmony_ci	if (hdsp_system_clock_mode(hdsp))
349762306a36Sopenharmony_ci		system_clock_mode = "Slave";
349862306a36Sopenharmony_ci	else
349962306a36Sopenharmony_ci		system_clock_mode = "Master";
350062306a36Sopenharmony_ci
350162306a36Sopenharmony_ci	switch (hdsp_pref_sync_ref (hdsp)) {
350262306a36Sopenharmony_ci	case HDSP_SYNC_FROM_WORD:
350362306a36Sopenharmony_ci		pref_sync_ref = "Word Clock";
350462306a36Sopenharmony_ci		break;
350562306a36Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT_SYNC:
350662306a36Sopenharmony_ci		pref_sync_ref = "ADAT Sync";
350762306a36Sopenharmony_ci		break;
350862306a36Sopenharmony_ci	case HDSP_SYNC_FROM_SPDIF:
350962306a36Sopenharmony_ci		pref_sync_ref = "SPDIF";
351062306a36Sopenharmony_ci		break;
351162306a36Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT1:
351262306a36Sopenharmony_ci		pref_sync_ref = "ADAT1";
351362306a36Sopenharmony_ci		break;
351462306a36Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT2:
351562306a36Sopenharmony_ci		pref_sync_ref = "ADAT2";
351662306a36Sopenharmony_ci		break;
351762306a36Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT3:
351862306a36Sopenharmony_ci		pref_sync_ref = "ADAT3";
351962306a36Sopenharmony_ci		break;
352062306a36Sopenharmony_ci	default:
352162306a36Sopenharmony_ci		pref_sync_ref = "Word Clock";
352262306a36Sopenharmony_ci		break;
352362306a36Sopenharmony_ci	}
352462306a36Sopenharmony_ci	snd_iprintf (buffer, "Preferred Sync Reference: %s\n", pref_sync_ref);
352562306a36Sopenharmony_ci
352662306a36Sopenharmony_ci	switch (hdsp_autosync_ref (hdsp)) {
352762306a36Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_WORD:
352862306a36Sopenharmony_ci		autosync_ref = "Word Clock";
352962306a36Sopenharmony_ci		break;
353062306a36Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_ADAT_SYNC:
353162306a36Sopenharmony_ci		autosync_ref = "ADAT Sync";
353262306a36Sopenharmony_ci		break;
353362306a36Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_SPDIF:
353462306a36Sopenharmony_ci		autosync_ref = "SPDIF";
353562306a36Sopenharmony_ci		break;
353662306a36Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_NONE:
353762306a36Sopenharmony_ci		autosync_ref = "None";
353862306a36Sopenharmony_ci		break;
353962306a36Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_ADAT1:
354062306a36Sopenharmony_ci		autosync_ref = "ADAT1";
354162306a36Sopenharmony_ci		break;
354262306a36Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_ADAT2:
354362306a36Sopenharmony_ci		autosync_ref = "ADAT2";
354462306a36Sopenharmony_ci		break;
354562306a36Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_ADAT3:
354662306a36Sopenharmony_ci		autosync_ref = "ADAT3";
354762306a36Sopenharmony_ci		break;
354862306a36Sopenharmony_ci	default:
354962306a36Sopenharmony_ci		autosync_ref = "---";
355062306a36Sopenharmony_ci		break;
355162306a36Sopenharmony_ci	}
355262306a36Sopenharmony_ci	snd_iprintf (buffer, "AutoSync Reference: %s\n", autosync_ref);
355362306a36Sopenharmony_ci
355462306a36Sopenharmony_ci	snd_iprintf (buffer, "AutoSync Frequency: %d\n", hdsp_external_sample_rate(hdsp));
355562306a36Sopenharmony_ci
355662306a36Sopenharmony_ci	snd_iprintf (buffer, "System Clock Mode: %s\n", system_clock_mode);
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_ci	snd_iprintf (buffer, "System Clock Frequency: %d\n", hdsp->system_sample_rate);
355962306a36Sopenharmony_ci	snd_iprintf (buffer, "System Clock Locked: %s\n", hdsp->clock_source_locked ? "Yes" : "No");
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci	snd_iprintf(buffer, "\n");
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci	if (hdsp->io_type != RPM) {
356462306a36Sopenharmony_ci		switch (hdsp_spdif_in(hdsp)) {
356562306a36Sopenharmony_ci		case HDSP_SPDIFIN_OPTICAL:
356662306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 input: Optical\n");
356762306a36Sopenharmony_ci			break;
356862306a36Sopenharmony_ci		case HDSP_SPDIFIN_COAXIAL:
356962306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 input: Coaxial\n");
357062306a36Sopenharmony_ci			break;
357162306a36Sopenharmony_ci		case HDSP_SPDIFIN_INTERNAL:
357262306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 input: Internal\n");
357362306a36Sopenharmony_ci			break;
357462306a36Sopenharmony_ci		case HDSP_SPDIFIN_AES:
357562306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 input: AES\n");
357662306a36Sopenharmony_ci			break;
357762306a36Sopenharmony_ci		default:
357862306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 input: ???\n");
357962306a36Sopenharmony_ci			break;
358062306a36Sopenharmony_ci		}
358162306a36Sopenharmony_ci	}
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_ci	if (RPM == hdsp->io_type) {
358462306a36Sopenharmony_ci		if (hdsp->control_register & HDSP_RPM_Bypass)
358562306a36Sopenharmony_ci			snd_iprintf(buffer, "RPM Bypass: disabled\n");
358662306a36Sopenharmony_ci		else
358762306a36Sopenharmony_ci			snd_iprintf(buffer, "RPM Bypass: enabled\n");
358862306a36Sopenharmony_ci		if (hdsp->control_register & HDSP_RPM_Disconnect)
358962306a36Sopenharmony_ci			snd_iprintf(buffer, "RPM disconnected\n");
359062306a36Sopenharmony_ci		else
359162306a36Sopenharmony_ci			snd_iprintf(buffer, "RPM connected\n");
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_ci		switch (hdsp->control_register & HDSP_RPM_Inp12) {
359462306a36Sopenharmony_ci		case HDSP_RPM_Inp12_Phon_6dB:
359562306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: Phono, 6dB\n");
359662306a36Sopenharmony_ci			break;
359762306a36Sopenharmony_ci		case HDSP_RPM_Inp12_Phon_0dB:
359862306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: Phono, 0dB\n");
359962306a36Sopenharmony_ci			break;
360062306a36Sopenharmony_ci		case HDSP_RPM_Inp12_Phon_n6dB:
360162306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: Phono, -6dB\n");
360262306a36Sopenharmony_ci			break;
360362306a36Sopenharmony_ci		case HDSP_RPM_Inp12_Line_0dB:
360462306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: Line, 0dB\n");
360562306a36Sopenharmony_ci			break;
360662306a36Sopenharmony_ci		case HDSP_RPM_Inp12_Line_n6dB:
360762306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: Line, -6dB\n");
360862306a36Sopenharmony_ci			break;
360962306a36Sopenharmony_ci		default:
361062306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: ???\n");
361162306a36Sopenharmony_ci		}
361262306a36Sopenharmony_ci
361362306a36Sopenharmony_ci		switch (hdsp->control_register & HDSP_RPM_Inp34) {
361462306a36Sopenharmony_ci		case HDSP_RPM_Inp34_Phon_6dB:
361562306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: Phono, 6dB\n");
361662306a36Sopenharmony_ci			break;
361762306a36Sopenharmony_ci		case HDSP_RPM_Inp34_Phon_0dB:
361862306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: Phono, 0dB\n");
361962306a36Sopenharmony_ci			break;
362062306a36Sopenharmony_ci		case HDSP_RPM_Inp34_Phon_n6dB:
362162306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: Phono, -6dB\n");
362262306a36Sopenharmony_ci			break;
362362306a36Sopenharmony_ci		case HDSP_RPM_Inp34_Line_0dB:
362462306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: Line, 0dB\n");
362562306a36Sopenharmony_ci			break;
362662306a36Sopenharmony_ci		case HDSP_RPM_Inp34_Line_n6dB:
362762306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: Line, -6dB\n");
362862306a36Sopenharmony_ci			break;
362962306a36Sopenharmony_ci		default:
363062306a36Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: ???\n");
363162306a36Sopenharmony_ci		}
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	} else {
363462306a36Sopenharmony_ci		if (hdsp->control_register & HDSP_SPDIFOpticalOut)
363562306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
363662306a36Sopenharmony_ci		else
363762306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 output: Coaxial only\n");
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_ci		if (hdsp->control_register & HDSP_SPDIFProfessional)
364062306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 quality: Professional\n");
364162306a36Sopenharmony_ci		else
364262306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 quality: Consumer\n");
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_ci		if (hdsp->control_register & HDSP_SPDIFEmphasis)
364562306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 emphasis: on\n");
364662306a36Sopenharmony_ci		else
364762306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 emphasis: off\n");
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_ci		if (hdsp->control_register & HDSP_SPDIFNonAudio)
365062306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 NonAudio: on\n");
365162306a36Sopenharmony_ci		else
365262306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 NonAudio: off\n");
365362306a36Sopenharmony_ci		x = hdsp_spdif_sample_rate(hdsp);
365462306a36Sopenharmony_ci		if (x != 0)
365562306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 sample rate: %d\n", x);
365662306a36Sopenharmony_ci		else
365762306a36Sopenharmony_ci			snd_iprintf(buffer, "IEC958 sample rate: Error flag set\n");
365862306a36Sopenharmony_ci	}
365962306a36Sopenharmony_ci	snd_iprintf(buffer, "\n");
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci	/* Sync Check */
366262306a36Sopenharmony_ci	x = status & HDSP_Sync0;
366362306a36Sopenharmony_ci	if (status & HDSP_Lock0)
366462306a36Sopenharmony_ci		snd_iprintf(buffer, "ADAT1: %s\n", x ? "Sync" : "Lock");
366562306a36Sopenharmony_ci	else
366662306a36Sopenharmony_ci		snd_iprintf(buffer, "ADAT1: No Lock\n");
366762306a36Sopenharmony_ci
366862306a36Sopenharmony_ci	switch (hdsp->io_type) {
366962306a36Sopenharmony_ci	case Digiface:
367062306a36Sopenharmony_ci	case H9652:
367162306a36Sopenharmony_ci		x = status & HDSP_Sync1;
367262306a36Sopenharmony_ci		if (status & HDSP_Lock1)
367362306a36Sopenharmony_ci			snd_iprintf(buffer, "ADAT2: %s\n", x ? "Sync" : "Lock");
367462306a36Sopenharmony_ci		else
367562306a36Sopenharmony_ci			snd_iprintf(buffer, "ADAT2: No Lock\n");
367662306a36Sopenharmony_ci		x = status & HDSP_Sync2;
367762306a36Sopenharmony_ci		if (status & HDSP_Lock2)
367862306a36Sopenharmony_ci			snd_iprintf(buffer, "ADAT3: %s\n", x ? "Sync" : "Lock");
367962306a36Sopenharmony_ci		else
368062306a36Sopenharmony_ci			snd_iprintf(buffer, "ADAT3: No Lock\n");
368162306a36Sopenharmony_ci		break;
368262306a36Sopenharmony_ci	default:
368362306a36Sopenharmony_ci		/* relax */
368462306a36Sopenharmony_ci		break;
368562306a36Sopenharmony_ci	}
368662306a36Sopenharmony_ci
368762306a36Sopenharmony_ci	x = status & HDSP_SPDIFSync;
368862306a36Sopenharmony_ci	if (status & HDSP_SPDIFErrorFlag)
368962306a36Sopenharmony_ci		snd_iprintf (buffer, "SPDIF: No Lock\n");
369062306a36Sopenharmony_ci	else
369162306a36Sopenharmony_ci		snd_iprintf (buffer, "SPDIF: %s\n", x ? "Sync" : "Lock");
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_ci	x = status2 & HDSP_wc_sync;
369462306a36Sopenharmony_ci	if (status2 & HDSP_wc_lock)
369562306a36Sopenharmony_ci		snd_iprintf (buffer, "Word Clock: %s\n", x ? "Sync" : "Lock");
369662306a36Sopenharmony_ci	else
369762306a36Sopenharmony_ci		snd_iprintf (buffer, "Word Clock: No Lock\n");
369862306a36Sopenharmony_ci
369962306a36Sopenharmony_ci	x = status & HDSP_TimecodeSync;
370062306a36Sopenharmony_ci	if (status & HDSP_TimecodeLock)
370162306a36Sopenharmony_ci		snd_iprintf(buffer, "ADAT Sync: %s\n", x ? "Sync" : "Lock");
370262306a36Sopenharmony_ci	else
370362306a36Sopenharmony_ci		snd_iprintf(buffer, "ADAT Sync: No Lock\n");
370462306a36Sopenharmony_ci
370562306a36Sopenharmony_ci	snd_iprintf(buffer, "\n");
370662306a36Sopenharmony_ci
370762306a36Sopenharmony_ci	/* Informations about H9632 specific controls */
370862306a36Sopenharmony_ci	if (hdsp->io_type == H9632) {
370962306a36Sopenharmony_ci		char *tmp;
371062306a36Sopenharmony_ci
371162306a36Sopenharmony_ci		switch (hdsp_ad_gain(hdsp)) {
371262306a36Sopenharmony_ci		case 0:
371362306a36Sopenharmony_ci			tmp = "-10 dBV";
371462306a36Sopenharmony_ci			break;
371562306a36Sopenharmony_ci		case 1:
371662306a36Sopenharmony_ci			tmp = "+4 dBu";
371762306a36Sopenharmony_ci			break;
371862306a36Sopenharmony_ci		default:
371962306a36Sopenharmony_ci			tmp = "Lo Gain";
372062306a36Sopenharmony_ci			break;
372162306a36Sopenharmony_ci		}
372262306a36Sopenharmony_ci		snd_iprintf(buffer, "AD Gain : %s\n", tmp);
372362306a36Sopenharmony_ci
372462306a36Sopenharmony_ci		switch (hdsp_da_gain(hdsp)) {
372562306a36Sopenharmony_ci		case 0:
372662306a36Sopenharmony_ci			tmp = "Hi Gain";
372762306a36Sopenharmony_ci			break;
372862306a36Sopenharmony_ci		case 1:
372962306a36Sopenharmony_ci			tmp = "+4 dBu";
373062306a36Sopenharmony_ci			break;
373162306a36Sopenharmony_ci		default:
373262306a36Sopenharmony_ci			tmp = "-10 dBV";
373362306a36Sopenharmony_ci			break;
373462306a36Sopenharmony_ci		}
373562306a36Sopenharmony_ci		snd_iprintf(buffer, "DA Gain : %s\n", tmp);
373662306a36Sopenharmony_ci
373762306a36Sopenharmony_ci		switch (hdsp_phone_gain(hdsp)) {
373862306a36Sopenharmony_ci		case 0:
373962306a36Sopenharmony_ci			tmp = "0 dB";
374062306a36Sopenharmony_ci			break;
374162306a36Sopenharmony_ci		case 1:
374262306a36Sopenharmony_ci			tmp = "-6 dB";
374362306a36Sopenharmony_ci			break;
374462306a36Sopenharmony_ci		default:
374562306a36Sopenharmony_ci			tmp = "-12 dB";
374662306a36Sopenharmony_ci			break;
374762306a36Sopenharmony_ci		}
374862306a36Sopenharmony_ci		snd_iprintf(buffer, "Phones Gain : %s\n", tmp);
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_ci		snd_iprintf(buffer, "XLR Breakout Cable : %s\n",
375162306a36Sopenharmony_ci			hdsp_toggle_setting(hdsp, HDSP_XLRBreakoutCable) ?
375262306a36Sopenharmony_ci			"yes" : "no");
375362306a36Sopenharmony_ci
375462306a36Sopenharmony_ci		if (hdsp->control_register & HDSP_AnalogExtensionBoard)
375562306a36Sopenharmony_ci			snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n");
375662306a36Sopenharmony_ci		else
375762306a36Sopenharmony_ci			snd_iprintf(buffer, "AEB : off (ADAT1 external)\n");
375862306a36Sopenharmony_ci		snd_iprintf(buffer, "\n");
375962306a36Sopenharmony_ci	}
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci}
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_cistatic void snd_hdsp_proc_init(struct hdsp *hdsp)
376462306a36Sopenharmony_ci{
376562306a36Sopenharmony_ci	snd_card_ro_proc_new(hdsp->card, "hdsp", hdsp, snd_hdsp_proc_read);
376662306a36Sopenharmony_ci}
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_cistatic int snd_hdsp_initialize_memory(struct hdsp *hdsp)
376962306a36Sopenharmony_ci{
377062306a36Sopenharmony_ci	struct snd_dma_buffer *capture_dma, *playback_dma;
377162306a36Sopenharmony_ci
377262306a36Sopenharmony_ci	capture_dma = snd_hammerfall_get_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES);
377362306a36Sopenharmony_ci	playback_dma = snd_hammerfall_get_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES);
377462306a36Sopenharmony_ci	if (!capture_dma || !playback_dma) {
377562306a36Sopenharmony_ci		dev_err(hdsp->card->dev,
377662306a36Sopenharmony_ci			"%s: no buffers available\n", hdsp->card_name);
377762306a36Sopenharmony_ci		return -ENOMEM;
377862306a36Sopenharmony_ci	}
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_ci	/* copy to the own data for alignment */
378162306a36Sopenharmony_ci	hdsp->capture_dma_buf = *capture_dma;
378262306a36Sopenharmony_ci	hdsp->playback_dma_buf = *playback_dma;
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ci	/* Align to bus-space 64K boundary */
378562306a36Sopenharmony_ci	hdsp->capture_dma_buf.addr = ALIGN(capture_dma->addr, 0x10000ul);
378662306a36Sopenharmony_ci	hdsp->playback_dma_buf.addr = ALIGN(playback_dma->addr, 0x10000ul);
378762306a36Sopenharmony_ci
378862306a36Sopenharmony_ci	/* Tell the card where it is */
378962306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_inputBufferAddress, hdsp->capture_dma_buf.addr);
379062306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_outputBufferAddress, hdsp->playback_dma_buf.addr);
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_ci	hdsp->capture_dma_buf.area += hdsp->capture_dma_buf.addr - capture_dma->addr;
379362306a36Sopenharmony_ci	hdsp->playback_dma_buf.area += hdsp->playback_dma_buf.addr - playback_dma->addr;
379462306a36Sopenharmony_ci	hdsp->capture_buffer = hdsp->capture_dma_buf.area;
379562306a36Sopenharmony_ci	hdsp->playback_buffer = hdsp->playback_dma_buf.area;
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci	return 0;
379862306a36Sopenharmony_ci}
379962306a36Sopenharmony_ci
380062306a36Sopenharmony_cistatic int snd_hdsp_set_defaults(struct hdsp *hdsp)
380162306a36Sopenharmony_ci{
380262306a36Sopenharmony_ci	unsigned int i;
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ci	/* ASSUMPTION: hdsp->lock is either held, or
380562306a36Sopenharmony_ci	   there is no need to hold it (e.g. during module
380662306a36Sopenharmony_ci	   initialization).
380762306a36Sopenharmony_ci	 */
380862306a36Sopenharmony_ci
380962306a36Sopenharmony_ci	/* set defaults:
381062306a36Sopenharmony_ci
381162306a36Sopenharmony_ci	   SPDIF Input via Coax
381262306a36Sopenharmony_ci	   Master clock mode
381362306a36Sopenharmony_ci	   maximum latency (7 => 2^7 = 8192 samples, 64Kbyte buffer,
381462306a36Sopenharmony_ci	                    which implies 2 4096 sample, 32Kbyte periods).
381562306a36Sopenharmony_ci           Enable line out.
381662306a36Sopenharmony_ci	 */
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_ci	hdsp->control_register = HDSP_ClockModeMaster |
381962306a36Sopenharmony_ci		                 HDSP_SPDIFInputCoaxial |
382062306a36Sopenharmony_ci		                 hdsp_encode_latency(7) |
382162306a36Sopenharmony_ci		                 HDSP_LineOut;
382262306a36Sopenharmony_ci
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
382562306a36Sopenharmony_ci
382662306a36Sopenharmony_ci#ifdef SNDRV_BIG_ENDIAN
382762306a36Sopenharmony_ci	hdsp->control2_register = HDSP_BIGENDIAN_MODE;
382862306a36Sopenharmony_ci#else
382962306a36Sopenharmony_ci	hdsp->control2_register = 0;
383062306a36Sopenharmony_ci#endif
383162306a36Sopenharmony_ci	if (hdsp->io_type == H9652)
383262306a36Sopenharmony_ci	        snd_hdsp_9652_enable_mixer (hdsp);
383362306a36Sopenharmony_ci	else
383462306a36Sopenharmony_ci		hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_ci	hdsp_reset_hw_pointer(hdsp);
383762306a36Sopenharmony_ci	hdsp_compute_period_size(hdsp);
383862306a36Sopenharmony_ci
383962306a36Sopenharmony_ci	/* silence everything */
384062306a36Sopenharmony_ci
384162306a36Sopenharmony_ci	for (i = 0; i < HDSP_MATRIX_MIXER_SIZE; ++i)
384262306a36Sopenharmony_ci		hdsp->mixer_matrix[i] = MINUS_INFINITY_GAIN;
384362306a36Sopenharmony_ci
384462306a36Sopenharmony_ci	for (i = 0; i < ((hdsp->io_type == H9652 || hdsp->io_type == H9632) ? 1352 : HDSP_MATRIX_MIXER_SIZE); ++i) {
384562306a36Sopenharmony_ci		if (hdsp_write_gain (hdsp, i, MINUS_INFINITY_GAIN))
384662306a36Sopenharmony_ci			return -EIO;
384762306a36Sopenharmony_ci	}
384862306a36Sopenharmony_ci
384962306a36Sopenharmony_ci	/* H9632 specific defaults */
385062306a36Sopenharmony_ci	if (hdsp->io_type == H9632) {
385162306a36Sopenharmony_ci		hdsp->control_register |= (HDSP_DAGainPlus4dBu | HDSP_ADGainPlus4dBu | HDSP_PhoneGain0dB);
385262306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
385362306a36Sopenharmony_ci	}
385462306a36Sopenharmony_ci
385562306a36Sopenharmony_ci	/* set a default rate so that the channel map is set up.
385662306a36Sopenharmony_ci	 */
385762306a36Sopenharmony_ci
385862306a36Sopenharmony_ci	hdsp_set_rate(hdsp, 48000, 1);
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci	return 0;
386162306a36Sopenharmony_ci}
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_cistatic void hdsp_midi_work(struct work_struct *work)
386462306a36Sopenharmony_ci{
386562306a36Sopenharmony_ci	struct hdsp *hdsp = container_of(work, struct hdsp, midi_work);
386662306a36Sopenharmony_ci
386762306a36Sopenharmony_ci	if (hdsp->midi[0].pending)
386862306a36Sopenharmony_ci		snd_hdsp_midi_input_read (&hdsp->midi[0]);
386962306a36Sopenharmony_ci	if (hdsp->midi[1].pending)
387062306a36Sopenharmony_ci		snd_hdsp_midi_input_read (&hdsp->midi[1]);
387162306a36Sopenharmony_ci}
387262306a36Sopenharmony_ci
387362306a36Sopenharmony_cistatic irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
387462306a36Sopenharmony_ci{
387562306a36Sopenharmony_ci	struct hdsp *hdsp = (struct hdsp *) dev_id;
387662306a36Sopenharmony_ci	unsigned int status;
387762306a36Sopenharmony_ci	int audio;
387862306a36Sopenharmony_ci	int midi0;
387962306a36Sopenharmony_ci	int midi1;
388062306a36Sopenharmony_ci	unsigned int midi0status;
388162306a36Sopenharmony_ci	unsigned int midi1status;
388262306a36Sopenharmony_ci	int schedule = 0;
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci	status = hdsp_read(hdsp, HDSP_statusRegister);
388562306a36Sopenharmony_ci
388662306a36Sopenharmony_ci	audio = status & HDSP_audioIRQPending;
388762306a36Sopenharmony_ci	midi0 = status & HDSP_midi0IRQPending;
388862306a36Sopenharmony_ci	midi1 = status & HDSP_midi1IRQPending;
388962306a36Sopenharmony_ci
389062306a36Sopenharmony_ci	if (!audio && !midi0 && !midi1)
389162306a36Sopenharmony_ci		return IRQ_NONE;
389262306a36Sopenharmony_ci
389362306a36Sopenharmony_ci	hdsp_write(hdsp, HDSP_interruptConfirmation, 0);
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci	midi0status = hdsp_read (hdsp, HDSP_midiStatusIn0) & 0xff;
389662306a36Sopenharmony_ci	midi1status = hdsp_read (hdsp, HDSP_midiStatusIn1) & 0xff;
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci	if (!(hdsp->state & HDSP_InitializationComplete))
389962306a36Sopenharmony_ci		return IRQ_HANDLED;
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci	if (audio) {
390262306a36Sopenharmony_ci		if (hdsp->capture_substream)
390362306a36Sopenharmony_ci			snd_pcm_period_elapsed(hdsp->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_ci		if (hdsp->playback_substream)
390662306a36Sopenharmony_ci			snd_pcm_period_elapsed(hdsp->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
390762306a36Sopenharmony_ci	}
390862306a36Sopenharmony_ci
390962306a36Sopenharmony_ci	if (midi0 && midi0status) {
391062306a36Sopenharmony_ci		if (hdsp->use_midi_work) {
391162306a36Sopenharmony_ci			/* we disable interrupts for this input until processing is done */
391262306a36Sopenharmony_ci			hdsp->control_register &= ~HDSP_Midi0InterruptEnable;
391362306a36Sopenharmony_ci			hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
391462306a36Sopenharmony_ci			hdsp->midi[0].pending = 1;
391562306a36Sopenharmony_ci			schedule = 1;
391662306a36Sopenharmony_ci		} else {
391762306a36Sopenharmony_ci			snd_hdsp_midi_input_read (&hdsp->midi[0]);
391862306a36Sopenharmony_ci		}
391962306a36Sopenharmony_ci	}
392062306a36Sopenharmony_ci	if (hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632 && midi1 && midi1status) {
392162306a36Sopenharmony_ci		if (hdsp->use_midi_work) {
392262306a36Sopenharmony_ci			/* we disable interrupts for this input until processing is done */
392362306a36Sopenharmony_ci			hdsp->control_register &= ~HDSP_Midi1InterruptEnable;
392462306a36Sopenharmony_ci			hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
392562306a36Sopenharmony_ci			hdsp->midi[1].pending = 1;
392662306a36Sopenharmony_ci			schedule = 1;
392762306a36Sopenharmony_ci		} else {
392862306a36Sopenharmony_ci			snd_hdsp_midi_input_read (&hdsp->midi[1]);
392962306a36Sopenharmony_ci		}
393062306a36Sopenharmony_ci	}
393162306a36Sopenharmony_ci	if (hdsp->use_midi_work && schedule)
393262306a36Sopenharmony_ci		queue_work(system_highpri_wq, &hdsp->midi_work);
393362306a36Sopenharmony_ci	return IRQ_HANDLED;
393462306a36Sopenharmony_ci}
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_hdsp_hw_pointer(struct snd_pcm_substream *substream)
393762306a36Sopenharmony_ci{
393862306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
393962306a36Sopenharmony_ci	return hdsp_hw_pointer(hdsp);
394062306a36Sopenharmony_ci}
394162306a36Sopenharmony_ci
394262306a36Sopenharmony_cistatic signed char *hdsp_channel_buffer_location(struct hdsp *hdsp,
394362306a36Sopenharmony_ci					     int stream,
394462306a36Sopenharmony_ci					     int channel)
394562306a36Sopenharmony_ci
394662306a36Sopenharmony_ci{
394762306a36Sopenharmony_ci	int mapped_channel;
394862306a36Sopenharmony_ci
394962306a36Sopenharmony_ci        if (snd_BUG_ON(channel < 0 || channel >= hdsp->max_channels))
395062306a36Sopenharmony_ci		return NULL;
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_ci	mapped_channel = hdsp->channel_map[channel];
395362306a36Sopenharmony_ci	if (mapped_channel < 0)
395462306a36Sopenharmony_ci		return NULL;
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_CAPTURE)
395762306a36Sopenharmony_ci		return hdsp->capture_buffer + (mapped_channel * HDSP_CHANNEL_BUFFER_BYTES);
395862306a36Sopenharmony_ci	else
395962306a36Sopenharmony_ci		return hdsp->playback_buffer + (mapped_channel * HDSP_CHANNEL_BUFFER_BYTES);
396062306a36Sopenharmony_ci}
396162306a36Sopenharmony_ci
396262306a36Sopenharmony_cistatic int snd_hdsp_playback_copy(struct snd_pcm_substream *substream,
396362306a36Sopenharmony_ci				  int channel, unsigned long pos,
396462306a36Sopenharmony_ci				  struct iov_iter *src, unsigned long count)
396562306a36Sopenharmony_ci{
396662306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
396762306a36Sopenharmony_ci	signed char *channel_buf;
396862306a36Sopenharmony_ci
396962306a36Sopenharmony_ci	if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES))
397062306a36Sopenharmony_ci		return -EINVAL;
397162306a36Sopenharmony_ci
397262306a36Sopenharmony_ci	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
397362306a36Sopenharmony_ci	if (snd_BUG_ON(!channel_buf))
397462306a36Sopenharmony_ci		return -EIO;
397562306a36Sopenharmony_ci	if (copy_from_iter(channel_buf + pos, count, src) != count)
397662306a36Sopenharmony_ci		return -EFAULT;
397762306a36Sopenharmony_ci	return 0;
397862306a36Sopenharmony_ci}
397962306a36Sopenharmony_ci
398062306a36Sopenharmony_cistatic int snd_hdsp_capture_copy(struct snd_pcm_substream *substream,
398162306a36Sopenharmony_ci				 int channel, unsigned long pos,
398262306a36Sopenharmony_ci				 struct iov_iter *dst, unsigned long count)
398362306a36Sopenharmony_ci{
398462306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
398562306a36Sopenharmony_ci	signed char *channel_buf;
398662306a36Sopenharmony_ci
398762306a36Sopenharmony_ci	if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES))
398862306a36Sopenharmony_ci		return -EINVAL;
398962306a36Sopenharmony_ci
399062306a36Sopenharmony_ci	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
399162306a36Sopenharmony_ci	if (snd_BUG_ON(!channel_buf))
399262306a36Sopenharmony_ci		return -EIO;
399362306a36Sopenharmony_ci	if (copy_to_iter(channel_buf + pos, count, dst) != count)
399462306a36Sopenharmony_ci		return -EFAULT;
399562306a36Sopenharmony_ci	return 0;
399662306a36Sopenharmony_ci}
399762306a36Sopenharmony_ci
399862306a36Sopenharmony_cistatic int snd_hdsp_hw_silence(struct snd_pcm_substream *substream,
399962306a36Sopenharmony_ci			       int channel, unsigned long pos,
400062306a36Sopenharmony_ci			       unsigned long count)
400162306a36Sopenharmony_ci{
400262306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
400362306a36Sopenharmony_ci	signed char *channel_buf;
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_ci	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
400662306a36Sopenharmony_ci	if (snd_BUG_ON(!channel_buf))
400762306a36Sopenharmony_ci		return -EIO;
400862306a36Sopenharmony_ci	memset(channel_buf + pos, 0, count);
400962306a36Sopenharmony_ci	return 0;
401062306a36Sopenharmony_ci}
401162306a36Sopenharmony_ci
401262306a36Sopenharmony_cistatic int snd_hdsp_reset(struct snd_pcm_substream *substream)
401362306a36Sopenharmony_ci{
401462306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
401562306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
401662306a36Sopenharmony_ci	struct snd_pcm_substream *other;
401762306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
401862306a36Sopenharmony_ci		other = hdsp->capture_substream;
401962306a36Sopenharmony_ci	else
402062306a36Sopenharmony_ci		other = hdsp->playback_substream;
402162306a36Sopenharmony_ci	if (hdsp->running)
402262306a36Sopenharmony_ci		runtime->status->hw_ptr = hdsp_hw_pointer(hdsp);
402362306a36Sopenharmony_ci	else
402462306a36Sopenharmony_ci		runtime->status->hw_ptr = 0;
402562306a36Sopenharmony_ci	if (other) {
402662306a36Sopenharmony_ci		struct snd_pcm_substream *s;
402762306a36Sopenharmony_ci		struct snd_pcm_runtime *oruntime = other->runtime;
402862306a36Sopenharmony_ci		snd_pcm_group_for_each_entry(s, substream) {
402962306a36Sopenharmony_ci			if (s == other) {
403062306a36Sopenharmony_ci				oruntime->status->hw_ptr = runtime->status->hw_ptr;
403162306a36Sopenharmony_ci				break;
403262306a36Sopenharmony_ci			}
403362306a36Sopenharmony_ci		}
403462306a36Sopenharmony_ci	}
403562306a36Sopenharmony_ci	return 0;
403662306a36Sopenharmony_ci}
403762306a36Sopenharmony_ci
403862306a36Sopenharmony_cistatic int snd_hdsp_hw_params(struct snd_pcm_substream *substream,
403962306a36Sopenharmony_ci				 struct snd_pcm_hw_params *params)
404062306a36Sopenharmony_ci{
404162306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
404262306a36Sopenharmony_ci	int err;
404362306a36Sopenharmony_ci	pid_t this_pid;
404462306a36Sopenharmony_ci	pid_t other_pid;
404562306a36Sopenharmony_ci
404662306a36Sopenharmony_ci	if (hdsp_check_for_iobox (hdsp))
404762306a36Sopenharmony_ci		return -EIO;
404862306a36Sopenharmony_ci
404962306a36Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 1))
405062306a36Sopenharmony_ci		return -EIO;
405162306a36Sopenharmony_ci
405262306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
405362306a36Sopenharmony_ci
405462306a36Sopenharmony_ci	if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
405562306a36Sopenharmony_ci		hdsp->control_register &= ~(HDSP_SPDIFProfessional | HDSP_SPDIFNonAudio | HDSP_SPDIFEmphasis);
405662306a36Sopenharmony_ci		hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register |= hdsp->creg_spdif_stream);
405762306a36Sopenharmony_ci		this_pid = hdsp->playback_pid;
405862306a36Sopenharmony_ci		other_pid = hdsp->capture_pid;
405962306a36Sopenharmony_ci	} else {
406062306a36Sopenharmony_ci		this_pid = hdsp->capture_pid;
406162306a36Sopenharmony_ci		other_pid = hdsp->playback_pid;
406262306a36Sopenharmony_ci	}
406362306a36Sopenharmony_ci
406462306a36Sopenharmony_ci	if ((other_pid > 0) && (this_pid != other_pid)) {
406562306a36Sopenharmony_ci
406662306a36Sopenharmony_ci		/* The other stream is open, and not by the same
406762306a36Sopenharmony_ci		   task as this one. Make sure that the parameters
406862306a36Sopenharmony_ci		   that matter are the same.
406962306a36Sopenharmony_ci		 */
407062306a36Sopenharmony_ci
407162306a36Sopenharmony_ci		if (params_rate(params) != hdsp->system_sample_rate) {
407262306a36Sopenharmony_ci			spin_unlock_irq(&hdsp->lock);
407362306a36Sopenharmony_ci			_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
407462306a36Sopenharmony_ci			return -EBUSY;
407562306a36Sopenharmony_ci		}
407662306a36Sopenharmony_ci
407762306a36Sopenharmony_ci		if (params_period_size(params) != hdsp->period_bytes / 4) {
407862306a36Sopenharmony_ci			spin_unlock_irq(&hdsp->lock);
407962306a36Sopenharmony_ci			_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
408062306a36Sopenharmony_ci			return -EBUSY;
408162306a36Sopenharmony_ci		}
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci		/* We're fine. */
408462306a36Sopenharmony_ci
408562306a36Sopenharmony_ci		spin_unlock_irq(&hdsp->lock);
408662306a36Sopenharmony_ci 		return 0;
408762306a36Sopenharmony_ci
408862306a36Sopenharmony_ci	} else {
408962306a36Sopenharmony_ci		spin_unlock_irq(&hdsp->lock);
409062306a36Sopenharmony_ci	}
409162306a36Sopenharmony_ci
409262306a36Sopenharmony_ci	/* how to make sure that the rate matches an externally-set one ?
409362306a36Sopenharmony_ci	 */
409462306a36Sopenharmony_ci
409562306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
409662306a36Sopenharmony_ci	if (! hdsp->clock_source_locked) {
409762306a36Sopenharmony_ci		err = hdsp_set_rate(hdsp, params_rate(params), 0);
409862306a36Sopenharmony_ci		if (err < 0) {
409962306a36Sopenharmony_ci			spin_unlock_irq(&hdsp->lock);
410062306a36Sopenharmony_ci			_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
410162306a36Sopenharmony_ci			return err;
410262306a36Sopenharmony_ci		}
410362306a36Sopenharmony_ci	}
410462306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
410562306a36Sopenharmony_ci
410662306a36Sopenharmony_ci	err = hdsp_set_interrupt_interval(hdsp, params_period_size(params));
410762306a36Sopenharmony_ci	if (err < 0) {
410862306a36Sopenharmony_ci		_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
410962306a36Sopenharmony_ci		return err;
411062306a36Sopenharmony_ci	}
411162306a36Sopenharmony_ci
411262306a36Sopenharmony_ci	return 0;
411362306a36Sopenharmony_ci}
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_cistatic int snd_hdsp_channel_info(struct snd_pcm_substream *substream,
411662306a36Sopenharmony_ci				    struct snd_pcm_channel_info *info)
411762306a36Sopenharmony_ci{
411862306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
411962306a36Sopenharmony_ci	unsigned int channel = info->channel;
412062306a36Sopenharmony_ci
412162306a36Sopenharmony_ci	if (snd_BUG_ON(channel >= hdsp->max_channels))
412262306a36Sopenharmony_ci		return -EINVAL;
412362306a36Sopenharmony_ci	channel = array_index_nospec(channel, hdsp->max_channels);
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_ci	if (hdsp->channel_map[channel] < 0)
412662306a36Sopenharmony_ci		return -EINVAL;
412762306a36Sopenharmony_ci
412862306a36Sopenharmony_ci	info->offset = hdsp->channel_map[channel] * HDSP_CHANNEL_BUFFER_BYTES;
412962306a36Sopenharmony_ci	info->first = 0;
413062306a36Sopenharmony_ci	info->step = 32;
413162306a36Sopenharmony_ci	return 0;
413262306a36Sopenharmony_ci}
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_cistatic int snd_hdsp_ioctl(struct snd_pcm_substream *substream,
413562306a36Sopenharmony_ci			     unsigned int cmd, void *arg)
413662306a36Sopenharmony_ci{
413762306a36Sopenharmony_ci	switch (cmd) {
413862306a36Sopenharmony_ci	case SNDRV_PCM_IOCTL1_RESET:
413962306a36Sopenharmony_ci		return snd_hdsp_reset(substream);
414062306a36Sopenharmony_ci	case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
414162306a36Sopenharmony_ci		return snd_hdsp_channel_info(substream, arg);
414262306a36Sopenharmony_ci	default:
414362306a36Sopenharmony_ci		break;
414462306a36Sopenharmony_ci	}
414562306a36Sopenharmony_ci
414662306a36Sopenharmony_ci	return snd_pcm_lib_ioctl(substream, cmd, arg);
414762306a36Sopenharmony_ci}
414862306a36Sopenharmony_ci
414962306a36Sopenharmony_cistatic int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd)
415062306a36Sopenharmony_ci{
415162306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
415262306a36Sopenharmony_ci	struct snd_pcm_substream *other;
415362306a36Sopenharmony_ci	int running;
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_ci	if (hdsp_check_for_iobox (hdsp))
415662306a36Sopenharmony_ci		return -EIO;
415762306a36Sopenharmony_ci
415862306a36Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 0)) /* no auto-loading in trigger */
415962306a36Sopenharmony_ci		return -EIO;
416062306a36Sopenharmony_ci
416162306a36Sopenharmony_ci	spin_lock(&hdsp->lock);
416262306a36Sopenharmony_ci	running = hdsp->running;
416362306a36Sopenharmony_ci	switch (cmd) {
416462306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
416562306a36Sopenharmony_ci		running |= 1 << substream->stream;
416662306a36Sopenharmony_ci		break;
416762306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
416862306a36Sopenharmony_ci		running &= ~(1 << substream->stream);
416962306a36Sopenharmony_ci		break;
417062306a36Sopenharmony_ci	default:
417162306a36Sopenharmony_ci		snd_BUG();
417262306a36Sopenharmony_ci		spin_unlock(&hdsp->lock);
417362306a36Sopenharmony_ci		return -EINVAL;
417462306a36Sopenharmony_ci	}
417562306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
417662306a36Sopenharmony_ci		other = hdsp->capture_substream;
417762306a36Sopenharmony_ci	else
417862306a36Sopenharmony_ci		other = hdsp->playback_substream;
417962306a36Sopenharmony_ci
418062306a36Sopenharmony_ci	if (other) {
418162306a36Sopenharmony_ci		struct snd_pcm_substream *s;
418262306a36Sopenharmony_ci		snd_pcm_group_for_each_entry(s, substream) {
418362306a36Sopenharmony_ci			if (s == other) {
418462306a36Sopenharmony_ci				snd_pcm_trigger_done(s, substream);
418562306a36Sopenharmony_ci				if (cmd == SNDRV_PCM_TRIGGER_START)
418662306a36Sopenharmony_ci					running |= 1 << s->stream;
418762306a36Sopenharmony_ci				else
418862306a36Sopenharmony_ci					running &= ~(1 << s->stream);
418962306a36Sopenharmony_ci				goto _ok;
419062306a36Sopenharmony_ci			}
419162306a36Sopenharmony_ci		}
419262306a36Sopenharmony_ci		if (cmd == SNDRV_PCM_TRIGGER_START) {
419362306a36Sopenharmony_ci			if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) &&
419462306a36Sopenharmony_ci			    substream->stream == SNDRV_PCM_STREAM_CAPTURE)
419562306a36Sopenharmony_ci				hdsp_silence_playback(hdsp);
419662306a36Sopenharmony_ci		} else {
419762306a36Sopenharmony_ci			if (running &&
419862306a36Sopenharmony_ci			    substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
419962306a36Sopenharmony_ci				hdsp_silence_playback(hdsp);
420062306a36Sopenharmony_ci		}
420162306a36Sopenharmony_ci	} else {
420262306a36Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
420362306a36Sopenharmony_ci				hdsp_silence_playback(hdsp);
420462306a36Sopenharmony_ci	}
420562306a36Sopenharmony_ci _ok:
420662306a36Sopenharmony_ci	snd_pcm_trigger_done(substream, substream);
420762306a36Sopenharmony_ci	if (!hdsp->running && running)
420862306a36Sopenharmony_ci		hdsp_start_audio(hdsp);
420962306a36Sopenharmony_ci	else if (hdsp->running && !running)
421062306a36Sopenharmony_ci		hdsp_stop_audio(hdsp);
421162306a36Sopenharmony_ci	hdsp->running = running;
421262306a36Sopenharmony_ci	spin_unlock(&hdsp->lock);
421362306a36Sopenharmony_ci
421462306a36Sopenharmony_ci	return 0;
421562306a36Sopenharmony_ci}
421662306a36Sopenharmony_ci
421762306a36Sopenharmony_cistatic int snd_hdsp_prepare(struct snd_pcm_substream *substream)
421862306a36Sopenharmony_ci{
421962306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
422062306a36Sopenharmony_ci	int result = 0;
422162306a36Sopenharmony_ci
422262306a36Sopenharmony_ci	if (hdsp_check_for_iobox (hdsp))
422362306a36Sopenharmony_ci		return -EIO;
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 1))
422662306a36Sopenharmony_ci		return -EIO;
422762306a36Sopenharmony_ci
422862306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
422962306a36Sopenharmony_ci	if (!hdsp->running)
423062306a36Sopenharmony_ci		hdsp_reset_hw_pointer(hdsp);
423162306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
423262306a36Sopenharmony_ci	return result;
423362306a36Sopenharmony_ci}
423462306a36Sopenharmony_ci
423562306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_hdsp_playback_subinfo =
423662306a36Sopenharmony_ci{
423762306a36Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
423862306a36Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
423962306a36Sopenharmony_ci				 SNDRV_PCM_INFO_NONINTERLEAVED |
424062306a36Sopenharmony_ci				 SNDRV_PCM_INFO_SYNC_START |
424162306a36Sopenharmony_ci				 SNDRV_PCM_INFO_DOUBLE),
424262306a36Sopenharmony_ci#ifdef SNDRV_BIG_ENDIAN
424362306a36Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_S32_BE,
424462306a36Sopenharmony_ci#else
424562306a36Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
424662306a36Sopenharmony_ci#endif
424762306a36Sopenharmony_ci	.rates =		(SNDRV_PCM_RATE_32000 |
424862306a36Sopenharmony_ci				 SNDRV_PCM_RATE_44100 |
424962306a36Sopenharmony_ci				 SNDRV_PCM_RATE_48000 |
425062306a36Sopenharmony_ci				 SNDRV_PCM_RATE_64000 |
425162306a36Sopenharmony_ci				 SNDRV_PCM_RATE_88200 |
425262306a36Sopenharmony_ci				 SNDRV_PCM_RATE_96000),
425362306a36Sopenharmony_ci	.rate_min =		32000,
425462306a36Sopenharmony_ci	.rate_max =		96000,
425562306a36Sopenharmony_ci	.channels_min =		6,
425662306a36Sopenharmony_ci	.channels_max =		HDSP_MAX_CHANNELS,
425762306a36Sopenharmony_ci	.buffer_bytes_max =	HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
425862306a36Sopenharmony_ci	.period_bytes_min =	(64 * 4) * 10,
425962306a36Sopenharmony_ci	.period_bytes_max =	(8192 * 4) * HDSP_MAX_CHANNELS,
426062306a36Sopenharmony_ci	.periods_min =		2,
426162306a36Sopenharmony_ci	.periods_max =		2,
426262306a36Sopenharmony_ci	.fifo_size =		0
426362306a36Sopenharmony_ci};
426462306a36Sopenharmony_ci
426562306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_hdsp_capture_subinfo =
426662306a36Sopenharmony_ci{
426762306a36Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
426862306a36Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
426962306a36Sopenharmony_ci				 SNDRV_PCM_INFO_NONINTERLEAVED |
427062306a36Sopenharmony_ci				 SNDRV_PCM_INFO_SYNC_START),
427162306a36Sopenharmony_ci#ifdef SNDRV_BIG_ENDIAN
427262306a36Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_S32_BE,
427362306a36Sopenharmony_ci#else
427462306a36Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
427562306a36Sopenharmony_ci#endif
427662306a36Sopenharmony_ci	.rates =		(SNDRV_PCM_RATE_32000 |
427762306a36Sopenharmony_ci				 SNDRV_PCM_RATE_44100 |
427862306a36Sopenharmony_ci				 SNDRV_PCM_RATE_48000 |
427962306a36Sopenharmony_ci				 SNDRV_PCM_RATE_64000 |
428062306a36Sopenharmony_ci				 SNDRV_PCM_RATE_88200 |
428162306a36Sopenharmony_ci				 SNDRV_PCM_RATE_96000),
428262306a36Sopenharmony_ci	.rate_min =		32000,
428362306a36Sopenharmony_ci	.rate_max =		96000,
428462306a36Sopenharmony_ci	.channels_min =		5,
428562306a36Sopenharmony_ci	.channels_max =		HDSP_MAX_CHANNELS,
428662306a36Sopenharmony_ci	.buffer_bytes_max =	HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
428762306a36Sopenharmony_ci	.period_bytes_min =	(64 * 4) * 10,
428862306a36Sopenharmony_ci	.period_bytes_max =	(8192 * 4) * HDSP_MAX_CHANNELS,
428962306a36Sopenharmony_ci	.periods_min =		2,
429062306a36Sopenharmony_ci	.periods_max =		2,
429162306a36Sopenharmony_ci	.fifo_size =		0
429262306a36Sopenharmony_ci};
429362306a36Sopenharmony_ci
429462306a36Sopenharmony_cistatic const unsigned int hdsp_period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
429562306a36Sopenharmony_ci
429662306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hdsp_hw_constraints_period_sizes = {
429762306a36Sopenharmony_ci	.count = ARRAY_SIZE(hdsp_period_sizes),
429862306a36Sopenharmony_ci	.list = hdsp_period_sizes,
429962306a36Sopenharmony_ci	.mask = 0
430062306a36Sopenharmony_ci};
430162306a36Sopenharmony_ci
430262306a36Sopenharmony_cistatic const unsigned int hdsp_9632_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 };
430362306a36Sopenharmony_ci
430462306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hdsp_hw_constraints_9632_sample_rates = {
430562306a36Sopenharmony_ci	.count = ARRAY_SIZE(hdsp_9632_sample_rates),
430662306a36Sopenharmony_ci	.list = hdsp_9632_sample_rates,
430762306a36Sopenharmony_ci	.mask = 0
430862306a36Sopenharmony_ci};
430962306a36Sopenharmony_ci
431062306a36Sopenharmony_cistatic int snd_hdsp_hw_rule_in_channels(struct snd_pcm_hw_params *params,
431162306a36Sopenharmony_ci					struct snd_pcm_hw_rule *rule)
431262306a36Sopenharmony_ci{
431362306a36Sopenharmony_ci	struct hdsp *hdsp = rule->private;
431462306a36Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
431562306a36Sopenharmony_ci	if (hdsp->io_type == H9632) {
431662306a36Sopenharmony_ci		unsigned int list[3];
431762306a36Sopenharmony_ci		list[0] = hdsp->qs_in_channels;
431862306a36Sopenharmony_ci		list[1] = hdsp->ds_in_channels;
431962306a36Sopenharmony_ci		list[2] = hdsp->ss_in_channels;
432062306a36Sopenharmony_ci		return snd_interval_list(c, 3, list, 0);
432162306a36Sopenharmony_ci	} else {
432262306a36Sopenharmony_ci		unsigned int list[2];
432362306a36Sopenharmony_ci		list[0] = hdsp->ds_in_channels;
432462306a36Sopenharmony_ci		list[1] = hdsp->ss_in_channels;
432562306a36Sopenharmony_ci		return snd_interval_list(c, 2, list, 0);
432662306a36Sopenharmony_ci	}
432762306a36Sopenharmony_ci}
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_cistatic int snd_hdsp_hw_rule_out_channels(struct snd_pcm_hw_params *params,
433062306a36Sopenharmony_ci					struct snd_pcm_hw_rule *rule)
433162306a36Sopenharmony_ci{
433262306a36Sopenharmony_ci	unsigned int list[3];
433362306a36Sopenharmony_ci	struct hdsp *hdsp = rule->private;
433462306a36Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
433562306a36Sopenharmony_ci	if (hdsp->io_type == H9632) {
433662306a36Sopenharmony_ci		list[0] = hdsp->qs_out_channels;
433762306a36Sopenharmony_ci		list[1] = hdsp->ds_out_channels;
433862306a36Sopenharmony_ci		list[2] = hdsp->ss_out_channels;
433962306a36Sopenharmony_ci		return snd_interval_list(c, 3, list, 0);
434062306a36Sopenharmony_ci	} else {
434162306a36Sopenharmony_ci		list[0] = hdsp->ds_out_channels;
434262306a36Sopenharmony_ci		list[1] = hdsp->ss_out_channels;
434362306a36Sopenharmony_ci	}
434462306a36Sopenharmony_ci	return snd_interval_list(c, 2, list, 0);
434562306a36Sopenharmony_ci}
434662306a36Sopenharmony_ci
434762306a36Sopenharmony_cistatic int snd_hdsp_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params,
434862306a36Sopenharmony_ci					     struct snd_pcm_hw_rule *rule)
434962306a36Sopenharmony_ci{
435062306a36Sopenharmony_ci	struct hdsp *hdsp = rule->private;
435162306a36Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
435262306a36Sopenharmony_ci	struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
435362306a36Sopenharmony_ci	if (r->min > 96000 && hdsp->io_type == H9632) {
435462306a36Sopenharmony_ci		struct snd_interval t = {
435562306a36Sopenharmony_ci			.min = hdsp->qs_in_channels,
435662306a36Sopenharmony_ci			.max = hdsp->qs_in_channels,
435762306a36Sopenharmony_ci			.integer = 1,
435862306a36Sopenharmony_ci		};
435962306a36Sopenharmony_ci		return snd_interval_refine(c, &t);
436062306a36Sopenharmony_ci	} else if (r->min > 48000 && r->max <= 96000) {
436162306a36Sopenharmony_ci		struct snd_interval t = {
436262306a36Sopenharmony_ci			.min = hdsp->ds_in_channels,
436362306a36Sopenharmony_ci			.max = hdsp->ds_in_channels,
436462306a36Sopenharmony_ci			.integer = 1,
436562306a36Sopenharmony_ci		};
436662306a36Sopenharmony_ci		return snd_interval_refine(c, &t);
436762306a36Sopenharmony_ci	} else if (r->max < 64000) {
436862306a36Sopenharmony_ci		struct snd_interval t = {
436962306a36Sopenharmony_ci			.min = hdsp->ss_in_channels,
437062306a36Sopenharmony_ci			.max = hdsp->ss_in_channels,
437162306a36Sopenharmony_ci			.integer = 1,
437262306a36Sopenharmony_ci		};
437362306a36Sopenharmony_ci		return snd_interval_refine(c, &t);
437462306a36Sopenharmony_ci	}
437562306a36Sopenharmony_ci	return 0;
437662306a36Sopenharmony_ci}
437762306a36Sopenharmony_ci
437862306a36Sopenharmony_cistatic int snd_hdsp_hw_rule_out_channels_rate(struct snd_pcm_hw_params *params,
437962306a36Sopenharmony_ci					     struct snd_pcm_hw_rule *rule)
438062306a36Sopenharmony_ci{
438162306a36Sopenharmony_ci	struct hdsp *hdsp = rule->private;
438262306a36Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
438362306a36Sopenharmony_ci	struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
438462306a36Sopenharmony_ci	if (r->min > 96000 && hdsp->io_type == H9632) {
438562306a36Sopenharmony_ci		struct snd_interval t = {
438662306a36Sopenharmony_ci			.min = hdsp->qs_out_channels,
438762306a36Sopenharmony_ci			.max = hdsp->qs_out_channels,
438862306a36Sopenharmony_ci			.integer = 1,
438962306a36Sopenharmony_ci		};
439062306a36Sopenharmony_ci		return snd_interval_refine(c, &t);
439162306a36Sopenharmony_ci	} else if (r->min > 48000 && r->max <= 96000) {
439262306a36Sopenharmony_ci		struct snd_interval t = {
439362306a36Sopenharmony_ci			.min = hdsp->ds_out_channels,
439462306a36Sopenharmony_ci			.max = hdsp->ds_out_channels,
439562306a36Sopenharmony_ci			.integer = 1,
439662306a36Sopenharmony_ci		};
439762306a36Sopenharmony_ci		return snd_interval_refine(c, &t);
439862306a36Sopenharmony_ci	} else if (r->max < 64000) {
439962306a36Sopenharmony_ci		struct snd_interval t = {
440062306a36Sopenharmony_ci			.min = hdsp->ss_out_channels,
440162306a36Sopenharmony_ci			.max = hdsp->ss_out_channels,
440262306a36Sopenharmony_ci			.integer = 1,
440362306a36Sopenharmony_ci		};
440462306a36Sopenharmony_ci		return snd_interval_refine(c, &t);
440562306a36Sopenharmony_ci	}
440662306a36Sopenharmony_ci	return 0;
440762306a36Sopenharmony_ci}
440862306a36Sopenharmony_ci
440962306a36Sopenharmony_cistatic int snd_hdsp_hw_rule_rate_out_channels(struct snd_pcm_hw_params *params,
441062306a36Sopenharmony_ci					     struct snd_pcm_hw_rule *rule)
441162306a36Sopenharmony_ci{
441262306a36Sopenharmony_ci	struct hdsp *hdsp = rule->private;
441362306a36Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
441462306a36Sopenharmony_ci	struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
441562306a36Sopenharmony_ci	if (c->min >= hdsp->ss_out_channels) {
441662306a36Sopenharmony_ci		struct snd_interval t = {
441762306a36Sopenharmony_ci			.min = 32000,
441862306a36Sopenharmony_ci			.max = 48000,
441962306a36Sopenharmony_ci			.integer = 1,
442062306a36Sopenharmony_ci		};
442162306a36Sopenharmony_ci		return snd_interval_refine(r, &t);
442262306a36Sopenharmony_ci	} else if (c->max <= hdsp->qs_out_channels && hdsp->io_type == H9632) {
442362306a36Sopenharmony_ci		struct snd_interval t = {
442462306a36Sopenharmony_ci			.min = 128000,
442562306a36Sopenharmony_ci			.max = 192000,
442662306a36Sopenharmony_ci			.integer = 1,
442762306a36Sopenharmony_ci		};
442862306a36Sopenharmony_ci		return snd_interval_refine(r, &t);
442962306a36Sopenharmony_ci	} else if (c->max <= hdsp->ds_out_channels) {
443062306a36Sopenharmony_ci		struct snd_interval t = {
443162306a36Sopenharmony_ci			.min = 64000,
443262306a36Sopenharmony_ci			.max = 96000,
443362306a36Sopenharmony_ci			.integer = 1,
443462306a36Sopenharmony_ci		};
443562306a36Sopenharmony_ci		return snd_interval_refine(r, &t);
443662306a36Sopenharmony_ci	}
443762306a36Sopenharmony_ci	return 0;
443862306a36Sopenharmony_ci}
443962306a36Sopenharmony_ci
444062306a36Sopenharmony_cistatic int snd_hdsp_hw_rule_rate_in_channels(struct snd_pcm_hw_params *params,
444162306a36Sopenharmony_ci					     struct snd_pcm_hw_rule *rule)
444262306a36Sopenharmony_ci{
444362306a36Sopenharmony_ci	struct hdsp *hdsp = rule->private;
444462306a36Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
444562306a36Sopenharmony_ci	struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
444662306a36Sopenharmony_ci	if (c->min >= hdsp->ss_in_channels) {
444762306a36Sopenharmony_ci		struct snd_interval t = {
444862306a36Sopenharmony_ci			.min = 32000,
444962306a36Sopenharmony_ci			.max = 48000,
445062306a36Sopenharmony_ci			.integer = 1,
445162306a36Sopenharmony_ci		};
445262306a36Sopenharmony_ci		return snd_interval_refine(r, &t);
445362306a36Sopenharmony_ci	} else if (c->max <= hdsp->qs_in_channels && hdsp->io_type == H9632) {
445462306a36Sopenharmony_ci		struct snd_interval t = {
445562306a36Sopenharmony_ci			.min = 128000,
445662306a36Sopenharmony_ci			.max = 192000,
445762306a36Sopenharmony_ci			.integer = 1,
445862306a36Sopenharmony_ci		};
445962306a36Sopenharmony_ci		return snd_interval_refine(r, &t);
446062306a36Sopenharmony_ci	} else if (c->max <= hdsp->ds_in_channels) {
446162306a36Sopenharmony_ci		struct snd_interval t = {
446262306a36Sopenharmony_ci			.min = 64000,
446362306a36Sopenharmony_ci			.max = 96000,
446462306a36Sopenharmony_ci			.integer = 1,
446562306a36Sopenharmony_ci		};
446662306a36Sopenharmony_ci		return snd_interval_refine(r, &t);
446762306a36Sopenharmony_ci	}
446862306a36Sopenharmony_ci	return 0;
446962306a36Sopenharmony_ci}
447062306a36Sopenharmony_ci
447162306a36Sopenharmony_cistatic int snd_hdsp_playback_open(struct snd_pcm_substream *substream)
447262306a36Sopenharmony_ci{
447362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
447462306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci	if (hdsp_check_for_iobox (hdsp))
447762306a36Sopenharmony_ci		return -EIO;
447862306a36Sopenharmony_ci
447962306a36Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 1))
448062306a36Sopenharmony_ci		return -EIO;
448162306a36Sopenharmony_ci
448262306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
448362306a36Sopenharmony_ci
448462306a36Sopenharmony_ci	snd_pcm_set_sync(substream);
448562306a36Sopenharmony_ci
448662306a36Sopenharmony_ci        runtime->hw = snd_hdsp_playback_subinfo;
448762306a36Sopenharmony_ci	snd_pcm_set_runtime_buffer(substream, &hdsp->playback_dma_buf);
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci	hdsp->playback_pid = current->pid;
449062306a36Sopenharmony_ci	hdsp->playback_substream = substream;
449162306a36Sopenharmony_ci
449262306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
449362306a36Sopenharmony_ci
449462306a36Sopenharmony_ci	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
449562306a36Sopenharmony_ci	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes);
449662306a36Sopenharmony_ci	if (hdsp->clock_source_locked) {
449762306a36Sopenharmony_ci		runtime->hw.rate_min = runtime->hw.rate_max = hdsp->system_sample_rate;
449862306a36Sopenharmony_ci	} else if (hdsp->io_type == H9632) {
449962306a36Sopenharmony_ci		runtime->hw.rate_max = 192000;
450062306a36Sopenharmony_ci		runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
450162306a36Sopenharmony_ci		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates);
450262306a36Sopenharmony_ci	}
450362306a36Sopenharmony_ci	if (hdsp->io_type == H9632) {
450462306a36Sopenharmony_ci		runtime->hw.channels_min = hdsp->qs_out_channels;
450562306a36Sopenharmony_ci		runtime->hw.channels_max = hdsp->ss_out_channels;
450662306a36Sopenharmony_ci	}
450762306a36Sopenharmony_ci
450862306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
450962306a36Sopenharmony_ci			     snd_hdsp_hw_rule_out_channels, hdsp,
451062306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
451162306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
451262306a36Sopenharmony_ci			     snd_hdsp_hw_rule_out_channels_rate, hdsp,
451362306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_RATE, -1);
451462306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
451562306a36Sopenharmony_ci			     snd_hdsp_hw_rule_rate_out_channels, hdsp,
451662306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
451762306a36Sopenharmony_ci
451862306a36Sopenharmony_ci	if (RPM != hdsp->io_type) {
451962306a36Sopenharmony_ci		hdsp->creg_spdif_stream = hdsp->creg_spdif;
452062306a36Sopenharmony_ci		hdsp->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
452162306a36Sopenharmony_ci		snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
452262306a36Sopenharmony_ci			SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
452362306a36Sopenharmony_ci	}
452462306a36Sopenharmony_ci	return 0;
452562306a36Sopenharmony_ci}
452662306a36Sopenharmony_ci
452762306a36Sopenharmony_cistatic int snd_hdsp_playback_release(struct snd_pcm_substream *substream)
452862306a36Sopenharmony_ci{
452962306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
453062306a36Sopenharmony_ci
453162306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
453262306a36Sopenharmony_ci
453362306a36Sopenharmony_ci	hdsp->playback_pid = -1;
453462306a36Sopenharmony_ci	hdsp->playback_substream = NULL;
453562306a36Sopenharmony_ci
453662306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
453762306a36Sopenharmony_ci
453862306a36Sopenharmony_ci	if (RPM != hdsp->io_type) {
453962306a36Sopenharmony_ci		hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
454062306a36Sopenharmony_ci		snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
454162306a36Sopenharmony_ci			SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
454262306a36Sopenharmony_ci	}
454362306a36Sopenharmony_ci	return 0;
454462306a36Sopenharmony_ci}
454562306a36Sopenharmony_ci
454662306a36Sopenharmony_ci
454762306a36Sopenharmony_cistatic int snd_hdsp_capture_open(struct snd_pcm_substream *substream)
454862306a36Sopenharmony_ci{
454962306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
455062306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
455162306a36Sopenharmony_ci
455262306a36Sopenharmony_ci	if (hdsp_check_for_iobox (hdsp))
455362306a36Sopenharmony_ci		return -EIO;
455462306a36Sopenharmony_ci
455562306a36Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 1))
455662306a36Sopenharmony_ci		return -EIO;
455762306a36Sopenharmony_ci
455862306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci	snd_pcm_set_sync(substream);
456162306a36Sopenharmony_ci
456262306a36Sopenharmony_ci	runtime->hw = snd_hdsp_capture_subinfo;
456362306a36Sopenharmony_ci	snd_pcm_set_runtime_buffer(substream, &hdsp->capture_dma_buf);
456462306a36Sopenharmony_ci
456562306a36Sopenharmony_ci	hdsp->capture_pid = current->pid;
456662306a36Sopenharmony_ci	hdsp->capture_substream = substream;
456762306a36Sopenharmony_ci
456862306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
456962306a36Sopenharmony_ci
457062306a36Sopenharmony_ci	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
457162306a36Sopenharmony_ci	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes);
457262306a36Sopenharmony_ci	if (hdsp->io_type == H9632) {
457362306a36Sopenharmony_ci		runtime->hw.channels_min = hdsp->qs_in_channels;
457462306a36Sopenharmony_ci		runtime->hw.channels_max = hdsp->ss_in_channels;
457562306a36Sopenharmony_ci		runtime->hw.rate_max = 192000;
457662306a36Sopenharmony_ci		runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
457762306a36Sopenharmony_ci		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates);
457862306a36Sopenharmony_ci	}
457962306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
458062306a36Sopenharmony_ci			     snd_hdsp_hw_rule_in_channels, hdsp,
458162306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
458262306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
458362306a36Sopenharmony_ci			     snd_hdsp_hw_rule_in_channels_rate, hdsp,
458462306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_RATE, -1);
458562306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
458662306a36Sopenharmony_ci			     snd_hdsp_hw_rule_rate_in_channels, hdsp,
458762306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
458862306a36Sopenharmony_ci	return 0;
458962306a36Sopenharmony_ci}
459062306a36Sopenharmony_ci
459162306a36Sopenharmony_cistatic int snd_hdsp_capture_release(struct snd_pcm_substream *substream)
459262306a36Sopenharmony_ci{
459362306a36Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
459462306a36Sopenharmony_ci
459562306a36Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
459662306a36Sopenharmony_ci
459762306a36Sopenharmony_ci	hdsp->capture_pid = -1;
459862306a36Sopenharmony_ci	hdsp->capture_substream = NULL;
459962306a36Sopenharmony_ci
460062306a36Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
460162306a36Sopenharmony_ci	return 0;
460262306a36Sopenharmony_ci}
460362306a36Sopenharmony_ci
460462306a36Sopenharmony_ci/* helper functions for copying meter values */
460562306a36Sopenharmony_cistatic inline int copy_u32_le(void __user *dest, void __iomem *src)
460662306a36Sopenharmony_ci{
460762306a36Sopenharmony_ci	u32 val = readl(src);
460862306a36Sopenharmony_ci	return copy_to_user(dest, &val, 4);
460962306a36Sopenharmony_ci}
461062306a36Sopenharmony_ci
461162306a36Sopenharmony_cistatic inline int copy_u64_le(void __user *dest, void __iomem *src_low, void __iomem *src_high)
461262306a36Sopenharmony_ci{
461362306a36Sopenharmony_ci	u32 rms_low, rms_high;
461462306a36Sopenharmony_ci	u64 rms;
461562306a36Sopenharmony_ci	rms_low = readl(src_low);
461662306a36Sopenharmony_ci	rms_high = readl(src_high);
461762306a36Sopenharmony_ci	rms = ((u64)rms_high << 32) | rms_low;
461862306a36Sopenharmony_ci	return copy_to_user(dest, &rms, 8);
461962306a36Sopenharmony_ci}
462062306a36Sopenharmony_ci
462162306a36Sopenharmony_cistatic inline int copy_u48_le(void __user *dest, void __iomem *src_low, void __iomem *src_high)
462262306a36Sopenharmony_ci{
462362306a36Sopenharmony_ci	u32 rms_low, rms_high;
462462306a36Sopenharmony_ci	u64 rms;
462562306a36Sopenharmony_ci	rms_low = readl(src_low) & 0xffffff00;
462662306a36Sopenharmony_ci	rms_high = readl(src_high) & 0xffffff00;
462762306a36Sopenharmony_ci	rms = ((u64)rms_high << 32) | rms_low;
462862306a36Sopenharmony_ci	return copy_to_user(dest, &rms, 8);
462962306a36Sopenharmony_ci}
463062306a36Sopenharmony_ci
463162306a36Sopenharmony_cistatic int hdsp_9652_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rms)
463262306a36Sopenharmony_ci{
463362306a36Sopenharmony_ci	int doublespeed = 0;
463462306a36Sopenharmony_ci	int i, j, channels, ofs;
463562306a36Sopenharmony_ci
463662306a36Sopenharmony_ci	if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus)
463762306a36Sopenharmony_ci		doublespeed = 1;
463862306a36Sopenharmony_ci	channels = doublespeed ? 14 : 26;
463962306a36Sopenharmony_ci	for (i = 0, j = 0; i < 26; ++i) {
464062306a36Sopenharmony_ci		if (doublespeed && (i & 4))
464162306a36Sopenharmony_ci			continue;
464262306a36Sopenharmony_ci		ofs = HDSP_9652_peakBase - j * 4;
464362306a36Sopenharmony_ci		if (copy_u32_le(&peak_rms->input_peaks[i], hdsp->iobase + ofs))
464462306a36Sopenharmony_ci			return -EFAULT;
464562306a36Sopenharmony_ci		ofs -= channels * 4;
464662306a36Sopenharmony_ci		if (copy_u32_le(&peak_rms->playback_peaks[i], hdsp->iobase + ofs))
464762306a36Sopenharmony_ci			return -EFAULT;
464862306a36Sopenharmony_ci		ofs -= channels * 4;
464962306a36Sopenharmony_ci		if (copy_u32_le(&peak_rms->output_peaks[i], hdsp->iobase + ofs))
465062306a36Sopenharmony_ci			return -EFAULT;
465162306a36Sopenharmony_ci		ofs = HDSP_9652_rmsBase + j * 8;
465262306a36Sopenharmony_ci		if (copy_u48_le(&peak_rms->input_rms[i], hdsp->iobase + ofs,
465362306a36Sopenharmony_ci				hdsp->iobase + ofs + 4))
465462306a36Sopenharmony_ci			return -EFAULT;
465562306a36Sopenharmony_ci		ofs += channels * 8;
465662306a36Sopenharmony_ci		if (copy_u48_le(&peak_rms->playback_rms[i], hdsp->iobase + ofs,
465762306a36Sopenharmony_ci				hdsp->iobase + ofs + 4))
465862306a36Sopenharmony_ci			return -EFAULT;
465962306a36Sopenharmony_ci		ofs += channels * 8;
466062306a36Sopenharmony_ci		if (copy_u48_le(&peak_rms->output_rms[i], hdsp->iobase + ofs,
466162306a36Sopenharmony_ci				hdsp->iobase + ofs + 4))
466262306a36Sopenharmony_ci			return -EFAULT;
466362306a36Sopenharmony_ci		j++;
466462306a36Sopenharmony_ci	}
466562306a36Sopenharmony_ci	return 0;
466662306a36Sopenharmony_ci}
466762306a36Sopenharmony_ci
466862306a36Sopenharmony_cistatic int hdsp_9632_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rms)
466962306a36Sopenharmony_ci{
467062306a36Sopenharmony_ci	int i, j;
467162306a36Sopenharmony_ci	struct hdsp_9632_meters __iomem *m;
467262306a36Sopenharmony_ci	int doublespeed = 0;
467362306a36Sopenharmony_ci
467462306a36Sopenharmony_ci	if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus)
467562306a36Sopenharmony_ci		doublespeed = 1;
467662306a36Sopenharmony_ci	m = (struct hdsp_9632_meters __iomem *)(hdsp->iobase+HDSP_9632_metersBase);
467762306a36Sopenharmony_ci	for (i = 0, j = 0; i < 16; ++i, ++j) {
467862306a36Sopenharmony_ci		if (copy_u32_le(&peak_rms->input_peaks[i], &m->input_peak[j]))
467962306a36Sopenharmony_ci			return -EFAULT;
468062306a36Sopenharmony_ci		if (copy_u32_le(&peak_rms->playback_peaks[i], &m->playback_peak[j]))
468162306a36Sopenharmony_ci			return -EFAULT;
468262306a36Sopenharmony_ci		if (copy_u32_le(&peak_rms->output_peaks[i], &m->output_peak[j]))
468362306a36Sopenharmony_ci			return -EFAULT;
468462306a36Sopenharmony_ci		if (copy_u64_le(&peak_rms->input_rms[i], &m->input_rms_low[j],
468562306a36Sopenharmony_ci				&m->input_rms_high[j]))
468662306a36Sopenharmony_ci			return -EFAULT;
468762306a36Sopenharmony_ci		if (copy_u64_le(&peak_rms->playback_rms[i], &m->playback_rms_low[j],
468862306a36Sopenharmony_ci				&m->playback_rms_high[j]))
468962306a36Sopenharmony_ci			return -EFAULT;
469062306a36Sopenharmony_ci		if (copy_u64_le(&peak_rms->output_rms[i], &m->output_rms_low[j],
469162306a36Sopenharmony_ci				&m->output_rms_high[j]))
469262306a36Sopenharmony_ci			return -EFAULT;
469362306a36Sopenharmony_ci		if (doublespeed && i == 3) i += 4;
469462306a36Sopenharmony_ci	}
469562306a36Sopenharmony_ci	return 0;
469662306a36Sopenharmony_ci}
469762306a36Sopenharmony_ci
469862306a36Sopenharmony_cistatic int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rms)
469962306a36Sopenharmony_ci{
470062306a36Sopenharmony_ci	int i;
470162306a36Sopenharmony_ci
470262306a36Sopenharmony_ci	for (i = 0; i < 26; i++) {
470362306a36Sopenharmony_ci		if (copy_u32_le(&peak_rms->playback_peaks[i],
470462306a36Sopenharmony_ci				hdsp->iobase + HDSP_playbackPeakLevel + i * 4))
470562306a36Sopenharmony_ci			return -EFAULT;
470662306a36Sopenharmony_ci		if (copy_u32_le(&peak_rms->input_peaks[i],
470762306a36Sopenharmony_ci				hdsp->iobase + HDSP_inputPeakLevel + i * 4))
470862306a36Sopenharmony_ci			return -EFAULT;
470962306a36Sopenharmony_ci	}
471062306a36Sopenharmony_ci	for (i = 0; i < 28; i++) {
471162306a36Sopenharmony_ci		if (copy_u32_le(&peak_rms->output_peaks[i],
471262306a36Sopenharmony_ci				hdsp->iobase + HDSP_outputPeakLevel + i * 4))
471362306a36Sopenharmony_ci			return -EFAULT;
471462306a36Sopenharmony_ci	}
471562306a36Sopenharmony_ci	for (i = 0; i < 26; ++i) {
471662306a36Sopenharmony_ci		if (copy_u64_le(&peak_rms->playback_rms[i],
471762306a36Sopenharmony_ci				hdsp->iobase + HDSP_playbackRmsLevel + i * 8 + 4,
471862306a36Sopenharmony_ci				hdsp->iobase + HDSP_playbackRmsLevel + i * 8))
471962306a36Sopenharmony_ci			return -EFAULT;
472062306a36Sopenharmony_ci		if (copy_u64_le(&peak_rms->input_rms[i],
472162306a36Sopenharmony_ci				hdsp->iobase + HDSP_inputRmsLevel + i * 8 + 4,
472262306a36Sopenharmony_ci				hdsp->iobase + HDSP_inputRmsLevel + i * 8))
472362306a36Sopenharmony_ci			return -EFAULT;
472462306a36Sopenharmony_ci	}
472562306a36Sopenharmony_ci	return 0;
472662306a36Sopenharmony_ci}
472762306a36Sopenharmony_ci
472862306a36Sopenharmony_cistatic int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
472962306a36Sopenharmony_ci{
473062306a36Sopenharmony_ci	struct hdsp *hdsp = hw->private_data;
473162306a36Sopenharmony_ci	void __user *argp = (void __user *)arg;
473262306a36Sopenharmony_ci	int err;
473362306a36Sopenharmony_ci
473462306a36Sopenharmony_ci	switch (cmd) {
473562306a36Sopenharmony_ci	case SNDRV_HDSP_IOCTL_GET_PEAK_RMS: {
473662306a36Sopenharmony_ci		struct hdsp_peak_rms __user *peak_rms = (struct hdsp_peak_rms __user *)arg;
473762306a36Sopenharmony_ci
473862306a36Sopenharmony_ci		err = hdsp_check_for_iobox(hdsp);
473962306a36Sopenharmony_ci		if (err < 0)
474062306a36Sopenharmony_ci			return err;
474162306a36Sopenharmony_ci
474262306a36Sopenharmony_ci		err = hdsp_check_for_firmware(hdsp, 1);
474362306a36Sopenharmony_ci		if (err < 0)
474462306a36Sopenharmony_ci			return err;
474562306a36Sopenharmony_ci
474662306a36Sopenharmony_ci		if (!(hdsp->state & HDSP_FirmwareLoaded)) {
474762306a36Sopenharmony_ci			dev_err(hdsp->card->dev,
474862306a36Sopenharmony_ci				"firmware needs to be uploaded to the card.\n");
474962306a36Sopenharmony_ci			return -EINVAL;
475062306a36Sopenharmony_ci		}
475162306a36Sopenharmony_ci
475262306a36Sopenharmony_ci		switch (hdsp->io_type) {
475362306a36Sopenharmony_ci		case H9652:
475462306a36Sopenharmony_ci			return hdsp_9652_get_peak(hdsp, peak_rms);
475562306a36Sopenharmony_ci		case H9632:
475662306a36Sopenharmony_ci			return hdsp_9632_get_peak(hdsp, peak_rms);
475762306a36Sopenharmony_ci		default:
475862306a36Sopenharmony_ci			return hdsp_get_peak(hdsp, peak_rms);
475962306a36Sopenharmony_ci		}
476062306a36Sopenharmony_ci	}
476162306a36Sopenharmony_ci	case SNDRV_HDSP_IOCTL_GET_CONFIG_INFO: {
476262306a36Sopenharmony_ci		struct hdsp_config_info info;
476362306a36Sopenharmony_ci		unsigned long flags;
476462306a36Sopenharmony_ci		int i;
476562306a36Sopenharmony_ci
476662306a36Sopenharmony_ci		err = hdsp_check_for_iobox(hdsp);
476762306a36Sopenharmony_ci		if (err < 0)
476862306a36Sopenharmony_ci			return err;
476962306a36Sopenharmony_ci
477062306a36Sopenharmony_ci		err = hdsp_check_for_firmware(hdsp, 1);
477162306a36Sopenharmony_ci		if (err < 0)
477262306a36Sopenharmony_ci			return err;
477362306a36Sopenharmony_ci
477462306a36Sopenharmony_ci		memset(&info, 0, sizeof(info));
477562306a36Sopenharmony_ci		spin_lock_irqsave(&hdsp->lock, flags);
477662306a36Sopenharmony_ci		info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp);
477762306a36Sopenharmony_ci		info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp);
477862306a36Sopenharmony_ci		if (hdsp->io_type != H9632)
477962306a36Sopenharmony_ci		    info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp);
478062306a36Sopenharmony_ci		info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp);
478162306a36Sopenharmony_ci		for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i)
478262306a36Sopenharmony_ci			info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i);
478362306a36Sopenharmony_ci		info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp);
478462306a36Sopenharmony_ci		info.spdif_out = (unsigned char)hdsp_toggle_setting(hdsp,
478562306a36Sopenharmony_ci				HDSP_SPDIFOpticalOut);
478662306a36Sopenharmony_ci		info.spdif_professional = (unsigned char)
478762306a36Sopenharmony_ci			hdsp_toggle_setting(hdsp, HDSP_SPDIFProfessional);
478862306a36Sopenharmony_ci		info.spdif_emphasis = (unsigned char)
478962306a36Sopenharmony_ci			hdsp_toggle_setting(hdsp, HDSP_SPDIFEmphasis);
479062306a36Sopenharmony_ci		info.spdif_nonaudio = (unsigned char)
479162306a36Sopenharmony_ci			hdsp_toggle_setting(hdsp, HDSP_SPDIFNonAudio);
479262306a36Sopenharmony_ci		info.spdif_sample_rate = hdsp_spdif_sample_rate(hdsp);
479362306a36Sopenharmony_ci		info.system_sample_rate = hdsp->system_sample_rate;
479462306a36Sopenharmony_ci		info.autosync_sample_rate = hdsp_external_sample_rate(hdsp);
479562306a36Sopenharmony_ci		info.system_clock_mode = (unsigned char)hdsp_system_clock_mode(hdsp);
479662306a36Sopenharmony_ci		info.clock_source = (unsigned char)hdsp_clock_source(hdsp);
479762306a36Sopenharmony_ci		info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp);
479862306a36Sopenharmony_ci		info.line_out = (unsigned char)
479962306a36Sopenharmony_ci			hdsp_toggle_setting(hdsp, HDSP_LineOut);
480062306a36Sopenharmony_ci		if (hdsp->io_type == H9632) {
480162306a36Sopenharmony_ci			info.da_gain = (unsigned char)hdsp_da_gain(hdsp);
480262306a36Sopenharmony_ci			info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp);
480362306a36Sopenharmony_ci			info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp);
480462306a36Sopenharmony_ci			info.xlr_breakout_cable =
480562306a36Sopenharmony_ci				(unsigned char)hdsp_toggle_setting(hdsp,
480662306a36Sopenharmony_ci					HDSP_XLRBreakoutCable);
480762306a36Sopenharmony_ci
480862306a36Sopenharmony_ci		} else if (hdsp->io_type == RPM) {
480962306a36Sopenharmony_ci			info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp);
481062306a36Sopenharmony_ci			info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp);
481162306a36Sopenharmony_ci		}
481262306a36Sopenharmony_ci		if (hdsp->io_type == H9632 || hdsp->io_type == H9652)
481362306a36Sopenharmony_ci			info.analog_extension_board =
481462306a36Sopenharmony_ci				(unsigned char)hdsp_toggle_setting(hdsp,
481562306a36Sopenharmony_ci					    HDSP_AnalogExtensionBoard);
481662306a36Sopenharmony_ci		spin_unlock_irqrestore(&hdsp->lock, flags);
481762306a36Sopenharmony_ci		if (copy_to_user(argp, &info, sizeof(info)))
481862306a36Sopenharmony_ci			return -EFAULT;
481962306a36Sopenharmony_ci		break;
482062306a36Sopenharmony_ci	}
482162306a36Sopenharmony_ci	case SNDRV_HDSP_IOCTL_GET_9632_AEB: {
482262306a36Sopenharmony_ci		struct hdsp_9632_aeb h9632_aeb;
482362306a36Sopenharmony_ci
482462306a36Sopenharmony_ci		if (hdsp->io_type != H9632) return -EINVAL;
482562306a36Sopenharmony_ci		h9632_aeb.aebi = hdsp->ss_in_channels - H9632_SS_CHANNELS;
482662306a36Sopenharmony_ci		h9632_aeb.aebo = hdsp->ss_out_channels - H9632_SS_CHANNELS;
482762306a36Sopenharmony_ci		if (copy_to_user(argp, &h9632_aeb, sizeof(h9632_aeb)))
482862306a36Sopenharmony_ci			return -EFAULT;
482962306a36Sopenharmony_ci		break;
483062306a36Sopenharmony_ci	}
483162306a36Sopenharmony_ci	case SNDRV_HDSP_IOCTL_GET_VERSION: {
483262306a36Sopenharmony_ci		struct hdsp_version hdsp_version;
483362306a36Sopenharmony_ci		int err;
483462306a36Sopenharmony_ci
483562306a36Sopenharmony_ci		if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL;
483662306a36Sopenharmony_ci		if (hdsp->io_type == Undefined) {
483762306a36Sopenharmony_ci			err = hdsp_get_iobox_version(hdsp);
483862306a36Sopenharmony_ci			if (err < 0)
483962306a36Sopenharmony_ci				return err;
484062306a36Sopenharmony_ci		}
484162306a36Sopenharmony_ci		memset(&hdsp_version, 0, sizeof(hdsp_version));
484262306a36Sopenharmony_ci		hdsp_version.io_type = hdsp->io_type;
484362306a36Sopenharmony_ci		hdsp_version.firmware_rev = hdsp->firmware_rev;
484462306a36Sopenharmony_ci		if (copy_to_user(argp, &hdsp_version, sizeof(hdsp_version)))
484562306a36Sopenharmony_ci			return -EFAULT;
484662306a36Sopenharmony_ci		break;
484762306a36Sopenharmony_ci	}
484862306a36Sopenharmony_ci	case SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE: {
484962306a36Sopenharmony_ci		struct hdsp_firmware firmware;
485062306a36Sopenharmony_ci		u32 __user *firmware_data;
485162306a36Sopenharmony_ci		int err;
485262306a36Sopenharmony_ci
485362306a36Sopenharmony_ci		if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL;
485462306a36Sopenharmony_ci		/* SNDRV_HDSP_IOCTL_GET_VERSION must have been called */
485562306a36Sopenharmony_ci		if (hdsp->io_type == Undefined) return -EINVAL;
485662306a36Sopenharmony_ci
485762306a36Sopenharmony_ci		if (hdsp->state & (HDSP_FirmwareCached | HDSP_FirmwareLoaded))
485862306a36Sopenharmony_ci			return -EBUSY;
485962306a36Sopenharmony_ci
486062306a36Sopenharmony_ci		dev_info(hdsp->card->dev,
486162306a36Sopenharmony_ci			 "initializing firmware upload\n");
486262306a36Sopenharmony_ci		if (copy_from_user(&firmware, argp, sizeof(firmware)))
486362306a36Sopenharmony_ci			return -EFAULT;
486462306a36Sopenharmony_ci		firmware_data = (u32 __user *)firmware.firmware_data;
486562306a36Sopenharmony_ci
486662306a36Sopenharmony_ci		if (hdsp_check_for_iobox (hdsp))
486762306a36Sopenharmony_ci			return -EIO;
486862306a36Sopenharmony_ci
486962306a36Sopenharmony_ci		if (!hdsp->fw_uploaded) {
487062306a36Sopenharmony_ci			hdsp->fw_uploaded = vmalloc(HDSP_FIRMWARE_SIZE);
487162306a36Sopenharmony_ci			if (!hdsp->fw_uploaded)
487262306a36Sopenharmony_ci				return -ENOMEM;
487362306a36Sopenharmony_ci		}
487462306a36Sopenharmony_ci
487562306a36Sopenharmony_ci		if (copy_from_user(hdsp->fw_uploaded, firmware_data,
487662306a36Sopenharmony_ci				   HDSP_FIRMWARE_SIZE)) {
487762306a36Sopenharmony_ci			vfree(hdsp->fw_uploaded);
487862306a36Sopenharmony_ci			hdsp->fw_uploaded = NULL;
487962306a36Sopenharmony_ci			return -EFAULT;
488062306a36Sopenharmony_ci		}
488162306a36Sopenharmony_ci
488262306a36Sopenharmony_ci		hdsp->state |= HDSP_FirmwareCached;
488362306a36Sopenharmony_ci
488462306a36Sopenharmony_ci		err = snd_hdsp_load_firmware_from_cache(hdsp);
488562306a36Sopenharmony_ci		if (err < 0)
488662306a36Sopenharmony_ci			return err;
488762306a36Sopenharmony_ci
488862306a36Sopenharmony_ci		if (!(hdsp->state & HDSP_InitializationComplete)) {
488962306a36Sopenharmony_ci			err = snd_hdsp_enable_io(hdsp);
489062306a36Sopenharmony_ci			if (err < 0)
489162306a36Sopenharmony_ci				return err;
489262306a36Sopenharmony_ci
489362306a36Sopenharmony_ci			snd_hdsp_initialize_channels(hdsp);
489462306a36Sopenharmony_ci			snd_hdsp_initialize_midi_flush(hdsp);
489562306a36Sopenharmony_ci
489662306a36Sopenharmony_ci			err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp);
489762306a36Sopenharmony_ci			if (err < 0) {
489862306a36Sopenharmony_ci				dev_err(hdsp->card->dev,
489962306a36Sopenharmony_ci					"error creating alsa devices\n");
490062306a36Sopenharmony_ci				return err;
490162306a36Sopenharmony_ci			}
490262306a36Sopenharmony_ci		}
490362306a36Sopenharmony_ci		break;
490462306a36Sopenharmony_ci	}
490562306a36Sopenharmony_ci	case SNDRV_HDSP_IOCTL_GET_MIXER: {
490662306a36Sopenharmony_ci		struct hdsp_mixer __user *mixer = (struct hdsp_mixer __user *)argp;
490762306a36Sopenharmony_ci		if (copy_to_user(mixer->matrix, hdsp->mixer_matrix, sizeof(unsigned short)*HDSP_MATRIX_MIXER_SIZE))
490862306a36Sopenharmony_ci			return -EFAULT;
490962306a36Sopenharmony_ci		break;
491062306a36Sopenharmony_ci	}
491162306a36Sopenharmony_ci	default:
491262306a36Sopenharmony_ci		return -EINVAL;
491362306a36Sopenharmony_ci	}
491462306a36Sopenharmony_ci	return 0;
491562306a36Sopenharmony_ci}
491662306a36Sopenharmony_ci
491762306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_hdsp_playback_ops = {
491862306a36Sopenharmony_ci	.open =		snd_hdsp_playback_open,
491962306a36Sopenharmony_ci	.close =	snd_hdsp_playback_release,
492062306a36Sopenharmony_ci	.ioctl =	snd_hdsp_ioctl,
492162306a36Sopenharmony_ci	.hw_params =	snd_hdsp_hw_params,
492262306a36Sopenharmony_ci	.prepare =	snd_hdsp_prepare,
492362306a36Sopenharmony_ci	.trigger =	snd_hdsp_trigger,
492462306a36Sopenharmony_ci	.pointer =	snd_hdsp_hw_pointer,
492562306a36Sopenharmony_ci	.copy =		snd_hdsp_playback_copy,
492662306a36Sopenharmony_ci	.fill_silence =	snd_hdsp_hw_silence,
492762306a36Sopenharmony_ci};
492862306a36Sopenharmony_ci
492962306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_hdsp_capture_ops = {
493062306a36Sopenharmony_ci	.open =		snd_hdsp_capture_open,
493162306a36Sopenharmony_ci	.close =	snd_hdsp_capture_release,
493262306a36Sopenharmony_ci	.ioctl =	snd_hdsp_ioctl,
493362306a36Sopenharmony_ci	.hw_params =	snd_hdsp_hw_params,
493462306a36Sopenharmony_ci	.prepare =	snd_hdsp_prepare,
493562306a36Sopenharmony_ci	.trigger =	snd_hdsp_trigger,
493662306a36Sopenharmony_ci	.pointer =	snd_hdsp_hw_pointer,
493762306a36Sopenharmony_ci	.copy =		snd_hdsp_capture_copy,
493862306a36Sopenharmony_ci};
493962306a36Sopenharmony_ci
494062306a36Sopenharmony_cistatic int snd_hdsp_create_hwdep(struct snd_card *card, struct hdsp *hdsp)
494162306a36Sopenharmony_ci{
494262306a36Sopenharmony_ci	struct snd_hwdep *hw;
494362306a36Sopenharmony_ci	int err;
494462306a36Sopenharmony_ci
494562306a36Sopenharmony_ci	err = snd_hwdep_new(card, "HDSP hwdep", 0, &hw);
494662306a36Sopenharmony_ci	if (err < 0)
494762306a36Sopenharmony_ci		return err;
494862306a36Sopenharmony_ci
494962306a36Sopenharmony_ci	hdsp->hwdep = hw;
495062306a36Sopenharmony_ci	hw->private_data = hdsp;
495162306a36Sopenharmony_ci	strcpy(hw->name, "HDSP hwdep interface");
495262306a36Sopenharmony_ci
495362306a36Sopenharmony_ci	hw->ops.ioctl = snd_hdsp_hwdep_ioctl;
495462306a36Sopenharmony_ci	hw->ops.ioctl_compat = snd_hdsp_hwdep_ioctl;
495562306a36Sopenharmony_ci
495662306a36Sopenharmony_ci	return 0;
495762306a36Sopenharmony_ci}
495862306a36Sopenharmony_ci
495962306a36Sopenharmony_cistatic int snd_hdsp_create_pcm(struct snd_card *card, struct hdsp *hdsp)
496062306a36Sopenharmony_ci{
496162306a36Sopenharmony_ci	struct snd_pcm *pcm;
496262306a36Sopenharmony_ci	int err;
496362306a36Sopenharmony_ci
496462306a36Sopenharmony_ci	err = snd_pcm_new(card, hdsp->card_name, 0, 1, 1, &pcm);
496562306a36Sopenharmony_ci	if (err < 0)
496662306a36Sopenharmony_ci		return err;
496762306a36Sopenharmony_ci
496862306a36Sopenharmony_ci	hdsp->pcm = pcm;
496962306a36Sopenharmony_ci	pcm->private_data = hdsp;
497062306a36Sopenharmony_ci	strcpy(pcm->name, hdsp->card_name);
497162306a36Sopenharmony_ci
497262306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_hdsp_playback_ops);
497362306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_hdsp_capture_ops);
497462306a36Sopenharmony_ci
497562306a36Sopenharmony_ci	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
497662306a36Sopenharmony_ci
497762306a36Sopenharmony_ci	return 0;
497862306a36Sopenharmony_ci}
497962306a36Sopenharmony_ci
498062306a36Sopenharmony_cistatic void snd_hdsp_9652_enable_mixer (struct hdsp *hdsp)
498162306a36Sopenharmony_ci{
498262306a36Sopenharmony_ci        hdsp->control2_register |= HDSP_9652_ENABLE_MIXER;
498362306a36Sopenharmony_ci	hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
498462306a36Sopenharmony_ci}
498562306a36Sopenharmony_ci
498662306a36Sopenharmony_cistatic int snd_hdsp_enable_io (struct hdsp *hdsp)
498762306a36Sopenharmony_ci{
498862306a36Sopenharmony_ci	int i;
498962306a36Sopenharmony_ci
499062306a36Sopenharmony_ci	if (hdsp_fifo_wait (hdsp, 0, 100)) {
499162306a36Sopenharmony_ci		dev_err(hdsp->card->dev,
499262306a36Sopenharmony_ci			"enable_io fifo_wait failed\n");
499362306a36Sopenharmony_ci		return -EIO;
499462306a36Sopenharmony_ci	}
499562306a36Sopenharmony_ci
499662306a36Sopenharmony_ci	for (i = 0; i < hdsp->max_channels; ++i) {
499762306a36Sopenharmony_ci		hdsp_write (hdsp, HDSP_inputEnable + (4 * i), 1);
499862306a36Sopenharmony_ci		hdsp_write (hdsp, HDSP_outputEnable + (4 * i), 1);
499962306a36Sopenharmony_ci	}
500062306a36Sopenharmony_ci
500162306a36Sopenharmony_ci	return 0;
500262306a36Sopenharmony_ci}
500362306a36Sopenharmony_ci
500462306a36Sopenharmony_cistatic void snd_hdsp_initialize_channels(struct hdsp *hdsp)
500562306a36Sopenharmony_ci{
500662306a36Sopenharmony_ci	int status, aebi_channels, aebo_channels, i;
500762306a36Sopenharmony_ci
500862306a36Sopenharmony_ci	switch (hdsp->io_type) {
500962306a36Sopenharmony_ci	case Digiface:
501062306a36Sopenharmony_ci		hdsp->card_name = "RME Hammerfall DSP + Digiface";
501162306a36Sopenharmony_ci		hdsp->ss_in_channels = hdsp->ss_out_channels = DIGIFACE_SS_CHANNELS;
501262306a36Sopenharmony_ci		hdsp->ds_in_channels = hdsp->ds_out_channels = DIGIFACE_DS_CHANNELS;
501362306a36Sopenharmony_ci		break;
501462306a36Sopenharmony_ci
501562306a36Sopenharmony_ci	case H9652:
501662306a36Sopenharmony_ci		hdsp->card_name = "RME Hammerfall HDSP 9652";
501762306a36Sopenharmony_ci		hdsp->ss_in_channels = hdsp->ss_out_channels = H9652_SS_CHANNELS;
501862306a36Sopenharmony_ci		hdsp->ds_in_channels = hdsp->ds_out_channels = H9652_DS_CHANNELS;
501962306a36Sopenharmony_ci		break;
502062306a36Sopenharmony_ci
502162306a36Sopenharmony_ci	case H9632:
502262306a36Sopenharmony_ci		status = hdsp_read(hdsp, HDSP_statusRegister);
502362306a36Sopenharmony_ci		/* HDSP_AEBx bits are low when AEB are connected */
502462306a36Sopenharmony_ci		aebi_channels = (status & HDSP_AEBI) ? 0 : 4;
502562306a36Sopenharmony_ci		aebo_channels = (status & HDSP_AEBO) ? 0 : 4;
502662306a36Sopenharmony_ci		hdsp->card_name = "RME Hammerfall HDSP 9632";
502762306a36Sopenharmony_ci		hdsp->ss_in_channels = H9632_SS_CHANNELS+aebi_channels;
502862306a36Sopenharmony_ci		hdsp->ds_in_channels = H9632_DS_CHANNELS+aebi_channels;
502962306a36Sopenharmony_ci		hdsp->qs_in_channels = H9632_QS_CHANNELS+aebi_channels;
503062306a36Sopenharmony_ci		hdsp->ss_out_channels = H9632_SS_CHANNELS+aebo_channels;
503162306a36Sopenharmony_ci		hdsp->ds_out_channels = H9632_DS_CHANNELS+aebo_channels;
503262306a36Sopenharmony_ci		hdsp->qs_out_channels = H9632_QS_CHANNELS+aebo_channels;
503362306a36Sopenharmony_ci		/* Disable loopback of output channels, as the set function
503462306a36Sopenharmony_ci		 * only sets on a change we fake all bits (channels) as enabled.
503562306a36Sopenharmony_ci		 */
503662306a36Sopenharmony_ci		hdsp->io_loopback = 0xffffffff;
503762306a36Sopenharmony_ci		for (i = 0; i < hdsp->max_channels; ++i)
503862306a36Sopenharmony_ci			hdsp_loopback_set(hdsp, i, false);
503962306a36Sopenharmony_ci		break;
504062306a36Sopenharmony_ci
504162306a36Sopenharmony_ci	case Multiface:
504262306a36Sopenharmony_ci		hdsp->card_name = "RME Hammerfall DSP + Multiface";
504362306a36Sopenharmony_ci		hdsp->ss_in_channels = hdsp->ss_out_channels = MULTIFACE_SS_CHANNELS;
504462306a36Sopenharmony_ci		hdsp->ds_in_channels = hdsp->ds_out_channels = MULTIFACE_DS_CHANNELS;
504562306a36Sopenharmony_ci		break;
504662306a36Sopenharmony_ci
504762306a36Sopenharmony_ci	case RPM:
504862306a36Sopenharmony_ci		hdsp->card_name = "RME Hammerfall DSP + RPM";
504962306a36Sopenharmony_ci		hdsp->ss_in_channels = RPM_CHANNELS-1;
505062306a36Sopenharmony_ci		hdsp->ss_out_channels = RPM_CHANNELS;
505162306a36Sopenharmony_ci		hdsp->ds_in_channels = RPM_CHANNELS-1;
505262306a36Sopenharmony_ci		hdsp->ds_out_channels = RPM_CHANNELS;
505362306a36Sopenharmony_ci		break;
505462306a36Sopenharmony_ci
505562306a36Sopenharmony_ci	default:
505662306a36Sopenharmony_ci 		/* should never get here */
505762306a36Sopenharmony_ci		break;
505862306a36Sopenharmony_ci	}
505962306a36Sopenharmony_ci}
506062306a36Sopenharmony_ci
506162306a36Sopenharmony_cistatic void snd_hdsp_initialize_midi_flush (struct hdsp *hdsp)
506262306a36Sopenharmony_ci{
506362306a36Sopenharmony_ci	snd_hdsp_flush_midi_input (hdsp, 0);
506462306a36Sopenharmony_ci	snd_hdsp_flush_midi_input (hdsp, 1);
506562306a36Sopenharmony_ci}
506662306a36Sopenharmony_ci
506762306a36Sopenharmony_cistatic int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp)
506862306a36Sopenharmony_ci{
506962306a36Sopenharmony_ci	int err;
507062306a36Sopenharmony_ci
507162306a36Sopenharmony_ci	err = snd_hdsp_create_pcm(card, hdsp);
507262306a36Sopenharmony_ci	if (err < 0) {
507362306a36Sopenharmony_ci		dev_err(card->dev,
507462306a36Sopenharmony_ci			"Error creating pcm interface\n");
507562306a36Sopenharmony_ci		return err;
507662306a36Sopenharmony_ci	}
507762306a36Sopenharmony_ci
507862306a36Sopenharmony_ci
507962306a36Sopenharmony_ci	err = snd_hdsp_create_midi(card, hdsp, 0);
508062306a36Sopenharmony_ci	if (err < 0) {
508162306a36Sopenharmony_ci		dev_err(card->dev,
508262306a36Sopenharmony_ci			"Error creating first midi interface\n");
508362306a36Sopenharmony_ci		return err;
508462306a36Sopenharmony_ci	}
508562306a36Sopenharmony_ci
508662306a36Sopenharmony_ci	if (hdsp->io_type == Digiface || hdsp->io_type == H9652) {
508762306a36Sopenharmony_ci		err = snd_hdsp_create_midi(card, hdsp, 1);
508862306a36Sopenharmony_ci		if (err < 0) {
508962306a36Sopenharmony_ci			dev_err(card->dev,
509062306a36Sopenharmony_ci				"Error creating second midi interface\n");
509162306a36Sopenharmony_ci			return err;
509262306a36Sopenharmony_ci		}
509362306a36Sopenharmony_ci	}
509462306a36Sopenharmony_ci
509562306a36Sopenharmony_ci	err = snd_hdsp_create_controls(card, hdsp);
509662306a36Sopenharmony_ci	if (err < 0) {
509762306a36Sopenharmony_ci		dev_err(card->dev,
509862306a36Sopenharmony_ci			"Error creating ctl interface\n");
509962306a36Sopenharmony_ci		return err;
510062306a36Sopenharmony_ci	}
510162306a36Sopenharmony_ci
510262306a36Sopenharmony_ci	snd_hdsp_proc_init(hdsp);
510362306a36Sopenharmony_ci
510462306a36Sopenharmony_ci	hdsp->system_sample_rate = -1;
510562306a36Sopenharmony_ci	hdsp->playback_pid = -1;
510662306a36Sopenharmony_ci	hdsp->capture_pid = -1;
510762306a36Sopenharmony_ci	hdsp->capture_substream = NULL;
510862306a36Sopenharmony_ci	hdsp->playback_substream = NULL;
510962306a36Sopenharmony_ci
511062306a36Sopenharmony_ci	err = snd_hdsp_set_defaults(hdsp);
511162306a36Sopenharmony_ci	if (err < 0) {
511262306a36Sopenharmony_ci		dev_err(card->dev,
511362306a36Sopenharmony_ci			"Error setting default values\n");
511462306a36Sopenharmony_ci		return err;
511562306a36Sopenharmony_ci	}
511662306a36Sopenharmony_ci
511762306a36Sopenharmony_ci	if (!(hdsp->state & HDSP_InitializationComplete)) {
511862306a36Sopenharmony_ci		strcpy(card->shortname, "Hammerfall DSP");
511962306a36Sopenharmony_ci		sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name,
512062306a36Sopenharmony_ci			hdsp->port, hdsp->irq);
512162306a36Sopenharmony_ci
512262306a36Sopenharmony_ci		err = snd_card_register(card);
512362306a36Sopenharmony_ci		if (err < 0) {
512462306a36Sopenharmony_ci			dev_err(card->dev,
512562306a36Sopenharmony_ci				"error registering card\n");
512662306a36Sopenharmony_ci			return err;
512762306a36Sopenharmony_ci		}
512862306a36Sopenharmony_ci		hdsp->state |= HDSP_InitializationComplete;
512962306a36Sopenharmony_ci	}
513062306a36Sopenharmony_ci
513162306a36Sopenharmony_ci	return 0;
513262306a36Sopenharmony_ci}
513362306a36Sopenharmony_ci
513462306a36Sopenharmony_ci/* load firmware via hotplug fw loader */
513562306a36Sopenharmony_cistatic int hdsp_request_fw_loader(struct hdsp *hdsp)
513662306a36Sopenharmony_ci{
513762306a36Sopenharmony_ci	const char *fwfile;
513862306a36Sopenharmony_ci	const struct firmware *fw;
513962306a36Sopenharmony_ci	int err;
514062306a36Sopenharmony_ci
514162306a36Sopenharmony_ci	if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
514262306a36Sopenharmony_ci		return 0;
514362306a36Sopenharmony_ci	if (hdsp->io_type == Undefined) {
514462306a36Sopenharmony_ci		err = hdsp_get_iobox_version(hdsp);
514562306a36Sopenharmony_ci		if (err < 0)
514662306a36Sopenharmony_ci			return err;
514762306a36Sopenharmony_ci		if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
514862306a36Sopenharmony_ci			return 0;
514962306a36Sopenharmony_ci	}
515062306a36Sopenharmony_ci
515162306a36Sopenharmony_ci	/* caution: max length of firmware filename is 30! */
515262306a36Sopenharmony_ci	switch (hdsp->io_type) {
515362306a36Sopenharmony_ci	case RPM:
515462306a36Sopenharmony_ci		fwfile = "rpm_firmware.bin";
515562306a36Sopenharmony_ci		break;
515662306a36Sopenharmony_ci	case Multiface:
515762306a36Sopenharmony_ci		if (hdsp->firmware_rev == 0xa)
515862306a36Sopenharmony_ci			fwfile = "multiface_firmware.bin";
515962306a36Sopenharmony_ci		else
516062306a36Sopenharmony_ci			fwfile = "multiface_firmware_rev11.bin";
516162306a36Sopenharmony_ci		break;
516262306a36Sopenharmony_ci	case Digiface:
516362306a36Sopenharmony_ci		if (hdsp->firmware_rev == 0xa)
516462306a36Sopenharmony_ci			fwfile = "digiface_firmware.bin";
516562306a36Sopenharmony_ci		else
516662306a36Sopenharmony_ci			fwfile = "digiface_firmware_rev11.bin";
516762306a36Sopenharmony_ci		break;
516862306a36Sopenharmony_ci	default:
516962306a36Sopenharmony_ci		dev_err(hdsp->card->dev,
517062306a36Sopenharmony_ci			"invalid io_type %d\n", hdsp->io_type);
517162306a36Sopenharmony_ci		return -EINVAL;
517262306a36Sopenharmony_ci	}
517362306a36Sopenharmony_ci
517462306a36Sopenharmony_ci	if (request_firmware(&fw, fwfile, &hdsp->pci->dev)) {
517562306a36Sopenharmony_ci		dev_err(hdsp->card->dev,
517662306a36Sopenharmony_ci			"cannot load firmware %s\n", fwfile);
517762306a36Sopenharmony_ci		return -ENOENT;
517862306a36Sopenharmony_ci	}
517962306a36Sopenharmony_ci	if (fw->size < HDSP_FIRMWARE_SIZE) {
518062306a36Sopenharmony_ci		dev_err(hdsp->card->dev,
518162306a36Sopenharmony_ci			"too short firmware size %d (expected %d)\n",
518262306a36Sopenharmony_ci			   (int)fw->size, HDSP_FIRMWARE_SIZE);
518362306a36Sopenharmony_ci		release_firmware(fw);
518462306a36Sopenharmony_ci		return -EINVAL;
518562306a36Sopenharmony_ci	}
518662306a36Sopenharmony_ci
518762306a36Sopenharmony_ci	hdsp->firmware = fw;
518862306a36Sopenharmony_ci
518962306a36Sopenharmony_ci	hdsp->state |= HDSP_FirmwareCached;
519062306a36Sopenharmony_ci
519162306a36Sopenharmony_ci	err = snd_hdsp_load_firmware_from_cache(hdsp);
519262306a36Sopenharmony_ci	if (err < 0)
519362306a36Sopenharmony_ci		return err;
519462306a36Sopenharmony_ci
519562306a36Sopenharmony_ci	if (!(hdsp->state & HDSP_InitializationComplete)) {
519662306a36Sopenharmony_ci		err = snd_hdsp_enable_io(hdsp);
519762306a36Sopenharmony_ci		if (err < 0)
519862306a36Sopenharmony_ci			return err;
519962306a36Sopenharmony_ci
520062306a36Sopenharmony_ci		err = snd_hdsp_create_hwdep(hdsp->card, hdsp);
520162306a36Sopenharmony_ci		if (err < 0) {
520262306a36Sopenharmony_ci			dev_err(hdsp->card->dev,
520362306a36Sopenharmony_ci				"error creating hwdep device\n");
520462306a36Sopenharmony_ci			return err;
520562306a36Sopenharmony_ci		}
520662306a36Sopenharmony_ci		snd_hdsp_initialize_channels(hdsp);
520762306a36Sopenharmony_ci		snd_hdsp_initialize_midi_flush(hdsp);
520862306a36Sopenharmony_ci		err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp);
520962306a36Sopenharmony_ci		if (err < 0) {
521062306a36Sopenharmony_ci			dev_err(hdsp->card->dev,
521162306a36Sopenharmony_ci				"error creating alsa devices\n");
521262306a36Sopenharmony_ci			return err;
521362306a36Sopenharmony_ci		}
521462306a36Sopenharmony_ci	}
521562306a36Sopenharmony_ci	return 0;
521662306a36Sopenharmony_ci}
521762306a36Sopenharmony_ci
521862306a36Sopenharmony_cistatic int snd_hdsp_create(struct snd_card *card,
521962306a36Sopenharmony_ci			   struct hdsp *hdsp)
522062306a36Sopenharmony_ci{
522162306a36Sopenharmony_ci	struct pci_dev *pci = hdsp->pci;
522262306a36Sopenharmony_ci	int err;
522362306a36Sopenharmony_ci	int is_9652 = 0;
522462306a36Sopenharmony_ci	int is_9632 = 0;
522562306a36Sopenharmony_ci
522662306a36Sopenharmony_ci	hdsp->irq = -1;
522762306a36Sopenharmony_ci	hdsp->state = 0;
522862306a36Sopenharmony_ci	hdsp->midi[0].rmidi = NULL;
522962306a36Sopenharmony_ci	hdsp->midi[1].rmidi = NULL;
523062306a36Sopenharmony_ci	hdsp->midi[0].input = NULL;
523162306a36Sopenharmony_ci	hdsp->midi[1].input = NULL;
523262306a36Sopenharmony_ci	hdsp->midi[0].output = NULL;
523362306a36Sopenharmony_ci	hdsp->midi[1].output = NULL;
523462306a36Sopenharmony_ci	hdsp->midi[0].pending = 0;
523562306a36Sopenharmony_ci	hdsp->midi[1].pending = 0;
523662306a36Sopenharmony_ci	spin_lock_init(&hdsp->midi[0].lock);
523762306a36Sopenharmony_ci	spin_lock_init(&hdsp->midi[1].lock);
523862306a36Sopenharmony_ci	hdsp->iobase = NULL;
523962306a36Sopenharmony_ci	hdsp->control_register = 0;
524062306a36Sopenharmony_ci	hdsp->control2_register = 0;
524162306a36Sopenharmony_ci	hdsp->io_type = Undefined;
524262306a36Sopenharmony_ci	hdsp->max_channels = 26;
524362306a36Sopenharmony_ci
524462306a36Sopenharmony_ci	hdsp->card = card;
524562306a36Sopenharmony_ci
524662306a36Sopenharmony_ci	spin_lock_init(&hdsp->lock);
524762306a36Sopenharmony_ci
524862306a36Sopenharmony_ci	INIT_WORK(&hdsp->midi_work, hdsp_midi_work);
524962306a36Sopenharmony_ci
525062306a36Sopenharmony_ci	pci_read_config_word(hdsp->pci, PCI_CLASS_REVISION, &hdsp->firmware_rev);
525162306a36Sopenharmony_ci	hdsp->firmware_rev &= 0xff;
525262306a36Sopenharmony_ci
525362306a36Sopenharmony_ci	/* From Martin Bjoernsen :
525462306a36Sopenharmony_ci	    "It is important that the card's latency timer register in
525562306a36Sopenharmony_ci	    the PCI configuration space is set to a value much larger
525662306a36Sopenharmony_ci	    than 0 by the computer's BIOS or the driver.
525762306a36Sopenharmony_ci	    The windows driver always sets this 8 bit register [...]
525862306a36Sopenharmony_ci	    to its maximum 255 to avoid problems with some computers."
525962306a36Sopenharmony_ci	*/
526062306a36Sopenharmony_ci	pci_write_config_byte(hdsp->pci, PCI_LATENCY_TIMER, 0xFF);
526162306a36Sopenharmony_ci
526262306a36Sopenharmony_ci	strcpy(card->driver, "H-DSP");
526362306a36Sopenharmony_ci	strcpy(card->mixername, "Xilinx FPGA");
526462306a36Sopenharmony_ci
526562306a36Sopenharmony_ci	if (hdsp->firmware_rev < 0xa)
526662306a36Sopenharmony_ci		return -ENODEV;
526762306a36Sopenharmony_ci	else if (hdsp->firmware_rev < 0x64)
526862306a36Sopenharmony_ci		hdsp->card_name = "RME Hammerfall DSP";
526962306a36Sopenharmony_ci	else if (hdsp->firmware_rev < 0x96) {
527062306a36Sopenharmony_ci		hdsp->card_name = "RME HDSP 9652";
527162306a36Sopenharmony_ci		is_9652 = 1;
527262306a36Sopenharmony_ci	} else {
527362306a36Sopenharmony_ci		hdsp->card_name = "RME HDSP 9632";
527462306a36Sopenharmony_ci		hdsp->max_channels = 16;
527562306a36Sopenharmony_ci		is_9632 = 1;
527662306a36Sopenharmony_ci	}
527762306a36Sopenharmony_ci
527862306a36Sopenharmony_ci	err = pcim_enable_device(pci);
527962306a36Sopenharmony_ci	if (err < 0)
528062306a36Sopenharmony_ci		return err;
528162306a36Sopenharmony_ci
528262306a36Sopenharmony_ci	pci_set_master(hdsp->pci);
528362306a36Sopenharmony_ci
528462306a36Sopenharmony_ci	err = pci_request_regions(pci, "hdsp");
528562306a36Sopenharmony_ci	if (err < 0)
528662306a36Sopenharmony_ci		return err;
528762306a36Sopenharmony_ci	hdsp->port = pci_resource_start(pci, 0);
528862306a36Sopenharmony_ci	hdsp->iobase = devm_ioremap(&pci->dev, hdsp->port, HDSP_IO_EXTENT);
528962306a36Sopenharmony_ci	if (!hdsp->iobase) {
529062306a36Sopenharmony_ci		dev_err(hdsp->card->dev, "unable to remap region 0x%lx-0x%lx\n",
529162306a36Sopenharmony_ci			hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1);
529262306a36Sopenharmony_ci		return -EBUSY;
529362306a36Sopenharmony_ci	}
529462306a36Sopenharmony_ci
529562306a36Sopenharmony_ci	if (devm_request_irq(&pci->dev, pci->irq, snd_hdsp_interrupt,
529662306a36Sopenharmony_ci			     IRQF_SHARED, KBUILD_MODNAME, hdsp)) {
529762306a36Sopenharmony_ci		dev_err(hdsp->card->dev, "unable to use IRQ %d\n", pci->irq);
529862306a36Sopenharmony_ci		return -EBUSY;
529962306a36Sopenharmony_ci	}
530062306a36Sopenharmony_ci
530162306a36Sopenharmony_ci	hdsp->irq = pci->irq;
530262306a36Sopenharmony_ci	card->sync_irq = hdsp->irq;
530362306a36Sopenharmony_ci	hdsp->precise_ptr = 0;
530462306a36Sopenharmony_ci	hdsp->use_midi_work = 1;
530562306a36Sopenharmony_ci	hdsp->dds_value = 0;
530662306a36Sopenharmony_ci
530762306a36Sopenharmony_ci	err = snd_hdsp_initialize_memory(hdsp);
530862306a36Sopenharmony_ci	if (err < 0)
530962306a36Sopenharmony_ci		return err;
531062306a36Sopenharmony_ci
531162306a36Sopenharmony_ci	if (!is_9652 && !is_9632) {
531262306a36Sopenharmony_ci		/* we wait a maximum of 10 seconds to let freshly
531362306a36Sopenharmony_ci		 * inserted cardbus cards do their hardware init */
531462306a36Sopenharmony_ci		err = hdsp_wait_for_iobox(hdsp, 1000, 10);
531562306a36Sopenharmony_ci
531662306a36Sopenharmony_ci		if (err < 0)
531762306a36Sopenharmony_ci			return err;
531862306a36Sopenharmony_ci
531962306a36Sopenharmony_ci		if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
532062306a36Sopenharmony_ci			err = hdsp_request_fw_loader(hdsp);
532162306a36Sopenharmony_ci			if (err < 0)
532262306a36Sopenharmony_ci				/* we don't fail as this can happen
532362306a36Sopenharmony_ci				   if userspace is not ready for
532462306a36Sopenharmony_ci				   firmware upload
532562306a36Sopenharmony_ci				*/
532662306a36Sopenharmony_ci				dev_err(hdsp->card->dev,
532762306a36Sopenharmony_ci					"couldn't get firmware from userspace. try using hdsploader\n");
532862306a36Sopenharmony_ci			else
532962306a36Sopenharmony_ci				/* init is complete, we return */
533062306a36Sopenharmony_ci				return 0;
533162306a36Sopenharmony_ci			/* we defer initialization */
533262306a36Sopenharmony_ci			dev_info(hdsp->card->dev,
533362306a36Sopenharmony_ci				 "card initialization pending : waiting for firmware\n");
533462306a36Sopenharmony_ci			err = snd_hdsp_create_hwdep(card, hdsp);
533562306a36Sopenharmony_ci			if (err < 0)
533662306a36Sopenharmony_ci				return err;
533762306a36Sopenharmony_ci			return 0;
533862306a36Sopenharmony_ci		} else {
533962306a36Sopenharmony_ci			dev_info(hdsp->card->dev,
534062306a36Sopenharmony_ci				 "Firmware already present, initializing card.\n");
534162306a36Sopenharmony_ci			if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
534262306a36Sopenharmony_ci				hdsp->io_type = RPM;
534362306a36Sopenharmony_ci			else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
534462306a36Sopenharmony_ci				hdsp->io_type = Multiface;
534562306a36Sopenharmony_ci			else
534662306a36Sopenharmony_ci				hdsp->io_type = Digiface;
534762306a36Sopenharmony_ci		}
534862306a36Sopenharmony_ci	}
534962306a36Sopenharmony_ci
535062306a36Sopenharmony_ci	err = snd_hdsp_enable_io(hdsp);
535162306a36Sopenharmony_ci	if (err)
535262306a36Sopenharmony_ci		return err;
535362306a36Sopenharmony_ci
535462306a36Sopenharmony_ci	if (is_9652)
535562306a36Sopenharmony_ci	        hdsp->io_type = H9652;
535662306a36Sopenharmony_ci
535762306a36Sopenharmony_ci	if (is_9632)
535862306a36Sopenharmony_ci		hdsp->io_type = H9632;
535962306a36Sopenharmony_ci
536062306a36Sopenharmony_ci	err = snd_hdsp_create_hwdep(card, hdsp);
536162306a36Sopenharmony_ci	if (err < 0)
536262306a36Sopenharmony_ci		return err;
536362306a36Sopenharmony_ci
536462306a36Sopenharmony_ci	snd_hdsp_initialize_channels(hdsp);
536562306a36Sopenharmony_ci	snd_hdsp_initialize_midi_flush(hdsp);
536662306a36Sopenharmony_ci
536762306a36Sopenharmony_ci	hdsp->state |= HDSP_FirmwareLoaded;
536862306a36Sopenharmony_ci
536962306a36Sopenharmony_ci	err = snd_hdsp_create_alsa_devices(card, hdsp);
537062306a36Sopenharmony_ci	if (err < 0)
537162306a36Sopenharmony_ci		return err;
537262306a36Sopenharmony_ci
537362306a36Sopenharmony_ci	return 0;
537462306a36Sopenharmony_ci}
537562306a36Sopenharmony_ci
537662306a36Sopenharmony_cistatic void snd_hdsp_card_free(struct snd_card *card)
537762306a36Sopenharmony_ci{
537862306a36Sopenharmony_ci	struct hdsp *hdsp = card->private_data;
537962306a36Sopenharmony_ci
538062306a36Sopenharmony_ci	if (hdsp->port) {
538162306a36Sopenharmony_ci		/* stop the audio, and cancel all interrupts */
538262306a36Sopenharmony_ci		cancel_work_sync(&hdsp->midi_work);
538362306a36Sopenharmony_ci		hdsp->control_register &= ~(HDSP_Start|HDSP_AudioInterruptEnable|HDSP_Midi0InterruptEnable|HDSP_Midi1InterruptEnable);
538462306a36Sopenharmony_ci		hdsp_write (hdsp, HDSP_controlRegister, hdsp->control_register);
538562306a36Sopenharmony_ci	}
538662306a36Sopenharmony_ci
538762306a36Sopenharmony_ci	release_firmware(hdsp->firmware);
538862306a36Sopenharmony_ci	vfree(hdsp->fw_uploaded);
538962306a36Sopenharmony_ci}
539062306a36Sopenharmony_ci
539162306a36Sopenharmony_cistatic int snd_hdsp_probe(struct pci_dev *pci,
539262306a36Sopenharmony_ci			  const struct pci_device_id *pci_id)
539362306a36Sopenharmony_ci{
539462306a36Sopenharmony_ci	static int dev;
539562306a36Sopenharmony_ci	struct hdsp *hdsp;
539662306a36Sopenharmony_ci	struct snd_card *card;
539762306a36Sopenharmony_ci	int err;
539862306a36Sopenharmony_ci
539962306a36Sopenharmony_ci	if (dev >= SNDRV_CARDS)
540062306a36Sopenharmony_ci		return -ENODEV;
540162306a36Sopenharmony_ci	if (!enable[dev]) {
540262306a36Sopenharmony_ci		dev++;
540362306a36Sopenharmony_ci		return -ENOENT;
540462306a36Sopenharmony_ci	}
540562306a36Sopenharmony_ci
540662306a36Sopenharmony_ci	err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
540762306a36Sopenharmony_ci				sizeof(struct hdsp), &card);
540862306a36Sopenharmony_ci	if (err < 0)
540962306a36Sopenharmony_ci		return err;
541062306a36Sopenharmony_ci
541162306a36Sopenharmony_ci	hdsp = card->private_data;
541262306a36Sopenharmony_ci	card->private_free = snd_hdsp_card_free;
541362306a36Sopenharmony_ci	hdsp->dev = dev;
541462306a36Sopenharmony_ci	hdsp->pci = pci;
541562306a36Sopenharmony_ci	err = snd_hdsp_create(card, hdsp);
541662306a36Sopenharmony_ci	if (err)
541762306a36Sopenharmony_ci		goto error;
541862306a36Sopenharmony_ci
541962306a36Sopenharmony_ci	strcpy(card->shortname, "Hammerfall DSP");
542062306a36Sopenharmony_ci	sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name,
542162306a36Sopenharmony_ci		hdsp->port, hdsp->irq);
542262306a36Sopenharmony_ci	err = snd_card_register(card);
542362306a36Sopenharmony_ci	if (err)
542462306a36Sopenharmony_ci		goto error;
542562306a36Sopenharmony_ci	pci_set_drvdata(pci, card);
542662306a36Sopenharmony_ci	dev++;
542762306a36Sopenharmony_ci	return 0;
542862306a36Sopenharmony_ci
542962306a36Sopenharmony_ci error:
543062306a36Sopenharmony_ci	snd_card_free(card);
543162306a36Sopenharmony_ci	return err;
543262306a36Sopenharmony_ci}
543362306a36Sopenharmony_ci
543462306a36Sopenharmony_cistatic struct pci_driver hdsp_driver = {
543562306a36Sopenharmony_ci	.name =     KBUILD_MODNAME,
543662306a36Sopenharmony_ci	.id_table = snd_hdsp_ids,
543762306a36Sopenharmony_ci	.probe =    snd_hdsp_probe,
543862306a36Sopenharmony_ci};
543962306a36Sopenharmony_ci
544062306a36Sopenharmony_cimodule_pci_driver(hdsp_driver);
5441