162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   ALSA driver for RME Digi9652 audio interfaces
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *	Copyright (c) 1999 IEM - Winfried Ritsch
662306a36Sopenharmony_ci *      Copyright (c) 1999-2001  Paul Davis
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/pci.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/nospec.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <sound/core.h>
1862306a36Sopenharmony_ci#include <sound/control.h>
1962306a36Sopenharmony_ci#include <sound/pcm.h>
2062306a36Sopenharmony_ci#include <sound/info.h>
2162306a36Sopenharmony_ci#include <sound/asoundef.h>
2262306a36Sopenharmony_ci#include <sound/initval.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <asm/current.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
2762306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
2862306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
2962306a36Sopenharmony_cistatic bool precise_ptr[SNDRV_CARDS];			/* Enable precise pointer */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444);
3262306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for RME Digi9652 (Hammerfall) soundcard.");
3362306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444);
3462306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for RME Digi9652 (Hammerfall) soundcard.");
3562306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444);
3662306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable/disable specific RME96{52,36} soundcards.");
3762306a36Sopenharmony_cimodule_param_array(precise_ptr, bool, NULL, 0444);
3862306a36Sopenharmony_ciMODULE_PARM_DESC(precise_ptr, "Enable precise pointer (doesn't work reliably).");
3962306a36Sopenharmony_ciMODULE_AUTHOR("Paul Davis <pbd@op.net>, Winfried Ritsch");
4062306a36Sopenharmony_ciMODULE_DESCRIPTION("RME Digi9652/Digi9636");
4162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* The Hammerfall has two sets of 24 ADAT + 2 S/PDIF channels, one for
4462306a36Sopenharmony_ci   capture, one for playback. Both the ADAT and S/PDIF channels appear
4562306a36Sopenharmony_ci   to the host CPU in the same block of memory. There is no functional
4662306a36Sopenharmony_ci   difference between them in terms of access.
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci   The Hammerfall Light is identical to the Hammerfall, except that it
4962306a36Sopenharmony_ci   has 2 sets 18 channels (16 ADAT + 2 S/PDIF) for capture and playback.
5062306a36Sopenharmony_ci*/
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define RME9652_NCHANNELS       26
5362306a36Sopenharmony_ci#define RME9636_NCHANNELS       18
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* Preferred sync source choices - used by "sync_pref" control switch */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define RME9652_SYNC_FROM_SPDIF 0
5862306a36Sopenharmony_ci#define RME9652_SYNC_FROM_ADAT1 1
5962306a36Sopenharmony_ci#define RME9652_SYNC_FROM_ADAT2 2
6062306a36Sopenharmony_ci#define RME9652_SYNC_FROM_ADAT3 3
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* Possible sources of S/PDIF input */
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define RME9652_SPDIFIN_OPTICAL 0	/* optical (ADAT1) */
6562306a36Sopenharmony_ci#define RME9652_SPDIFIN_COAXIAL 1	/* coaxial (RCA) */
6662306a36Sopenharmony_ci#define RME9652_SPDIFIN_INTERN  2	/* internal (CDROM) */
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* ------------- Status-Register bits --------------------- */
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define RME9652_IRQ	   (1<<0)	/* IRQ is High if not reset by irq_clear */
7162306a36Sopenharmony_ci#define RME9652_lock_2	   (1<<1)	/* ADAT 3-PLL: 1=locked, 0=unlocked */
7262306a36Sopenharmony_ci#define RME9652_lock_1	   (1<<2)	/* ADAT 2-PLL: 1=locked, 0=unlocked */
7362306a36Sopenharmony_ci#define RME9652_lock_0	   (1<<3)	/* ADAT 1-PLL: 1=locked, 0=unlocked */
7462306a36Sopenharmony_ci#define RME9652_fs48	   (1<<4)	/* sample rate is 0=44.1/88.2,1=48/96 Khz */
7562306a36Sopenharmony_ci#define RME9652_wsel_rd	   (1<<5)	/* if Word-Clock is used and valid then 1 */
7662306a36Sopenharmony_ci                                        /* bits 6-15 encode h/w buffer pointer position */
7762306a36Sopenharmony_ci#define RME9652_sync_2	   (1<<16)	/* if ADAT-IN 3 in sync to system clock */
7862306a36Sopenharmony_ci#define RME9652_sync_1	   (1<<17)	/* if ADAT-IN 2 in sync to system clock */
7962306a36Sopenharmony_ci#define RME9652_sync_0	   (1<<18)	/* if ADAT-IN 1 in sync to system clock */
8062306a36Sopenharmony_ci#define RME9652_DS_rd	   (1<<19)	/* 1=Double Speed Mode, 0=Normal Speed */
8162306a36Sopenharmony_ci#define RME9652_tc_busy	   (1<<20)	/* 1=time-code copy in progress (960ms) */
8262306a36Sopenharmony_ci#define RME9652_tc_out	   (1<<21)	/* time-code out bit */
8362306a36Sopenharmony_ci#define RME9652_F_0	   (1<<22)	/* 000=64kHz, 100=88.2kHz, 011=96kHz  */
8462306a36Sopenharmony_ci#define RME9652_F_1	   (1<<23)	/* 111=32kHz, 110=44.1kHz, 101=48kHz, */
8562306a36Sopenharmony_ci#define RME9652_F_2	   (1<<24)	/* external Crystal Chip if ERF=1 */
8662306a36Sopenharmony_ci#define RME9652_ERF	   (1<<25)	/* Error-Flag of SDPIF Receiver (1=No Lock) */
8762306a36Sopenharmony_ci#define RME9652_buffer_id  (1<<26)	/* toggles by each interrupt on rec/play */
8862306a36Sopenharmony_ci#define RME9652_tc_valid   (1<<27)	/* 1 = a signal is detected on time-code input */
8962306a36Sopenharmony_ci#define RME9652_SPDIF_READ (1<<28)      /* byte available from Rev 1.5+ S/PDIF interface */
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define RME9652_sync	  (RME9652_sync_0|RME9652_sync_1|RME9652_sync_2)
9262306a36Sopenharmony_ci#define RME9652_lock	  (RME9652_lock_0|RME9652_lock_1|RME9652_lock_2)
9362306a36Sopenharmony_ci#define RME9652_F	  (RME9652_F_0|RME9652_F_1|RME9652_F_2)
9462306a36Sopenharmony_ci#define rme9652_decode_spdif_rate(x) ((x)>>22)
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* Bit 6..15 : h/w buffer pointer */
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define RME9652_buf_pos	  0x000FFC0
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* Bits 31,30,29 are bits 5,4,3 of h/w pointer position on later
10162306a36Sopenharmony_ci   Rev G EEPROMS and Rev 1.5 cards or later.
10262306a36Sopenharmony_ci*/
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define RME9652_REV15_buf_pos(x) ((((x)&0xE0000000)>>26)|((x)&RME9652_buf_pos))
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/* amount of io space we remap for register access. i'm not sure we
10762306a36Sopenharmony_ci   even need this much, but 1K is nice round number :)
10862306a36Sopenharmony_ci*/
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define RME9652_IO_EXTENT     1024
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#define RME9652_init_buffer       0
11362306a36Sopenharmony_ci#define RME9652_play_buffer       32	/* holds ptr to 26x64kBit host RAM */
11462306a36Sopenharmony_ci#define RME9652_rec_buffer        36	/* holds ptr to 26x64kBit host RAM */
11562306a36Sopenharmony_ci#define RME9652_control_register  64
11662306a36Sopenharmony_ci#define RME9652_irq_clear         96
11762306a36Sopenharmony_ci#define RME9652_time_code         100	/* useful if used with alesis adat */
11862306a36Sopenharmony_ci#define RME9652_thru_base         128	/* 132...228 Thru for 26 channels */
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/* Read-only registers */
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* Writing to any of the register locations writes to the status
12362306a36Sopenharmony_ci   register. We'll use the first location as our point of access.
12462306a36Sopenharmony_ci*/
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#define RME9652_status_register    0
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/* --------- Control-Register Bits ---------------- */
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci#define RME9652_start_bit	   (1<<0)	/* start record/play */
13262306a36Sopenharmony_ci                                                /* bits 1-3 encode buffersize/latency */
13362306a36Sopenharmony_ci#define RME9652_Master		   (1<<4)	/* Clock Mode Master=1,Slave/Auto=0 */
13462306a36Sopenharmony_ci#define RME9652_IE		   (1<<5)	/* Interrupt Enable */
13562306a36Sopenharmony_ci#define RME9652_freq		   (1<<6)       /* samplerate 0=44.1/88.2, 1=48/96 kHz */
13662306a36Sopenharmony_ci#define RME9652_freq1		   (1<<7)       /* if 0, 32kHz, else always 1 */
13762306a36Sopenharmony_ci#define RME9652_DS                 (1<<8)	/* Doule Speed 0=44.1/48, 1=88.2/96 Khz */
13862306a36Sopenharmony_ci#define RME9652_PRO		   (1<<9)	/* S/PDIF out: 0=consumer, 1=professional */
13962306a36Sopenharmony_ci#define RME9652_EMP		   (1<<10)	/*  Emphasis 0=None, 1=ON */
14062306a36Sopenharmony_ci#define RME9652_Dolby		   (1<<11)	/*  Non-audio bit 1=set, 0=unset */
14162306a36Sopenharmony_ci#define RME9652_opt_out	           (1<<12)	/* Use 1st optical OUT as SPDIF: 1=yes,0=no */
14262306a36Sopenharmony_ci#define RME9652_wsel		   (1<<13)	/* use Wordclock as sync (overwrites master) */
14362306a36Sopenharmony_ci#define RME9652_inp_0		   (1<<14)	/* SPDIF-IN: 00=optical (ADAT1),     */
14462306a36Sopenharmony_ci#define RME9652_inp_1		   (1<<15)	/* 01=koaxial (Cinch), 10=Internal CDROM */
14562306a36Sopenharmony_ci#define RME9652_SyncPref_ADAT2	   (1<<16)
14662306a36Sopenharmony_ci#define RME9652_SyncPref_ADAT3	   (1<<17)
14762306a36Sopenharmony_ci#define RME9652_SPDIF_RESET        (1<<18)      /* Rev 1.5+: h/w S/PDIF receiver */
14862306a36Sopenharmony_ci#define RME9652_SPDIF_SELECT       (1<<19)
14962306a36Sopenharmony_ci#define RME9652_SPDIF_CLOCK        (1<<20)
15062306a36Sopenharmony_ci#define RME9652_SPDIF_WRITE        (1<<21)
15162306a36Sopenharmony_ci#define RME9652_ADAT1_INTERNAL     (1<<22)      /* Rev 1.5+: if set, internal CD connector carries ADAT */
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/* buffersize = 512Bytes * 2^n, where n is made from Bit2 ... Bit0 */
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci#define RME9652_latency            0x0e
15662306a36Sopenharmony_ci#define rme9652_encode_latency(x)  (((x)&0x7)<<1)
15762306a36Sopenharmony_ci#define rme9652_decode_latency(x)  (((x)>>1)&0x7)
15862306a36Sopenharmony_ci#define rme9652_running_double_speed(s) ((s)->control_register & RME9652_DS)
15962306a36Sopenharmony_ci#define RME9652_inp                (RME9652_inp_0|RME9652_inp_1)
16062306a36Sopenharmony_ci#define rme9652_encode_spdif_in(x) (((x)&0x3)<<14)
16162306a36Sopenharmony_ci#define rme9652_decode_spdif_in(x) (((x)>>14)&0x3)
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci#define RME9652_SyncPref_Mask      (RME9652_SyncPref_ADAT2|RME9652_SyncPref_ADAT3)
16462306a36Sopenharmony_ci#define RME9652_SyncPref_ADAT1	   0
16562306a36Sopenharmony_ci#define RME9652_SyncPref_SPDIF	   (RME9652_SyncPref_ADAT2|RME9652_SyncPref_ADAT3)
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/* the size of a substream (1 mono data stream) */
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci#define RME9652_CHANNEL_BUFFER_SAMPLES  (16*1024)
17062306a36Sopenharmony_ci#define RME9652_CHANNEL_BUFFER_BYTES    (4*RME9652_CHANNEL_BUFFER_SAMPLES)
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/* the size of the area we need to allocate for DMA transfers. the
17362306a36Sopenharmony_ci   size is the same regardless of the number of channels - the
17462306a36Sopenharmony_ci   9636 still uses the same memory area.
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci   Note that we allocate 1 more channel than is apparently needed
17762306a36Sopenharmony_ci   because the h/w seems to write 1 byte beyond the end of the last
17862306a36Sopenharmony_ci   page. Sigh.
17962306a36Sopenharmony_ci*/
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#define RME9652_DMA_AREA_BYTES ((RME9652_NCHANNELS+1) * RME9652_CHANNEL_BUFFER_BYTES)
18262306a36Sopenharmony_ci#define RME9652_DMA_AREA_KILOBYTES (RME9652_DMA_AREA_BYTES/1024)
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistruct snd_rme9652 {
18562306a36Sopenharmony_ci	int dev;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	spinlock_t lock;
18862306a36Sopenharmony_ci	int irq;
18962306a36Sopenharmony_ci	unsigned long port;
19062306a36Sopenharmony_ci	void __iomem *iobase;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	int precise_ptr;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	u32 control_register;	/* cached value */
19562306a36Sopenharmony_ci	u32 thru_bits;		/* thru 1=on, 0=off channel 1=Bit1... channel 26= Bit26 */
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	u32 creg_spdif;
19862306a36Sopenharmony_ci	u32 creg_spdif_stream;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	char *card_name;		/* hammerfall or hammerfall light names */
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci        size_t hw_offsetmask;     	/* &-with status register to get real hw_offset */
20362306a36Sopenharmony_ci	size_t prev_hw_offset;		/* previous hw offset */
20462306a36Sopenharmony_ci	size_t max_jitter;		/* maximum jitter in frames for
20562306a36Sopenharmony_ci					   hw pointer */
20662306a36Sopenharmony_ci	size_t period_bytes;		/* guess what this is */
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	unsigned char ds_channels;
20962306a36Sopenharmony_ci	unsigned char ss_channels;	/* different for hammerfall/hammerfall-light */
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* DMA buffers; those are copied instances from the original snd_dma_buf
21262306a36Sopenharmony_ci	 * objects (which are managed via devres) for the address alignments
21362306a36Sopenharmony_ci	 */
21462306a36Sopenharmony_ci	struct snd_dma_buffer playback_dma_buf;
21562306a36Sopenharmony_ci	struct snd_dma_buffer capture_dma_buf;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	unsigned char *capture_buffer;	/* suitably aligned address */
21862306a36Sopenharmony_ci	unsigned char *playback_buffer;	/* suitably aligned address */
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	pid_t capture_pid;
22162306a36Sopenharmony_ci	pid_t playback_pid;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	struct snd_pcm_substream *capture_substream;
22462306a36Sopenharmony_ci	struct snd_pcm_substream *playback_substream;
22562306a36Sopenharmony_ci	int running;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci        int passthru;                   /* non-zero if doing pass-thru */
22862306a36Sopenharmony_ci        int hw_rev;                     /* h/w rev * 10 (i.e. 1.5 has hw_rev = 15) */
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	int last_spdif_sample_rate;	/* so that we can catch externally ... */
23162306a36Sopenharmony_ci	int last_adat_sample_rate;	/* ... induced rate changes            */
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	const signed char *channel_map;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	struct snd_card *card;
23662306a36Sopenharmony_ci	struct snd_pcm *pcm;
23762306a36Sopenharmony_ci	struct pci_dev *pci;
23862306a36Sopenharmony_ci	struct snd_kcontrol *spdif_ctl;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci};
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci/* These tables map the ALSA channels 1..N to the channels that we
24362306a36Sopenharmony_ci   need to use in order to find the relevant channel buffer. RME
24462306a36Sopenharmony_ci   refer to this kind of mapping as between "the ADAT channel and
24562306a36Sopenharmony_ci   the DMA channel." We index it using the logical audio channel,
24662306a36Sopenharmony_ci   and the value is the DMA channel (i.e. channel buffer number)
24762306a36Sopenharmony_ci   where the data for that channel can be read/written from/to.
24862306a36Sopenharmony_ci*/
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic const signed char channel_map_9652_ss[26] = {
25162306a36Sopenharmony_ci	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
25262306a36Sopenharmony_ci	18, 19, 20, 21, 22, 23, 24, 25
25362306a36Sopenharmony_ci};
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic const signed char channel_map_9636_ss[26] = {
25662306a36Sopenharmony_ci	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
25762306a36Sopenharmony_ci	/* channels 16 and 17 are S/PDIF */
25862306a36Sopenharmony_ci	24, 25,
25962306a36Sopenharmony_ci	/* channels 18-25 don't exist */
26062306a36Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1
26162306a36Sopenharmony_ci};
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic const signed char channel_map_9652_ds[26] = {
26462306a36Sopenharmony_ci	/* ADAT channels are remapped */
26562306a36Sopenharmony_ci	1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23,
26662306a36Sopenharmony_ci	/* channels 12 and 13 are S/PDIF */
26762306a36Sopenharmony_ci	24, 25,
26862306a36Sopenharmony_ci	/* others don't exist */
26962306a36Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
27062306a36Sopenharmony_ci};
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic const signed char channel_map_9636_ds[26] = {
27362306a36Sopenharmony_ci	/* ADAT channels are remapped */
27462306a36Sopenharmony_ci	1, 3, 5, 7, 9, 11, 13, 15,
27562306a36Sopenharmony_ci	/* channels 8 and 9 are S/PDIF */
27662306a36Sopenharmony_ci	24, 25,
27762306a36Sopenharmony_ci	/* others don't exist */
27862306a36Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
27962306a36Sopenharmony_ci};
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic struct snd_dma_buffer *
28262306a36Sopenharmony_cisnd_hammerfall_get_buffer(struct pci_dev *pci, size_t size)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	return snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV, size);
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic const struct pci_device_id snd_rme9652_ids[] = {
28862306a36Sopenharmony_ci	{
28962306a36Sopenharmony_ci		.vendor	   = 0x10ee,
29062306a36Sopenharmony_ci		.device	   = 0x3fc4,
29162306a36Sopenharmony_ci		.subvendor = PCI_ANY_ID,
29262306a36Sopenharmony_ci		.subdevice = PCI_ANY_ID,
29362306a36Sopenharmony_ci	},	/* RME Digi9652 */
29462306a36Sopenharmony_ci	{ 0, },
29562306a36Sopenharmony_ci};
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_rme9652_ids);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic inline void rme9652_write(struct snd_rme9652 *rme9652, int reg, int val)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	writel(val, rme9652->iobase + reg);
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic inline unsigned int rme9652_read(struct snd_rme9652 *rme9652, int reg)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	return readl(rme9652->iobase + reg);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic inline int snd_rme9652_use_is_exclusive(struct snd_rme9652 *rme9652)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	unsigned long flags;
31262306a36Sopenharmony_ci	int ret = 1;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	spin_lock_irqsave(&rme9652->lock, flags);
31562306a36Sopenharmony_ci	if ((rme9652->playback_pid != rme9652->capture_pid) &&
31662306a36Sopenharmony_ci	    (rme9652->playback_pid >= 0) && (rme9652->capture_pid >= 0)) {
31762306a36Sopenharmony_ci		ret = 0;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci	spin_unlock_irqrestore(&rme9652->lock, flags);
32062306a36Sopenharmony_ci	return ret;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic inline int rme9652_adat_sample_rate(struct snd_rme9652 *rme9652)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	if (rme9652_running_double_speed(rme9652)) {
32662306a36Sopenharmony_ci		return (rme9652_read(rme9652, RME9652_status_register) &
32762306a36Sopenharmony_ci			RME9652_fs48) ? 96000 : 88200;
32862306a36Sopenharmony_ci	} else {
32962306a36Sopenharmony_ci		return (rme9652_read(rme9652, RME9652_status_register) &
33062306a36Sopenharmony_ci			RME9652_fs48) ? 48000 : 44100;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic inline void rme9652_compute_period_size(struct snd_rme9652 *rme9652)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	unsigned int i;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	i = rme9652->control_register & RME9652_latency;
33962306a36Sopenharmony_ci	rme9652->period_bytes = 1 << ((rme9652_decode_latency(i) + 8));
34062306a36Sopenharmony_ci	rme9652->hw_offsetmask =
34162306a36Sopenharmony_ci		(rme9652->period_bytes * 2 - 1) & RME9652_buf_pos;
34262306a36Sopenharmony_ci	rme9652->max_jitter = 80;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	int status;
34862306a36Sopenharmony_ci	unsigned int offset, frag;
34962306a36Sopenharmony_ci	snd_pcm_uframes_t period_size = rme9652->period_bytes / 4;
35062306a36Sopenharmony_ci	snd_pcm_sframes_t delta;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	status = rme9652_read(rme9652, RME9652_status_register);
35362306a36Sopenharmony_ci	if (!rme9652->precise_ptr)
35462306a36Sopenharmony_ci		return (status & RME9652_buffer_id) ? period_size : 0;
35562306a36Sopenharmony_ci	offset = status & RME9652_buf_pos;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/* The hardware may give a backward movement for up to 80 frames
35862306a36Sopenharmony_ci           Martin Kirst <martin.kirst@freenet.de> knows the details.
35962306a36Sopenharmony_ci	*/
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	delta = rme9652->prev_hw_offset - offset;
36262306a36Sopenharmony_ci	delta &= 0xffff;
36362306a36Sopenharmony_ci	if (delta <= (snd_pcm_sframes_t)rme9652->max_jitter * 4)
36462306a36Sopenharmony_ci		offset = rme9652->prev_hw_offset;
36562306a36Sopenharmony_ci	else
36662306a36Sopenharmony_ci		rme9652->prev_hw_offset = offset;
36762306a36Sopenharmony_ci	offset &= rme9652->hw_offsetmask;
36862306a36Sopenharmony_ci	offset /= 4;
36962306a36Sopenharmony_ci	frag = status & RME9652_buffer_id;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (offset < period_size) {
37262306a36Sopenharmony_ci		if (offset > rme9652->max_jitter) {
37362306a36Sopenharmony_ci			if (frag)
37462306a36Sopenharmony_ci				dev_err(rme9652->card->dev,
37562306a36Sopenharmony_ci					"Unexpected hw_pointer position (bufid == 0): status: %x offset: %d\n",
37662306a36Sopenharmony_ci					status, offset);
37762306a36Sopenharmony_ci		} else if (!frag)
37862306a36Sopenharmony_ci			return 0;
37962306a36Sopenharmony_ci		offset -= rme9652->max_jitter;
38062306a36Sopenharmony_ci		if ((int)offset < 0)
38162306a36Sopenharmony_ci			offset += period_size * 2;
38262306a36Sopenharmony_ci	} else {
38362306a36Sopenharmony_ci		if (offset > period_size + rme9652->max_jitter) {
38462306a36Sopenharmony_ci			if (!frag)
38562306a36Sopenharmony_ci				dev_err(rme9652->card->dev,
38662306a36Sopenharmony_ci					"Unexpected hw_pointer position (bufid == 1): status: %x offset: %d\n",
38762306a36Sopenharmony_ci					status, offset);
38862306a36Sopenharmony_ci		} else if (frag)
38962306a36Sopenharmony_ci			return period_size;
39062306a36Sopenharmony_ci		offset -= rme9652->max_jitter;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return offset;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic inline void rme9652_reset_hw_pointer(struct snd_rme9652 *rme9652)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	int i;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* reset the FIFO pointer to zero. We do this by writing to 8
40162306a36Sopenharmony_ci	   registers, each of which is a 32bit wide register, and set
40262306a36Sopenharmony_ci	   them all to zero. Note that s->iobase is a pointer to
40362306a36Sopenharmony_ci	   int32, not pointer to char.
40462306a36Sopenharmony_ci	*/
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
40762306a36Sopenharmony_ci		rme9652_write(rme9652, i * 4, 0);
40862306a36Sopenharmony_ci		udelay(10);
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci	rme9652->prev_hw_offset = 0;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic inline void rme9652_start(struct snd_rme9652 *s)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	s->control_register |= (RME9652_IE | RME9652_start_bit);
41662306a36Sopenharmony_ci	rme9652_write(s, RME9652_control_register, s->control_register);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic inline void rme9652_stop(struct snd_rme9652 *s)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	s->control_register &= ~(RME9652_start_bit | RME9652_IE);
42262306a36Sopenharmony_ci	rme9652_write(s, RME9652_control_register, s->control_register);
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic int rme9652_set_interrupt_interval(struct snd_rme9652 *s,
42662306a36Sopenharmony_ci					  unsigned int frames)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	int restart = 0;
42962306a36Sopenharmony_ci	int n;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	spin_lock_irq(&s->lock);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	restart = s->running;
43462306a36Sopenharmony_ci	if (restart)
43562306a36Sopenharmony_ci		rme9652_stop(s);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	frames >>= 7;
43862306a36Sopenharmony_ci	n = 0;
43962306a36Sopenharmony_ci	while (frames) {
44062306a36Sopenharmony_ci		n++;
44162306a36Sopenharmony_ci		frames >>= 1;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	s->control_register &= ~RME9652_latency;
44562306a36Sopenharmony_ci	s->control_register |= rme9652_encode_latency(n);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	rme9652_write(s, RME9652_control_register, s->control_register);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	rme9652_compute_period_size(s);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (restart)
45262306a36Sopenharmony_ci		rme9652_start(s);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	spin_unlock_irq(&s->lock);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	return 0;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic int rme9652_set_rate(struct snd_rme9652 *rme9652, int rate)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	int restart;
46262306a36Sopenharmony_ci	int reject_if_open = 0;
46362306a36Sopenharmony_ci	int xrate;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (!snd_rme9652_use_is_exclusive (rme9652)) {
46662306a36Sopenharmony_ci		return -EBUSY;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	/* Changing from a "single speed" to a "double speed" rate is
47062306a36Sopenharmony_ci	   not allowed if any substreams are open. This is because
47162306a36Sopenharmony_ci	   such a change causes a shift in the location of
47262306a36Sopenharmony_ci	   the DMA buffers and a reduction in the number of available
47362306a36Sopenharmony_ci	   buffers.
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	   Note that a similar but essentially insoluble problem
47662306a36Sopenharmony_ci	   exists for externally-driven rate changes. All we can do
47762306a36Sopenharmony_ci	   is to flag rate changes in the read/write routines.
47862306a36Sopenharmony_ci	 */
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
48162306a36Sopenharmony_ci	xrate = rme9652_adat_sample_rate(rme9652);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	switch (rate) {
48462306a36Sopenharmony_ci	case 44100:
48562306a36Sopenharmony_ci		if (xrate > 48000) {
48662306a36Sopenharmony_ci			reject_if_open = 1;
48762306a36Sopenharmony_ci		}
48862306a36Sopenharmony_ci		rate = 0;
48962306a36Sopenharmony_ci		break;
49062306a36Sopenharmony_ci	case 48000:
49162306a36Sopenharmony_ci		if (xrate > 48000) {
49262306a36Sopenharmony_ci			reject_if_open = 1;
49362306a36Sopenharmony_ci		}
49462306a36Sopenharmony_ci		rate = RME9652_freq;
49562306a36Sopenharmony_ci		break;
49662306a36Sopenharmony_ci	case 88200:
49762306a36Sopenharmony_ci		if (xrate < 48000) {
49862306a36Sopenharmony_ci			reject_if_open = 1;
49962306a36Sopenharmony_ci		}
50062306a36Sopenharmony_ci		rate = RME9652_DS;
50162306a36Sopenharmony_ci		break;
50262306a36Sopenharmony_ci	case 96000:
50362306a36Sopenharmony_ci		if (xrate < 48000) {
50462306a36Sopenharmony_ci			reject_if_open = 1;
50562306a36Sopenharmony_ci		}
50662306a36Sopenharmony_ci		rate = RME9652_DS | RME9652_freq;
50762306a36Sopenharmony_ci		break;
50862306a36Sopenharmony_ci	default:
50962306a36Sopenharmony_ci		spin_unlock_irq(&rme9652->lock);
51062306a36Sopenharmony_ci		return -EINVAL;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (reject_if_open && (rme9652->capture_pid >= 0 || rme9652->playback_pid >= 0)) {
51462306a36Sopenharmony_ci		spin_unlock_irq(&rme9652->lock);
51562306a36Sopenharmony_ci		return -EBUSY;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	restart = rme9652->running;
51962306a36Sopenharmony_ci	if (restart)
52062306a36Sopenharmony_ci		rme9652_stop(rme9652);
52162306a36Sopenharmony_ci	rme9652->control_register &= ~(RME9652_freq | RME9652_DS);
52262306a36Sopenharmony_ci	rme9652->control_register |= rate;
52362306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (restart)
52662306a36Sopenharmony_ci		rme9652_start(rme9652);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (rate & RME9652_DS) {
52962306a36Sopenharmony_ci		if (rme9652->ss_channels == RME9652_NCHANNELS) {
53062306a36Sopenharmony_ci			rme9652->channel_map = channel_map_9652_ds;
53162306a36Sopenharmony_ci		} else {
53262306a36Sopenharmony_ci			rme9652->channel_map = channel_map_9636_ds;
53362306a36Sopenharmony_ci		}
53462306a36Sopenharmony_ci	} else {
53562306a36Sopenharmony_ci		if (rme9652->ss_channels == RME9652_NCHANNELS) {
53662306a36Sopenharmony_ci			rme9652->channel_map = channel_map_9652_ss;
53762306a36Sopenharmony_ci		} else {
53862306a36Sopenharmony_ci			rme9652->channel_map = channel_map_9636_ss;
53962306a36Sopenharmony_ci		}
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
54362306a36Sopenharmony_ci	return 0;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic void rme9652_set_thru(struct snd_rme9652 *rme9652, int channel, int enable)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	int i;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	rme9652->passthru = 0;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (channel < 0) {
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci		/* set thru for all channels */
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		if (enable) {
55762306a36Sopenharmony_ci			for (i = 0; i < RME9652_NCHANNELS; i++) {
55862306a36Sopenharmony_ci				rme9652->thru_bits |= (1 << i);
55962306a36Sopenharmony_ci				rme9652_write(rme9652, RME9652_thru_base + i * 4, 1);
56062306a36Sopenharmony_ci			}
56162306a36Sopenharmony_ci		} else {
56262306a36Sopenharmony_ci			for (i = 0; i < RME9652_NCHANNELS; i++) {
56362306a36Sopenharmony_ci				rme9652->thru_bits &= ~(1 << i);
56462306a36Sopenharmony_ci				rme9652_write(rme9652, RME9652_thru_base + i * 4, 0);
56562306a36Sopenharmony_ci			}
56662306a36Sopenharmony_ci		}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	} else {
56962306a36Sopenharmony_ci		int mapped_channel;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		mapped_channel = rme9652->channel_map[channel];
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci		if (enable) {
57462306a36Sopenharmony_ci			rme9652->thru_bits |= (1 << mapped_channel);
57562306a36Sopenharmony_ci		} else {
57662306a36Sopenharmony_ci			rme9652->thru_bits &= ~(1 << mapped_channel);
57762306a36Sopenharmony_ci		}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		rme9652_write(rme9652,
58062306a36Sopenharmony_ci			       RME9652_thru_base + mapped_channel * 4,
58162306a36Sopenharmony_ci			       enable ? 1 : 0);
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic int rme9652_set_passthru(struct snd_rme9652 *rme9652, int onoff)
58662306a36Sopenharmony_ci{
58762306a36Sopenharmony_ci	if (onoff) {
58862306a36Sopenharmony_ci		rme9652_set_thru(rme9652, -1, 1);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		/* we don't want interrupts, so do a
59162306a36Sopenharmony_ci		   custom version of rme9652_start().
59262306a36Sopenharmony_ci		*/
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		rme9652->control_register =
59562306a36Sopenharmony_ci			RME9652_inp_0 |
59662306a36Sopenharmony_ci			rme9652_encode_latency(7) |
59762306a36Sopenharmony_ci			RME9652_start_bit;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci		rme9652_reset_hw_pointer(rme9652);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci		rme9652_write(rme9652, RME9652_control_register,
60262306a36Sopenharmony_ci			      rme9652->control_register);
60362306a36Sopenharmony_ci		rme9652->passthru = 1;
60462306a36Sopenharmony_ci	} else {
60562306a36Sopenharmony_ci		rme9652_set_thru(rme9652, -1, 0);
60662306a36Sopenharmony_ci		rme9652_stop(rme9652);
60762306a36Sopenharmony_ci		rme9652->passthru = 0;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	return 0;
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_cistatic void rme9652_spdif_set_bit (struct snd_rme9652 *rme9652, int mask, int onoff)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	if (onoff)
61662306a36Sopenharmony_ci		rme9652->control_register |= mask;
61762306a36Sopenharmony_ci	else
61862306a36Sopenharmony_ci		rme9652->control_register &= ~mask;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic void rme9652_spdif_write_byte (struct snd_rme9652 *rme9652, const int val)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	long mask;
62662306a36Sopenharmony_ci	long i;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) {
62962306a36Sopenharmony_ci		if (val & mask)
63062306a36Sopenharmony_ci			rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_WRITE, 1);
63162306a36Sopenharmony_ci		else
63262306a36Sopenharmony_ci			rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_WRITE, 0);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 1);
63562306a36Sopenharmony_ci		rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 0);
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic int rme9652_spdif_read_byte (struct snd_rme9652 *rme9652)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	long mask;
64262306a36Sopenharmony_ci	long val;
64362306a36Sopenharmony_ci	long i;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	val = 0;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	for (i = 0, mask = 0x80;  i < 8; i++, mask >>= 1) {
64862306a36Sopenharmony_ci		rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 1);
64962306a36Sopenharmony_ci		if (rme9652_read (rme9652, RME9652_status_register) & RME9652_SPDIF_READ)
65062306a36Sopenharmony_ci			val |= mask;
65162306a36Sopenharmony_ci		rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 0);
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	return val;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic void rme9652_write_spdif_codec (struct snd_rme9652 *rme9652, const int address, const int data)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 1);
66062306a36Sopenharmony_ci	rme9652_spdif_write_byte (rme9652, 0x20);
66162306a36Sopenharmony_ci	rme9652_spdif_write_byte (rme9652, address);
66262306a36Sopenharmony_ci	rme9652_spdif_write_byte (rme9652, data);
66362306a36Sopenharmony_ci	rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 0);
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic int rme9652_spdif_read_codec (struct snd_rme9652 *rme9652, const int address)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	int ret;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 1);
67262306a36Sopenharmony_ci	rme9652_spdif_write_byte (rme9652, 0x20);
67362306a36Sopenharmony_ci	rme9652_spdif_write_byte (rme9652, address);
67462306a36Sopenharmony_ci	rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 0);
67562306a36Sopenharmony_ci	rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 1);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	rme9652_spdif_write_byte (rme9652, 0x21);
67862306a36Sopenharmony_ci	ret = rme9652_spdif_read_byte (rme9652);
67962306a36Sopenharmony_ci	rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 0);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	return ret;
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_cistatic void rme9652_initialize_spdif_receiver (struct snd_rme9652 *rme9652)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	/* XXX what unsets this ? */
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	rme9652->control_register |= RME9652_SPDIF_RESET;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	rme9652_write_spdif_codec (rme9652, 4, 0x40);
69162306a36Sopenharmony_ci	rme9652_write_spdif_codec (rme9652, 17, 0x13);
69262306a36Sopenharmony_ci	rme9652_write_spdif_codec (rme9652, 6, 0x02);
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cistatic inline int rme9652_spdif_sample_rate(struct snd_rme9652 *s)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	unsigned int rate_bits;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	if (rme9652_read(s, RME9652_status_register) & RME9652_ERF) {
70062306a36Sopenharmony_ci		return -1;	/* error condition */
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	if (s->hw_rev == 15) {
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		int x, y, ret;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		x = rme9652_spdif_read_codec (s, 30);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		if (x != 0)
71062306a36Sopenharmony_ci			y = 48000 * 64 / x;
71162306a36Sopenharmony_ci		else
71262306a36Sopenharmony_ci			y = 0;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci		if      (y > 30400 && y < 33600)  ret = 32000;
71562306a36Sopenharmony_ci		else if (y > 41900 && y < 46000)  ret = 44100;
71662306a36Sopenharmony_ci		else if (y > 46000 && y < 50400)  ret = 48000;
71762306a36Sopenharmony_ci		else if (y > 60800 && y < 67200)  ret = 64000;
71862306a36Sopenharmony_ci		else if (y > 83700 && y < 92000)  ret = 88200;
71962306a36Sopenharmony_ci		else if (y > 92000 && y < 100000) ret = 96000;
72062306a36Sopenharmony_ci		else                              ret = 0;
72162306a36Sopenharmony_ci		return ret;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	rate_bits = rme9652_read(s, RME9652_status_register) & RME9652_F;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	switch (rme9652_decode_spdif_rate(rate_bits)) {
72762306a36Sopenharmony_ci	case 0x7:
72862306a36Sopenharmony_ci		return 32000;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	case 0x6:
73162306a36Sopenharmony_ci		return 44100;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	case 0x5:
73462306a36Sopenharmony_ci		return 48000;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	case 0x4:
73762306a36Sopenharmony_ci		return 88200;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	case 0x3:
74062306a36Sopenharmony_ci		return 96000;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	case 0x0:
74362306a36Sopenharmony_ci		return 64000;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	default:
74662306a36Sopenharmony_ci		dev_err(s->card->dev,
74762306a36Sopenharmony_ci			"%s: unknown S/PDIF input rate (bits = 0x%x)\n",
74862306a36Sopenharmony_ci			   s->card_name, rate_bits);
74962306a36Sopenharmony_ci		return 0;
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci/*-----------------------------------------------------------------------------
75462306a36Sopenharmony_ci  Control Interface
75562306a36Sopenharmony_ci  ----------------------------------------------------------------------------*/
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic u32 snd_rme9652_convert_from_aes(struct snd_aes_iec958 *aes)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	u32 val = 0;
76062306a36Sopenharmony_ci	val |= (aes->status[0] & IEC958_AES0_PROFESSIONAL) ? RME9652_PRO : 0;
76162306a36Sopenharmony_ci	val |= (aes->status[0] & IEC958_AES0_NONAUDIO) ? RME9652_Dolby : 0;
76262306a36Sopenharmony_ci	if (val & RME9652_PRO)
76362306a36Sopenharmony_ci		val |= (aes->status[0] & IEC958_AES0_PRO_EMPHASIS_5015) ? RME9652_EMP : 0;
76462306a36Sopenharmony_ci	else
76562306a36Sopenharmony_ci		val |= (aes->status[0] & IEC958_AES0_CON_EMPHASIS_5015) ? RME9652_EMP : 0;
76662306a36Sopenharmony_ci	return val;
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic void snd_rme9652_convert_to_aes(struct snd_aes_iec958 *aes, u32 val)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	aes->status[0] = ((val & RME9652_PRO) ? IEC958_AES0_PROFESSIONAL : 0) |
77262306a36Sopenharmony_ci			 ((val & RME9652_Dolby) ? IEC958_AES0_NONAUDIO : 0);
77362306a36Sopenharmony_ci	if (val & RME9652_PRO)
77462306a36Sopenharmony_ci		aes->status[0] |= (val & RME9652_EMP) ? IEC958_AES0_PRO_EMPHASIS_5015 : 0;
77562306a36Sopenharmony_ci	else
77662306a36Sopenharmony_ci		aes->status[0] |= (val & RME9652_EMP) ? IEC958_AES0_CON_EMPHASIS_5015 : 0;
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic int snd_rme9652_control_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
78262306a36Sopenharmony_ci	uinfo->count = 1;
78362306a36Sopenharmony_ci	return 0;
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic int snd_rme9652_control_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	snd_rme9652_convert_to_aes(&ucontrol->value.iec958, rme9652->creg_spdif);
79162306a36Sopenharmony_ci	return 0;
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_cistatic int snd_rme9652_control_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
79762306a36Sopenharmony_ci	int change;
79862306a36Sopenharmony_ci	u32 val;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	val = snd_rme9652_convert_from_aes(&ucontrol->value.iec958);
80162306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
80262306a36Sopenharmony_ci	change = val != rme9652->creg_spdif;
80362306a36Sopenharmony_ci	rme9652->creg_spdif = val;
80462306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
80562306a36Sopenharmony_ci	return change;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic int snd_rme9652_control_spdif_stream_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
81162306a36Sopenharmony_ci	uinfo->count = 1;
81262306a36Sopenharmony_ci	return 0;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic int snd_rme9652_control_spdif_stream_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	snd_rme9652_convert_to_aes(&ucontrol->value.iec958, rme9652->creg_spdif_stream);
82062306a36Sopenharmony_ci	return 0;
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic int snd_rme9652_control_spdif_stream_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
82662306a36Sopenharmony_ci	int change;
82762306a36Sopenharmony_ci	u32 val;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	val = snd_rme9652_convert_from_aes(&ucontrol->value.iec958);
83062306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
83162306a36Sopenharmony_ci	change = val != rme9652->creg_spdif_stream;
83262306a36Sopenharmony_ci	rme9652->creg_spdif_stream = val;
83362306a36Sopenharmony_ci	rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP);
83462306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= val);
83562306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
83662306a36Sopenharmony_ci	return change;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic int snd_rme9652_control_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
84262306a36Sopenharmony_ci	uinfo->count = 1;
84362306a36Sopenharmony_ci	return 0;
84462306a36Sopenharmony_ci}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_cistatic int snd_rme9652_control_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = kcontrol->private_value;
84962306a36Sopenharmony_ci	return 0;
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci#define RME9652_ADAT1_IN(xname, xindex) \
85362306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
85462306a36Sopenharmony_ci  .info = snd_rme9652_info_adat1_in, \
85562306a36Sopenharmony_ci  .get = snd_rme9652_get_adat1_in, \
85662306a36Sopenharmony_ci  .put = snd_rme9652_put_adat1_in }
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic unsigned int rme9652_adat1_in(struct snd_rme9652 *rme9652)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	if (rme9652->control_register & RME9652_ADAT1_INTERNAL)
86162306a36Sopenharmony_ci		return 1;
86262306a36Sopenharmony_ci	return 0;
86362306a36Sopenharmony_ci}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_cistatic int rme9652_set_adat1_input(struct snd_rme9652 *rme9652, int internal)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	int restart = 0;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	if (internal) {
87062306a36Sopenharmony_ci		rme9652->control_register |= RME9652_ADAT1_INTERNAL;
87162306a36Sopenharmony_ci	} else {
87262306a36Sopenharmony_ci		rme9652->control_register &= ~RME9652_ADAT1_INTERNAL;
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	/* XXX do we actually need to stop the card when we do this ? */
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	restart = rme9652->running;
87862306a36Sopenharmony_ci	if (restart)
87962306a36Sopenharmony_ci		rme9652_stop(rme9652);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (restart)
88462306a36Sopenharmony_ci		rme9652_start(rme9652);
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	return 0;
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic int snd_rme9652_info_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	static const char * const texts[2] = {"ADAT1", "Internal"};
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 2, texts);
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_cistatic int snd_rme9652_get_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
90162306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = rme9652_adat1_in(rme9652);
90262306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
90362306a36Sopenharmony_ci	return 0;
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic int snd_rme9652_put_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
90962306a36Sopenharmony_ci	int change;
91062306a36Sopenharmony_ci	unsigned int val;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	if (!snd_rme9652_use_is_exclusive(rme9652))
91362306a36Sopenharmony_ci		return -EBUSY;
91462306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0] % 2;
91562306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
91662306a36Sopenharmony_ci	change = val != rme9652_adat1_in(rme9652);
91762306a36Sopenharmony_ci	if (change)
91862306a36Sopenharmony_ci		rme9652_set_adat1_input(rme9652, val);
91962306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
92062306a36Sopenharmony_ci	return change;
92162306a36Sopenharmony_ci}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci#define RME9652_SPDIF_IN(xname, xindex) \
92462306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
92562306a36Sopenharmony_ci  .info = snd_rme9652_info_spdif_in, \
92662306a36Sopenharmony_ci  .get = snd_rme9652_get_spdif_in, .put = snd_rme9652_put_spdif_in }
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_cistatic unsigned int rme9652_spdif_in(struct snd_rme9652 *rme9652)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	return rme9652_decode_spdif_in(rme9652->control_register &
93162306a36Sopenharmony_ci				       RME9652_inp);
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cistatic int rme9652_set_spdif_input(struct snd_rme9652 *rme9652, int in)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	int restart = 0;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	rme9652->control_register &= ~RME9652_inp;
93962306a36Sopenharmony_ci	rme9652->control_register |= rme9652_encode_spdif_in(in);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	restart = rme9652->running;
94262306a36Sopenharmony_ci	if (restart)
94362306a36Sopenharmony_ci		rme9652_stop(rme9652);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	if (restart)
94862306a36Sopenharmony_ci		rme9652_start(rme9652);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	return 0;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_cistatic int snd_rme9652_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	static const char * const texts[3] = {"ADAT1", "Coaxial", "Internal"};
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_cistatic int snd_rme9652_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
96562306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = rme9652_spdif_in(rme9652);
96662306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
96762306a36Sopenharmony_ci	return 0;
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cistatic int snd_rme9652_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
97362306a36Sopenharmony_ci	int change;
97462306a36Sopenharmony_ci	unsigned int val;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	if (!snd_rme9652_use_is_exclusive(rme9652))
97762306a36Sopenharmony_ci		return -EBUSY;
97862306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0] % 3;
97962306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
98062306a36Sopenharmony_ci	change = val != rme9652_spdif_in(rme9652);
98162306a36Sopenharmony_ci	if (change)
98262306a36Sopenharmony_ci		rme9652_set_spdif_input(rme9652, val);
98362306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
98462306a36Sopenharmony_ci	return change;
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci#define RME9652_SPDIF_OUT(xname, xindex) \
98862306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
98962306a36Sopenharmony_ci  .info = snd_rme9652_info_spdif_out, \
99062306a36Sopenharmony_ci  .get = snd_rme9652_get_spdif_out, .put = snd_rme9652_put_spdif_out }
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic int rme9652_spdif_out(struct snd_rme9652 *rme9652)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	return (rme9652->control_register & RME9652_opt_out) ? 1 : 0;
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic int rme9652_set_spdif_output(struct snd_rme9652 *rme9652, int out)
99862306a36Sopenharmony_ci{
99962306a36Sopenharmony_ci	int restart = 0;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	if (out) {
100262306a36Sopenharmony_ci		rme9652->control_register |= RME9652_opt_out;
100362306a36Sopenharmony_ci	} else {
100462306a36Sopenharmony_ci		rme9652->control_register &= ~RME9652_opt_out;
100562306a36Sopenharmony_ci	}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	restart = rme9652->running;
100862306a36Sopenharmony_ci	if (restart)
100962306a36Sopenharmony_ci		rme9652_stop(rme9652);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	if (restart)
101462306a36Sopenharmony_ci		rme9652_start(rme9652);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	return 0;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci#define snd_rme9652_info_spdif_out	snd_ctl_boolean_mono_info
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic int snd_rme9652_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
102262306a36Sopenharmony_ci{
102362306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
102662306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = rme9652_spdif_out(rme9652);
102762306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
102862306a36Sopenharmony_ci	return 0;
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic int snd_rme9652_put_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
103462306a36Sopenharmony_ci	int change;
103562306a36Sopenharmony_ci	unsigned int val;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	if (!snd_rme9652_use_is_exclusive(rme9652))
103862306a36Sopenharmony_ci		return -EBUSY;
103962306a36Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
104062306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
104162306a36Sopenharmony_ci	change = (int)val != rme9652_spdif_out(rme9652);
104262306a36Sopenharmony_ci	rme9652_set_spdif_output(rme9652, val);
104362306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
104462306a36Sopenharmony_ci	return change;
104562306a36Sopenharmony_ci}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci#define RME9652_SYNC_MODE(xname, xindex) \
104862306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
104962306a36Sopenharmony_ci  .info = snd_rme9652_info_sync_mode, \
105062306a36Sopenharmony_ci  .get = snd_rme9652_get_sync_mode, .put = snd_rme9652_put_sync_mode }
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_cistatic int rme9652_sync_mode(struct snd_rme9652 *rme9652)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	if (rme9652->control_register & RME9652_wsel) {
105562306a36Sopenharmony_ci		return 2;
105662306a36Sopenharmony_ci	} else if (rme9652->control_register & RME9652_Master) {
105762306a36Sopenharmony_ci		return 1;
105862306a36Sopenharmony_ci	} else {
105962306a36Sopenharmony_ci		return 0;
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_cistatic int rme9652_set_sync_mode(struct snd_rme9652 *rme9652, int mode)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	int restart = 0;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	switch (mode) {
106862306a36Sopenharmony_ci	case 0:
106962306a36Sopenharmony_ci		rme9652->control_register &=
107062306a36Sopenharmony_ci		    ~(RME9652_Master | RME9652_wsel);
107162306a36Sopenharmony_ci		break;
107262306a36Sopenharmony_ci	case 1:
107362306a36Sopenharmony_ci		rme9652->control_register =
107462306a36Sopenharmony_ci		    (rme9652->control_register & ~RME9652_wsel) | RME9652_Master;
107562306a36Sopenharmony_ci		break;
107662306a36Sopenharmony_ci	case 2:
107762306a36Sopenharmony_ci		rme9652->control_register |=
107862306a36Sopenharmony_ci		    (RME9652_Master | RME9652_wsel);
107962306a36Sopenharmony_ci		break;
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	restart = rme9652->running;
108362306a36Sopenharmony_ci	if (restart)
108462306a36Sopenharmony_ci		rme9652_stop(rme9652);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	if (restart)
108962306a36Sopenharmony_ci		rme9652_start(rme9652);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	return 0;
109262306a36Sopenharmony_ci}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_cistatic int snd_rme9652_info_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
109562306a36Sopenharmony_ci{
109662306a36Sopenharmony_ci	static const char * const texts[3] = {
109762306a36Sopenharmony_ci		"AutoSync", "Master", "Word Clock"
109862306a36Sopenharmony_ci	};
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
110162306a36Sopenharmony_ci}
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cistatic int snd_rme9652_get_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
110862306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = rme9652_sync_mode(rme9652);
110962306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
111062306a36Sopenharmony_ci	return 0;
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic int snd_rme9652_put_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
111462306a36Sopenharmony_ci{
111562306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
111662306a36Sopenharmony_ci	int change;
111762306a36Sopenharmony_ci	unsigned int val;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0] % 3;
112062306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
112162306a36Sopenharmony_ci	change = (int)val != rme9652_sync_mode(rme9652);
112262306a36Sopenharmony_ci	rme9652_set_sync_mode(rme9652, val);
112362306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
112462306a36Sopenharmony_ci	return change;
112562306a36Sopenharmony_ci}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci#define RME9652_SYNC_PREF(xname, xindex) \
112862306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
112962306a36Sopenharmony_ci  .info = snd_rme9652_info_sync_pref, \
113062306a36Sopenharmony_ci  .get = snd_rme9652_get_sync_pref, .put = snd_rme9652_put_sync_pref }
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_cistatic int rme9652_sync_pref(struct snd_rme9652 *rme9652)
113362306a36Sopenharmony_ci{
113462306a36Sopenharmony_ci	switch (rme9652->control_register & RME9652_SyncPref_Mask) {
113562306a36Sopenharmony_ci	case RME9652_SyncPref_ADAT1:
113662306a36Sopenharmony_ci		return RME9652_SYNC_FROM_ADAT1;
113762306a36Sopenharmony_ci	case RME9652_SyncPref_ADAT2:
113862306a36Sopenharmony_ci		return RME9652_SYNC_FROM_ADAT2;
113962306a36Sopenharmony_ci	case RME9652_SyncPref_ADAT3:
114062306a36Sopenharmony_ci		return RME9652_SYNC_FROM_ADAT3;
114162306a36Sopenharmony_ci	case RME9652_SyncPref_SPDIF:
114262306a36Sopenharmony_ci		return RME9652_SYNC_FROM_SPDIF;
114362306a36Sopenharmony_ci	}
114462306a36Sopenharmony_ci	/* Not reachable */
114562306a36Sopenharmony_ci	return 0;
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_cistatic int rme9652_set_sync_pref(struct snd_rme9652 *rme9652, int pref)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	int restart;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	rme9652->control_register &= ~RME9652_SyncPref_Mask;
115362306a36Sopenharmony_ci	switch (pref) {
115462306a36Sopenharmony_ci	case RME9652_SYNC_FROM_ADAT1:
115562306a36Sopenharmony_ci		rme9652->control_register |= RME9652_SyncPref_ADAT1;
115662306a36Sopenharmony_ci		break;
115762306a36Sopenharmony_ci	case RME9652_SYNC_FROM_ADAT2:
115862306a36Sopenharmony_ci		rme9652->control_register |= RME9652_SyncPref_ADAT2;
115962306a36Sopenharmony_ci		break;
116062306a36Sopenharmony_ci	case RME9652_SYNC_FROM_ADAT3:
116162306a36Sopenharmony_ci		rme9652->control_register |= RME9652_SyncPref_ADAT3;
116262306a36Sopenharmony_ci		break;
116362306a36Sopenharmony_ci	case RME9652_SYNC_FROM_SPDIF:
116462306a36Sopenharmony_ci		rme9652->control_register |= RME9652_SyncPref_SPDIF;
116562306a36Sopenharmony_ci		break;
116662306a36Sopenharmony_ci	}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	restart = rme9652->running;
116962306a36Sopenharmony_ci	if (restart)
117062306a36Sopenharmony_ci		rme9652_stop(rme9652);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	if (restart)
117562306a36Sopenharmony_ci		rme9652_start(rme9652);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	return 0;
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic int snd_rme9652_info_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	static const char * const texts[4] = {
118362306a36Sopenharmony_ci		"IEC958 In", "ADAT1 In", "ADAT2 In", "ADAT3 In"
118462306a36Sopenharmony_ci	};
118562306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1,
118862306a36Sopenharmony_ci				 rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3,
118962306a36Sopenharmony_ci				 texts);
119062306a36Sopenharmony_ci}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_cistatic int snd_rme9652_get_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
119762306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = rme9652_sync_pref(rme9652);
119862306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
119962306a36Sopenharmony_ci	return 0;
120062306a36Sopenharmony_ci}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistatic int snd_rme9652_put_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
120362306a36Sopenharmony_ci{
120462306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
120562306a36Sopenharmony_ci	int change, max;
120662306a36Sopenharmony_ci	unsigned int val;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	if (!snd_rme9652_use_is_exclusive(rme9652))
120962306a36Sopenharmony_ci		return -EBUSY;
121062306a36Sopenharmony_ci	max = rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3;
121162306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0] % max;
121262306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
121362306a36Sopenharmony_ci	change = (int)val != rme9652_sync_pref(rme9652);
121462306a36Sopenharmony_ci	rme9652_set_sync_pref(rme9652, val);
121562306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
121662306a36Sopenharmony_ci	return change;
121762306a36Sopenharmony_ci}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_cistatic int snd_rme9652_info_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
122062306a36Sopenharmony_ci{
122162306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
122262306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
122362306a36Sopenharmony_ci	uinfo->count = rme9652->ss_channels;
122462306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
122562306a36Sopenharmony_ci	uinfo->value.integer.max = 1;
122662306a36Sopenharmony_ci	return 0;
122762306a36Sopenharmony_ci}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_cistatic int snd_rme9652_get_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
123262306a36Sopenharmony_ci	unsigned int k;
123362306a36Sopenharmony_ci	u32 thru_bits = rme9652->thru_bits;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	for (k = 0; k < rme9652->ss_channels; ++k) {
123662306a36Sopenharmony_ci		ucontrol->value.integer.value[k] = !!(thru_bits & (1 << k));
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci	return 0;
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_cistatic int snd_rme9652_put_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
124262306a36Sopenharmony_ci{
124362306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
124462306a36Sopenharmony_ci	int change;
124562306a36Sopenharmony_ci	unsigned int chn;
124662306a36Sopenharmony_ci	u32 thru_bits = 0;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	if (!snd_rme9652_use_is_exclusive(rme9652))
124962306a36Sopenharmony_ci		return -EBUSY;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	for (chn = 0; chn < rme9652->ss_channels; ++chn) {
125262306a36Sopenharmony_ci		if (ucontrol->value.integer.value[chn])
125362306a36Sopenharmony_ci			thru_bits |= 1 << chn;
125462306a36Sopenharmony_ci	}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
125762306a36Sopenharmony_ci	change = thru_bits ^ rme9652->thru_bits;
125862306a36Sopenharmony_ci	if (change) {
125962306a36Sopenharmony_ci		for (chn = 0; chn < rme9652->ss_channels; ++chn) {
126062306a36Sopenharmony_ci			if (!(change & (1 << chn)))
126162306a36Sopenharmony_ci				continue;
126262306a36Sopenharmony_ci			rme9652_set_thru(rme9652,chn,thru_bits&(1<<chn));
126362306a36Sopenharmony_ci		}
126462306a36Sopenharmony_ci	}
126562306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
126662306a36Sopenharmony_ci	return !!change;
126762306a36Sopenharmony_ci}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci#define RME9652_PASSTHRU(xname, xindex) \
127062306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
127162306a36Sopenharmony_ci  .info = snd_rme9652_info_passthru, \
127262306a36Sopenharmony_ci  .put = snd_rme9652_put_passthru, \
127362306a36Sopenharmony_ci  .get = snd_rme9652_get_passthru }
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci#define snd_rme9652_info_passthru	snd_ctl_boolean_mono_info
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_cistatic int snd_rme9652_get_passthru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
127862306a36Sopenharmony_ci{
127962306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
128262306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = rme9652->passthru;
128362306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
128462306a36Sopenharmony_ci	return 0;
128562306a36Sopenharmony_ci}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_cistatic int snd_rme9652_put_passthru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
128862306a36Sopenharmony_ci{
128962306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
129062306a36Sopenharmony_ci	int change;
129162306a36Sopenharmony_ci	unsigned int val;
129262306a36Sopenharmony_ci	int err = 0;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	if (!snd_rme9652_use_is_exclusive(rme9652))
129562306a36Sopenharmony_ci		return -EBUSY;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
129862306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
129962306a36Sopenharmony_ci	change = (ucontrol->value.integer.value[0] != rme9652->passthru);
130062306a36Sopenharmony_ci	if (change)
130162306a36Sopenharmony_ci		err = rme9652_set_passthru(rme9652, val);
130262306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
130362306a36Sopenharmony_ci	return err ? err : change;
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci/* Read-only switches */
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci#define RME9652_SPDIF_RATE(xname, xindex) \
130962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
131062306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
131162306a36Sopenharmony_ci  .info = snd_rme9652_info_spdif_rate, \
131262306a36Sopenharmony_ci  .get = snd_rme9652_get_spdif_rate }
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_cistatic int snd_rme9652_info_spdif_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
131562306a36Sopenharmony_ci{
131662306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
131762306a36Sopenharmony_ci	uinfo->count = 1;
131862306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
131962306a36Sopenharmony_ci	uinfo->value.integer.max = 96000;
132062306a36Sopenharmony_ci	return 0;
132162306a36Sopenharmony_ci}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_cistatic int snd_rme9652_get_spdif_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
132462306a36Sopenharmony_ci{
132562306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
132862306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = rme9652_spdif_sample_rate(rme9652);
132962306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
133062306a36Sopenharmony_ci	return 0;
133162306a36Sopenharmony_ci}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci#define RME9652_ADAT_SYNC(xname, xindex, xidx) \
133462306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
133562306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
133662306a36Sopenharmony_ci  .info = snd_rme9652_info_adat_sync, \
133762306a36Sopenharmony_ci  .get = snd_rme9652_get_adat_sync, .private_value = xidx }
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_cistatic int snd_rme9652_info_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
134062306a36Sopenharmony_ci{
134162306a36Sopenharmony_ci	static const char * const texts[4] = {
134262306a36Sopenharmony_ci		"No Lock", "Lock", "No Lock Sync", "Lock Sync"
134362306a36Sopenharmony_ci	};
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 4, texts);
134662306a36Sopenharmony_ci}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_cistatic int snd_rme9652_get_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
135162306a36Sopenharmony_ci	unsigned int mask1, mask2, val;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	switch (kcontrol->private_value) {
135462306a36Sopenharmony_ci	case 0: mask1 = RME9652_lock_0; mask2 = RME9652_sync_0; break;
135562306a36Sopenharmony_ci	case 1: mask1 = RME9652_lock_1; mask2 = RME9652_sync_1; break;
135662306a36Sopenharmony_ci	case 2: mask1 = RME9652_lock_2; mask2 = RME9652_sync_2; break;
135762306a36Sopenharmony_ci	default: return -EINVAL;
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci	val = rme9652_read(rme9652, RME9652_status_register);
136062306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = (val & mask1) ? 1 : 0;
136162306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] |= (val & mask2) ? 2 : 0;
136262306a36Sopenharmony_ci	return 0;
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci#define RME9652_TC_VALID(xname, xindex) \
136662306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
136762306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
136862306a36Sopenharmony_ci  .info = snd_rme9652_info_tc_valid, \
136962306a36Sopenharmony_ci  .get = snd_rme9652_get_tc_valid }
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci#define snd_rme9652_info_tc_valid	snd_ctl_boolean_mono_info
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_cistatic int snd_rme9652_get_tc_valid(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
137462306a36Sopenharmony_ci{
137562306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	ucontrol->value.integer.value[0] =
137862306a36Sopenharmony_ci		(rme9652_read(rme9652, RME9652_status_register) & RME9652_tc_valid) ? 1 : 0;
137962306a36Sopenharmony_ci	return 0;
138062306a36Sopenharmony_ci}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci#ifdef ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci/* FIXME: this routine needs a port to the new control API --jk */
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_cistatic int snd_rme9652_get_tc_value(void *private_data,
138762306a36Sopenharmony_ci				    snd_kswitch_t *kswitch,
138862306a36Sopenharmony_ci				    snd_switch_t *uswitch)
138962306a36Sopenharmony_ci{
139062306a36Sopenharmony_ci	struct snd_rme9652 *s = (struct snd_rme9652 *) private_data;
139162306a36Sopenharmony_ci	u32 value;
139262306a36Sopenharmony_ci	int i;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	uswitch->type = SNDRV_SW_TYPE_DWORD;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if ((rme9652_read(s, RME9652_status_register) &
139762306a36Sopenharmony_ci	     RME9652_tc_valid) == 0) {
139862306a36Sopenharmony_ci		uswitch->value.data32[0] = 0;
139962306a36Sopenharmony_ci		return 0;
140062306a36Sopenharmony_ci	}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	/* timecode request */
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	rme9652_write(s, RME9652_time_code, 0);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	/* XXX bug alert: loop-based timing !!!! */
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	for (i = 0; i < 50; i++) {
140962306a36Sopenharmony_ci		if (!(rme9652_read(s, i * 4) & RME9652_tc_busy))
141062306a36Sopenharmony_ci			break;
141162306a36Sopenharmony_ci	}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	if (!(rme9652_read(s, i * 4) & RME9652_tc_busy)) {
141462306a36Sopenharmony_ci		return -EIO;
141562306a36Sopenharmony_ci	}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	value = 0;
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	for (i = 0; i < 32; i++) {
142062306a36Sopenharmony_ci		value >>= 1;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci		if (rme9652_read(s, i * 4) & RME9652_tc_out)
142362306a36Sopenharmony_ci			value |= 0x80000000;
142462306a36Sopenharmony_ci	}
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	if (value > 2 * 60 * 48000) {
142762306a36Sopenharmony_ci		value -= 2 * 60 * 48000;
142862306a36Sopenharmony_ci	} else {
142962306a36Sopenharmony_ci		value = 0;
143062306a36Sopenharmony_ci	}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	uswitch->value.data32[0] = value;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	return 0;
143562306a36Sopenharmony_ci}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci#endif				/* ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE */
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_rme9652_controls[] = {
144062306a36Sopenharmony_ci{
144162306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
144262306a36Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
144362306a36Sopenharmony_ci	.info =		snd_rme9652_control_spdif_info,
144462306a36Sopenharmony_ci	.get =		snd_rme9652_control_spdif_get,
144562306a36Sopenharmony_ci	.put =		snd_rme9652_control_spdif_put,
144662306a36Sopenharmony_ci},
144762306a36Sopenharmony_ci{
144862306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
144962306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
145062306a36Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
145162306a36Sopenharmony_ci	.info =		snd_rme9652_control_spdif_stream_info,
145262306a36Sopenharmony_ci	.get =		snd_rme9652_control_spdif_stream_get,
145362306a36Sopenharmony_ci	.put =		snd_rme9652_control_spdif_stream_put,
145462306a36Sopenharmony_ci},
145562306a36Sopenharmony_ci{
145662306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
145762306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
145862306a36Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
145962306a36Sopenharmony_ci	.info =		snd_rme9652_control_spdif_mask_info,
146062306a36Sopenharmony_ci	.get =		snd_rme9652_control_spdif_mask_get,
146162306a36Sopenharmony_ci	.private_value = IEC958_AES0_NONAUDIO |
146262306a36Sopenharmony_ci			IEC958_AES0_PROFESSIONAL |
146362306a36Sopenharmony_ci			IEC958_AES0_CON_EMPHASIS,
146462306a36Sopenharmony_ci},
146562306a36Sopenharmony_ci{
146662306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
146762306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
146862306a36Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
146962306a36Sopenharmony_ci	.info =		snd_rme9652_control_spdif_mask_info,
147062306a36Sopenharmony_ci	.get =		snd_rme9652_control_spdif_mask_get,
147162306a36Sopenharmony_ci	.private_value = IEC958_AES0_NONAUDIO |
147262306a36Sopenharmony_ci			IEC958_AES0_PROFESSIONAL |
147362306a36Sopenharmony_ci			IEC958_AES0_PRO_EMPHASIS,
147462306a36Sopenharmony_ci},
147562306a36Sopenharmony_ciRME9652_SPDIF_IN("IEC958 Input Connector", 0),
147662306a36Sopenharmony_ciRME9652_SPDIF_OUT("IEC958 Output also on ADAT1", 0),
147762306a36Sopenharmony_ciRME9652_SYNC_MODE("Sync Mode", 0),
147862306a36Sopenharmony_ciRME9652_SYNC_PREF("Preferred Sync Source", 0),
147962306a36Sopenharmony_ci{
148062306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
148162306a36Sopenharmony_ci	.name = "Channels Thru",
148262306a36Sopenharmony_ci	.index = 0,
148362306a36Sopenharmony_ci	.info = snd_rme9652_info_thru,
148462306a36Sopenharmony_ci	.get = snd_rme9652_get_thru,
148562306a36Sopenharmony_ci	.put = snd_rme9652_put_thru,
148662306a36Sopenharmony_ci},
148762306a36Sopenharmony_ciRME9652_SPDIF_RATE("IEC958 Sample Rate", 0),
148862306a36Sopenharmony_ciRME9652_ADAT_SYNC("ADAT1 Sync Check", 0, 0),
148962306a36Sopenharmony_ciRME9652_ADAT_SYNC("ADAT2 Sync Check", 0, 1),
149062306a36Sopenharmony_ciRME9652_TC_VALID("Timecode Valid", 0),
149162306a36Sopenharmony_ciRME9652_PASSTHRU("Passthru", 0)
149262306a36Sopenharmony_ci};
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_rme9652_adat3_check =
149562306a36Sopenharmony_ciRME9652_ADAT_SYNC("ADAT3 Sync Check", 0, 2);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_rme9652_adat1_input =
149862306a36Sopenharmony_ciRME9652_ADAT1_IN("ADAT1 Input Source", 0);
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_cistatic int snd_rme9652_create_controls(struct snd_card *card, struct snd_rme9652 *rme9652)
150162306a36Sopenharmony_ci{
150262306a36Sopenharmony_ci	unsigned int idx;
150362306a36Sopenharmony_ci	int err;
150462306a36Sopenharmony_ci	struct snd_kcontrol *kctl;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	for (idx = 0; idx < ARRAY_SIZE(snd_rme9652_controls); idx++) {
150762306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_rme9652_controls[idx], rme9652);
150862306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
150962306a36Sopenharmony_ci		if (err < 0)
151062306a36Sopenharmony_ci			return err;
151162306a36Sopenharmony_ci		if (idx == 1)	/* IEC958 (S/PDIF) Stream */
151262306a36Sopenharmony_ci			rme9652->spdif_ctl = kctl;
151362306a36Sopenharmony_ci	}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	if (rme9652->ss_channels == RME9652_NCHANNELS) {
151662306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_rme9652_adat3_check, rme9652);
151762306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
151862306a36Sopenharmony_ci		if (err < 0)
151962306a36Sopenharmony_ci			return err;
152062306a36Sopenharmony_ci	}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	if (rme9652->hw_rev >= 15) {
152362306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_rme9652_adat1_input, rme9652);
152462306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
152562306a36Sopenharmony_ci		if (err < 0)
152662306a36Sopenharmony_ci			return err;
152762306a36Sopenharmony_ci	}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	return 0;
153062306a36Sopenharmony_ci}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci/*------------------------------------------------------------
153362306a36Sopenharmony_ci   /proc interface
153462306a36Sopenharmony_ci ------------------------------------------------------------*/
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_cistatic void
153762306a36Sopenharmony_cisnd_rme9652_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
153862306a36Sopenharmony_ci{
153962306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) entry->private_data;
154062306a36Sopenharmony_ci	u32 thru_bits = rme9652->thru_bits;
154162306a36Sopenharmony_ci	int show_auto_sync_source = 0;
154262306a36Sopenharmony_ci	int i;
154362306a36Sopenharmony_ci	unsigned int status;
154462306a36Sopenharmony_ci	int x;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	status = rme9652_read(rme9652, RME9652_status_register);
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	snd_iprintf(buffer, "%s (Card #%d)\n", rme9652->card_name, rme9652->card->number + 1);
154962306a36Sopenharmony_ci	snd_iprintf(buffer, "Buffers: capture %p playback %p\n",
155062306a36Sopenharmony_ci		    rme9652->capture_buffer, rme9652->playback_buffer);
155162306a36Sopenharmony_ci	snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
155262306a36Sopenharmony_ci		    rme9652->irq, rme9652->port, (unsigned long)rme9652->iobase);
155362306a36Sopenharmony_ci	snd_iprintf(buffer, "Control register: %x\n", rme9652->control_register);
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	snd_iprintf(buffer, "\n");
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	x = 1 << (6 + rme9652_decode_latency(rme9652->control_register &
155862306a36Sopenharmony_ci					     RME9652_latency));
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	snd_iprintf(buffer, "Latency: %d samples (2 periods of %lu bytes)\n",
156162306a36Sopenharmony_ci		    x, (unsigned long) rme9652->period_bytes);
156262306a36Sopenharmony_ci	snd_iprintf(buffer, "Hardware pointer (frames): %ld\n",
156362306a36Sopenharmony_ci		    rme9652_hw_pointer(rme9652));
156462306a36Sopenharmony_ci	snd_iprintf(buffer, "Passthru: %s\n",
156562306a36Sopenharmony_ci		    rme9652->passthru ? "yes" : "no");
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	if ((rme9652->control_register & (RME9652_Master | RME9652_wsel)) == 0) {
156862306a36Sopenharmony_ci		snd_iprintf(buffer, "Clock mode: autosync\n");
156962306a36Sopenharmony_ci		show_auto_sync_source = 1;
157062306a36Sopenharmony_ci	} else if (rme9652->control_register & RME9652_wsel) {
157162306a36Sopenharmony_ci		if (status & RME9652_wsel_rd) {
157262306a36Sopenharmony_ci			snd_iprintf(buffer, "Clock mode: word clock\n");
157362306a36Sopenharmony_ci		} else {
157462306a36Sopenharmony_ci			snd_iprintf(buffer, "Clock mode: word clock (no signal)\n");
157562306a36Sopenharmony_ci		}
157662306a36Sopenharmony_ci	} else {
157762306a36Sopenharmony_ci		snd_iprintf(buffer, "Clock mode: master\n");
157862306a36Sopenharmony_ci	}
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	if (show_auto_sync_source) {
158162306a36Sopenharmony_ci		switch (rme9652->control_register & RME9652_SyncPref_Mask) {
158262306a36Sopenharmony_ci		case RME9652_SyncPref_ADAT1:
158362306a36Sopenharmony_ci			snd_iprintf(buffer, "Pref. sync source: ADAT1\n");
158462306a36Sopenharmony_ci			break;
158562306a36Sopenharmony_ci		case RME9652_SyncPref_ADAT2:
158662306a36Sopenharmony_ci			snd_iprintf(buffer, "Pref. sync source: ADAT2\n");
158762306a36Sopenharmony_ci			break;
158862306a36Sopenharmony_ci		case RME9652_SyncPref_ADAT3:
158962306a36Sopenharmony_ci			snd_iprintf(buffer, "Pref. sync source: ADAT3\n");
159062306a36Sopenharmony_ci			break;
159162306a36Sopenharmony_ci		case RME9652_SyncPref_SPDIF:
159262306a36Sopenharmony_ci			snd_iprintf(buffer, "Pref. sync source: IEC958\n");
159362306a36Sopenharmony_ci			break;
159462306a36Sopenharmony_ci		default:
159562306a36Sopenharmony_ci			snd_iprintf(buffer, "Pref. sync source: ???\n");
159662306a36Sopenharmony_ci		}
159762306a36Sopenharmony_ci	}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	if (rme9652->hw_rev >= 15)
160062306a36Sopenharmony_ci		snd_iprintf(buffer, "\nADAT1 Input source: %s\n",
160162306a36Sopenharmony_ci			    (rme9652->control_register & RME9652_ADAT1_INTERNAL) ?
160262306a36Sopenharmony_ci			    "Internal" : "ADAT1 optical");
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	snd_iprintf(buffer, "\n");
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	switch (rme9652_decode_spdif_in(rme9652->control_register &
160762306a36Sopenharmony_ci					RME9652_inp)) {
160862306a36Sopenharmony_ci	case RME9652_SPDIFIN_OPTICAL:
160962306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 input: ADAT1\n");
161062306a36Sopenharmony_ci		break;
161162306a36Sopenharmony_ci	case RME9652_SPDIFIN_COAXIAL:
161262306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 input: Coaxial\n");
161362306a36Sopenharmony_ci		break;
161462306a36Sopenharmony_ci	case RME9652_SPDIFIN_INTERN:
161562306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 input: Internal\n");
161662306a36Sopenharmony_ci		break;
161762306a36Sopenharmony_ci	default:
161862306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 input: ???\n");
161962306a36Sopenharmony_ci		break;
162062306a36Sopenharmony_ci	}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	if (rme9652->control_register & RME9652_opt_out) {
162362306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
162462306a36Sopenharmony_ci	} else {
162562306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 output: Coaxial only\n");
162662306a36Sopenharmony_ci	}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	if (rme9652->control_register & RME9652_PRO) {
162962306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 quality: Professional\n");
163062306a36Sopenharmony_ci	} else {
163162306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 quality: Consumer\n");
163262306a36Sopenharmony_ci	}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	if (rme9652->control_register & RME9652_EMP) {
163562306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 emphasis: on\n");
163662306a36Sopenharmony_ci	} else {
163762306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 emphasis: off\n");
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	if (rme9652->control_register & RME9652_Dolby) {
164162306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 Dolby: on\n");
164262306a36Sopenharmony_ci	} else {
164362306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 Dolby: off\n");
164462306a36Sopenharmony_ci	}
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	i = rme9652_spdif_sample_rate(rme9652);
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	if (i < 0) {
164962306a36Sopenharmony_ci		snd_iprintf(buffer,
165062306a36Sopenharmony_ci			    "IEC958 sample rate: error flag set\n");
165162306a36Sopenharmony_ci	} else if (i == 0) {
165262306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 sample rate: undetermined\n");
165362306a36Sopenharmony_ci	} else {
165462306a36Sopenharmony_ci		snd_iprintf(buffer, "IEC958 sample rate: %d\n", i);
165562306a36Sopenharmony_ci	}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	snd_iprintf(buffer, "\n");
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	snd_iprintf(buffer, "ADAT Sample rate: %dHz\n",
166062306a36Sopenharmony_ci		    rme9652_adat_sample_rate(rme9652));
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	/* Sync Check */
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	x = status & RME9652_sync_0;
166562306a36Sopenharmony_ci	if (status & RME9652_lock_0) {
166662306a36Sopenharmony_ci		snd_iprintf(buffer, "ADAT1: %s\n", x ? "Sync" : "Lock");
166762306a36Sopenharmony_ci	} else {
166862306a36Sopenharmony_ci		snd_iprintf(buffer, "ADAT1: No Lock\n");
166962306a36Sopenharmony_ci	}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	x = status & RME9652_sync_1;
167262306a36Sopenharmony_ci	if (status & RME9652_lock_1) {
167362306a36Sopenharmony_ci		snd_iprintf(buffer, "ADAT2: %s\n", x ? "Sync" : "Lock");
167462306a36Sopenharmony_ci	} else {
167562306a36Sopenharmony_ci		snd_iprintf(buffer, "ADAT2: No Lock\n");
167662306a36Sopenharmony_ci	}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	x = status & RME9652_sync_2;
167962306a36Sopenharmony_ci	if (status & RME9652_lock_2) {
168062306a36Sopenharmony_ci		snd_iprintf(buffer, "ADAT3: %s\n", x ? "Sync" : "Lock");
168162306a36Sopenharmony_ci	} else {
168262306a36Sopenharmony_ci		snd_iprintf(buffer, "ADAT3: No Lock\n");
168362306a36Sopenharmony_ci	}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	snd_iprintf(buffer, "\n");
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	snd_iprintf(buffer, "Timecode signal: %s\n",
168862306a36Sopenharmony_ci		    (status & RME9652_tc_valid) ? "yes" : "no");
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	/* thru modes */
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	snd_iprintf(buffer, "Punch Status:\n\n");
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	for (i = 0; i < rme9652->ss_channels; i++) {
169562306a36Sopenharmony_ci		if (thru_bits & (1 << i)) {
169662306a36Sopenharmony_ci			snd_iprintf(buffer, "%2d:  on ", i + 1);
169762306a36Sopenharmony_ci		} else {
169862306a36Sopenharmony_ci			snd_iprintf(buffer, "%2d: off ", i + 1);
169962306a36Sopenharmony_ci		}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci		if (((i + 1) % 8) == 0) {
170262306a36Sopenharmony_ci			snd_iprintf(buffer, "\n");
170362306a36Sopenharmony_ci		}
170462306a36Sopenharmony_ci	}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	snd_iprintf(buffer, "\n");
170762306a36Sopenharmony_ci}
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_cistatic void snd_rme9652_proc_init(struct snd_rme9652 *rme9652)
171062306a36Sopenharmony_ci{
171162306a36Sopenharmony_ci	snd_card_ro_proc_new(rme9652->card, "rme9652", rme9652,
171262306a36Sopenharmony_ci			     snd_rme9652_proc_read);
171362306a36Sopenharmony_ci}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_cistatic void snd_rme9652_card_free(struct snd_card *card)
171662306a36Sopenharmony_ci{
171762306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) card->private_data;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	if (rme9652->irq >= 0)
172062306a36Sopenharmony_ci		rme9652_stop(rme9652);
172162306a36Sopenharmony_ci}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_cistatic int snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652)
172462306a36Sopenharmony_ci{
172562306a36Sopenharmony_ci	struct snd_dma_buffer *capture_dma, *playback_dma;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	capture_dma = snd_hammerfall_get_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES);
172862306a36Sopenharmony_ci	playback_dma = snd_hammerfall_get_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES);
172962306a36Sopenharmony_ci	if (!capture_dma || !playback_dma) {
173062306a36Sopenharmony_ci		dev_err(rme9652->card->dev,
173162306a36Sopenharmony_ci			"%s: no buffers available\n", rme9652->card_name);
173262306a36Sopenharmony_ci		return -ENOMEM;
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	/* copy to the own data for alignment */
173662306a36Sopenharmony_ci	rme9652->capture_dma_buf = *capture_dma;
173762306a36Sopenharmony_ci	rme9652->playback_dma_buf = *playback_dma;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	/* Align to bus-space 64K boundary */
174062306a36Sopenharmony_ci	rme9652->capture_dma_buf.addr = ALIGN(capture_dma->addr, 0x10000ul);
174162306a36Sopenharmony_ci	rme9652->playback_dma_buf.addr = ALIGN(playback_dma->addr, 0x10000ul);
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	/* Tell the card where it is */
174462306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_rec_buffer, rme9652->capture_dma_buf.addr);
174562306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_play_buffer, rme9652->playback_dma_buf.addr);
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	rme9652->capture_dma_buf.area += rme9652->capture_dma_buf.addr - capture_dma->addr;
174862306a36Sopenharmony_ci	rme9652->playback_dma_buf.area += rme9652->playback_dma_buf.addr - playback_dma->addr;
174962306a36Sopenharmony_ci	rme9652->capture_buffer = rme9652->capture_dma_buf.area;
175062306a36Sopenharmony_ci	rme9652->playback_buffer = rme9652->playback_dma_buf.area;
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	return 0;
175362306a36Sopenharmony_ci}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_cistatic void snd_rme9652_set_defaults(struct snd_rme9652 *rme9652)
175662306a36Sopenharmony_ci{
175762306a36Sopenharmony_ci	unsigned int k;
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	/* ASSUMPTION: rme9652->lock is either held, or
176062306a36Sopenharmony_ci	   there is no need to hold it (e.g. during module
176162306a36Sopenharmony_ci	   initialization).
176262306a36Sopenharmony_ci	 */
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	/* set defaults:
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	   SPDIF Input via Coax
176762306a36Sopenharmony_ci	   autosync clock mode
176862306a36Sopenharmony_ci	   maximum latency (7 = 8192 samples, 64Kbyte buffer,
176962306a36Sopenharmony_ci	   which implies 2 4096 sample, 32Kbyte periods).
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	   if rev 1.5, initialize the S/PDIF receiver.
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	 */
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	rme9652->control_register =
177662306a36Sopenharmony_ci	    RME9652_inp_0 | rme9652_encode_latency(7);
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	rme9652_reset_hw_pointer(rme9652);
178162306a36Sopenharmony_ci	rme9652_compute_period_size(rme9652);
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	/* default: thru off for all channels */
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	for (k = 0; k < RME9652_NCHANNELS; ++k)
178662306a36Sopenharmony_ci		rme9652_write(rme9652, RME9652_thru_base + k * 4, 0);
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	rme9652->thru_bits = 0;
178962306a36Sopenharmony_ci	rme9652->passthru = 0;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	/* set a default rate so that the channel map is set up */
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	rme9652_set_rate(rme9652, 48000);
179462306a36Sopenharmony_ci}
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_cistatic irqreturn_t snd_rme9652_interrupt(int irq, void *dev_id)
179762306a36Sopenharmony_ci{
179862306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) dev_id;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	if (!(rme9652_read(rme9652, RME9652_status_register) & RME9652_IRQ)) {
180162306a36Sopenharmony_ci		return IRQ_NONE;
180262306a36Sopenharmony_ci	}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	rme9652_write(rme9652, RME9652_irq_clear, 0);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	if (rme9652->capture_substream) {
180762306a36Sopenharmony_ci		snd_pcm_period_elapsed(rme9652->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
180862306a36Sopenharmony_ci	}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	if (rme9652->playback_substream) {
181162306a36Sopenharmony_ci		snd_pcm_period_elapsed(rme9652->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
181262306a36Sopenharmony_ci	}
181362306a36Sopenharmony_ci	return IRQ_HANDLED;
181462306a36Sopenharmony_ci}
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_rme9652_hw_pointer(struct snd_pcm_substream *substream)
181762306a36Sopenharmony_ci{
181862306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
181962306a36Sopenharmony_ci	return rme9652_hw_pointer(rme9652);
182062306a36Sopenharmony_ci}
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_cistatic signed char *rme9652_channel_buffer_location(struct snd_rme9652 *rme9652,
182362306a36Sopenharmony_ci					     int stream,
182462306a36Sopenharmony_ci					     int channel)
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci{
182762306a36Sopenharmony_ci	int mapped_channel;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	if (snd_BUG_ON(channel < 0 || channel >= RME9652_NCHANNELS))
183062306a36Sopenharmony_ci		return NULL;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	mapped_channel = rme9652->channel_map[channel];
183362306a36Sopenharmony_ci	if (mapped_channel < 0)
183462306a36Sopenharmony_ci		return NULL;
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_CAPTURE) {
183762306a36Sopenharmony_ci		return rme9652->capture_buffer +
183862306a36Sopenharmony_ci			(mapped_channel * RME9652_CHANNEL_BUFFER_BYTES);
183962306a36Sopenharmony_ci	} else {
184062306a36Sopenharmony_ci		return rme9652->playback_buffer +
184162306a36Sopenharmony_ci			(mapped_channel * RME9652_CHANNEL_BUFFER_BYTES);
184262306a36Sopenharmony_ci	}
184362306a36Sopenharmony_ci}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_cistatic int snd_rme9652_playback_copy(struct snd_pcm_substream *substream,
184662306a36Sopenharmony_ci				     int channel, unsigned long pos,
184762306a36Sopenharmony_ci				     struct iov_iter *src, unsigned long count)
184862306a36Sopenharmony_ci{
184962306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
185062306a36Sopenharmony_ci	signed char *channel_buf;
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES))
185362306a36Sopenharmony_ci		return -EINVAL;
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	channel_buf = rme9652_channel_buffer_location (rme9652,
185662306a36Sopenharmony_ci						       substream->pstr->stream,
185762306a36Sopenharmony_ci						       channel);
185862306a36Sopenharmony_ci	if (snd_BUG_ON(!channel_buf))
185962306a36Sopenharmony_ci		return -EIO;
186062306a36Sopenharmony_ci	if (copy_from_iter(channel_buf + pos, count, src) != count)
186162306a36Sopenharmony_ci		return -EFAULT;
186262306a36Sopenharmony_ci	return 0;
186362306a36Sopenharmony_ci}
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_cistatic int snd_rme9652_capture_copy(struct snd_pcm_substream *substream,
186662306a36Sopenharmony_ci				    int channel, unsigned long pos,
186762306a36Sopenharmony_ci				    struct iov_iter *dst, unsigned long count)
186862306a36Sopenharmony_ci{
186962306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
187062306a36Sopenharmony_ci	signed char *channel_buf;
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES))
187362306a36Sopenharmony_ci		return -EINVAL;
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	channel_buf = rme9652_channel_buffer_location (rme9652,
187662306a36Sopenharmony_ci						       substream->pstr->stream,
187762306a36Sopenharmony_ci						       channel);
187862306a36Sopenharmony_ci	if (snd_BUG_ON(!channel_buf))
187962306a36Sopenharmony_ci		return -EIO;
188062306a36Sopenharmony_ci	if (copy_to_iter(channel_buf + pos, count, dst) != count)
188162306a36Sopenharmony_ci		return -EFAULT;
188262306a36Sopenharmony_ci	return 0;
188362306a36Sopenharmony_ci}
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_cistatic int snd_rme9652_hw_silence(struct snd_pcm_substream *substream,
188662306a36Sopenharmony_ci				  int channel, unsigned long pos,
188762306a36Sopenharmony_ci				  unsigned long count)
188862306a36Sopenharmony_ci{
188962306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
189062306a36Sopenharmony_ci	signed char *channel_buf;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	channel_buf = rme9652_channel_buffer_location (rme9652,
189362306a36Sopenharmony_ci						       substream->pstr->stream,
189462306a36Sopenharmony_ci						       channel);
189562306a36Sopenharmony_ci	if (snd_BUG_ON(!channel_buf))
189662306a36Sopenharmony_ci		return -EIO;
189762306a36Sopenharmony_ci	memset(channel_buf + pos, 0, count);
189862306a36Sopenharmony_ci	return 0;
189962306a36Sopenharmony_ci}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_cistatic int snd_rme9652_reset(struct snd_pcm_substream *substream)
190262306a36Sopenharmony_ci{
190362306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
190462306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
190562306a36Sopenharmony_ci	struct snd_pcm_substream *other;
190662306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
190762306a36Sopenharmony_ci		other = rme9652->capture_substream;
190862306a36Sopenharmony_ci	else
190962306a36Sopenharmony_ci		other = rme9652->playback_substream;
191062306a36Sopenharmony_ci	if (rme9652->running)
191162306a36Sopenharmony_ci		runtime->status->hw_ptr = rme9652_hw_pointer(rme9652);
191262306a36Sopenharmony_ci	else
191362306a36Sopenharmony_ci		runtime->status->hw_ptr = 0;
191462306a36Sopenharmony_ci	if (other) {
191562306a36Sopenharmony_ci		struct snd_pcm_substream *s;
191662306a36Sopenharmony_ci		struct snd_pcm_runtime *oruntime = other->runtime;
191762306a36Sopenharmony_ci		snd_pcm_group_for_each_entry(s, substream) {
191862306a36Sopenharmony_ci			if (s == other) {
191962306a36Sopenharmony_ci				oruntime->status->hw_ptr = runtime->status->hw_ptr;
192062306a36Sopenharmony_ci				break;
192162306a36Sopenharmony_ci			}
192262306a36Sopenharmony_ci		}
192362306a36Sopenharmony_ci	}
192462306a36Sopenharmony_ci	return 0;
192562306a36Sopenharmony_ci}
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_cistatic int snd_rme9652_hw_params(struct snd_pcm_substream *substream,
192862306a36Sopenharmony_ci				 struct snd_pcm_hw_params *params)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
193162306a36Sopenharmony_ci	int err;
193262306a36Sopenharmony_ci	pid_t this_pid;
193362306a36Sopenharmony_ci	pid_t other_pid;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
193862306a36Sopenharmony_ci		rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP);
193962306a36Sopenharmony_ci		rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= rme9652->creg_spdif_stream);
194062306a36Sopenharmony_ci		this_pid = rme9652->playback_pid;
194162306a36Sopenharmony_ci		other_pid = rme9652->capture_pid;
194262306a36Sopenharmony_ci	} else {
194362306a36Sopenharmony_ci		this_pid = rme9652->capture_pid;
194462306a36Sopenharmony_ci		other_pid = rme9652->playback_pid;
194562306a36Sopenharmony_ci	}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	if ((other_pid > 0) && (this_pid != other_pid)) {
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci		/* The other stream is open, and not by the same
195062306a36Sopenharmony_ci		   task as this one. Make sure that the parameters
195162306a36Sopenharmony_ci		   that matter are the same.
195262306a36Sopenharmony_ci		 */
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci		if ((int)params_rate(params) !=
195562306a36Sopenharmony_ci		    rme9652_adat_sample_rate(rme9652)) {
195662306a36Sopenharmony_ci			spin_unlock_irq(&rme9652->lock);
195762306a36Sopenharmony_ci			_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
195862306a36Sopenharmony_ci			return -EBUSY;
195962306a36Sopenharmony_ci		}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci		if (params_period_size(params) != rme9652->period_bytes / 4) {
196262306a36Sopenharmony_ci			spin_unlock_irq(&rme9652->lock);
196362306a36Sopenharmony_ci			_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
196462306a36Sopenharmony_ci			return -EBUSY;
196562306a36Sopenharmony_ci		}
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci		/* We're fine. */
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci		spin_unlock_irq(&rme9652->lock);
197062306a36Sopenharmony_ci 		return 0;
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	} else {
197362306a36Sopenharmony_ci		spin_unlock_irq(&rme9652->lock);
197462306a36Sopenharmony_ci	}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	/* how to make sure that the rate matches an externally-set one ?
197762306a36Sopenharmony_ci	 */
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	err = rme9652_set_rate(rme9652, params_rate(params));
198062306a36Sopenharmony_ci	if (err < 0) {
198162306a36Sopenharmony_ci		_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
198262306a36Sopenharmony_ci		return err;
198362306a36Sopenharmony_ci	}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	err = rme9652_set_interrupt_interval(rme9652, params_period_size(params));
198662306a36Sopenharmony_ci	if (err < 0) {
198762306a36Sopenharmony_ci		_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
198862306a36Sopenharmony_ci		return err;
198962306a36Sopenharmony_ci	}
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	return 0;
199262306a36Sopenharmony_ci}
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_cistatic int snd_rme9652_channel_info(struct snd_pcm_substream *substream,
199562306a36Sopenharmony_ci				    struct snd_pcm_channel_info *info)
199662306a36Sopenharmony_ci{
199762306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
199862306a36Sopenharmony_ci	int chn;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	if (snd_BUG_ON(info->channel >= RME9652_NCHANNELS))
200162306a36Sopenharmony_ci		return -EINVAL;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	chn = rme9652->channel_map[array_index_nospec(info->channel,
200462306a36Sopenharmony_ci						      RME9652_NCHANNELS)];
200562306a36Sopenharmony_ci	if (chn < 0)
200662306a36Sopenharmony_ci		return -EINVAL;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	info->offset = chn * RME9652_CHANNEL_BUFFER_BYTES;
200962306a36Sopenharmony_ci	info->first = 0;
201062306a36Sopenharmony_ci	info->step = 32;
201162306a36Sopenharmony_ci	return 0;
201262306a36Sopenharmony_ci}
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_cistatic int snd_rme9652_ioctl(struct snd_pcm_substream *substream,
201562306a36Sopenharmony_ci			     unsigned int cmd, void *arg)
201662306a36Sopenharmony_ci{
201762306a36Sopenharmony_ci	switch (cmd) {
201862306a36Sopenharmony_ci	case SNDRV_PCM_IOCTL1_RESET:
201962306a36Sopenharmony_ci	{
202062306a36Sopenharmony_ci		return snd_rme9652_reset(substream);
202162306a36Sopenharmony_ci	}
202262306a36Sopenharmony_ci	case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
202362306a36Sopenharmony_ci	{
202462306a36Sopenharmony_ci		struct snd_pcm_channel_info *info = arg;
202562306a36Sopenharmony_ci		return snd_rme9652_channel_info(substream, info);
202662306a36Sopenharmony_ci	}
202762306a36Sopenharmony_ci	default:
202862306a36Sopenharmony_ci		break;
202962306a36Sopenharmony_ci	}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	return snd_pcm_lib_ioctl(substream, cmd, arg);
203262306a36Sopenharmony_ci}
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_cistatic void rme9652_silence_playback(struct snd_rme9652 *rme9652)
203562306a36Sopenharmony_ci{
203662306a36Sopenharmony_ci	memset(rme9652->playback_buffer, 0, RME9652_DMA_AREA_BYTES);
203762306a36Sopenharmony_ci}
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_cistatic int snd_rme9652_trigger(struct snd_pcm_substream *substream,
204062306a36Sopenharmony_ci			       int cmd)
204162306a36Sopenharmony_ci{
204262306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
204362306a36Sopenharmony_ci	struct snd_pcm_substream *other;
204462306a36Sopenharmony_ci	int running;
204562306a36Sopenharmony_ci	spin_lock(&rme9652->lock);
204662306a36Sopenharmony_ci	running = rme9652->running;
204762306a36Sopenharmony_ci	switch (cmd) {
204862306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
204962306a36Sopenharmony_ci		running |= 1 << substream->stream;
205062306a36Sopenharmony_ci		break;
205162306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
205262306a36Sopenharmony_ci		running &= ~(1 << substream->stream);
205362306a36Sopenharmony_ci		break;
205462306a36Sopenharmony_ci	default:
205562306a36Sopenharmony_ci		snd_BUG();
205662306a36Sopenharmony_ci		spin_unlock(&rme9652->lock);
205762306a36Sopenharmony_ci		return -EINVAL;
205862306a36Sopenharmony_ci	}
205962306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
206062306a36Sopenharmony_ci		other = rme9652->capture_substream;
206162306a36Sopenharmony_ci	else
206262306a36Sopenharmony_ci		other = rme9652->playback_substream;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	if (other) {
206562306a36Sopenharmony_ci		struct snd_pcm_substream *s;
206662306a36Sopenharmony_ci		snd_pcm_group_for_each_entry(s, substream) {
206762306a36Sopenharmony_ci			if (s == other) {
206862306a36Sopenharmony_ci				snd_pcm_trigger_done(s, substream);
206962306a36Sopenharmony_ci				if (cmd == SNDRV_PCM_TRIGGER_START)
207062306a36Sopenharmony_ci					running |= 1 << s->stream;
207162306a36Sopenharmony_ci				else
207262306a36Sopenharmony_ci					running &= ~(1 << s->stream);
207362306a36Sopenharmony_ci				goto _ok;
207462306a36Sopenharmony_ci			}
207562306a36Sopenharmony_ci		}
207662306a36Sopenharmony_ci		if (cmd == SNDRV_PCM_TRIGGER_START) {
207762306a36Sopenharmony_ci			if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) &&
207862306a36Sopenharmony_ci			    substream->stream == SNDRV_PCM_STREAM_CAPTURE)
207962306a36Sopenharmony_ci				rme9652_silence_playback(rme9652);
208062306a36Sopenharmony_ci		} else {
208162306a36Sopenharmony_ci			if (running &&
208262306a36Sopenharmony_ci			    substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
208362306a36Sopenharmony_ci				rme9652_silence_playback(rme9652);
208462306a36Sopenharmony_ci		}
208562306a36Sopenharmony_ci	} else {
208662306a36Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
208762306a36Sopenharmony_ci			rme9652_silence_playback(rme9652);
208862306a36Sopenharmony_ci	}
208962306a36Sopenharmony_ci _ok:
209062306a36Sopenharmony_ci	snd_pcm_trigger_done(substream, substream);
209162306a36Sopenharmony_ci	if (!rme9652->running && running)
209262306a36Sopenharmony_ci		rme9652_start(rme9652);
209362306a36Sopenharmony_ci	else if (rme9652->running && !running)
209462306a36Sopenharmony_ci		rme9652_stop(rme9652);
209562306a36Sopenharmony_ci	rme9652->running = running;
209662306a36Sopenharmony_ci	spin_unlock(&rme9652->lock);
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	return 0;
209962306a36Sopenharmony_ci}
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_cistatic int snd_rme9652_prepare(struct snd_pcm_substream *substream)
210262306a36Sopenharmony_ci{
210362306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
210462306a36Sopenharmony_ci	unsigned long flags;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	spin_lock_irqsave(&rme9652->lock, flags);
210762306a36Sopenharmony_ci	if (!rme9652->running)
210862306a36Sopenharmony_ci		rme9652_reset_hw_pointer(rme9652);
210962306a36Sopenharmony_ci	spin_unlock_irqrestore(&rme9652->lock, flags);
211062306a36Sopenharmony_ci	return 0;
211162306a36Sopenharmony_ci}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_rme9652_playback_subinfo =
211462306a36Sopenharmony_ci{
211562306a36Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
211662306a36Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
211762306a36Sopenharmony_ci				 SNDRV_PCM_INFO_NONINTERLEAVED |
211862306a36Sopenharmony_ci				 SNDRV_PCM_INFO_SYNC_START |
211962306a36Sopenharmony_ci				 SNDRV_PCM_INFO_DOUBLE),
212062306a36Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
212162306a36Sopenharmony_ci	.rates =		(SNDRV_PCM_RATE_44100 |
212262306a36Sopenharmony_ci				 SNDRV_PCM_RATE_48000 |
212362306a36Sopenharmony_ci				 SNDRV_PCM_RATE_88200 |
212462306a36Sopenharmony_ci				 SNDRV_PCM_RATE_96000),
212562306a36Sopenharmony_ci	.rate_min =		44100,
212662306a36Sopenharmony_ci	.rate_max =		96000,
212762306a36Sopenharmony_ci	.channels_min =		10,
212862306a36Sopenharmony_ci	.channels_max =		26,
212962306a36Sopenharmony_ci	.buffer_bytes_max =	RME9652_CHANNEL_BUFFER_BYTES * 26,
213062306a36Sopenharmony_ci	.period_bytes_min =	(64 * 4) * 10,
213162306a36Sopenharmony_ci	.period_bytes_max =	(8192 * 4) * 26,
213262306a36Sopenharmony_ci	.periods_min =		2,
213362306a36Sopenharmony_ci	.periods_max =		2,
213462306a36Sopenharmony_ci	.fifo_size =		0,
213562306a36Sopenharmony_ci};
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_rme9652_capture_subinfo =
213862306a36Sopenharmony_ci{
213962306a36Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
214062306a36Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
214162306a36Sopenharmony_ci				 SNDRV_PCM_INFO_NONINTERLEAVED |
214262306a36Sopenharmony_ci				 SNDRV_PCM_INFO_SYNC_START),
214362306a36Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
214462306a36Sopenharmony_ci	.rates =		(SNDRV_PCM_RATE_44100 |
214562306a36Sopenharmony_ci				 SNDRV_PCM_RATE_48000 |
214662306a36Sopenharmony_ci				 SNDRV_PCM_RATE_88200 |
214762306a36Sopenharmony_ci				 SNDRV_PCM_RATE_96000),
214862306a36Sopenharmony_ci	.rate_min =		44100,
214962306a36Sopenharmony_ci	.rate_max =		96000,
215062306a36Sopenharmony_ci	.channels_min =		10,
215162306a36Sopenharmony_ci	.channels_max =		26,
215262306a36Sopenharmony_ci	.buffer_bytes_max =	RME9652_CHANNEL_BUFFER_BYTES *26,
215362306a36Sopenharmony_ci	.period_bytes_min =	(64 * 4) * 10,
215462306a36Sopenharmony_ci	.period_bytes_max =	(8192 * 4) * 26,
215562306a36Sopenharmony_ci	.periods_min =		2,
215662306a36Sopenharmony_ci	.periods_max =		2,
215762306a36Sopenharmony_ci	.fifo_size =		0,
215862306a36Sopenharmony_ci};
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_cistatic const unsigned int period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hw_constraints_period_sizes = {
216362306a36Sopenharmony_ci	.count = ARRAY_SIZE(period_sizes),
216462306a36Sopenharmony_ci	.list = period_sizes,
216562306a36Sopenharmony_ci	.mask = 0
216662306a36Sopenharmony_ci};
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_cistatic int snd_rme9652_hw_rule_channels(struct snd_pcm_hw_params *params,
216962306a36Sopenharmony_ci					struct snd_pcm_hw_rule *rule)
217062306a36Sopenharmony_ci{
217162306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = rule->private;
217262306a36Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
217362306a36Sopenharmony_ci	unsigned int list[2] = { rme9652->ds_channels, rme9652->ss_channels };
217462306a36Sopenharmony_ci	return snd_interval_list(c, 2, list, 0);
217562306a36Sopenharmony_ci}
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_cistatic int snd_rme9652_hw_rule_channels_rate(struct snd_pcm_hw_params *params,
217862306a36Sopenharmony_ci					     struct snd_pcm_hw_rule *rule)
217962306a36Sopenharmony_ci{
218062306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = rule->private;
218162306a36Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
218262306a36Sopenharmony_ci	struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
218362306a36Sopenharmony_ci	if (r->min > 48000) {
218462306a36Sopenharmony_ci		struct snd_interval t = {
218562306a36Sopenharmony_ci			.min = rme9652->ds_channels,
218662306a36Sopenharmony_ci			.max = rme9652->ds_channels,
218762306a36Sopenharmony_ci			.integer = 1,
218862306a36Sopenharmony_ci		};
218962306a36Sopenharmony_ci		return snd_interval_refine(c, &t);
219062306a36Sopenharmony_ci	} else if (r->max < 88200) {
219162306a36Sopenharmony_ci		struct snd_interval t = {
219262306a36Sopenharmony_ci			.min = rme9652->ss_channels,
219362306a36Sopenharmony_ci			.max = rme9652->ss_channels,
219462306a36Sopenharmony_ci			.integer = 1,
219562306a36Sopenharmony_ci		};
219662306a36Sopenharmony_ci		return snd_interval_refine(c, &t);
219762306a36Sopenharmony_ci	}
219862306a36Sopenharmony_ci	return 0;
219962306a36Sopenharmony_ci}
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_cistatic int snd_rme9652_hw_rule_rate_channels(struct snd_pcm_hw_params *params,
220262306a36Sopenharmony_ci					     struct snd_pcm_hw_rule *rule)
220362306a36Sopenharmony_ci{
220462306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = rule->private;
220562306a36Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
220662306a36Sopenharmony_ci	struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
220762306a36Sopenharmony_ci	if (c->min >= rme9652->ss_channels) {
220862306a36Sopenharmony_ci		struct snd_interval t = {
220962306a36Sopenharmony_ci			.min = 44100,
221062306a36Sopenharmony_ci			.max = 48000,
221162306a36Sopenharmony_ci			.integer = 1,
221262306a36Sopenharmony_ci		};
221362306a36Sopenharmony_ci		return snd_interval_refine(r, &t);
221462306a36Sopenharmony_ci	} else if (c->max <= rme9652->ds_channels) {
221562306a36Sopenharmony_ci		struct snd_interval t = {
221662306a36Sopenharmony_ci			.min = 88200,
221762306a36Sopenharmony_ci			.max = 96000,
221862306a36Sopenharmony_ci			.integer = 1,
221962306a36Sopenharmony_ci		};
222062306a36Sopenharmony_ci		return snd_interval_refine(r, &t);
222162306a36Sopenharmony_ci	}
222262306a36Sopenharmony_ci	return 0;
222362306a36Sopenharmony_ci}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_cistatic int snd_rme9652_playback_open(struct snd_pcm_substream *substream)
222662306a36Sopenharmony_ci{
222762306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
222862306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	snd_pcm_set_sync(substream);
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci        runtime->hw = snd_rme9652_playback_subinfo;
223562306a36Sopenharmony_ci	snd_pcm_set_runtime_buffer(substream, &rme9652->playback_dma_buf);
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	if (rme9652->capture_substream == NULL) {
223862306a36Sopenharmony_ci		rme9652_stop(rme9652);
223962306a36Sopenharmony_ci		rme9652_set_thru(rme9652, -1, 0);
224062306a36Sopenharmony_ci	}
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	rme9652->playback_pid = current->pid;
224362306a36Sopenharmony_ci	rme9652->playback_substream = substream;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
224862306a36Sopenharmony_ci	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes);
224962306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
225062306a36Sopenharmony_ci			     snd_rme9652_hw_rule_channels, rme9652,
225162306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
225262306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
225362306a36Sopenharmony_ci			     snd_rme9652_hw_rule_channels_rate, rme9652,
225462306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_RATE, -1);
225562306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
225662306a36Sopenharmony_ci			     snd_rme9652_hw_rule_rate_channels, rme9652,
225762306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	rme9652->creg_spdif_stream = rme9652->creg_spdif;
226062306a36Sopenharmony_ci	rme9652->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
226162306a36Sopenharmony_ci	snd_ctl_notify(rme9652->card, SNDRV_CTL_EVENT_MASK_VALUE |
226262306a36Sopenharmony_ci		       SNDRV_CTL_EVENT_MASK_INFO, &rme9652->spdif_ctl->id);
226362306a36Sopenharmony_ci	return 0;
226462306a36Sopenharmony_ci}
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_cistatic int snd_rme9652_playback_release(struct snd_pcm_substream *substream)
226762306a36Sopenharmony_ci{
226862306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	rme9652->playback_pid = -1;
227362306a36Sopenharmony_ci	rme9652->playback_substream = NULL;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	rme9652->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
227862306a36Sopenharmony_ci	snd_ctl_notify(rme9652->card, SNDRV_CTL_EVENT_MASK_VALUE |
227962306a36Sopenharmony_ci		       SNDRV_CTL_EVENT_MASK_INFO, &rme9652->spdif_ctl->id);
228062306a36Sopenharmony_ci	return 0;
228162306a36Sopenharmony_ci}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_cistatic int snd_rme9652_capture_open(struct snd_pcm_substream *substream)
228562306a36Sopenharmony_ci{
228662306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
228762306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	snd_pcm_set_sync(substream);
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	runtime->hw = snd_rme9652_capture_subinfo;
229462306a36Sopenharmony_ci	snd_pcm_set_runtime_buffer(substream, &rme9652->capture_dma_buf);
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	if (rme9652->playback_substream == NULL) {
229762306a36Sopenharmony_ci		rme9652_stop(rme9652);
229862306a36Sopenharmony_ci		rme9652_set_thru(rme9652, -1, 0);
229962306a36Sopenharmony_ci	}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	rme9652->capture_pid = current->pid;
230262306a36Sopenharmony_ci	rme9652->capture_substream = substream;
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
230762306a36Sopenharmony_ci	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes);
230862306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
230962306a36Sopenharmony_ci			     snd_rme9652_hw_rule_channels, rme9652,
231062306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
231162306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
231262306a36Sopenharmony_ci			     snd_rme9652_hw_rule_channels_rate, rme9652,
231362306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_RATE, -1);
231462306a36Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
231562306a36Sopenharmony_ci			     snd_rme9652_hw_rule_rate_channels, rme9652,
231662306a36Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
231762306a36Sopenharmony_ci	return 0;
231862306a36Sopenharmony_ci}
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_cistatic int snd_rme9652_capture_release(struct snd_pcm_substream *substream)
232162306a36Sopenharmony_ci{
232262306a36Sopenharmony_ci	struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	spin_lock_irq(&rme9652->lock);
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	rme9652->capture_pid = -1;
232762306a36Sopenharmony_ci	rme9652->capture_substream = NULL;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	spin_unlock_irq(&rme9652->lock);
233062306a36Sopenharmony_ci	return 0;
233162306a36Sopenharmony_ci}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_rme9652_playback_ops = {
233462306a36Sopenharmony_ci	.open =		snd_rme9652_playback_open,
233562306a36Sopenharmony_ci	.close =	snd_rme9652_playback_release,
233662306a36Sopenharmony_ci	.ioctl =	snd_rme9652_ioctl,
233762306a36Sopenharmony_ci	.hw_params =	snd_rme9652_hw_params,
233862306a36Sopenharmony_ci	.prepare =	snd_rme9652_prepare,
233962306a36Sopenharmony_ci	.trigger =	snd_rme9652_trigger,
234062306a36Sopenharmony_ci	.pointer =	snd_rme9652_hw_pointer,
234162306a36Sopenharmony_ci	.copy =		snd_rme9652_playback_copy,
234262306a36Sopenharmony_ci	.fill_silence =	snd_rme9652_hw_silence,
234362306a36Sopenharmony_ci};
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_rme9652_capture_ops = {
234662306a36Sopenharmony_ci	.open =		snd_rme9652_capture_open,
234762306a36Sopenharmony_ci	.close =	snd_rme9652_capture_release,
234862306a36Sopenharmony_ci	.ioctl =	snd_rme9652_ioctl,
234962306a36Sopenharmony_ci	.hw_params =	snd_rme9652_hw_params,
235062306a36Sopenharmony_ci	.prepare =	snd_rme9652_prepare,
235162306a36Sopenharmony_ci	.trigger =	snd_rme9652_trigger,
235262306a36Sopenharmony_ci	.pointer =	snd_rme9652_hw_pointer,
235362306a36Sopenharmony_ci	.copy =		snd_rme9652_capture_copy,
235462306a36Sopenharmony_ci};
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_cistatic int snd_rme9652_create_pcm(struct snd_card *card,
235762306a36Sopenharmony_ci				  struct snd_rme9652 *rme9652)
235862306a36Sopenharmony_ci{
235962306a36Sopenharmony_ci	struct snd_pcm *pcm;
236062306a36Sopenharmony_ci	int err;
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	err = snd_pcm_new(card, rme9652->card_name, 0, 1, 1, &pcm);
236362306a36Sopenharmony_ci	if (err < 0)
236462306a36Sopenharmony_ci		return err;
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	rme9652->pcm = pcm;
236762306a36Sopenharmony_ci	pcm->private_data = rme9652;
236862306a36Sopenharmony_ci	strcpy(pcm->name, rme9652->card_name);
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme9652_playback_ops);
237162306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme9652_capture_ops);
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci	return 0;
237662306a36Sopenharmony_ci}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_cistatic int snd_rme9652_create(struct snd_card *card,
237962306a36Sopenharmony_ci			      struct snd_rme9652 *rme9652,
238062306a36Sopenharmony_ci			      int precise_ptr)
238162306a36Sopenharmony_ci{
238262306a36Sopenharmony_ci	struct pci_dev *pci = rme9652->pci;
238362306a36Sopenharmony_ci	int err;
238462306a36Sopenharmony_ci	int status;
238562306a36Sopenharmony_ci	unsigned short rev;
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	rme9652->irq = -1;
238862306a36Sopenharmony_ci	rme9652->card = card;
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	pci_read_config_word(rme9652->pci, PCI_CLASS_REVISION, &rev);
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	switch (rev & 0xff) {
239362306a36Sopenharmony_ci	case 3:
239462306a36Sopenharmony_ci	case 4:
239562306a36Sopenharmony_ci	case 8:
239662306a36Sopenharmony_ci	case 9:
239762306a36Sopenharmony_ci		break;
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	default:
240062306a36Sopenharmony_ci		/* who knows? */
240162306a36Sopenharmony_ci		return -ENODEV;
240262306a36Sopenharmony_ci	}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	err = pcim_enable_device(pci);
240562306a36Sopenharmony_ci	if (err < 0)
240662306a36Sopenharmony_ci		return err;
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	spin_lock_init(&rme9652->lock);
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	err = pci_request_regions(pci, "rme9652");
241162306a36Sopenharmony_ci	if (err < 0)
241262306a36Sopenharmony_ci		return err;
241362306a36Sopenharmony_ci	rme9652->port = pci_resource_start(pci, 0);
241462306a36Sopenharmony_ci	rme9652->iobase = devm_ioremap(&pci->dev, rme9652->port, RME9652_IO_EXTENT);
241562306a36Sopenharmony_ci	if (rme9652->iobase == NULL) {
241662306a36Sopenharmony_ci		dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n",
241762306a36Sopenharmony_ci			rme9652->port, rme9652->port + RME9652_IO_EXTENT - 1);
241862306a36Sopenharmony_ci		return -EBUSY;
241962306a36Sopenharmony_ci	}
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	if (devm_request_irq(&pci->dev, pci->irq, snd_rme9652_interrupt,
242262306a36Sopenharmony_ci			     IRQF_SHARED, KBUILD_MODNAME, rme9652)) {
242362306a36Sopenharmony_ci		dev_err(card->dev, "unable to request IRQ %d\n", pci->irq);
242462306a36Sopenharmony_ci		return -EBUSY;
242562306a36Sopenharmony_ci	}
242662306a36Sopenharmony_ci	rme9652->irq = pci->irq;
242762306a36Sopenharmony_ci	card->sync_irq = rme9652->irq;
242862306a36Sopenharmony_ci	rme9652->precise_ptr = precise_ptr;
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	/* Determine the h/w rev level of the card. This seems like
243162306a36Sopenharmony_ci	   a particularly kludgy way to encode it, but its what RME
243262306a36Sopenharmony_ci	   chose to do, so we follow them ...
243362306a36Sopenharmony_ci	*/
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	status = rme9652_read(rme9652, RME9652_status_register);
243662306a36Sopenharmony_ci	if (rme9652_decode_spdif_rate(status&RME9652_F) == 1) {
243762306a36Sopenharmony_ci		rme9652->hw_rev = 15;
243862306a36Sopenharmony_ci	} else {
243962306a36Sopenharmony_ci		rme9652->hw_rev = 11;
244062306a36Sopenharmony_ci	}
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	/* Differentiate between the standard Hammerfall, and the
244362306a36Sopenharmony_ci	   "Light", which does not have the expansion board. This
244462306a36Sopenharmony_ci	   method comes from information received from Mathhias
244562306a36Sopenharmony_ci	   Clausen at RME. Display the EEPROM and h/w revID where
244662306a36Sopenharmony_ci	   relevant.
244762306a36Sopenharmony_ci	*/
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	switch (rev) {
245062306a36Sopenharmony_ci	case 8: /* original eprom */
245162306a36Sopenharmony_ci		strcpy(card->driver, "RME9636");
245262306a36Sopenharmony_ci		if (rme9652->hw_rev == 15) {
245362306a36Sopenharmony_ci			rme9652->card_name = "RME Digi9636 (Rev 1.5)";
245462306a36Sopenharmony_ci		} else {
245562306a36Sopenharmony_ci			rme9652->card_name = "RME Digi9636";
245662306a36Sopenharmony_ci		}
245762306a36Sopenharmony_ci		rme9652->ss_channels = RME9636_NCHANNELS;
245862306a36Sopenharmony_ci		break;
245962306a36Sopenharmony_ci	case 9: /* W36_G EPROM */
246062306a36Sopenharmony_ci		strcpy(card->driver, "RME9636");
246162306a36Sopenharmony_ci		rme9652->card_name = "RME Digi9636 (Rev G)";
246262306a36Sopenharmony_ci		rme9652->ss_channels = RME9636_NCHANNELS;
246362306a36Sopenharmony_ci		break;
246462306a36Sopenharmony_ci	case 4: /* W52_G EPROM */
246562306a36Sopenharmony_ci		strcpy(card->driver, "RME9652");
246662306a36Sopenharmony_ci		rme9652->card_name = "RME Digi9652 (Rev G)";
246762306a36Sopenharmony_ci		rme9652->ss_channels = RME9652_NCHANNELS;
246862306a36Sopenharmony_ci		break;
246962306a36Sopenharmony_ci	case 3: /* original eprom */
247062306a36Sopenharmony_ci		strcpy(card->driver, "RME9652");
247162306a36Sopenharmony_ci		if (rme9652->hw_rev == 15) {
247262306a36Sopenharmony_ci			rme9652->card_name = "RME Digi9652 (Rev 1.5)";
247362306a36Sopenharmony_ci		} else {
247462306a36Sopenharmony_ci			rme9652->card_name = "RME Digi9652";
247562306a36Sopenharmony_ci		}
247662306a36Sopenharmony_ci		rme9652->ss_channels = RME9652_NCHANNELS;
247762306a36Sopenharmony_ci		break;
247862306a36Sopenharmony_ci	}
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	rme9652->ds_channels = (rme9652->ss_channels - 2) / 2 + 2;
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	pci_set_master(rme9652->pci);
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	err = snd_rme9652_initialize_memory(rme9652);
248562306a36Sopenharmony_ci	if (err < 0)
248662306a36Sopenharmony_ci		return err;
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	err = snd_rme9652_create_pcm(card, rme9652);
248962306a36Sopenharmony_ci	if (err < 0)
249062306a36Sopenharmony_ci		return err;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	err = snd_rme9652_create_controls(card, rme9652);
249362306a36Sopenharmony_ci	if (err < 0)
249462306a36Sopenharmony_ci		return err;
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	snd_rme9652_proc_init(rme9652);
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	rme9652->last_spdif_sample_rate = -1;
249962306a36Sopenharmony_ci	rme9652->last_adat_sample_rate = -1;
250062306a36Sopenharmony_ci	rme9652->playback_pid = -1;
250162306a36Sopenharmony_ci	rme9652->capture_pid = -1;
250262306a36Sopenharmony_ci	rme9652->capture_substream = NULL;
250362306a36Sopenharmony_ci	rme9652->playback_substream = NULL;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	snd_rme9652_set_defaults(rme9652);
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	if (rme9652->hw_rev == 15) {
250862306a36Sopenharmony_ci		rme9652_initialize_spdif_receiver (rme9652);
250962306a36Sopenharmony_ci	}
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	return 0;
251262306a36Sopenharmony_ci}
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_cistatic int snd_rme9652_probe(struct pci_dev *pci,
251562306a36Sopenharmony_ci			     const struct pci_device_id *pci_id)
251662306a36Sopenharmony_ci{
251762306a36Sopenharmony_ci	static int dev;
251862306a36Sopenharmony_ci	struct snd_rme9652 *rme9652;
251962306a36Sopenharmony_ci	struct snd_card *card;
252062306a36Sopenharmony_ci	int err;
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci	if (dev >= SNDRV_CARDS)
252362306a36Sopenharmony_ci		return -ENODEV;
252462306a36Sopenharmony_ci	if (!enable[dev]) {
252562306a36Sopenharmony_ci		dev++;
252662306a36Sopenharmony_ci		return -ENOENT;
252762306a36Sopenharmony_ci	}
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
253062306a36Sopenharmony_ci				sizeof(struct snd_rme9652), &card);
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci	if (err < 0)
253362306a36Sopenharmony_ci		return err;
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	rme9652 = (struct snd_rme9652 *) card->private_data;
253662306a36Sopenharmony_ci	card->private_free = snd_rme9652_card_free;
253762306a36Sopenharmony_ci	rme9652->dev = dev;
253862306a36Sopenharmony_ci	rme9652->pci = pci;
253962306a36Sopenharmony_ci	err = snd_rme9652_create(card, rme9652, precise_ptr[dev]);
254062306a36Sopenharmony_ci	if (err)
254162306a36Sopenharmony_ci		goto error;
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	strcpy(card->shortname, rme9652->card_name);
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	sprintf(card->longname, "%s at 0x%lx, irq %d",
254662306a36Sopenharmony_ci		card->shortname, rme9652->port, rme9652->irq);
254762306a36Sopenharmony_ci	err = snd_card_register(card);
254862306a36Sopenharmony_ci	if (err)
254962306a36Sopenharmony_ci		goto error;
255062306a36Sopenharmony_ci	pci_set_drvdata(pci, card);
255162306a36Sopenharmony_ci	dev++;
255262306a36Sopenharmony_ci	return 0;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci error:
255562306a36Sopenharmony_ci	snd_card_free(card);
255662306a36Sopenharmony_ci	return err;
255762306a36Sopenharmony_ci}
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_cistatic struct pci_driver rme9652_driver = {
256062306a36Sopenharmony_ci	.name	  = KBUILD_MODNAME,
256162306a36Sopenharmony_ci	.id_table = snd_rme9652_ids,
256262306a36Sopenharmony_ci	.probe	  = snd_rme9652_probe,
256362306a36Sopenharmony_ci};
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_cimodule_pci_driver(rme9652_driver);
2566