18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ALSA driver for RME Digi9652 audio interfaces 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 1999 IEM - Winfried Ritsch 68c2ecf20Sopenharmony_ci * Copyright (c) 1999-2001 Paul Davis 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/pci.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/nospec.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <sound/core.h> 188c2ecf20Sopenharmony_ci#include <sound/control.h> 198c2ecf20Sopenharmony_ci#include <sound/pcm.h> 208c2ecf20Sopenharmony_ci#include <sound/info.h> 218c2ecf20Sopenharmony_ci#include <sound/asoundef.h> 228c2ecf20Sopenharmony_ci#include <sound/initval.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <asm/current.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 278c2ecf20Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 288c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ 298c2ecf20Sopenharmony_cistatic bool precise_ptr[SNDRV_CARDS]; /* Enable precise pointer */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for RME Digi9652 (Hammerfall) soundcard."); 338c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for RME Digi9652 (Hammerfall) soundcard."); 358c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable/disable specific RME96{52,36} soundcards."); 378c2ecf20Sopenharmony_cimodule_param_array(precise_ptr, bool, NULL, 0444); 388c2ecf20Sopenharmony_ciMODULE_PARM_DESC(precise_ptr, "Enable precise pointer (doesn't work reliably)."); 398c2ecf20Sopenharmony_ciMODULE_AUTHOR("Paul Davis <pbd@op.net>, Winfried Ritsch"); 408c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RME Digi9652/Digi9636"); 418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 428c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{{RME,Hammerfall}," 438c2ecf20Sopenharmony_ci "{RME,Hammerfall-Light}}"); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* The Hammerfall has two sets of 24 ADAT + 2 S/PDIF channels, one for 468c2ecf20Sopenharmony_ci capture, one for playback. Both the ADAT and S/PDIF channels appear 478c2ecf20Sopenharmony_ci to the host CPU in the same block of memory. There is no functional 488c2ecf20Sopenharmony_ci difference between them in terms of access. 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci The Hammerfall Light is identical to the Hammerfall, except that it 518c2ecf20Sopenharmony_ci has 2 sets 18 channels (16 ADAT + 2 S/PDIF) for capture and playback. 528c2ecf20Sopenharmony_ci*/ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define RME9652_NCHANNELS 26 558c2ecf20Sopenharmony_ci#define RME9636_NCHANNELS 18 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* Preferred sync source choices - used by "sync_pref" control switch */ 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define RME9652_SYNC_FROM_SPDIF 0 608c2ecf20Sopenharmony_ci#define RME9652_SYNC_FROM_ADAT1 1 618c2ecf20Sopenharmony_ci#define RME9652_SYNC_FROM_ADAT2 2 628c2ecf20Sopenharmony_ci#define RME9652_SYNC_FROM_ADAT3 3 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Possible sources of S/PDIF input */ 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define RME9652_SPDIFIN_OPTICAL 0 /* optical (ADAT1) */ 678c2ecf20Sopenharmony_ci#define RME9652_SPDIFIN_COAXIAL 1 /* coaxial (RCA) */ 688c2ecf20Sopenharmony_ci#define RME9652_SPDIFIN_INTERN 2 /* internal (CDROM) */ 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* ------------- Status-Register bits --------------------- */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define RME9652_IRQ (1<<0) /* IRQ is High if not reset by irq_clear */ 738c2ecf20Sopenharmony_ci#define RME9652_lock_2 (1<<1) /* ADAT 3-PLL: 1=locked, 0=unlocked */ 748c2ecf20Sopenharmony_ci#define RME9652_lock_1 (1<<2) /* ADAT 2-PLL: 1=locked, 0=unlocked */ 758c2ecf20Sopenharmony_ci#define RME9652_lock_0 (1<<3) /* ADAT 1-PLL: 1=locked, 0=unlocked */ 768c2ecf20Sopenharmony_ci#define RME9652_fs48 (1<<4) /* sample rate is 0=44.1/88.2,1=48/96 Khz */ 778c2ecf20Sopenharmony_ci#define RME9652_wsel_rd (1<<5) /* if Word-Clock is used and valid then 1 */ 788c2ecf20Sopenharmony_ci /* bits 6-15 encode h/w buffer pointer position */ 798c2ecf20Sopenharmony_ci#define RME9652_sync_2 (1<<16) /* if ADAT-IN 3 in sync to system clock */ 808c2ecf20Sopenharmony_ci#define RME9652_sync_1 (1<<17) /* if ADAT-IN 2 in sync to system clock */ 818c2ecf20Sopenharmony_ci#define RME9652_sync_0 (1<<18) /* if ADAT-IN 1 in sync to system clock */ 828c2ecf20Sopenharmony_ci#define RME9652_DS_rd (1<<19) /* 1=Double Speed Mode, 0=Normal Speed */ 838c2ecf20Sopenharmony_ci#define RME9652_tc_busy (1<<20) /* 1=time-code copy in progress (960ms) */ 848c2ecf20Sopenharmony_ci#define RME9652_tc_out (1<<21) /* time-code out bit */ 858c2ecf20Sopenharmony_ci#define RME9652_F_0 (1<<22) /* 000=64kHz, 100=88.2kHz, 011=96kHz */ 868c2ecf20Sopenharmony_ci#define RME9652_F_1 (1<<23) /* 111=32kHz, 110=44.1kHz, 101=48kHz, */ 878c2ecf20Sopenharmony_ci#define RME9652_F_2 (1<<24) /* external Crystal Chip if ERF=1 */ 888c2ecf20Sopenharmony_ci#define RME9652_ERF (1<<25) /* Error-Flag of SDPIF Receiver (1=No Lock) */ 898c2ecf20Sopenharmony_ci#define RME9652_buffer_id (1<<26) /* toggles by each interrupt on rec/play */ 908c2ecf20Sopenharmony_ci#define RME9652_tc_valid (1<<27) /* 1 = a signal is detected on time-code input */ 918c2ecf20Sopenharmony_ci#define RME9652_SPDIF_READ (1<<28) /* byte available from Rev 1.5+ S/PDIF interface */ 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#define RME9652_sync (RME9652_sync_0|RME9652_sync_1|RME9652_sync_2) 948c2ecf20Sopenharmony_ci#define RME9652_lock (RME9652_lock_0|RME9652_lock_1|RME9652_lock_2) 958c2ecf20Sopenharmony_ci#define RME9652_F (RME9652_F_0|RME9652_F_1|RME9652_F_2) 968c2ecf20Sopenharmony_ci#define rme9652_decode_spdif_rate(x) ((x)>>22) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* Bit 6..15 : h/w buffer pointer */ 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define RME9652_buf_pos 0x000FFC0 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* Bits 31,30,29 are bits 5,4,3 of h/w pointer position on later 1038c2ecf20Sopenharmony_ci Rev G EEPROMS and Rev 1.5 cards or later. 1048c2ecf20Sopenharmony_ci*/ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define RME9652_REV15_buf_pos(x) ((((x)&0xE0000000)>>26)|((x)&RME9652_buf_pos)) 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* amount of io space we remap for register access. i'm not sure we 1098c2ecf20Sopenharmony_ci even need this much, but 1K is nice round number :) 1108c2ecf20Sopenharmony_ci*/ 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define RME9652_IO_EXTENT 1024 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci#define RME9652_init_buffer 0 1158c2ecf20Sopenharmony_ci#define RME9652_play_buffer 32 /* holds ptr to 26x64kBit host RAM */ 1168c2ecf20Sopenharmony_ci#define RME9652_rec_buffer 36 /* holds ptr to 26x64kBit host RAM */ 1178c2ecf20Sopenharmony_ci#define RME9652_control_register 64 1188c2ecf20Sopenharmony_ci#define RME9652_irq_clear 96 1198c2ecf20Sopenharmony_ci#define RME9652_time_code 100 /* useful if used with alesis adat */ 1208c2ecf20Sopenharmony_ci#define RME9652_thru_base 128 /* 132...228 Thru for 26 channels */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* Read-only registers */ 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* Writing to any of the register locations writes to the status 1258c2ecf20Sopenharmony_ci register. We'll use the first location as our point of access. 1268c2ecf20Sopenharmony_ci*/ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#define RME9652_status_register 0 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* --------- Control-Register Bits ---------------- */ 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#define RME9652_start_bit (1<<0) /* start record/play */ 1348c2ecf20Sopenharmony_ci /* bits 1-3 encode buffersize/latency */ 1358c2ecf20Sopenharmony_ci#define RME9652_Master (1<<4) /* Clock Mode Master=1,Slave/Auto=0 */ 1368c2ecf20Sopenharmony_ci#define RME9652_IE (1<<5) /* Interrupt Enable */ 1378c2ecf20Sopenharmony_ci#define RME9652_freq (1<<6) /* samplerate 0=44.1/88.2, 1=48/96 kHz */ 1388c2ecf20Sopenharmony_ci#define RME9652_freq1 (1<<7) /* if 0, 32kHz, else always 1 */ 1398c2ecf20Sopenharmony_ci#define RME9652_DS (1<<8) /* Doule Speed 0=44.1/48, 1=88.2/96 Khz */ 1408c2ecf20Sopenharmony_ci#define RME9652_PRO (1<<9) /* S/PDIF out: 0=consumer, 1=professional */ 1418c2ecf20Sopenharmony_ci#define RME9652_EMP (1<<10) /* Emphasis 0=None, 1=ON */ 1428c2ecf20Sopenharmony_ci#define RME9652_Dolby (1<<11) /* Non-audio bit 1=set, 0=unset */ 1438c2ecf20Sopenharmony_ci#define RME9652_opt_out (1<<12) /* Use 1st optical OUT as SPDIF: 1=yes,0=no */ 1448c2ecf20Sopenharmony_ci#define RME9652_wsel (1<<13) /* use Wordclock as sync (overwrites master) */ 1458c2ecf20Sopenharmony_ci#define RME9652_inp_0 (1<<14) /* SPDIF-IN: 00=optical (ADAT1), */ 1468c2ecf20Sopenharmony_ci#define RME9652_inp_1 (1<<15) /* 01=koaxial (Cinch), 10=Internal CDROM */ 1478c2ecf20Sopenharmony_ci#define RME9652_SyncPref_ADAT2 (1<<16) 1488c2ecf20Sopenharmony_ci#define RME9652_SyncPref_ADAT3 (1<<17) 1498c2ecf20Sopenharmony_ci#define RME9652_SPDIF_RESET (1<<18) /* Rev 1.5+: h/w S/PDIF receiver */ 1508c2ecf20Sopenharmony_ci#define RME9652_SPDIF_SELECT (1<<19) 1518c2ecf20Sopenharmony_ci#define RME9652_SPDIF_CLOCK (1<<20) 1528c2ecf20Sopenharmony_ci#define RME9652_SPDIF_WRITE (1<<21) 1538c2ecf20Sopenharmony_ci#define RME9652_ADAT1_INTERNAL (1<<22) /* Rev 1.5+: if set, internal CD connector carries ADAT */ 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* buffersize = 512Bytes * 2^n, where n is made from Bit2 ... Bit0 */ 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#define RME9652_latency 0x0e 1588c2ecf20Sopenharmony_ci#define rme9652_encode_latency(x) (((x)&0x7)<<1) 1598c2ecf20Sopenharmony_ci#define rme9652_decode_latency(x) (((x)>>1)&0x7) 1608c2ecf20Sopenharmony_ci#define rme9652_running_double_speed(s) ((s)->control_register & RME9652_DS) 1618c2ecf20Sopenharmony_ci#define RME9652_inp (RME9652_inp_0|RME9652_inp_1) 1628c2ecf20Sopenharmony_ci#define rme9652_encode_spdif_in(x) (((x)&0x3)<<14) 1638c2ecf20Sopenharmony_ci#define rme9652_decode_spdif_in(x) (((x)>>14)&0x3) 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci#define RME9652_SyncPref_Mask (RME9652_SyncPref_ADAT2|RME9652_SyncPref_ADAT3) 1668c2ecf20Sopenharmony_ci#define RME9652_SyncPref_ADAT1 0 1678c2ecf20Sopenharmony_ci#define RME9652_SyncPref_SPDIF (RME9652_SyncPref_ADAT2|RME9652_SyncPref_ADAT3) 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* the size of a substream (1 mono data stream) */ 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#define RME9652_CHANNEL_BUFFER_SAMPLES (16*1024) 1728c2ecf20Sopenharmony_ci#define RME9652_CHANNEL_BUFFER_BYTES (4*RME9652_CHANNEL_BUFFER_SAMPLES) 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/* the size of the area we need to allocate for DMA transfers. the 1758c2ecf20Sopenharmony_ci size is the same regardless of the number of channels - the 1768c2ecf20Sopenharmony_ci 9636 still uses the same memory area. 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci Note that we allocate 1 more channel than is apparently needed 1798c2ecf20Sopenharmony_ci because the h/w seems to write 1 byte beyond the end of the last 1808c2ecf20Sopenharmony_ci page. Sigh. 1818c2ecf20Sopenharmony_ci*/ 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#define RME9652_DMA_AREA_BYTES ((RME9652_NCHANNELS+1) * RME9652_CHANNEL_BUFFER_BYTES) 1848c2ecf20Sopenharmony_ci#define RME9652_DMA_AREA_KILOBYTES (RME9652_DMA_AREA_BYTES/1024) 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistruct snd_rme9652 { 1878c2ecf20Sopenharmony_ci int dev; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci spinlock_t lock; 1908c2ecf20Sopenharmony_ci int irq; 1918c2ecf20Sopenharmony_ci unsigned long port; 1928c2ecf20Sopenharmony_ci void __iomem *iobase; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci int precise_ptr; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci u32 control_register; /* cached value */ 1978c2ecf20Sopenharmony_ci u32 thru_bits; /* thru 1=on, 0=off channel 1=Bit1... channel 26= Bit26 */ 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci u32 creg_spdif; 2008c2ecf20Sopenharmony_ci u32 creg_spdif_stream; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci char *card_name; /* hammerfall or hammerfall light names */ 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci size_t hw_offsetmask; /* &-with status register to get real hw_offset */ 2058c2ecf20Sopenharmony_ci size_t prev_hw_offset; /* previous hw offset */ 2068c2ecf20Sopenharmony_ci size_t max_jitter; /* maximum jitter in frames for 2078c2ecf20Sopenharmony_ci hw pointer */ 2088c2ecf20Sopenharmony_ci size_t period_bytes; /* guess what this is */ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci unsigned char ds_channels; 2118c2ecf20Sopenharmony_ci unsigned char ss_channels; /* different for hammerfall/hammerfall-light */ 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci struct snd_dma_buffer playback_dma_buf; 2148c2ecf20Sopenharmony_ci struct snd_dma_buffer capture_dma_buf; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci unsigned char *capture_buffer; /* suitably aligned address */ 2178c2ecf20Sopenharmony_ci unsigned char *playback_buffer; /* suitably aligned address */ 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci pid_t capture_pid; 2208c2ecf20Sopenharmony_ci pid_t playback_pid; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci struct snd_pcm_substream *capture_substream; 2238c2ecf20Sopenharmony_ci struct snd_pcm_substream *playback_substream; 2248c2ecf20Sopenharmony_ci int running; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci int passthru; /* non-zero if doing pass-thru */ 2278c2ecf20Sopenharmony_ci int hw_rev; /* h/w rev * 10 (i.e. 1.5 has hw_rev = 15) */ 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci int last_spdif_sample_rate; /* so that we can catch externally ... */ 2308c2ecf20Sopenharmony_ci int last_adat_sample_rate; /* ... induced rate changes */ 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci const signed char *channel_map; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci struct snd_card *card; 2358c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 2368c2ecf20Sopenharmony_ci struct pci_dev *pci; 2378c2ecf20Sopenharmony_ci struct snd_kcontrol *spdif_ctl; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* These tables map the ALSA channels 1..N to the channels that we 2428c2ecf20Sopenharmony_ci need to use in order to find the relevant channel buffer. RME 2438c2ecf20Sopenharmony_ci refer to this kind of mapping as between "the ADAT channel and 2448c2ecf20Sopenharmony_ci the DMA channel." We index it using the logical audio channel, 2458c2ecf20Sopenharmony_ci and the value is the DMA channel (i.e. channel buffer number) 2468c2ecf20Sopenharmony_ci where the data for that channel can be read/written from/to. 2478c2ecf20Sopenharmony_ci*/ 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic const signed char channel_map_9652_ss[26] = { 2508c2ecf20Sopenharmony_ci 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 2518c2ecf20Sopenharmony_ci 18, 19, 20, 21, 22, 23, 24, 25 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic const signed char channel_map_9636_ss[26] = { 2558c2ecf20Sopenharmony_ci 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 2568c2ecf20Sopenharmony_ci /* channels 16 and 17 are S/PDIF */ 2578c2ecf20Sopenharmony_ci 24, 25, 2588c2ecf20Sopenharmony_ci /* channels 18-25 don't exist */ 2598c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 2608c2ecf20Sopenharmony_ci}; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic const signed char channel_map_9652_ds[26] = { 2638c2ecf20Sopenharmony_ci /* ADAT channels are remapped */ 2648c2ecf20Sopenharmony_ci 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 2658c2ecf20Sopenharmony_ci /* channels 12 and 13 are S/PDIF */ 2668c2ecf20Sopenharmony_ci 24, 25, 2678c2ecf20Sopenharmony_ci /* others don't exist */ 2688c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 2698c2ecf20Sopenharmony_ci}; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic const signed char channel_map_9636_ds[26] = { 2728c2ecf20Sopenharmony_ci /* ADAT channels are remapped */ 2738c2ecf20Sopenharmony_ci 1, 3, 5, 7, 9, 11, 13, 15, 2748c2ecf20Sopenharmony_ci /* channels 8 and 9 are S/PDIF */ 2758c2ecf20Sopenharmony_ci 24, 25, 2768c2ecf20Sopenharmony_ci /* others don't exist */ 2778c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 2788c2ecf20Sopenharmony_ci}; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer *dmab, size_t size) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, size, dmab); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci if (dmab->area) 2888c2ecf20Sopenharmony_ci snd_dma_free_pages(dmab); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic const struct pci_device_id snd_rme9652_ids[] = { 2938c2ecf20Sopenharmony_ci { 2948c2ecf20Sopenharmony_ci .vendor = 0x10ee, 2958c2ecf20Sopenharmony_ci .device = 0x3fc4, 2968c2ecf20Sopenharmony_ci .subvendor = PCI_ANY_ID, 2978c2ecf20Sopenharmony_ci .subdevice = PCI_ANY_ID, 2988c2ecf20Sopenharmony_ci }, /* RME Digi9652 */ 2998c2ecf20Sopenharmony_ci { 0, }, 3008c2ecf20Sopenharmony_ci}; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_rme9652_ids); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic inline void rme9652_write(struct snd_rme9652 *rme9652, int reg, int val) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci writel(val, rme9652->iobase + reg); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic inline unsigned int rme9652_read(struct snd_rme9652 *rme9652, int reg) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci return readl(rme9652->iobase + reg); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic inline int snd_rme9652_use_is_exclusive(struct snd_rme9652 *rme9652) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci unsigned long flags; 3178c2ecf20Sopenharmony_ci int ret = 1; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci spin_lock_irqsave(&rme9652->lock, flags); 3208c2ecf20Sopenharmony_ci if ((rme9652->playback_pid != rme9652->capture_pid) && 3218c2ecf20Sopenharmony_ci (rme9652->playback_pid >= 0) && (rme9652->capture_pid >= 0)) { 3228c2ecf20Sopenharmony_ci ret = 0; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rme9652->lock, flags); 3258c2ecf20Sopenharmony_ci return ret; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic inline int rme9652_adat_sample_rate(struct snd_rme9652 *rme9652) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci if (rme9652_running_double_speed(rme9652)) { 3318c2ecf20Sopenharmony_ci return (rme9652_read(rme9652, RME9652_status_register) & 3328c2ecf20Sopenharmony_ci RME9652_fs48) ? 96000 : 88200; 3338c2ecf20Sopenharmony_ci } else { 3348c2ecf20Sopenharmony_ci return (rme9652_read(rme9652, RME9652_status_register) & 3358c2ecf20Sopenharmony_ci RME9652_fs48) ? 48000 : 44100; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic inline void rme9652_compute_period_size(struct snd_rme9652 *rme9652) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci unsigned int i; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci i = rme9652->control_register & RME9652_latency; 3448c2ecf20Sopenharmony_ci rme9652->period_bytes = 1 << ((rme9652_decode_latency(i) + 8)); 3458c2ecf20Sopenharmony_ci rme9652->hw_offsetmask = 3468c2ecf20Sopenharmony_ci (rme9652->period_bytes * 2 - 1) & RME9652_buf_pos; 3478c2ecf20Sopenharmony_ci rme9652->max_jitter = 80; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci int status; 3538c2ecf20Sopenharmony_ci unsigned int offset, frag; 3548c2ecf20Sopenharmony_ci snd_pcm_uframes_t period_size = rme9652->period_bytes / 4; 3558c2ecf20Sopenharmony_ci snd_pcm_sframes_t delta; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci status = rme9652_read(rme9652, RME9652_status_register); 3588c2ecf20Sopenharmony_ci if (!rme9652->precise_ptr) 3598c2ecf20Sopenharmony_ci return (status & RME9652_buffer_id) ? period_size : 0; 3608c2ecf20Sopenharmony_ci offset = status & RME9652_buf_pos; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* The hardware may give a backward movement for up to 80 frames 3638c2ecf20Sopenharmony_ci Martin Kirst <martin.kirst@freenet.de> knows the details. 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci delta = rme9652->prev_hw_offset - offset; 3678c2ecf20Sopenharmony_ci delta &= 0xffff; 3688c2ecf20Sopenharmony_ci if (delta <= (snd_pcm_sframes_t)rme9652->max_jitter * 4) 3698c2ecf20Sopenharmony_ci offset = rme9652->prev_hw_offset; 3708c2ecf20Sopenharmony_ci else 3718c2ecf20Sopenharmony_ci rme9652->prev_hw_offset = offset; 3728c2ecf20Sopenharmony_ci offset &= rme9652->hw_offsetmask; 3738c2ecf20Sopenharmony_ci offset /= 4; 3748c2ecf20Sopenharmony_ci frag = status & RME9652_buffer_id; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (offset < period_size) { 3778c2ecf20Sopenharmony_ci if (offset > rme9652->max_jitter) { 3788c2ecf20Sopenharmony_ci if (frag) 3798c2ecf20Sopenharmony_ci dev_err(rme9652->card->dev, 3808c2ecf20Sopenharmony_ci "Unexpected hw_pointer position (bufid == 0): status: %x offset: %d\n", 3818c2ecf20Sopenharmony_ci status, offset); 3828c2ecf20Sopenharmony_ci } else if (!frag) 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci offset -= rme9652->max_jitter; 3858c2ecf20Sopenharmony_ci if ((int)offset < 0) 3868c2ecf20Sopenharmony_ci offset += period_size * 2; 3878c2ecf20Sopenharmony_ci } else { 3888c2ecf20Sopenharmony_ci if (offset > period_size + rme9652->max_jitter) { 3898c2ecf20Sopenharmony_ci if (!frag) 3908c2ecf20Sopenharmony_ci dev_err(rme9652->card->dev, 3918c2ecf20Sopenharmony_ci "Unexpected hw_pointer position (bufid == 1): status: %x offset: %d\n", 3928c2ecf20Sopenharmony_ci status, offset); 3938c2ecf20Sopenharmony_ci } else if (frag) 3948c2ecf20Sopenharmony_ci return period_size; 3958c2ecf20Sopenharmony_ci offset -= rme9652->max_jitter; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return offset; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic inline void rme9652_reset_hw_pointer(struct snd_rme9652 *rme9652) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci int i; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* reset the FIFO pointer to zero. We do this by writing to 8 4068c2ecf20Sopenharmony_ci registers, each of which is a 32bit wide register, and set 4078c2ecf20Sopenharmony_ci them all to zero. Note that s->iobase is a pointer to 4088c2ecf20Sopenharmony_ci int32, not pointer to char. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 4128c2ecf20Sopenharmony_ci rme9652_write(rme9652, i * 4, 0); 4138c2ecf20Sopenharmony_ci udelay(10); 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci rme9652->prev_hw_offset = 0; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic inline void rme9652_start(struct snd_rme9652 *s) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci s->control_register |= (RME9652_IE | RME9652_start_bit); 4218c2ecf20Sopenharmony_ci rme9652_write(s, RME9652_control_register, s->control_register); 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic inline void rme9652_stop(struct snd_rme9652 *s) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci s->control_register &= ~(RME9652_start_bit | RME9652_IE); 4278c2ecf20Sopenharmony_ci rme9652_write(s, RME9652_control_register, s->control_register); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int rme9652_set_interrupt_interval(struct snd_rme9652 *s, 4318c2ecf20Sopenharmony_ci unsigned int frames) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci int restart = 0; 4348c2ecf20Sopenharmony_ci int n; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci spin_lock_irq(&s->lock); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if ((restart = s->running)) { 4398c2ecf20Sopenharmony_ci rme9652_stop(s); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci frames >>= 7; 4438c2ecf20Sopenharmony_ci n = 0; 4448c2ecf20Sopenharmony_ci while (frames) { 4458c2ecf20Sopenharmony_ci n++; 4468c2ecf20Sopenharmony_ci frames >>= 1; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci s->control_register &= ~RME9652_latency; 4508c2ecf20Sopenharmony_ci s->control_register |= rme9652_encode_latency(n); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci rme9652_write(s, RME9652_control_register, s->control_register); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci rme9652_compute_period_size(s); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (restart) 4578c2ecf20Sopenharmony_ci rme9652_start(s); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci spin_unlock_irq(&s->lock); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic int rme9652_set_rate(struct snd_rme9652 *rme9652, int rate) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci int restart; 4678c2ecf20Sopenharmony_ci int reject_if_open = 0; 4688c2ecf20Sopenharmony_ci int xrate; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (!snd_rme9652_use_is_exclusive (rme9652)) { 4718c2ecf20Sopenharmony_ci return -EBUSY; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* Changing from a "single speed" to a "double speed" rate is 4758c2ecf20Sopenharmony_ci not allowed if any substreams are open. This is because 4768c2ecf20Sopenharmony_ci such a change causes a shift in the location of 4778c2ecf20Sopenharmony_ci the DMA buffers and a reduction in the number of available 4788c2ecf20Sopenharmony_ci buffers. 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci Note that a similar but essentially insoluble problem 4818c2ecf20Sopenharmony_ci exists for externally-driven rate changes. All we can do 4828c2ecf20Sopenharmony_ci is to flag rate changes in the read/write routines. 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 4868c2ecf20Sopenharmony_ci xrate = rme9652_adat_sample_rate(rme9652); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci switch (rate) { 4898c2ecf20Sopenharmony_ci case 44100: 4908c2ecf20Sopenharmony_ci if (xrate > 48000) { 4918c2ecf20Sopenharmony_ci reject_if_open = 1; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci rate = 0; 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci case 48000: 4968c2ecf20Sopenharmony_ci if (xrate > 48000) { 4978c2ecf20Sopenharmony_ci reject_if_open = 1; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci rate = RME9652_freq; 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci case 88200: 5028c2ecf20Sopenharmony_ci if (xrate < 48000) { 5038c2ecf20Sopenharmony_ci reject_if_open = 1; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci rate = RME9652_DS; 5068c2ecf20Sopenharmony_ci break; 5078c2ecf20Sopenharmony_ci case 96000: 5088c2ecf20Sopenharmony_ci if (xrate < 48000) { 5098c2ecf20Sopenharmony_ci reject_if_open = 1; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci rate = RME9652_DS | RME9652_freq; 5128c2ecf20Sopenharmony_ci break; 5138c2ecf20Sopenharmony_ci default: 5148c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 5158c2ecf20Sopenharmony_ci return -EINVAL; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (reject_if_open && (rme9652->capture_pid >= 0 || rme9652->playback_pid >= 0)) { 5198c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 5208c2ecf20Sopenharmony_ci return -EBUSY; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if ((restart = rme9652->running)) { 5248c2ecf20Sopenharmony_ci rme9652_stop(rme9652); 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci rme9652->control_register &= ~(RME9652_freq | RME9652_DS); 5278c2ecf20Sopenharmony_ci rme9652->control_register |= rate; 5288c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (restart) { 5318c2ecf20Sopenharmony_ci rme9652_start(rme9652); 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (rate & RME9652_DS) { 5358c2ecf20Sopenharmony_ci if (rme9652->ss_channels == RME9652_NCHANNELS) { 5368c2ecf20Sopenharmony_ci rme9652->channel_map = channel_map_9652_ds; 5378c2ecf20Sopenharmony_ci } else { 5388c2ecf20Sopenharmony_ci rme9652->channel_map = channel_map_9636_ds; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci } else { 5418c2ecf20Sopenharmony_ci if (rme9652->ss_channels == RME9652_NCHANNELS) { 5428c2ecf20Sopenharmony_ci rme9652->channel_map = channel_map_9652_ss; 5438c2ecf20Sopenharmony_ci } else { 5448c2ecf20Sopenharmony_ci rme9652->channel_map = channel_map_9636_ss; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 5498c2ecf20Sopenharmony_ci return 0; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic void rme9652_set_thru(struct snd_rme9652 *rme9652, int channel, int enable) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci int i; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci rme9652->passthru = 0; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (channel < 0) { 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* set thru for all channels */ 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (enable) { 5638c2ecf20Sopenharmony_ci for (i = 0; i < RME9652_NCHANNELS; i++) { 5648c2ecf20Sopenharmony_ci rme9652->thru_bits |= (1 << i); 5658c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_thru_base + i * 4, 1); 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci } else { 5688c2ecf20Sopenharmony_ci for (i = 0; i < RME9652_NCHANNELS; i++) { 5698c2ecf20Sopenharmony_ci rme9652->thru_bits &= ~(1 << i); 5708c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_thru_base + i * 4, 0); 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci } else { 5758c2ecf20Sopenharmony_ci int mapped_channel; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci mapped_channel = rme9652->channel_map[channel]; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (enable) { 5808c2ecf20Sopenharmony_ci rme9652->thru_bits |= (1 << mapped_channel); 5818c2ecf20Sopenharmony_ci } else { 5828c2ecf20Sopenharmony_ci rme9652->thru_bits &= ~(1 << mapped_channel); 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci rme9652_write(rme9652, 5868c2ecf20Sopenharmony_ci RME9652_thru_base + mapped_channel * 4, 5878c2ecf20Sopenharmony_ci enable ? 1 : 0); 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic int rme9652_set_passthru(struct snd_rme9652 *rme9652, int onoff) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci if (onoff) { 5948c2ecf20Sopenharmony_ci rme9652_set_thru(rme9652, -1, 1); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* we don't want interrupts, so do a 5978c2ecf20Sopenharmony_ci custom version of rme9652_start(). 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci rme9652->control_register = 6018c2ecf20Sopenharmony_ci RME9652_inp_0 | 6028c2ecf20Sopenharmony_ci rme9652_encode_latency(7) | 6038c2ecf20Sopenharmony_ci RME9652_start_bit; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci rme9652_reset_hw_pointer(rme9652); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_control_register, 6088c2ecf20Sopenharmony_ci rme9652->control_register); 6098c2ecf20Sopenharmony_ci rme9652->passthru = 1; 6108c2ecf20Sopenharmony_ci } else { 6118c2ecf20Sopenharmony_ci rme9652_set_thru(rme9652, -1, 0); 6128c2ecf20Sopenharmony_ci rme9652_stop(rme9652); 6138c2ecf20Sopenharmony_ci rme9652->passthru = 0; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic void rme9652_spdif_set_bit (struct snd_rme9652 *rme9652, int mask, int onoff) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci if (onoff) 6228c2ecf20Sopenharmony_ci rme9652->control_register |= mask; 6238c2ecf20Sopenharmony_ci else 6248c2ecf20Sopenharmony_ci rme9652->control_register &= ~mask; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic void rme9652_spdif_write_byte (struct snd_rme9652 *rme9652, const int val) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci long mask; 6328c2ecf20Sopenharmony_ci long i; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) { 6358c2ecf20Sopenharmony_ci if (val & mask) 6368c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_WRITE, 1); 6378c2ecf20Sopenharmony_ci else 6388c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_WRITE, 0); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 1); 6418c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 0); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic int rme9652_spdif_read_byte (struct snd_rme9652 *rme9652) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci long mask; 6488c2ecf20Sopenharmony_ci long val; 6498c2ecf20Sopenharmony_ci long i; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci val = 0; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) { 6548c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 1); 6558c2ecf20Sopenharmony_ci if (rme9652_read (rme9652, RME9652_status_register) & RME9652_SPDIF_READ) 6568c2ecf20Sopenharmony_ci val |= mask; 6578c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 0); 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return val; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic void rme9652_write_spdif_codec (struct snd_rme9652 *rme9652, const int address, const int data) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 1); 6668c2ecf20Sopenharmony_ci rme9652_spdif_write_byte (rme9652, 0x20); 6678c2ecf20Sopenharmony_ci rme9652_spdif_write_byte (rme9652, address); 6688c2ecf20Sopenharmony_ci rme9652_spdif_write_byte (rme9652, data); 6698c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 0); 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic int rme9652_spdif_read_codec (struct snd_rme9652 *rme9652, const int address) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci int ret; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 1); 6788c2ecf20Sopenharmony_ci rme9652_spdif_write_byte (rme9652, 0x20); 6798c2ecf20Sopenharmony_ci rme9652_spdif_write_byte (rme9652, address); 6808c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 0); 6818c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 1); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci rme9652_spdif_write_byte (rme9652, 0x21); 6848c2ecf20Sopenharmony_ci ret = rme9652_spdif_read_byte (rme9652); 6858c2ecf20Sopenharmony_ci rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 0); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return ret; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic void rme9652_initialize_spdif_receiver (struct snd_rme9652 *rme9652) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci /* XXX what unsets this ? */ 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci rme9652->control_register |= RME9652_SPDIF_RESET; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci rme9652_write_spdif_codec (rme9652, 4, 0x40); 6978c2ecf20Sopenharmony_ci rme9652_write_spdif_codec (rme9652, 17, 0x13); 6988c2ecf20Sopenharmony_ci rme9652_write_spdif_codec (rme9652, 6, 0x02); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic inline int rme9652_spdif_sample_rate(struct snd_rme9652 *s) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci unsigned int rate_bits; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (rme9652_read(s, RME9652_status_register) & RME9652_ERF) { 7068c2ecf20Sopenharmony_ci return -1; /* error condition */ 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (s->hw_rev == 15) { 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci int x, y, ret; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci x = rme9652_spdif_read_codec (s, 30); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (x != 0) 7168c2ecf20Sopenharmony_ci y = 48000 * 64 / x; 7178c2ecf20Sopenharmony_ci else 7188c2ecf20Sopenharmony_ci y = 0; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (y > 30400 && y < 33600) ret = 32000; 7218c2ecf20Sopenharmony_ci else if (y > 41900 && y < 46000) ret = 44100; 7228c2ecf20Sopenharmony_ci else if (y > 46000 && y < 50400) ret = 48000; 7238c2ecf20Sopenharmony_ci else if (y > 60800 && y < 67200) ret = 64000; 7248c2ecf20Sopenharmony_ci else if (y > 83700 && y < 92000) ret = 88200; 7258c2ecf20Sopenharmony_ci else if (y > 92000 && y < 100000) ret = 96000; 7268c2ecf20Sopenharmony_ci else ret = 0; 7278c2ecf20Sopenharmony_ci return ret; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci rate_bits = rme9652_read(s, RME9652_status_register) & RME9652_F; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci switch (rme9652_decode_spdif_rate(rate_bits)) { 7338c2ecf20Sopenharmony_ci case 0x7: 7348c2ecf20Sopenharmony_ci return 32000; 7358c2ecf20Sopenharmony_ci break; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci case 0x6: 7388c2ecf20Sopenharmony_ci return 44100; 7398c2ecf20Sopenharmony_ci break; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci case 0x5: 7428c2ecf20Sopenharmony_ci return 48000; 7438c2ecf20Sopenharmony_ci break; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci case 0x4: 7468c2ecf20Sopenharmony_ci return 88200; 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci case 0x3: 7508c2ecf20Sopenharmony_ci return 96000; 7518c2ecf20Sopenharmony_ci break; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci case 0x0: 7548c2ecf20Sopenharmony_ci return 64000; 7558c2ecf20Sopenharmony_ci break; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci default: 7588c2ecf20Sopenharmony_ci dev_err(s->card->dev, 7598c2ecf20Sopenharmony_ci "%s: unknown S/PDIF input rate (bits = 0x%x)\n", 7608c2ecf20Sopenharmony_ci s->card_name, rate_bits); 7618c2ecf20Sopenharmony_ci return 0; 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------------- 7678c2ecf20Sopenharmony_ci Control Interface 7688c2ecf20Sopenharmony_ci ----------------------------------------------------------------------------*/ 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic u32 snd_rme9652_convert_from_aes(struct snd_aes_iec958 *aes) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci u32 val = 0; 7738c2ecf20Sopenharmony_ci val |= (aes->status[0] & IEC958_AES0_PROFESSIONAL) ? RME9652_PRO : 0; 7748c2ecf20Sopenharmony_ci val |= (aes->status[0] & IEC958_AES0_NONAUDIO) ? RME9652_Dolby : 0; 7758c2ecf20Sopenharmony_ci if (val & RME9652_PRO) 7768c2ecf20Sopenharmony_ci val |= (aes->status[0] & IEC958_AES0_PRO_EMPHASIS_5015) ? RME9652_EMP : 0; 7778c2ecf20Sopenharmony_ci else 7788c2ecf20Sopenharmony_ci val |= (aes->status[0] & IEC958_AES0_CON_EMPHASIS_5015) ? RME9652_EMP : 0; 7798c2ecf20Sopenharmony_ci return val; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic void snd_rme9652_convert_to_aes(struct snd_aes_iec958 *aes, u32 val) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci aes->status[0] = ((val & RME9652_PRO) ? IEC958_AES0_PROFESSIONAL : 0) | 7858c2ecf20Sopenharmony_ci ((val & RME9652_Dolby) ? IEC958_AES0_NONAUDIO : 0); 7868c2ecf20Sopenharmony_ci if (val & RME9652_PRO) 7878c2ecf20Sopenharmony_ci aes->status[0] |= (val & RME9652_EMP) ? IEC958_AES0_PRO_EMPHASIS_5015 : 0; 7888c2ecf20Sopenharmony_ci else 7898c2ecf20Sopenharmony_ci aes->status[0] |= (val & RME9652_EMP) ? IEC958_AES0_CON_EMPHASIS_5015 : 0; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic int snd_rme9652_control_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 7958c2ecf20Sopenharmony_ci uinfo->count = 1; 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic int snd_rme9652_control_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci snd_rme9652_convert_to_aes(&ucontrol->value.iec958, rme9652->creg_spdif); 8048c2ecf20Sopenharmony_ci return 0; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic int snd_rme9652_control_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 8108c2ecf20Sopenharmony_ci int change; 8118c2ecf20Sopenharmony_ci u32 val; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci val = snd_rme9652_convert_from_aes(&ucontrol->value.iec958); 8148c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 8158c2ecf20Sopenharmony_ci change = val != rme9652->creg_spdif; 8168c2ecf20Sopenharmony_ci rme9652->creg_spdif = val; 8178c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 8188c2ecf20Sopenharmony_ci return change; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic int snd_rme9652_control_spdif_stream_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 8248c2ecf20Sopenharmony_ci uinfo->count = 1; 8258c2ecf20Sopenharmony_ci return 0; 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic int snd_rme9652_control_spdif_stream_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci snd_rme9652_convert_to_aes(&ucontrol->value.iec958, rme9652->creg_spdif_stream); 8338c2ecf20Sopenharmony_ci return 0; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic int snd_rme9652_control_spdif_stream_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 8398c2ecf20Sopenharmony_ci int change; 8408c2ecf20Sopenharmony_ci u32 val; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci val = snd_rme9652_convert_from_aes(&ucontrol->value.iec958); 8438c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 8448c2ecf20Sopenharmony_ci change = val != rme9652->creg_spdif_stream; 8458c2ecf20Sopenharmony_ci rme9652->creg_spdif_stream = val; 8468c2ecf20Sopenharmony_ci rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP); 8478c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= val); 8488c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 8498c2ecf20Sopenharmony_ci return change; 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cistatic int snd_rme9652_control_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 8558c2ecf20Sopenharmony_ci uinfo->count = 1; 8568c2ecf20Sopenharmony_ci return 0; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic int snd_rme9652_control_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[0] = kcontrol->private_value; 8628c2ecf20Sopenharmony_ci return 0; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci#define RME9652_ADAT1_IN(xname, xindex) \ 8668c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 8678c2ecf20Sopenharmony_ci .info = snd_rme9652_info_adat1_in, \ 8688c2ecf20Sopenharmony_ci .get = snd_rme9652_get_adat1_in, \ 8698c2ecf20Sopenharmony_ci .put = snd_rme9652_put_adat1_in } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_cistatic unsigned int rme9652_adat1_in(struct snd_rme9652 *rme9652) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci if (rme9652->control_register & RME9652_ADAT1_INTERNAL) 8748c2ecf20Sopenharmony_ci return 1; 8758c2ecf20Sopenharmony_ci return 0; 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic int rme9652_set_adat1_input(struct snd_rme9652 *rme9652, int internal) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci int restart = 0; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (internal) { 8838c2ecf20Sopenharmony_ci rme9652->control_register |= RME9652_ADAT1_INTERNAL; 8848c2ecf20Sopenharmony_ci } else { 8858c2ecf20Sopenharmony_ci rme9652->control_register &= ~RME9652_ADAT1_INTERNAL; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* XXX do we actually need to stop the card when we do this ? */ 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if ((restart = rme9652->running)) { 8918c2ecf20Sopenharmony_ci rme9652_stop(rme9652); 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (restart) { 8978c2ecf20Sopenharmony_ci rme9652_start(rme9652); 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci return 0; 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cistatic int snd_rme9652_info_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci static const char * const texts[2] = {"ADAT1", "Internal"}; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic int snd_rme9652_get_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 9158c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = rme9652_adat1_in(rme9652); 9168c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 9178c2ecf20Sopenharmony_ci return 0; 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cistatic int snd_rme9652_put_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 9238c2ecf20Sopenharmony_ci int change; 9248c2ecf20Sopenharmony_ci unsigned int val; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (!snd_rme9652_use_is_exclusive(rme9652)) 9278c2ecf20Sopenharmony_ci return -EBUSY; 9288c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0] % 2; 9298c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 9308c2ecf20Sopenharmony_ci change = val != rme9652_adat1_in(rme9652); 9318c2ecf20Sopenharmony_ci if (change) 9328c2ecf20Sopenharmony_ci rme9652_set_adat1_input(rme9652, val); 9338c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 9348c2ecf20Sopenharmony_ci return change; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci#define RME9652_SPDIF_IN(xname, xindex) \ 9388c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 9398c2ecf20Sopenharmony_ci .info = snd_rme9652_info_spdif_in, \ 9408c2ecf20Sopenharmony_ci .get = snd_rme9652_get_spdif_in, .put = snd_rme9652_put_spdif_in } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic unsigned int rme9652_spdif_in(struct snd_rme9652 *rme9652) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci return rme9652_decode_spdif_in(rme9652->control_register & 9458c2ecf20Sopenharmony_ci RME9652_inp); 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic int rme9652_set_spdif_input(struct snd_rme9652 *rme9652, int in) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci int restart = 0; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci rme9652->control_register &= ~RME9652_inp; 9538c2ecf20Sopenharmony_ci rme9652->control_register |= rme9652_encode_spdif_in(in); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if ((restart = rme9652->running)) { 9568c2ecf20Sopenharmony_ci rme9652_stop(rme9652); 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (restart) { 9628c2ecf20Sopenharmony_ci rme9652_start(rme9652); 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci return 0; 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_cistatic int snd_rme9652_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci static const char * const texts[3] = {"ADAT1", "Coaxial", "Internal"}; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 3, texts); 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic int snd_rme9652_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 9808c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = rme9652_spdif_in(rme9652); 9818c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 9828c2ecf20Sopenharmony_ci return 0; 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_cistatic int snd_rme9652_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 9888c2ecf20Sopenharmony_ci int change; 9898c2ecf20Sopenharmony_ci unsigned int val; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci if (!snd_rme9652_use_is_exclusive(rme9652)) 9928c2ecf20Sopenharmony_ci return -EBUSY; 9938c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0] % 3; 9948c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 9958c2ecf20Sopenharmony_ci change = val != rme9652_spdif_in(rme9652); 9968c2ecf20Sopenharmony_ci if (change) 9978c2ecf20Sopenharmony_ci rme9652_set_spdif_input(rme9652, val); 9988c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 9998c2ecf20Sopenharmony_ci return change; 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci#define RME9652_SPDIF_OUT(xname, xindex) \ 10038c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 10048c2ecf20Sopenharmony_ci .info = snd_rme9652_info_spdif_out, \ 10058c2ecf20Sopenharmony_ci .get = snd_rme9652_get_spdif_out, .put = snd_rme9652_put_spdif_out } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cistatic int rme9652_spdif_out(struct snd_rme9652 *rme9652) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci return (rme9652->control_register & RME9652_opt_out) ? 1 : 0; 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_cistatic int rme9652_set_spdif_output(struct snd_rme9652 *rme9652, int out) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci int restart = 0; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (out) { 10178c2ecf20Sopenharmony_ci rme9652->control_register |= RME9652_opt_out; 10188c2ecf20Sopenharmony_ci } else { 10198c2ecf20Sopenharmony_ci rme9652->control_register &= ~RME9652_opt_out; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if ((restart = rme9652->running)) { 10238c2ecf20Sopenharmony_ci rme9652_stop(rme9652); 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (restart) { 10298c2ecf20Sopenharmony_ci rme9652_start(rme9652); 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci return 0; 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci#define snd_rme9652_info_spdif_out snd_ctl_boolean_mono_info 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_cistatic int snd_rme9652_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 10428c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = rme9652_spdif_out(rme9652); 10438c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 10448c2ecf20Sopenharmony_ci return 0; 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic int snd_rme9652_put_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 10508c2ecf20Sopenharmony_ci int change; 10518c2ecf20Sopenharmony_ci unsigned int val; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci if (!snd_rme9652_use_is_exclusive(rme9652)) 10548c2ecf20Sopenharmony_ci return -EBUSY; 10558c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0] & 1; 10568c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 10578c2ecf20Sopenharmony_ci change = (int)val != rme9652_spdif_out(rme9652); 10588c2ecf20Sopenharmony_ci rme9652_set_spdif_output(rme9652, val); 10598c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 10608c2ecf20Sopenharmony_ci return change; 10618c2ecf20Sopenharmony_ci} 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci#define RME9652_SYNC_MODE(xname, xindex) \ 10648c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 10658c2ecf20Sopenharmony_ci .info = snd_rme9652_info_sync_mode, \ 10668c2ecf20Sopenharmony_ci .get = snd_rme9652_get_sync_mode, .put = snd_rme9652_put_sync_mode } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cistatic int rme9652_sync_mode(struct snd_rme9652 *rme9652) 10698c2ecf20Sopenharmony_ci{ 10708c2ecf20Sopenharmony_ci if (rme9652->control_register & RME9652_wsel) { 10718c2ecf20Sopenharmony_ci return 2; 10728c2ecf20Sopenharmony_ci } else if (rme9652->control_register & RME9652_Master) { 10738c2ecf20Sopenharmony_ci return 1; 10748c2ecf20Sopenharmony_ci } else { 10758c2ecf20Sopenharmony_ci return 0; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci} 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_cistatic int rme9652_set_sync_mode(struct snd_rme9652 *rme9652, int mode) 10808c2ecf20Sopenharmony_ci{ 10818c2ecf20Sopenharmony_ci int restart = 0; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci switch (mode) { 10848c2ecf20Sopenharmony_ci case 0: 10858c2ecf20Sopenharmony_ci rme9652->control_register &= 10868c2ecf20Sopenharmony_ci ~(RME9652_Master | RME9652_wsel); 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci case 1: 10898c2ecf20Sopenharmony_ci rme9652->control_register = 10908c2ecf20Sopenharmony_ci (rme9652->control_register & ~RME9652_wsel) | RME9652_Master; 10918c2ecf20Sopenharmony_ci break; 10928c2ecf20Sopenharmony_ci case 2: 10938c2ecf20Sopenharmony_ci rme9652->control_register |= 10948c2ecf20Sopenharmony_ci (RME9652_Master | RME9652_wsel); 10958c2ecf20Sopenharmony_ci break; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if ((restart = rme9652->running)) { 10998c2ecf20Sopenharmony_ci rme9652_stop(rme9652); 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci if (restart) { 11058c2ecf20Sopenharmony_ci rme9652_start(rme9652); 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci return 0; 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cistatic int snd_rme9652_info_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 11128c2ecf20Sopenharmony_ci{ 11138c2ecf20Sopenharmony_ci static const char * const texts[3] = { 11148c2ecf20Sopenharmony_ci "AutoSync", "Master", "Word Clock" 11158c2ecf20Sopenharmony_ci }; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 3, texts); 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cistatic int snd_rme9652_get_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 11258c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = rme9652_sync_mode(rme9652); 11268c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 11278c2ecf20Sopenharmony_ci return 0; 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cistatic int snd_rme9652_put_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 11338c2ecf20Sopenharmony_ci int change; 11348c2ecf20Sopenharmony_ci unsigned int val; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0] % 3; 11378c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 11388c2ecf20Sopenharmony_ci change = (int)val != rme9652_sync_mode(rme9652); 11398c2ecf20Sopenharmony_ci rme9652_set_sync_mode(rme9652, val); 11408c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 11418c2ecf20Sopenharmony_ci return change; 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci#define RME9652_SYNC_PREF(xname, xindex) \ 11458c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 11468c2ecf20Sopenharmony_ci .info = snd_rme9652_info_sync_pref, \ 11478c2ecf20Sopenharmony_ci .get = snd_rme9652_get_sync_pref, .put = snd_rme9652_put_sync_pref } 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_cistatic int rme9652_sync_pref(struct snd_rme9652 *rme9652) 11508c2ecf20Sopenharmony_ci{ 11518c2ecf20Sopenharmony_ci switch (rme9652->control_register & RME9652_SyncPref_Mask) { 11528c2ecf20Sopenharmony_ci case RME9652_SyncPref_ADAT1: 11538c2ecf20Sopenharmony_ci return RME9652_SYNC_FROM_ADAT1; 11548c2ecf20Sopenharmony_ci case RME9652_SyncPref_ADAT2: 11558c2ecf20Sopenharmony_ci return RME9652_SYNC_FROM_ADAT2; 11568c2ecf20Sopenharmony_ci case RME9652_SyncPref_ADAT3: 11578c2ecf20Sopenharmony_ci return RME9652_SYNC_FROM_ADAT3; 11588c2ecf20Sopenharmony_ci case RME9652_SyncPref_SPDIF: 11598c2ecf20Sopenharmony_ci return RME9652_SYNC_FROM_SPDIF; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci /* Not reachable */ 11628c2ecf20Sopenharmony_ci return 0; 11638c2ecf20Sopenharmony_ci} 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_cistatic int rme9652_set_sync_pref(struct snd_rme9652 *rme9652, int pref) 11668c2ecf20Sopenharmony_ci{ 11678c2ecf20Sopenharmony_ci int restart; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci rme9652->control_register &= ~RME9652_SyncPref_Mask; 11708c2ecf20Sopenharmony_ci switch (pref) { 11718c2ecf20Sopenharmony_ci case RME9652_SYNC_FROM_ADAT1: 11728c2ecf20Sopenharmony_ci rme9652->control_register |= RME9652_SyncPref_ADAT1; 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci case RME9652_SYNC_FROM_ADAT2: 11758c2ecf20Sopenharmony_ci rme9652->control_register |= RME9652_SyncPref_ADAT2; 11768c2ecf20Sopenharmony_ci break; 11778c2ecf20Sopenharmony_ci case RME9652_SYNC_FROM_ADAT3: 11788c2ecf20Sopenharmony_ci rme9652->control_register |= RME9652_SyncPref_ADAT3; 11798c2ecf20Sopenharmony_ci break; 11808c2ecf20Sopenharmony_ci case RME9652_SYNC_FROM_SPDIF: 11818c2ecf20Sopenharmony_ci rme9652->control_register |= RME9652_SyncPref_SPDIF; 11828c2ecf20Sopenharmony_ci break; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci if ((restart = rme9652->running)) { 11868c2ecf20Sopenharmony_ci rme9652_stop(rme9652); 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci if (restart) { 11928c2ecf20Sopenharmony_ci rme9652_start(rme9652); 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci return 0; 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic int snd_rme9652_info_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci static const char * const texts[4] = { 12018c2ecf20Sopenharmony_ci "IEC958 In", "ADAT1 In", "ADAT2 In", "ADAT3 In" 12028c2ecf20Sopenharmony_ci }; 12038c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 12068c2ecf20Sopenharmony_ci rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3, 12078c2ecf20Sopenharmony_ci texts); 12088c2ecf20Sopenharmony_ci} 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_cistatic int snd_rme9652_get_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 12118c2ecf20Sopenharmony_ci{ 12128c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 12158c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = rme9652_sync_pref(rme9652); 12168c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 12178c2ecf20Sopenharmony_ci return 0; 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_cistatic int snd_rme9652_put_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 12238c2ecf20Sopenharmony_ci int change, max; 12248c2ecf20Sopenharmony_ci unsigned int val; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (!snd_rme9652_use_is_exclusive(rme9652)) 12278c2ecf20Sopenharmony_ci return -EBUSY; 12288c2ecf20Sopenharmony_ci max = rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3; 12298c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0] % max; 12308c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 12318c2ecf20Sopenharmony_ci change = (int)val != rme9652_sync_pref(rme9652); 12328c2ecf20Sopenharmony_ci rme9652_set_sync_pref(rme9652, val); 12338c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 12348c2ecf20Sopenharmony_ci return change; 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic int snd_rme9652_info_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 12408c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 12418c2ecf20Sopenharmony_ci uinfo->count = rme9652->ss_channels; 12428c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 12438c2ecf20Sopenharmony_ci uinfo->value.integer.max = 1; 12448c2ecf20Sopenharmony_ci return 0; 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic int snd_rme9652_get_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 12488c2ecf20Sopenharmony_ci{ 12498c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 12508c2ecf20Sopenharmony_ci unsigned int k; 12518c2ecf20Sopenharmony_ci u32 thru_bits = rme9652->thru_bits; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci for (k = 0; k < rme9652->ss_channels; ++k) { 12548c2ecf20Sopenharmony_ci ucontrol->value.integer.value[k] = !!(thru_bits & (1 << k)); 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci return 0; 12578c2ecf20Sopenharmony_ci} 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_cistatic int snd_rme9652_put_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 12628c2ecf20Sopenharmony_ci int change; 12638c2ecf20Sopenharmony_ci unsigned int chn; 12648c2ecf20Sopenharmony_ci u32 thru_bits = 0; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci if (!snd_rme9652_use_is_exclusive(rme9652)) 12678c2ecf20Sopenharmony_ci return -EBUSY; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci for (chn = 0; chn < rme9652->ss_channels; ++chn) { 12708c2ecf20Sopenharmony_ci if (ucontrol->value.integer.value[chn]) 12718c2ecf20Sopenharmony_ci thru_bits |= 1 << chn; 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 12758c2ecf20Sopenharmony_ci change = thru_bits ^ rme9652->thru_bits; 12768c2ecf20Sopenharmony_ci if (change) { 12778c2ecf20Sopenharmony_ci for (chn = 0; chn < rme9652->ss_channels; ++chn) { 12788c2ecf20Sopenharmony_ci if (!(change & (1 << chn))) 12798c2ecf20Sopenharmony_ci continue; 12808c2ecf20Sopenharmony_ci rme9652_set_thru(rme9652,chn,thru_bits&(1<<chn)); 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 12848c2ecf20Sopenharmony_ci return !!change; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci#define RME9652_PASSTHRU(xname, xindex) \ 12888c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 12898c2ecf20Sopenharmony_ci .info = snd_rme9652_info_passthru, \ 12908c2ecf20Sopenharmony_ci .put = snd_rme9652_put_passthru, \ 12918c2ecf20Sopenharmony_ci .get = snd_rme9652_get_passthru } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci#define snd_rme9652_info_passthru snd_ctl_boolean_mono_info 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic int snd_rme9652_get_passthru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 12968c2ecf20Sopenharmony_ci{ 12978c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 13008c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = rme9652->passthru; 13018c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 13028c2ecf20Sopenharmony_ci return 0; 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cistatic int snd_rme9652_put_passthru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 13088c2ecf20Sopenharmony_ci int change; 13098c2ecf20Sopenharmony_ci unsigned int val; 13108c2ecf20Sopenharmony_ci int err = 0; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci if (!snd_rme9652_use_is_exclusive(rme9652)) 13138c2ecf20Sopenharmony_ci return -EBUSY; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0] & 1; 13168c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 13178c2ecf20Sopenharmony_ci change = (ucontrol->value.integer.value[0] != rme9652->passthru); 13188c2ecf20Sopenharmony_ci if (change) 13198c2ecf20Sopenharmony_ci err = rme9652_set_passthru(rme9652, val); 13208c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 13218c2ecf20Sopenharmony_ci return err ? err : change; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci/* Read-only switches */ 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci#define RME9652_SPDIF_RATE(xname, xindex) \ 13278c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 13288c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 13298c2ecf20Sopenharmony_ci .info = snd_rme9652_info_spdif_rate, \ 13308c2ecf20Sopenharmony_ci .get = snd_rme9652_get_spdif_rate } 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cistatic int snd_rme9652_info_spdif_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13358c2ecf20Sopenharmony_ci uinfo->count = 1; 13368c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 13378c2ecf20Sopenharmony_ci uinfo->value.integer.max = 96000; 13388c2ecf20Sopenharmony_ci return 0; 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic int snd_rme9652_get_spdif_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 13468c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = rme9652_spdif_sample_rate(rme9652); 13478c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 13488c2ecf20Sopenharmony_ci return 0; 13498c2ecf20Sopenharmony_ci} 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci#define RME9652_ADAT_SYNC(xname, xindex, xidx) \ 13528c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 13538c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 13548c2ecf20Sopenharmony_ci .info = snd_rme9652_info_adat_sync, \ 13558c2ecf20Sopenharmony_ci .get = snd_rme9652_get_adat_sync, .private_value = xidx } 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_cistatic int snd_rme9652_info_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13588c2ecf20Sopenharmony_ci{ 13598c2ecf20Sopenharmony_ci static const char * const texts[4] = { 13608c2ecf20Sopenharmony_ci "No Lock", "Lock", "No Lock Sync", "Lock Sync" 13618c2ecf20Sopenharmony_ci }; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 4, texts); 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_cistatic int snd_rme9652_get_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 13678c2ecf20Sopenharmony_ci{ 13688c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 13698c2ecf20Sopenharmony_ci unsigned int mask1, mask2, val; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci switch (kcontrol->private_value) { 13728c2ecf20Sopenharmony_ci case 0: mask1 = RME9652_lock_0; mask2 = RME9652_sync_0; break; 13738c2ecf20Sopenharmony_ci case 1: mask1 = RME9652_lock_1; mask2 = RME9652_sync_1; break; 13748c2ecf20Sopenharmony_ci case 2: mask1 = RME9652_lock_2; mask2 = RME9652_sync_2; break; 13758c2ecf20Sopenharmony_ci default: return -EINVAL; 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci val = rme9652_read(rme9652, RME9652_status_register); 13788c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = (val & mask1) ? 1 : 0; 13798c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] |= (val & mask2) ? 2 : 0; 13808c2ecf20Sopenharmony_ci return 0; 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci#define RME9652_TC_VALID(xname, xindex) \ 13848c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 13858c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 13868c2ecf20Sopenharmony_ci .info = snd_rme9652_info_tc_valid, \ 13878c2ecf20Sopenharmony_ci .get = snd_rme9652_get_tc_valid } 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci#define snd_rme9652_info_tc_valid snd_ctl_boolean_mono_info 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_cistatic int snd_rme9652_get_tc_valid(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 13928c2ecf20Sopenharmony_ci{ 13938c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 13968c2ecf20Sopenharmony_ci (rme9652_read(rme9652, RME9652_status_register) & RME9652_tc_valid) ? 1 : 0; 13978c2ecf20Sopenharmony_ci return 0; 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci#ifdef ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci/* FIXME: this routine needs a port to the new control API --jk */ 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_cistatic int snd_rme9652_get_tc_value(void *private_data, 14058c2ecf20Sopenharmony_ci snd_kswitch_t *kswitch, 14068c2ecf20Sopenharmony_ci snd_switch_t *uswitch) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci struct snd_rme9652 *s = (struct snd_rme9652 *) private_data; 14098c2ecf20Sopenharmony_ci u32 value; 14108c2ecf20Sopenharmony_ci int i; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci uswitch->type = SNDRV_SW_TYPE_DWORD; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci if ((rme9652_read(s, RME9652_status_register) & 14158c2ecf20Sopenharmony_ci RME9652_tc_valid) == 0) { 14168c2ecf20Sopenharmony_ci uswitch->value.data32[0] = 0; 14178c2ecf20Sopenharmony_ci return 0; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* timecode request */ 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci rme9652_write(s, RME9652_time_code, 0); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci /* XXX bug alert: loop-based timing !!!! */ 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci for (i = 0; i < 50; i++) { 14278c2ecf20Sopenharmony_ci if (!(rme9652_read(s, i * 4) & RME9652_tc_busy)) 14288c2ecf20Sopenharmony_ci break; 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci if (!(rme9652_read(s, i * 4) & RME9652_tc_busy)) { 14328c2ecf20Sopenharmony_ci return -EIO; 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci value = 0; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 14388c2ecf20Sopenharmony_ci value >>= 1; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci if (rme9652_read(s, i * 4) & RME9652_tc_out) 14418c2ecf20Sopenharmony_ci value |= 0x80000000; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci if (value > 2 * 60 * 48000) { 14458c2ecf20Sopenharmony_ci value -= 2 * 60 * 48000; 14468c2ecf20Sopenharmony_ci } else { 14478c2ecf20Sopenharmony_ci value = 0; 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci uswitch->value.data32[0] = value; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci return 0; 14538c2ecf20Sopenharmony_ci} 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci#endif /* ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE */ 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_rme9652_controls[] = { 14588c2ecf20Sopenharmony_ci{ 14598c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14608c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 14618c2ecf20Sopenharmony_ci .info = snd_rme9652_control_spdif_info, 14628c2ecf20Sopenharmony_ci .get = snd_rme9652_control_spdif_get, 14638c2ecf20Sopenharmony_ci .put = snd_rme9652_control_spdif_put, 14648c2ecf20Sopenharmony_ci}, 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 14678c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14688c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM), 14698c2ecf20Sopenharmony_ci .info = snd_rme9652_control_spdif_stream_info, 14708c2ecf20Sopenharmony_ci .get = snd_rme9652_control_spdif_stream_get, 14718c2ecf20Sopenharmony_ci .put = snd_rme9652_control_spdif_stream_put, 14728c2ecf20Sopenharmony_ci}, 14738c2ecf20Sopenharmony_ci{ 14748c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 14758c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14768c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), 14778c2ecf20Sopenharmony_ci .info = snd_rme9652_control_spdif_mask_info, 14788c2ecf20Sopenharmony_ci .get = snd_rme9652_control_spdif_mask_get, 14798c2ecf20Sopenharmony_ci .private_value = IEC958_AES0_NONAUDIO | 14808c2ecf20Sopenharmony_ci IEC958_AES0_PROFESSIONAL | 14818c2ecf20Sopenharmony_ci IEC958_AES0_CON_EMPHASIS, 14828c2ecf20Sopenharmony_ci}, 14838c2ecf20Sopenharmony_ci{ 14848c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 14858c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14868c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), 14878c2ecf20Sopenharmony_ci .info = snd_rme9652_control_spdif_mask_info, 14888c2ecf20Sopenharmony_ci .get = snd_rme9652_control_spdif_mask_get, 14898c2ecf20Sopenharmony_ci .private_value = IEC958_AES0_NONAUDIO | 14908c2ecf20Sopenharmony_ci IEC958_AES0_PROFESSIONAL | 14918c2ecf20Sopenharmony_ci IEC958_AES0_PRO_EMPHASIS, 14928c2ecf20Sopenharmony_ci}, 14938c2ecf20Sopenharmony_ciRME9652_SPDIF_IN("IEC958 Input Connector", 0), 14948c2ecf20Sopenharmony_ciRME9652_SPDIF_OUT("IEC958 Output also on ADAT1", 0), 14958c2ecf20Sopenharmony_ciRME9652_SYNC_MODE("Sync Mode", 0), 14968c2ecf20Sopenharmony_ciRME9652_SYNC_PREF("Preferred Sync Source", 0), 14978c2ecf20Sopenharmony_ci{ 14988c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 14998c2ecf20Sopenharmony_ci .name = "Channels Thru", 15008c2ecf20Sopenharmony_ci .index = 0, 15018c2ecf20Sopenharmony_ci .info = snd_rme9652_info_thru, 15028c2ecf20Sopenharmony_ci .get = snd_rme9652_get_thru, 15038c2ecf20Sopenharmony_ci .put = snd_rme9652_put_thru, 15048c2ecf20Sopenharmony_ci}, 15058c2ecf20Sopenharmony_ciRME9652_SPDIF_RATE("IEC958 Sample Rate", 0), 15068c2ecf20Sopenharmony_ciRME9652_ADAT_SYNC("ADAT1 Sync Check", 0, 0), 15078c2ecf20Sopenharmony_ciRME9652_ADAT_SYNC("ADAT2 Sync Check", 0, 1), 15088c2ecf20Sopenharmony_ciRME9652_TC_VALID("Timecode Valid", 0), 15098c2ecf20Sopenharmony_ciRME9652_PASSTHRU("Passthru", 0) 15108c2ecf20Sopenharmony_ci}; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_rme9652_adat3_check = 15138c2ecf20Sopenharmony_ciRME9652_ADAT_SYNC("ADAT3 Sync Check", 0, 2); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_rme9652_adat1_input = 15168c2ecf20Sopenharmony_ciRME9652_ADAT1_IN("ADAT1 Input Source", 0); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_cistatic int snd_rme9652_create_controls(struct snd_card *card, struct snd_rme9652 *rme9652) 15198c2ecf20Sopenharmony_ci{ 15208c2ecf20Sopenharmony_ci unsigned int idx; 15218c2ecf20Sopenharmony_ci int err; 15228c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(snd_rme9652_controls); idx++) { 15258c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_controls[idx], rme9652))) < 0) 15268c2ecf20Sopenharmony_ci return err; 15278c2ecf20Sopenharmony_ci if (idx == 1) /* IEC958 (S/PDIF) Stream */ 15288c2ecf20Sopenharmony_ci rme9652->spdif_ctl = kctl; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if (rme9652->ss_channels == RME9652_NCHANNELS) 15328c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_adat3_check, rme9652))) < 0) 15338c2ecf20Sopenharmony_ci return err; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (rme9652->hw_rev >= 15) 15368c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_adat1_input, rme9652))) < 0) 15378c2ecf20Sopenharmony_ci return err; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci return 0; 15408c2ecf20Sopenharmony_ci} 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci/*------------------------------------------------------------ 15438c2ecf20Sopenharmony_ci /proc interface 15448c2ecf20Sopenharmony_ci ------------------------------------------------------------*/ 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_cistatic void 15478c2ecf20Sopenharmony_cisnd_rme9652_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 15488c2ecf20Sopenharmony_ci{ 15498c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) entry->private_data; 15508c2ecf20Sopenharmony_ci u32 thru_bits = rme9652->thru_bits; 15518c2ecf20Sopenharmony_ci int show_auto_sync_source = 0; 15528c2ecf20Sopenharmony_ci int i; 15538c2ecf20Sopenharmony_ci unsigned int status; 15548c2ecf20Sopenharmony_ci int x; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci status = rme9652_read(rme9652, RME9652_status_register); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%s (Card #%d)\n", rme9652->card_name, rme9652->card->number + 1); 15598c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Buffers: capture %p playback %p\n", 15608c2ecf20Sopenharmony_ci rme9652->capture_buffer, rme9652->playback_buffer); 15618c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", 15628c2ecf20Sopenharmony_ci rme9652->irq, rme9652->port, (unsigned long)rme9652->iobase); 15638c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Control register: %x\n", rme9652->control_register); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci x = 1 << (6 + rme9652_decode_latency(rme9652->control_register & 15688c2ecf20Sopenharmony_ci RME9652_latency)); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Latency: %d samples (2 periods of %lu bytes)\n", 15718c2ecf20Sopenharmony_ci x, (unsigned long) rme9652->period_bytes); 15728c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Hardware pointer (frames): %ld\n", 15738c2ecf20Sopenharmony_ci rme9652_hw_pointer(rme9652)); 15748c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Passthru: %s\n", 15758c2ecf20Sopenharmony_ci rme9652->passthru ? "yes" : "no"); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci if ((rme9652->control_register & (RME9652_Master | RME9652_wsel)) == 0) { 15788c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Clock mode: autosync\n"); 15798c2ecf20Sopenharmony_ci show_auto_sync_source = 1; 15808c2ecf20Sopenharmony_ci } else if (rme9652->control_register & RME9652_wsel) { 15818c2ecf20Sopenharmony_ci if (status & RME9652_wsel_rd) { 15828c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Clock mode: word clock\n"); 15838c2ecf20Sopenharmony_ci } else { 15848c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Clock mode: word clock (no signal)\n"); 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci } else { 15878c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Clock mode: master\n"); 15888c2ecf20Sopenharmony_ci } 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci if (show_auto_sync_source) { 15918c2ecf20Sopenharmony_ci switch (rme9652->control_register & RME9652_SyncPref_Mask) { 15928c2ecf20Sopenharmony_ci case RME9652_SyncPref_ADAT1: 15938c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Pref. sync source: ADAT1\n"); 15948c2ecf20Sopenharmony_ci break; 15958c2ecf20Sopenharmony_ci case RME9652_SyncPref_ADAT2: 15968c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Pref. sync source: ADAT2\n"); 15978c2ecf20Sopenharmony_ci break; 15988c2ecf20Sopenharmony_ci case RME9652_SyncPref_ADAT3: 15998c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Pref. sync source: ADAT3\n"); 16008c2ecf20Sopenharmony_ci break; 16018c2ecf20Sopenharmony_ci case RME9652_SyncPref_SPDIF: 16028c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Pref. sync source: IEC958\n"); 16038c2ecf20Sopenharmony_ci break; 16048c2ecf20Sopenharmony_ci default: 16058c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Pref. sync source: ???\n"); 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci if (rme9652->hw_rev >= 15) 16108c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\nADAT1 Input source: %s\n", 16118c2ecf20Sopenharmony_ci (rme9652->control_register & RME9652_ADAT1_INTERNAL) ? 16128c2ecf20Sopenharmony_ci "Internal" : "ADAT1 optical"); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci switch (rme9652_decode_spdif_in(rme9652->control_register & 16178c2ecf20Sopenharmony_ci RME9652_inp)) { 16188c2ecf20Sopenharmony_ci case RME9652_SPDIFIN_OPTICAL: 16198c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 input: ADAT1\n"); 16208c2ecf20Sopenharmony_ci break; 16218c2ecf20Sopenharmony_ci case RME9652_SPDIFIN_COAXIAL: 16228c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 input: Coaxial\n"); 16238c2ecf20Sopenharmony_ci break; 16248c2ecf20Sopenharmony_ci case RME9652_SPDIFIN_INTERN: 16258c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 input: Internal\n"); 16268c2ecf20Sopenharmony_ci break; 16278c2ecf20Sopenharmony_ci default: 16288c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 input: ???\n"); 16298c2ecf20Sopenharmony_ci break; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci if (rme9652->control_register & RME9652_opt_out) { 16338c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n"); 16348c2ecf20Sopenharmony_ci } else { 16358c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 output: Coaxial only\n"); 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (rme9652->control_register & RME9652_PRO) { 16398c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 quality: Professional\n"); 16408c2ecf20Sopenharmony_ci } else { 16418c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 quality: Consumer\n"); 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (rme9652->control_register & RME9652_EMP) { 16458c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 emphasis: on\n"); 16468c2ecf20Sopenharmony_ci } else { 16478c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 emphasis: off\n"); 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci if (rme9652->control_register & RME9652_Dolby) { 16518c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 Dolby: on\n"); 16528c2ecf20Sopenharmony_ci } else { 16538c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 Dolby: off\n"); 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci i = rme9652_spdif_sample_rate(rme9652); 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (i < 0) { 16598c2ecf20Sopenharmony_ci snd_iprintf(buffer, 16608c2ecf20Sopenharmony_ci "IEC958 sample rate: error flag set\n"); 16618c2ecf20Sopenharmony_ci } else if (i == 0) { 16628c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 sample rate: undetermined\n"); 16638c2ecf20Sopenharmony_ci } else { 16648c2ecf20Sopenharmony_ci snd_iprintf(buffer, "IEC958 sample rate: %d\n", i); 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci snd_iprintf(buffer, "ADAT Sample rate: %dHz\n", 16708c2ecf20Sopenharmony_ci rme9652_adat_sample_rate(rme9652)); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci /* Sync Check */ 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci x = status & RME9652_sync_0; 16758c2ecf20Sopenharmony_ci if (status & RME9652_lock_0) { 16768c2ecf20Sopenharmony_ci snd_iprintf(buffer, "ADAT1: %s\n", x ? "Sync" : "Lock"); 16778c2ecf20Sopenharmony_ci } else { 16788c2ecf20Sopenharmony_ci snd_iprintf(buffer, "ADAT1: No Lock\n"); 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci x = status & RME9652_sync_1; 16828c2ecf20Sopenharmony_ci if (status & RME9652_lock_1) { 16838c2ecf20Sopenharmony_ci snd_iprintf(buffer, "ADAT2: %s\n", x ? "Sync" : "Lock"); 16848c2ecf20Sopenharmony_ci } else { 16858c2ecf20Sopenharmony_ci snd_iprintf(buffer, "ADAT2: No Lock\n"); 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci x = status & RME9652_sync_2; 16898c2ecf20Sopenharmony_ci if (status & RME9652_lock_2) { 16908c2ecf20Sopenharmony_ci snd_iprintf(buffer, "ADAT3: %s\n", x ? "Sync" : "Lock"); 16918c2ecf20Sopenharmony_ci } else { 16928c2ecf20Sopenharmony_ci snd_iprintf(buffer, "ADAT3: No Lock\n"); 16938c2ecf20Sopenharmony_ci } 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Timecode signal: %s\n", 16988c2ecf20Sopenharmony_ci (status & RME9652_tc_valid) ? "yes" : "no"); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci /* thru modes */ 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Punch Status:\n\n"); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci for (i = 0; i < rme9652->ss_channels; i++) { 17058c2ecf20Sopenharmony_ci if (thru_bits & (1 << i)) { 17068c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%2d: on ", i + 1); 17078c2ecf20Sopenharmony_ci } else { 17088c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%2d: off ", i + 1); 17098c2ecf20Sopenharmony_ci } 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci if (((i + 1) % 8) == 0) { 17128c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 17178c2ecf20Sopenharmony_ci} 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_cistatic void snd_rme9652_proc_init(struct snd_rme9652 *rme9652) 17208c2ecf20Sopenharmony_ci{ 17218c2ecf20Sopenharmony_ci snd_card_ro_proc_new(rme9652->card, "rme9652", rme9652, 17228c2ecf20Sopenharmony_ci snd_rme9652_proc_read); 17238c2ecf20Sopenharmony_ci} 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_cistatic void snd_rme9652_free_buffers(struct snd_rme9652 *rme9652) 17268c2ecf20Sopenharmony_ci{ 17278c2ecf20Sopenharmony_ci snd_hammerfall_free_buffer(&rme9652->capture_dma_buf, rme9652->pci); 17288c2ecf20Sopenharmony_ci snd_hammerfall_free_buffer(&rme9652->playback_dma_buf, rme9652->pci); 17298c2ecf20Sopenharmony_ci} 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_cistatic int snd_rme9652_free(struct snd_rme9652 *rme9652) 17328c2ecf20Sopenharmony_ci{ 17338c2ecf20Sopenharmony_ci if (rme9652->irq >= 0) 17348c2ecf20Sopenharmony_ci rme9652_stop(rme9652); 17358c2ecf20Sopenharmony_ci snd_rme9652_free_buffers(rme9652); 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci if (rme9652->irq >= 0) 17388c2ecf20Sopenharmony_ci free_irq(rme9652->irq, (void *)rme9652); 17398c2ecf20Sopenharmony_ci iounmap(rme9652->iobase); 17408c2ecf20Sopenharmony_ci if (rme9652->port) 17418c2ecf20Sopenharmony_ci pci_release_regions(rme9652->pci); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci if (pci_is_enabled(rme9652->pci)) 17448c2ecf20Sopenharmony_ci pci_disable_device(rme9652->pci); 17458c2ecf20Sopenharmony_ci return 0; 17468c2ecf20Sopenharmony_ci} 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_cistatic int snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652) 17498c2ecf20Sopenharmony_ci{ 17508c2ecf20Sopenharmony_ci unsigned long pb_bus, cb_bus; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci if (snd_hammerfall_get_buffer(rme9652->pci, &rme9652->capture_dma_buf, RME9652_DMA_AREA_BYTES) < 0 || 17538c2ecf20Sopenharmony_ci snd_hammerfall_get_buffer(rme9652->pci, &rme9652->playback_dma_buf, RME9652_DMA_AREA_BYTES) < 0) { 17548c2ecf20Sopenharmony_ci if (rme9652->capture_dma_buf.area) 17558c2ecf20Sopenharmony_ci snd_dma_free_pages(&rme9652->capture_dma_buf); 17568c2ecf20Sopenharmony_ci dev_err(rme9652->card->dev, 17578c2ecf20Sopenharmony_ci "%s: no buffers available\n", rme9652->card_name); 17588c2ecf20Sopenharmony_ci return -ENOMEM; 17598c2ecf20Sopenharmony_ci } 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci /* Align to bus-space 64K boundary */ 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci cb_bus = ALIGN(rme9652->capture_dma_buf.addr, 0x10000ul); 17648c2ecf20Sopenharmony_ci pb_bus = ALIGN(rme9652->playback_dma_buf.addr, 0x10000ul); 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci /* Tell the card where it is */ 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_rec_buffer, cb_bus); 17698c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_play_buffer, pb_bus); 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci rme9652->capture_buffer = rme9652->capture_dma_buf.area + (cb_bus - rme9652->capture_dma_buf.addr); 17728c2ecf20Sopenharmony_ci rme9652->playback_buffer = rme9652->playback_dma_buf.area + (pb_bus - rme9652->playback_dma_buf.addr); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci return 0; 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_cistatic void snd_rme9652_set_defaults(struct snd_rme9652 *rme9652) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci unsigned int k; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci /* ASSUMPTION: rme9652->lock is either held, or 17828c2ecf20Sopenharmony_ci there is no need to hold it (e.g. during module 17838c2ecf20Sopenharmony_ci initialization). 17848c2ecf20Sopenharmony_ci */ 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci /* set defaults: 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci SPDIF Input via Coax 17898c2ecf20Sopenharmony_ci autosync clock mode 17908c2ecf20Sopenharmony_ci maximum latency (7 = 8192 samples, 64Kbyte buffer, 17918c2ecf20Sopenharmony_ci which implies 2 4096 sample, 32Kbyte periods). 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci if rev 1.5, initialize the S/PDIF receiver. 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci */ 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci rme9652->control_register = 17988c2ecf20Sopenharmony_ci RME9652_inp_0 | rme9652_encode_latency(7); 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci rme9652_reset_hw_pointer(rme9652); 18038c2ecf20Sopenharmony_ci rme9652_compute_period_size(rme9652); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci /* default: thru off for all channels */ 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci for (k = 0; k < RME9652_NCHANNELS; ++k) 18088c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_thru_base + k * 4, 0); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci rme9652->thru_bits = 0; 18118c2ecf20Sopenharmony_ci rme9652->passthru = 0; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci /* set a default rate so that the channel map is set up */ 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci rme9652_set_rate(rme9652, 48000); 18168c2ecf20Sopenharmony_ci} 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_cistatic irqreturn_t snd_rme9652_interrupt(int irq, void *dev_id) 18198c2ecf20Sopenharmony_ci{ 18208c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) dev_id; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci if (!(rme9652_read(rme9652, RME9652_status_register) & RME9652_IRQ)) { 18238c2ecf20Sopenharmony_ci return IRQ_NONE; 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_irq_clear, 0); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci if (rme9652->capture_substream) { 18298c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(rme9652->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); 18308c2ecf20Sopenharmony_ci } 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci if (rme9652->playback_substream) { 18338c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(rme9652->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream); 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_ci return IRQ_HANDLED; 18368c2ecf20Sopenharmony_ci} 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t snd_rme9652_hw_pointer(struct snd_pcm_substream *substream) 18398c2ecf20Sopenharmony_ci{ 18408c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 18418c2ecf20Sopenharmony_ci return rme9652_hw_pointer(rme9652); 18428c2ecf20Sopenharmony_ci} 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_cistatic signed char *rme9652_channel_buffer_location(struct snd_rme9652 *rme9652, 18458c2ecf20Sopenharmony_ci int stream, 18468c2ecf20Sopenharmony_ci int channel) 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci{ 18498c2ecf20Sopenharmony_ci int mapped_channel; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci if (snd_BUG_ON(channel < 0 || channel >= RME9652_NCHANNELS)) 18528c2ecf20Sopenharmony_ci return NULL; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci if ((mapped_channel = rme9652->channel_map[channel]) < 0) { 18558c2ecf20Sopenharmony_ci return NULL; 18568c2ecf20Sopenharmony_ci } 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_CAPTURE) { 18598c2ecf20Sopenharmony_ci return rme9652->capture_buffer + 18608c2ecf20Sopenharmony_ci (mapped_channel * RME9652_CHANNEL_BUFFER_BYTES); 18618c2ecf20Sopenharmony_ci } else { 18628c2ecf20Sopenharmony_ci return rme9652->playback_buffer + 18638c2ecf20Sopenharmony_ci (mapped_channel * RME9652_CHANNEL_BUFFER_BYTES); 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_cistatic int snd_rme9652_playback_copy(struct snd_pcm_substream *substream, 18688c2ecf20Sopenharmony_ci int channel, unsigned long pos, 18698c2ecf20Sopenharmony_ci void __user *src, unsigned long count) 18708c2ecf20Sopenharmony_ci{ 18718c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 18728c2ecf20Sopenharmony_ci signed char *channel_buf; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES)) 18758c2ecf20Sopenharmony_ci return -EINVAL; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci channel_buf = rme9652_channel_buffer_location (rme9652, 18788c2ecf20Sopenharmony_ci substream->pstr->stream, 18798c2ecf20Sopenharmony_ci channel); 18808c2ecf20Sopenharmony_ci if (snd_BUG_ON(!channel_buf)) 18818c2ecf20Sopenharmony_ci return -EIO; 18828c2ecf20Sopenharmony_ci if (copy_from_user(channel_buf + pos, src, count)) 18838c2ecf20Sopenharmony_ci return -EFAULT; 18848c2ecf20Sopenharmony_ci return 0; 18858c2ecf20Sopenharmony_ci} 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_cistatic int snd_rme9652_playback_copy_kernel(struct snd_pcm_substream *substream, 18888c2ecf20Sopenharmony_ci int channel, unsigned long pos, 18898c2ecf20Sopenharmony_ci void *src, unsigned long count) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 18928c2ecf20Sopenharmony_ci signed char *channel_buf; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci channel_buf = rme9652_channel_buffer_location(rme9652, 18958c2ecf20Sopenharmony_ci substream->pstr->stream, 18968c2ecf20Sopenharmony_ci channel); 18978c2ecf20Sopenharmony_ci if (snd_BUG_ON(!channel_buf)) 18988c2ecf20Sopenharmony_ci return -EIO; 18998c2ecf20Sopenharmony_ci memcpy(channel_buf + pos, src, count); 19008c2ecf20Sopenharmony_ci return 0; 19018c2ecf20Sopenharmony_ci} 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_cistatic int snd_rme9652_capture_copy(struct snd_pcm_substream *substream, 19048c2ecf20Sopenharmony_ci int channel, unsigned long pos, 19058c2ecf20Sopenharmony_ci void __user *dst, unsigned long count) 19068c2ecf20Sopenharmony_ci{ 19078c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 19088c2ecf20Sopenharmony_ci signed char *channel_buf; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES)) 19118c2ecf20Sopenharmony_ci return -EINVAL; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci channel_buf = rme9652_channel_buffer_location (rme9652, 19148c2ecf20Sopenharmony_ci substream->pstr->stream, 19158c2ecf20Sopenharmony_ci channel); 19168c2ecf20Sopenharmony_ci if (snd_BUG_ON(!channel_buf)) 19178c2ecf20Sopenharmony_ci return -EIO; 19188c2ecf20Sopenharmony_ci if (copy_to_user(dst, channel_buf + pos, count)) 19198c2ecf20Sopenharmony_ci return -EFAULT; 19208c2ecf20Sopenharmony_ci return 0; 19218c2ecf20Sopenharmony_ci} 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_cistatic int snd_rme9652_capture_copy_kernel(struct snd_pcm_substream *substream, 19248c2ecf20Sopenharmony_ci int channel, unsigned long pos, 19258c2ecf20Sopenharmony_ci void *dst, unsigned long count) 19268c2ecf20Sopenharmony_ci{ 19278c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 19288c2ecf20Sopenharmony_ci signed char *channel_buf; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci channel_buf = rme9652_channel_buffer_location(rme9652, 19318c2ecf20Sopenharmony_ci substream->pstr->stream, 19328c2ecf20Sopenharmony_ci channel); 19338c2ecf20Sopenharmony_ci if (snd_BUG_ON(!channel_buf)) 19348c2ecf20Sopenharmony_ci return -EIO; 19358c2ecf20Sopenharmony_ci memcpy(dst, channel_buf + pos, count); 19368c2ecf20Sopenharmony_ci return 0; 19378c2ecf20Sopenharmony_ci} 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_cistatic int snd_rme9652_hw_silence(struct snd_pcm_substream *substream, 19408c2ecf20Sopenharmony_ci int channel, unsigned long pos, 19418c2ecf20Sopenharmony_ci unsigned long count) 19428c2ecf20Sopenharmony_ci{ 19438c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 19448c2ecf20Sopenharmony_ci signed char *channel_buf; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci channel_buf = rme9652_channel_buffer_location (rme9652, 19478c2ecf20Sopenharmony_ci substream->pstr->stream, 19488c2ecf20Sopenharmony_ci channel); 19498c2ecf20Sopenharmony_ci if (snd_BUG_ON(!channel_buf)) 19508c2ecf20Sopenharmony_ci return -EIO; 19518c2ecf20Sopenharmony_ci memset(channel_buf + pos, 0, count); 19528c2ecf20Sopenharmony_ci return 0; 19538c2ecf20Sopenharmony_ci} 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_cistatic int snd_rme9652_reset(struct snd_pcm_substream *substream) 19568c2ecf20Sopenharmony_ci{ 19578c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 19588c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 19598c2ecf20Sopenharmony_ci struct snd_pcm_substream *other; 19608c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 19618c2ecf20Sopenharmony_ci other = rme9652->capture_substream; 19628c2ecf20Sopenharmony_ci else 19638c2ecf20Sopenharmony_ci other = rme9652->playback_substream; 19648c2ecf20Sopenharmony_ci if (rme9652->running) 19658c2ecf20Sopenharmony_ci runtime->status->hw_ptr = rme9652_hw_pointer(rme9652); 19668c2ecf20Sopenharmony_ci else 19678c2ecf20Sopenharmony_ci runtime->status->hw_ptr = 0; 19688c2ecf20Sopenharmony_ci if (other) { 19698c2ecf20Sopenharmony_ci struct snd_pcm_substream *s; 19708c2ecf20Sopenharmony_ci struct snd_pcm_runtime *oruntime = other->runtime; 19718c2ecf20Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 19728c2ecf20Sopenharmony_ci if (s == other) { 19738c2ecf20Sopenharmony_ci oruntime->status->hw_ptr = runtime->status->hw_ptr; 19748c2ecf20Sopenharmony_ci break; 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci } 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci return 0; 19798c2ecf20Sopenharmony_ci} 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_cistatic int snd_rme9652_hw_params(struct snd_pcm_substream *substream, 19828c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 19838c2ecf20Sopenharmony_ci{ 19848c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 19858c2ecf20Sopenharmony_ci int err; 19868c2ecf20Sopenharmony_ci pid_t this_pid; 19878c2ecf20Sopenharmony_ci pid_t other_pid; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { 19928c2ecf20Sopenharmony_ci rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP); 19938c2ecf20Sopenharmony_ci rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= rme9652->creg_spdif_stream); 19948c2ecf20Sopenharmony_ci this_pid = rme9652->playback_pid; 19958c2ecf20Sopenharmony_ci other_pid = rme9652->capture_pid; 19968c2ecf20Sopenharmony_ci } else { 19978c2ecf20Sopenharmony_ci this_pid = rme9652->capture_pid; 19988c2ecf20Sopenharmony_ci other_pid = rme9652->playback_pid; 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci if ((other_pid > 0) && (this_pid != other_pid)) { 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci /* The other stream is open, and not by the same 20048c2ecf20Sopenharmony_ci task as this one. Make sure that the parameters 20058c2ecf20Sopenharmony_ci that matter are the same. 20068c2ecf20Sopenharmony_ci */ 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci if ((int)params_rate(params) != 20098c2ecf20Sopenharmony_ci rme9652_adat_sample_rate(rme9652)) { 20108c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 20118c2ecf20Sopenharmony_ci _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); 20128c2ecf20Sopenharmony_ci return -EBUSY; 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci if (params_period_size(params) != rme9652->period_bytes / 4) { 20168c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 20178c2ecf20Sopenharmony_ci _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 20188c2ecf20Sopenharmony_ci return -EBUSY; 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci /* We're fine. */ 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 20248c2ecf20Sopenharmony_ci return 0; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci } else { 20278c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci /* how to make sure that the rate matches an externally-set one ? 20318c2ecf20Sopenharmony_ci */ 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci if ((err = rme9652_set_rate(rme9652, params_rate(params))) < 0) { 20348c2ecf20Sopenharmony_ci _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); 20358c2ecf20Sopenharmony_ci return err; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci if ((err = rme9652_set_interrupt_interval(rme9652, params_period_size(params))) < 0) { 20398c2ecf20Sopenharmony_ci _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 20408c2ecf20Sopenharmony_ci return err; 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci return 0; 20448c2ecf20Sopenharmony_ci} 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_cistatic int snd_rme9652_channel_info(struct snd_pcm_substream *substream, 20478c2ecf20Sopenharmony_ci struct snd_pcm_channel_info *info) 20488c2ecf20Sopenharmony_ci{ 20498c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 20508c2ecf20Sopenharmony_ci int chn; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (snd_BUG_ON(info->channel >= RME9652_NCHANNELS)) 20538c2ecf20Sopenharmony_ci return -EINVAL; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci chn = rme9652->channel_map[array_index_nospec(info->channel, 20568c2ecf20Sopenharmony_ci RME9652_NCHANNELS)]; 20578c2ecf20Sopenharmony_ci if (chn < 0) 20588c2ecf20Sopenharmony_ci return -EINVAL; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci info->offset = chn * RME9652_CHANNEL_BUFFER_BYTES; 20618c2ecf20Sopenharmony_ci info->first = 0; 20628c2ecf20Sopenharmony_ci info->step = 32; 20638c2ecf20Sopenharmony_ci return 0; 20648c2ecf20Sopenharmony_ci} 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_cistatic int snd_rme9652_ioctl(struct snd_pcm_substream *substream, 20678c2ecf20Sopenharmony_ci unsigned int cmd, void *arg) 20688c2ecf20Sopenharmony_ci{ 20698c2ecf20Sopenharmony_ci switch (cmd) { 20708c2ecf20Sopenharmony_ci case SNDRV_PCM_IOCTL1_RESET: 20718c2ecf20Sopenharmony_ci { 20728c2ecf20Sopenharmony_ci return snd_rme9652_reset(substream); 20738c2ecf20Sopenharmony_ci } 20748c2ecf20Sopenharmony_ci case SNDRV_PCM_IOCTL1_CHANNEL_INFO: 20758c2ecf20Sopenharmony_ci { 20768c2ecf20Sopenharmony_ci struct snd_pcm_channel_info *info = arg; 20778c2ecf20Sopenharmony_ci return snd_rme9652_channel_info(substream, info); 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci default: 20808c2ecf20Sopenharmony_ci break; 20818c2ecf20Sopenharmony_ci } 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci return snd_pcm_lib_ioctl(substream, cmd, arg); 20848c2ecf20Sopenharmony_ci} 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_cistatic void rme9652_silence_playback(struct snd_rme9652 *rme9652) 20878c2ecf20Sopenharmony_ci{ 20888c2ecf20Sopenharmony_ci memset(rme9652->playback_buffer, 0, RME9652_DMA_AREA_BYTES); 20898c2ecf20Sopenharmony_ci} 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_cistatic int snd_rme9652_trigger(struct snd_pcm_substream *substream, 20928c2ecf20Sopenharmony_ci int cmd) 20938c2ecf20Sopenharmony_ci{ 20948c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 20958c2ecf20Sopenharmony_ci struct snd_pcm_substream *other; 20968c2ecf20Sopenharmony_ci int running; 20978c2ecf20Sopenharmony_ci spin_lock(&rme9652->lock); 20988c2ecf20Sopenharmony_ci running = rme9652->running; 20998c2ecf20Sopenharmony_ci switch (cmd) { 21008c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 21018c2ecf20Sopenharmony_ci running |= 1 << substream->stream; 21028c2ecf20Sopenharmony_ci break; 21038c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 21048c2ecf20Sopenharmony_ci running &= ~(1 << substream->stream); 21058c2ecf20Sopenharmony_ci break; 21068c2ecf20Sopenharmony_ci default: 21078c2ecf20Sopenharmony_ci snd_BUG(); 21088c2ecf20Sopenharmony_ci spin_unlock(&rme9652->lock); 21098c2ecf20Sopenharmony_ci return -EINVAL; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 21128c2ecf20Sopenharmony_ci other = rme9652->capture_substream; 21138c2ecf20Sopenharmony_ci else 21148c2ecf20Sopenharmony_ci other = rme9652->playback_substream; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci if (other) { 21178c2ecf20Sopenharmony_ci struct snd_pcm_substream *s; 21188c2ecf20Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 21198c2ecf20Sopenharmony_ci if (s == other) { 21208c2ecf20Sopenharmony_ci snd_pcm_trigger_done(s, substream); 21218c2ecf20Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) 21228c2ecf20Sopenharmony_ci running |= 1 << s->stream; 21238c2ecf20Sopenharmony_ci else 21248c2ecf20Sopenharmony_ci running &= ~(1 << s->stream); 21258c2ecf20Sopenharmony_ci goto _ok; 21268c2ecf20Sopenharmony_ci } 21278c2ecf20Sopenharmony_ci } 21288c2ecf20Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) { 21298c2ecf20Sopenharmony_ci if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) && 21308c2ecf20Sopenharmony_ci substream->stream == SNDRV_PCM_STREAM_CAPTURE) 21318c2ecf20Sopenharmony_ci rme9652_silence_playback(rme9652); 21328c2ecf20Sopenharmony_ci } else { 21338c2ecf20Sopenharmony_ci if (running && 21348c2ecf20Sopenharmony_ci substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 21358c2ecf20Sopenharmony_ci rme9652_silence_playback(rme9652); 21368c2ecf20Sopenharmony_ci } 21378c2ecf20Sopenharmony_ci } else { 21388c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 21398c2ecf20Sopenharmony_ci rme9652_silence_playback(rme9652); 21408c2ecf20Sopenharmony_ci } 21418c2ecf20Sopenharmony_ci _ok: 21428c2ecf20Sopenharmony_ci snd_pcm_trigger_done(substream, substream); 21438c2ecf20Sopenharmony_ci if (!rme9652->running && running) 21448c2ecf20Sopenharmony_ci rme9652_start(rme9652); 21458c2ecf20Sopenharmony_ci else if (rme9652->running && !running) 21468c2ecf20Sopenharmony_ci rme9652_stop(rme9652); 21478c2ecf20Sopenharmony_ci rme9652->running = running; 21488c2ecf20Sopenharmony_ci spin_unlock(&rme9652->lock); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci return 0; 21518c2ecf20Sopenharmony_ci} 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_cistatic int snd_rme9652_prepare(struct snd_pcm_substream *substream) 21548c2ecf20Sopenharmony_ci{ 21558c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 21568c2ecf20Sopenharmony_ci unsigned long flags; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci spin_lock_irqsave(&rme9652->lock, flags); 21598c2ecf20Sopenharmony_ci if (!rme9652->running) 21608c2ecf20Sopenharmony_ci rme9652_reset_hw_pointer(rme9652); 21618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rme9652->lock, flags); 21628c2ecf20Sopenharmony_ci return 0; 21638c2ecf20Sopenharmony_ci} 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_rme9652_playback_subinfo = 21668c2ecf20Sopenharmony_ci{ 21678c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 21688c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 21698c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_NONINTERLEAVED | 21708c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START | 21718c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_DOUBLE), 21728c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 21738c2ecf20Sopenharmony_ci .rates = (SNDRV_PCM_RATE_44100 | 21748c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | 21758c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_88200 | 21768c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_96000), 21778c2ecf20Sopenharmony_ci .rate_min = 44100, 21788c2ecf20Sopenharmony_ci .rate_max = 96000, 21798c2ecf20Sopenharmony_ci .channels_min = 10, 21808c2ecf20Sopenharmony_ci .channels_max = 26, 21818c2ecf20Sopenharmony_ci .buffer_bytes_max = RME9652_CHANNEL_BUFFER_BYTES * 26, 21828c2ecf20Sopenharmony_ci .period_bytes_min = (64 * 4) * 10, 21838c2ecf20Sopenharmony_ci .period_bytes_max = (8192 * 4) * 26, 21848c2ecf20Sopenharmony_ci .periods_min = 2, 21858c2ecf20Sopenharmony_ci .periods_max = 2, 21868c2ecf20Sopenharmony_ci .fifo_size = 0, 21878c2ecf20Sopenharmony_ci}; 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_rme9652_capture_subinfo = 21908c2ecf20Sopenharmony_ci{ 21918c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 21928c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 21938c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_NONINTERLEAVED | 21948c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START), 21958c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 21968c2ecf20Sopenharmony_ci .rates = (SNDRV_PCM_RATE_44100 | 21978c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | 21988c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_88200 | 21998c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_96000), 22008c2ecf20Sopenharmony_ci .rate_min = 44100, 22018c2ecf20Sopenharmony_ci .rate_max = 96000, 22028c2ecf20Sopenharmony_ci .channels_min = 10, 22038c2ecf20Sopenharmony_ci .channels_max = 26, 22048c2ecf20Sopenharmony_ci .buffer_bytes_max = RME9652_CHANNEL_BUFFER_BYTES *26, 22058c2ecf20Sopenharmony_ci .period_bytes_min = (64 * 4) * 10, 22068c2ecf20Sopenharmony_ci .period_bytes_max = (8192 * 4) * 26, 22078c2ecf20Sopenharmony_ci .periods_min = 2, 22088c2ecf20Sopenharmony_ci .periods_max = 2, 22098c2ecf20Sopenharmony_ci .fifo_size = 0, 22108c2ecf20Sopenharmony_ci}; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_cistatic const unsigned int period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hw_constraints_period_sizes = { 22158c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(period_sizes), 22168c2ecf20Sopenharmony_ci .list = period_sizes, 22178c2ecf20Sopenharmony_ci .mask = 0 22188c2ecf20Sopenharmony_ci}; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_cistatic int snd_rme9652_hw_rule_channels(struct snd_pcm_hw_params *params, 22218c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 22228c2ecf20Sopenharmony_ci{ 22238c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = rule->private; 22248c2ecf20Sopenharmony_ci struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 22258c2ecf20Sopenharmony_ci unsigned int list[2] = { rme9652->ds_channels, rme9652->ss_channels }; 22268c2ecf20Sopenharmony_ci return snd_interval_list(c, 2, list, 0); 22278c2ecf20Sopenharmony_ci} 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_cistatic int snd_rme9652_hw_rule_channels_rate(struct snd_pcm_hw_params *params, 22308c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 22318c2ecf20Sopenharmony_ci{ 22328c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = rule->private; 22338c2ecf20Sopenharmony_ci struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 22348c2ecf20Sopenharmony_ci struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 22358c2ecf20Sopenharmony_ci if (r->min > 48000) { 22368c2ecf20Sopenharmony_ci struct snd_interval t = { 22378c2ecf20Sopenharmony_ci .min = rme9652->ds_channels, 22388c2ecf20Sopenharmony_ci .max = rme9652->ds_channels, 22398c2ecf20Sopenharmony_ci .integer = 1, 22408c2ecf20Sopenharmony_ci }; 22418c2ecf20Sopenharmony_ci return snd_interval_refine(c, &t); 22428c2ecf20Sopenharmony_ci } else if (r->max < 88200) { 22438c2ecf20Sopenharmony_ci struct snd_interval t = { 22448c2ecf20Sopenharmony_ci .min = rme9652->ss_channels, 22458c2ecf20Sopenharmony_ci .max = rme9652->ss_channels, 22468c2ecf20Sopenharmony_ci .integer = 1, 22478c2ecf20Sopenharmony_ci }; 22488c2ecf20Sopenharmony_ci return snd_interval_refine(c, &t); 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci return 0; 22518c2ecf20Sopenharmony_ci} 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_cistatic int snd_rme9652_hw_rule_rate_channels(struct snd_pcm_hw_params *params, 22548c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 22558c2ecf20Sopenharmony_ci{ 22568c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = rule->private; 22578c2ecf20Sopenharmony_ci struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 22588c2ecf20Sopenharmony_ci struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 22598c2ecf20Sopenharmony_ci if (c->min >= rme9652->ss_channels) { 22608c2ecf20Sopenharmony_ci struct snd_interval t = { 22618c2ecf20Sopenharmony_ci .min = 44100, 22628c2ecf20Sopenharmony_ci .max = 48000, 22638c2ecf20Sopenharmony_ci .integer = 1, 22648c2ecf20Sopenharmony_ci }; 22658c2ecf20Sopenharmony_ci return snd_interval_refine(r, &t); 22668c2ecf20Sopenharmony_ci } else if (c->max <= rme9652->ds_channels) { 22678c2ecf20Sopenharmony_ci struct snd_interval t = { 22688c2ecf20Sopenharmony_ci .min = 88200, 22698c2ecf20Sopenharmony_ci .max = 96000, 22708c2ecf20Sopenharmony_ci .integer = 1, 22718c2ecf20Sopenharmony_ci }; 22728c2ecf20Sopenharmony_ci return snd_interval_refine(r, &t); 22738c2ecf20Sopenharmony_ci } 22748c2ecf20Sopenharmony_ci return 0; 22758c2ecf20Sopenharmony_ci} 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_cistatic int snd_rme9652_playback_open(struct snd_pcm_substream *substream) 22788c2ecf20Sopenharmony_ci{ 22798c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 22808c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci snd_pcm_set_sync(substream); 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci runtime->hw = snd_rme9652_playback_subinfo; 22878c2ecf20Sopenharmony_ci runtime->dma_area = rme9652->playback_buffer; 22888c2ecf20Sopenharmony_ci runtime->dma_bytes = RME9652_DMA_AREA_BYTES; 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci if (rme9652->capture_substream == NULL) { 22918c2ecf20Sopenharmony_ci rme9652_stop(rme9652); 22928c2ecf20Sopenharmony_ci rme9652_set_thru(rme9652, -1, 0); 22938c2ecf20Sopenharmony_ci } 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci rme9652->playback_pid = current->pid; 22968c2ecf20Sopenharmony_ci rme9652->playback_substream = substream; 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 23018c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes); 23028c2ecf20Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 23038c2ecf20Sopenharmony_ci snd_rme9652_hw_rule_channels, rme9652, 23048c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 23058c2ecf20Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 23068c2ecf20Sopenharmony_ci snd_rme9652_hw_rule_channels_rate, rme9652, 23078c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, -1); 23088c2ecf20Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 23098c2ecf20Sopenharmony_ci snd_rme9652_hw_rule_rate_channels, rme9652, 23108c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci rme9652->creg_spdif_stream = rme9652->creg_spdif; 23138c2ecf20Sopenharmony_ci rme9652->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; 23148c2ecf20Sopenharmony_ci snd_ctl_notify(rme9652->card, SNDRV_CTL_EVENT_MASK_VALUE | 23158c2ecf20Sopenharmony_ci SNDRV_CTL_EVENT_MASK_INFO, &rme9652->spdif_ctl->id); 23168c2ecf20Sopenharmony_ci return 0; 23178c2ecf20Sopenharmony_ci} 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_cistatic int snd_rme9652_playback_release(struct snd_pcm_substream *substream) 23208c2ecf20Sopenharmony_ci{ 23218c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci rme9652->playback_pid = -1; 23268c2ecf20Sopenharmony_ci rme9652->playback_substream = NULL; 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci rme9652->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; 23318c2ecf20Sopenharmony_ci snd_ctl_notify(rme9652->card, SNDRV_CTL_EVENT_MASK_VALUE | 23328c2ecf20Sopenharmony_ci SNDRV_CTL_EVENT_MASK_INFO, &rme9652->spdif_ctl->id); 23338c2ecf20Sopenharmony_ci return 0; 23348c2ecf20Sopenharmony_ci} 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_cistatic int snd_rme9652_capture_open(struct snd_pcm_substream *substream) 23388c2ecf20Sopenharmony_ci{ 23398c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 23408c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci snd_pcm_set_sync(substream); 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci runtime->hw = snd_rme9652_capture_subinfo; 23478c2ecf20Sopenharmony_ci runtime->dma_area = rme9652->capture_buffer; 23488c2ecf20Sopenharmony_ci runtime->dma_bytes = RME9652_DMA_AREA_BYTES; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci if (rme9652->playback_substream == NULL) { 23518c2ecf20Sopenharmony_ci rme9652_stop(rme9652); 23528c2ecf20Sopenharmony_ci rme9652_set_thru(rme9652, -1, 0); 23538c2ecf20Sopenharmony_ci } 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci rme9652->capture_pid = current->pid; 23568c2ecf20Sopenharmony_ci rme9652->capture_substream = substream; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 23618c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes); 23628c2ecf20Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 23638c2ecf20Sopenharmony_ci snd_rme9652_hw_rule_channels, rme9652, 23648c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 23658c2ecf20Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 23668c2ecf20Sopenharmony_ci snd_rme9652_hw_rule_channels_rate, rme9652, 23678c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, -1); 23688c2ecf20Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 23698c2ecf20Sopenharmony_ci snd_rme9652_hw_rule_rate_channels, rme9652, 23708c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 23718c2ecf20Sopenharmony_ci return 0; 23728c2ecf20Sopenharmony_ci} 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_cistatic int snd_rme9652_capture_release(struct snd_pcm_substream *substream) 23758c2ecf20Sopenharmony_ci{ 23768c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci spin_lock_irq(&rme9652->lock); 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci rme9652->capture_pid = -1; 23818c2ecf20Sopenharmony_ci rme9652->capture_substream = NULL; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci spin_unlock_irq(&rme9652->lock); 23848c2ecf20Sopenharmony_ci return 0; 23858c2ecf20Sopenharmony_ci} 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_rme9652_playback_ops = { 23888c2ecf20Sopenharmony_ci .open = snd_rme9652_playback_open, 23898c2ecf20Sopenharmony_ci .close = snd_rme9652_playback_release, 23908c2ecf20Sopenharmony_ci .ioctl = snd_rme9652_ioctl, 23918c2ecf20Sopenharmony_ci .hw_params = snd_rme9652_hw_params, 23928c2ecf20Sopenharmony_ci .prepare = snd_rme9652_prepare, 23938c2ecf20Sopenharmony_ci .trigger = snd_rme9652_trigger, 23948c2ecf20Sopenharmony_ci .pointer = snd_rme9652_hw_pointer, 23958c2ecf20Sopenharmony_ci .copy_user = snd_rme9652_playback_copy, 23968c2ecf20Sopenharmony_ci .copy_kernel = snd_rme9652_playback_copy_kernel, 23978c2ecf20Sopenharmony_ci .fill_silence = snd_rme9652_hw_silence, 23988c2ecf20Sopenharmony_ci}; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_rme9652_capture_ops = { 24018c2ecf20Sopenharmony_ci .open = snd_rme9652_capture_open, 24028c2ecf20Sopenharmony_ci .close = snd_rme9652_capture_release, 24038c2ecf20Sopenharmony_ci .ioctl = snd_rme9652_ioctl, 24048c2ecf20Sopenharmony_ci .hw_params = snd_rme9652_hw_params, 24058c2ecf20Sopenharmony_ci .prepare = snd_rme9652_prepare, 24068c2ecf20Sopenharmony_ci .trigger = snd_rme9652_trigger, 24078c2ecf20Sopenharmony_ci .pointer = snd_rme9652_hw_pointer, 24088c2ecf20Sopenharmony_ci .copy_user = snd_rme9652_capture_copy, 24098c2ecf20Sopenharmony_ci .copy_kernel = snd_rme9652_capture_copy_kernel, 24108c2ecf20Sopenharmony_ci}; 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_cistatic int snd_rme9652_create_pcm(struct snd_card *card, 24138c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652) 24148c2ecf20Sopenharmony_ci{ 24158c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 24168c2ecf20Sopenharmony_ci int err; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci if ((err = snd_pcm_new(card, 24198c2ecf20Sopenharmony_ci rme9652->card_name, 24208c2ecf20Sopenharmony_ci 0, 1, 1, &pcm)) < 0) { 24218c2ecf20Sopenharmony_ci return err; 24228c2ecf20Sopenharmony_ci } 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci rme9652->pcm = pcm; 24258c2ecf20Sopenharmony_ci pcm->private_data = rme9652; 24268c2ecf20Sopenharmony_ci strcpy(pcm->name, rme9652->card_name); 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme9652_playback_ops); 24298c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme9652_capture_ops); 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci return 0; 24348c2ecf20Sopenharmony_ci} 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_cistatic int snd_rme9652_create(struct snd_card *card, 24378c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652, 24388c2ecf20Sopenharmony_ci int precise_ptr) 24398c2ecf20Sopenharmony_ci{ 24408c2ecf20Sopenharmony_ci struct pci_dev *pci = rme9652->pci; 24418c2ecf20Sopenharmony_ci int err; 24428c2ecf20Sopenharmony_ci int status; 24438c2ecf20Sopenharmony_ci unsigned short rev; 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci rme9652->irq = -1; 24468c2ecf20Sopenharmony_ci rme9652->card = card; 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci pci_read_config_word(rme9652->pci, PCI_CLASS_REVISION, &rev); 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci switch (rev & 0xff) { 24518c2ecf20Sopenharmony_ci case 3: 24528c2ecf20Sopenharmony_ci case 4: 24538c2ecf20Sopenharmony_ci case 8: 24548c2ecf20Sopenharmony_ci case 9: 24558c2ecf20Sopenharmony_ci break; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci default: 24588c2ecf20Sopenharmony_ci /* who knows? */ 24598c2ecf20Sopenharmony_ci return -ENODEV; 24608c2ecf20Sopenharmony_ci } 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci if ((err = pci_enable_device(pci)) < 0) 24638c2ecf20Sopenharmony_ci return err; 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci spin_lock_init(&rme9652->lock); 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci if ((err = pci_request_regions(pci, "rme9652")) < 0) 24688c2ecf20Sopenharmony_ci return err; 24698c2ecf20Sopenharmony_ci rme9652->port = pci_resource_start(pci, 0); 24708c2ecf20Sopenharmony_ci rme9652->iobase = ioremap(rme9652->port, RME9652_IO_EXTENT); 24718c2ecf20Sopenharmony_ci if (rme9652->iobase == NULL) { 24728c2ecf20Sopenharmony_ci dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n", 24738c2ecf20Sopenharmony_ci rme9652->port, rme9652->port + RME9652_IO_EXTENT - 1); 24748c2ecf20Sopenharmony_ci return -EBUSY; 24758c2ecf20Sopenharmony_ci } 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci if (request_irq(pci->irq, snd_rme9652_interrupt, IRQF_SHARED, 24788c2ecf20Sopenharmony_ci KBUILD_MODNAME, rme9652)) { 24798c2ecf20Sopenharmony_ci dev_err(card->dev, "unable to request IRQ %d\n", pci->irq); 24808c2ecf20Sopenharmony_ci return -EBUSY; 24818c2ecf20Sopenharmony_ci } 24828c2ecf20Sopenharmony_ci rme9652->irq = pci->irq; 24838c2ecf20Sopenharmony_ci card->sync_irq = rme9652->irq; 24848c2ecf20Sopenharmony_ci rme9652->precise_ptr = precise_ptr; 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci /* Determine the h/w rev level of the card. This seems like 24878c2ecf20Sopenharmony_ci a particularly kludgy way to encode it, but its what RME 24888c2ecf20Sopenharmony_ci chose to do, so we follow them ... 24898c2ecf20Sopenharmony_ci */ 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci status = rme9652_read(rme9652, RME9652_status_register); 24928c2ecf20Sopenharmony_ci if (rme9652_decode_spdif_rate(status&RME9652_F) == 1) { 24938c2ecf20Sopenharmony_ci rme9652->hw_rev = 15; 24948c2ecf20Sopenharmony_ci } else { 24958c2ecf20Sopenharmony_ci rme9652->hw_rev = 11; 24968c2ecf20Sopenharmony_ci } 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci /* Differentiate between the standard Hammerfall, and the 24998c2ecf20Sopenharmony_ci "Light", which does not have the expansion board. This 25008c2ecf20Sopenharmony_ci method comes from information received from Mathhias 25018c2ecf20Sopenharmony_ci Clausen at RME. Display the EEPROM and h/w revID where 25028c2ecf20Sopenharmony_ci relevant. 25038c2ecf20Sopenharmony_ci */ 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci switch (rev) { 25068c2ecf20Sopenharmony_ci case 8: /* original eprom */ 25078c2ecf20Sopenharmony_ci strcpy(card->driver, "RME9636"); 25088c2ecf20Sopenharmony_ci if (rme9652->hw_rev == 15) { 25098c2ecf20Sopenharmony_ci rme9652->card_name = "RME Digi9636 (Rev 1.5)"; 25108c2ecf20Sopenharmony_ci } else { 25118c2ecf20Sopenharmony_ci rme9652->card_name = "RME Digi9636"; 25128c2ecf20Sopenharmony_ci } 25138c2ecf20Sopenharmony_ci rme9652->ss_channels = RME9636_NCHANNELS; 25148c2ecf20Sopenharmony_ci break; 25158c2ecf20Sopenharmony_ci case 9: /* W36_G EPROM */ 25168c2ecf20Sopenharmony_ci strcpy(card->driver, "RME9636"); 25178c2ecf20Sopenharmony_ci rme9652->card_name = "RME Digi9636 (Rev G)"; 25188c2ecf20Sopenharmony_ci rme9652->ss_channels = RME9636_NCHANNELS; 25198c2ecf20Sopenharmony_ci break; 25208c2ecf20Sopenharmony_ci case 4: /* W52_G EPROM */ 25218c2ecf20Sopenharmony_ci strcpy(card->driver, "RME9652"); 25228c2ecf20Sopenharmony_ci rme9652->card_name = "RME Digi9652 (Rev G)"; 25238c2ecf20Sopenharmony_ci rme9652->ss_channels = RME9652_NCHANNELS; 25248c2ecf20Sopenharmony_ci break; 25258c2ecf20Sopenharmony_ci case 3: /* original eprom */ 25268c2ecf20Sopenharmony_ci strcpy(card->driver, "RME9652"); 25278c2ecf20Sopenharmony_ci if (rme9652->hw_rev == 15) { 25288c2ecf20Sopenharmony_ci rme9652->card_name = "RME Digi9652 (Rev 1.5)"; 25298c2ecf20Sopenharmony_ci } else { 25308c2ecf20Sopenharmony_ci rme9652->card_name = "RME Digi9652"; 25318c2ecf20Sopenharmony_ci } 25328c2ecf20Sopenharmony_ci rme9652->ss_channels = RME9652_NCHANNELS; 25338c2ecf20Sopenharmony_ci break; 25348c2ecf20Sopenharmony_ci } 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci rme9652->ds_channels = (rme9652->ss_channels - 2) / 2 + 2; 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci pci_set_master(rme9652->pci); 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci if ((err = snd_rme9652_initialize_memory(rme9652)) < 0) { 25418c2ecf20Sopenharmony_ci return err; 25428c2ecf20Sopenharmony_ci } 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci if ((err = snd_rme9652_create_pcm(card, rme9652)) < 0) { 25458c2ecf20Sopenharmony_ci return err; 25468c2ecf20Sopenharmony_ci } 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci if ((err = snd_rme9652_create_controls(card, rme9652)) < 0) { 25498c2ecf20Sopenharmony_ci return err; 25508c2ecf20Sopenharmony_ci } 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci snd_rme9652_proc_init(rme9652); 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci rme9652->last_spdif_sample_rate = -1; 25558c2ecf20Sopenharmony_ci rme9652->last_adat_sample_rate = -1; 25568c2ecf20Sopenharmony_ci rme9652->playback_pid = -1; 25578c2ecf20Sopenharmony_ci rme9652->capture_pid = -1; 25588c2ecf20Sopenharmony_ci rme9652->capture_substream = NULL; 25598c2ecf20Sopenharmony_ci rme9652->playback_substream = NULL; 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci snd_rme9652_set_defaults(rme9652); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci if (rme9652->hw_rev == 15) { 25648c2ecf20Sopenharmony_ci rme9652_initialize_spdif_receiver (rme9652); 25658c2ecf20Sopenharmony_ci } 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci return 0; 25688c2ecf20Sopenharmony_ci} 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_cistatic void snd_rme9652_card_free(struct snd_card *card) 25718c2ecf20Sopenharmony_ci{ 25728c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) card->private_data; 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci if (rme9652) 25758c2ecf20Sopenharmony_ci snd_rme9652_free(rme9652); 25768c2ecf20Sopenharmony_ci} 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_cistatic int snd_rme9652_probe(struct pci_dev *pci, 25798c2ecf20Sopenharmony_ci const struct pci_device_id *pci_id) 25808c2ecf20Sopenharmony_ci{ 25818c2ecf20Sopenharmony_ci static int dev; 25828c2ecf20Sopenharmony_ci struct snd_rme9652 *rme9652; 25838c2ecf20Sopenharmony_ci struct snd_card *card; 25848c2ecf20Sopenharmony_ci int err; 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci if (dev >= SNDRV_CARDS) 25878c2ecf20Sopenharmony_ci return -ENODEV; 25888c2ecf20Sopenharmony_ci if (!enable[dev]) { 25898c2ecf20Sopenharmony_ci dev++; 25908c2ecf20Sopenharmony_ci return -ENOENT; 25918c2ecf20Sopenharmony_ci } 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 25948c2ecf20Sopenharmony_ci sizeof(struct snd_rme9652), &card); 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci if (err < 0) 25978c2ecf20Sopenharmony_ci return err; 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci rme9652 = (struct snd_rme9652 *) card->private_data; 26008c2ecf20Sopenharmony_ci card->private_free = snd_rme9652_card_free; 26018c2ecf20Sopenharmony_ci rme9652->dev = dev; 26028c2ecf20Sopenharmony_ci rme9652->pci = pci; 26038c2ecf20Sopenharmony_ci err = snd_rme9652_create(card, rme9652, precise_ptr[dev]); 26048c2ecf20Sopenharmony_ci if (err) 26058c2ecf20Sopenharmony_ci goto free_card; 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci strcpy(card->shortname, rme9652->card_name); 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci sprintf(card->longname, "%s at 0x%lx, irq %d", 26108c2ecf20Sopenharmony_ci card->shortname, rme9652->port, rme9652->irq); 26118c2ecf20Sopenharmony_ci err = snd_card_register(card); 26128c2ecf20Sopenharmony_ci if (err) { 26138c2ecf20Sopenharmony_cifree_card: 26148c2ecf20Sopenharmony_ci snd_card_free(card); 26158c2ecf20Sopenharmony_ci return err; 26168c2ecf20Sopenharmony_ci } 26178c2ecf20Sopenharmony_ci pci_set_drvdata(pci, card); 26188c2ecf20Sopenharmony_ci dev++; 26198c2ecf20Sopenharmony_ci return 0; 26208c2ecf20Sopenharmony_ci} 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_cistatic void snd_rme9652_remove(struct pci_dev *pci) 26238c2ecf20Sopenharmony_ci{ 26248c2ecf20Sopenharmony_ci snd_card_free(pci_get_drvdata(pci)); 26258c2ecf20Sopenharmony_ci} 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_cistatic struct pci_driver rme9652_driver = { 26288c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 26298c2ecf20Sopenharmony_ci .id_table = snd_rme9652_ids, 26308c2ecf20Sopenharmony_ci .probe = snd_rme9652_probe, 26318c2ecf20Sopenharmony_ci .remove = snd_rme9652_remove, 26328c2ecf20Sopenharmony_ci}; 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_cimodule_pci_driver(rme9652_driver); 2635