162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ALSA driver for RME Hammerfall DSP MADI audio interface(s) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2003 Winfried Ritsch (IEM) 662306a36Sopenharmony_ci * code based on hdsp.c Paul Davis 762306a36Sopenharmony_ci * Marcus Andersson 862306a36Sopenharmony_ci * Thomas Charbonnel 962306a36Sopenharmony_ci * Modified 2006-06-01 for AES32 support by Remy Bruno 1062306a36Sopenharmony_ci * <remy.bruno@trinnov.com> 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Modified 2009-04-13 for proper metering by Florian Faber 1362306a36Sopenharmony_ci * <faber@faberman.de> 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Modified 2009-04-14 for native float support by Florian Faber 1662306a36Sopenharmony_ci * <faber@faberman.de> 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Modified 2009-04-26 fixed bug in rms metering by Florian Faber 1962306a36Sopenharmony_ci * <faber@faberman.de> 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * Modified 2009-04-30 added hw serial number support by Florian Faber 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Modified 2011-01-14 added S/PDIF input on RayDATs by Adrian Knoth 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * Modified 2011-01-25 variable period sizes on RayDAT/AIO by Adrian Knoth 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Modified 2019-05-23 fix AIO single speed ADAT capture and playback 2862306a36Sopenharmony_ci * by Philippe.Bekaert@uhasselt.be 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* ************* Register Documentation ******************************************************* 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * Work in progress! Documentation is based on the code in this file. 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * --------- HDSPM_controlRegister --------- 3662306a36Sopenharmony_ci * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte 3762306a36Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 3862306a36Sopenharmony_ci * :3322.2222:2222.1111:1111.1100:0000.0000: bit number 3962306a36Sopenharmony_ci * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 4062306a36Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 4162306a36Sopenharmony_ci * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit 4262306a36Sopenharmony_ci * : . : . : . : x . : HDSPM_AudioInterruptEnable \_ setting both bits 4362306a36Sopenharmony_ci * : . : . : . : . x: HDSPM_Start / enables audio IO 4462306a36Sopenharmony_ci * : . : . : . : x. : HDSPM_ClockModeMaster - 1: Master, 0: Slave 4562306a36Sopenharmony_ci * : . : . : . : .210 : HDSPM_LatencyMask - 3 Bit value for latency 4662306a36Sopenharmony_ci * : . : . : . : . : 0:64, 1:128, 2:256, 3:512, 4762306a36Sopenharmony_ci * : . : . : . : . : 4:1024, 5:2048, 6:4096, 7:8192 4862306a36Sopenharmony_ci * :x . : . : . x:xx . : HDSPM_FrequencyMask 4962306a36Sopenharmony_ci * : . : . : . :10 . : HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=?? 5062306a36Sopenharmony_ci * : . : . : . x: . : <MADI> HDSPM_DoubleSpeed 5162306a36Sopenharmony_ci * :x . : . : . : . : <MADI> HDSPM_QuadSpeed 5262306a36Sopenharmony_ci * : . 3 : . 10: 2 . : . : HDSPM_SyncRefMask : 5362306a36Sopenharmony_ci * : . : . x: . : . : HDSPM_SyncRef0 5462306a36Sopenharmony_ci * : . : . x : . : . : HDSPM_SyncRef1 5562306a36Sopenharmony_ci * : . : . : x . : . : <AES32> HDSPM_SyncRef2 5662306a36Sopenharmony_ci * : . x : . : . : . : <AES32> HDSPM_SyncRef3 5762306a36Sopenharmony_ci * : . : . 10: . : . : <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn 5862306a36Sopenharmony_ci * : . 3 : . 10: 2 . : . : <AES32> 0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn? 5962306a36Sopenharmony_ci * : . x : . : . : . : <MADIe> HDSPe_FLOAT_FORMAT 6062306a36Sopenharmony_ci * : . : . : x . : . : <MADI> HDSPM_InputSelect0 : 0=optical,1=coax 6162306a36Sopenharmony_ci * : . : . :x . : . : <MADI> HDSPM_InputSelect1 6262306a36Sopenharmony_ci * : . : .x : . : . : <MADI> HDSPM_clr_tms 6362306a36Sopenharmony_ci * : . : . : . x : . : <MADI> HDSPM_TX_64ch 6462306a36Sopenharmony_ci * : . : . : . x : . : <AES32> HDSPM_Emphasis 6562306a36Sopenharmony_ci * : . : . : .x : . : <MADI> HDSPM_AutoInp 6662306a36Sopenharmony_ci * : . : . x : . : . : <MADI> HDSPM_SMUX 6762306a36Sopenharmony_ci * : . : .x : . : . : <MADI> HDSPM_clr_tms 6862306a36Sopenharmony_ci * : . : x. : . : . : <MADI> HDSPM_taxi_reset 6962306a36Sopenharmony_ci * : . x: . : . : . : <MADI> HDSPM_LineOut 7062306a36Sopenharmony_ci * : . x: . : . : . : <AES32> ?????????????????? 7162306a36Sopenharmony_ci * : . : x. : . : . : <AES32> HDSPM_WCK48 7262306a36Sopenharmony_ci * : . : . : .x : . : <AES32> HDSPM_Dolby 7362306a36Sopenharmony_ci * : . : x . : . : . : HDSPM_Midi0InterruptEnable 7462306a36Sopenharmony_ci * : . :x . : . : . : HDSPM_Midi1InterruptEnable 7562306a36Sopenharmony_ci * : . : x . : . : . : HDSPM_Midi2InterruptEnable 7662306a36Sopenharmony_ci * : . x : . : . : . : <MADI> HDSPM_Midi3InterruptEnable 7762306a36Sopenharmony_ci * : . x : . : . : . : <AES32> HDSPM_DS_DoubleWire 7862306a36Sopenharmony_ci * : .x : . : . : . : <AES32> HDSPM_QS_DoubleWire 7962306a36Sopenharmony_ci * : x. : . : . : . : <AES32> HDSPM_QS_QuadWire 8062306a36Sopenharmony_ci * : . : . : . x : . : <AES32> HDSPM_Professional 8162306a36Sopenharmony_ci * : x . : . : . : . : HDSPM_wclk_sel 8262306a36Sopenharmony_ci * : . : . : . : . : 8362306a36Sopenharmony_ci * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte 8462306a36Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 8562306a36Sopenharmony_ci * :3322.2222:2222.1111:1111.1100:0000.0000: bit number 8662306a36Sopenharmony_ci * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 8762306a36Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 8862306a36Sopenharmony_ci * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * AIO / RayDAT only 9362306a36Sopenharmony_ci * 9462306a36Sopenharmony_ci * ------------ HDSPM_WR_SETTINGS ---------- 9562306a36Sopenharmony_ci * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte 9662306a36Sopenharmony_ci * :1098.7654:3210.9876:5432.1098:7654.3210: 9762306a36Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: bit number 9862306a36Sopenharmony_ci * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 9962306a36Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 10062306a36Sopenharmony_ci * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit 10162306a36Sopenharmony_ci * : . : . : . : . x: HDSPM_c0Master 1: Master, 0: Slave 10262306a36Sopenharmony_ci * : . : . : . : . x : HDSPM_c0_SyncRef0 10362306a36Sopenharmony_ci * : . : . : . : . x : HDSPM_c0_SyncRef1 10462306a36Sopenharmony_ci * : . : . : . : .x : HDSPM_c0_SyncRef2 10562306a36Sopenharmony_ci * : . : . : . : x. : HDSPM_c0_SyncRef3 10662306a36Sopenharmony_ci * : . : . : . : 3.210 : HDSPM_c0_SyncRefMask: 10762306a36Sopenharmony_ci * : . : . : . : . : RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4, 10862306a36Sopenharmony_ci * : . : . : . : . : 9:TCO, 10:SyncIn 10962306a36Sopenharmony_ci * : . : . : . : . : AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT, 11062306a36Sopenharmony_ci * : . : . : . : . : 9:TCO, 10:SyncIn 11162306a36Sopenharmony_ci * : . : . : . : . : 11262306a36Sopenharmony_ci * : . : . : . : . : 11362306a36Sopenharmony_ci * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte 11462306a36Sopenharmony_ci * :1098.7654:3210.9876:5432.1098:7654.3210: 11562306a36Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: bit number 11662306a36Sopenharmony_ci * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 11762306a36Sopenharmony_ci * :||||.||||:||||.||||:||||.||||:||||.||||: 11862306a36Sopenharmony_ci * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci#include <linux/init.h> 12262306a36Sopenharmony_ci#include <linux/delay.h> 12362306a36Sopenharmony_ci#include <linux/interrupt.h> 12462306a36Sopenharmony_ci#include <linux/module.h> 12562306a36Sopenharmony_ci#include <linux/slab.h> 12662306a36Sopenharmony_ci#include <linux/pci.h> 12762306a36Sopenharmony_ci#include <linux/math64.h> 12862306a36Sopenharmony_ci#include <linux/io.h> 12962306a36Sopenharmony_ci#include <linux/nospec.h> 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci#include <sound/core.h> 13262306a36Sopenharmony_ci#include <sound/control.h> 13362306a36Sopenharmony_ci#include <sound/pcm.h> 13462306a36Sopenharmony_ci#include <sound/pcm_params.h> 13562306a36Sopenharmony_ci#include <sound/info.h> 13662306a36Sopenharmony_ci#include <sound/asoundef.h> 13762306a36Sopenharmony_ci#include <sound/rawmidi.h> 13862306a36Sopenharmony_ci#include <sound/hwdep.h> 13962306a36Sopenharmony_ci#include <sound/initval.h> 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci#include <sound/hdspm.h> 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 14462306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 14562306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 14862306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for RME HDSPM interface."); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 15162306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for RME HDSPM interface."); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 15462306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards."); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ciMODULE_AUTHOR 15862306a36Sopenharmony_ci( 15962306a36Sopenharmony_ci "Winfried Ritsch <ritsch_AT_iem.at>, " 16062306a36Sopenharmony_ci "Paul Davis <paul@linuxaudiosystems.com>, " 16162306a36Sopenharmony_ci "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, " 16262306a36Sopenharmony_ci "Remy Bruno <remy.bruno@trinnov.com>, " 16362306a36Sopenharmony_ci "Florian Faber <faberman@linuxproaudio.org>, " 16462306a36Sopenharmony_ci "Adrian Knoth <adi@drcomp.erfurt.thur.de>" 16562306a36Sopenharmony_ci); 16662306a36Sopenharmony_ciMODULE_DESCRIPTION("RME HDSPM"); 16762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* --- Write registers. --- 17062306a36Sopenharmony_ci These are defined as byte-offsets from the iobase value. */ 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci#define HDSPM_WR_SETTINGS 0 17362306a36Sopenharmony_ci#define HDSPM_outputBufferAddress 32 17462306a36Sopenharmony_ci#define HDSPM_inputBufferAddress 36 17562306a36Sopenharmony_ci#define HDSPM_controlRegister 64 17662306a36Sopenharmony_ci#define HDSPM_interruptConfirmation 96 17762306a36Sopenharmony_ci#define HDSPM_control2Reg 256 /* not in specs ???????? */ 17862306a36Sopenharmony_ci#define HDSPM_freqReg 256 /* for setting arbitrary clock values (DDS feature) */ 17962306a36Sopenharmony_ci#define HDSPM_midiDataOut0 352 /* just believe in old code */ 18062306a36Sopenharmony_ci#define HDSPM_midiDataOut1 356 18162306a36Sopenharmony_ci#define HDSPM_eeprom_wr 384 /* for AES32 */ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* DMA enable for 64 channels, only Bit 0 is relevant */ 18462306a36Sopenharmony_ci#define HDSPM_outputEnableBase 512 /* 512-767 input DMA */ 18562306a36Sopenharmony_ci#define HDSPM_inputEnableBase 768 /* 768-1023 output DMA */ 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* 16 page addresses for each of the 64 channels DMA buffer in and out 18862306a36Sopenharmony_ci (each 64k=16*4k) Buffer must be 4k aligned (which is default i386 ????) */ 18962306a36Sopenharmony_ci#define HDSPM_pageAddressBufferOut 8192 19062306a36Sopenharmony_ci#define HDSPM_pageAddressBufferIn (HDSPM_pageAddressBufferOut+64*16*4) 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci#define HDSPM_MADI_mixerBase 32768 /* 32768-65535 for 2x64x64 Fader */ 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci#define HDSPM_MATRIX_MIXER_SIZE 8192 /* = 2*64*64 * 4 Byte => 32kB */ 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/* --- Read registers. --- 19762306a36Sopenharmony_ci These are defined as byte-offsets from the iobase value */ 19862306a36Sopenharmony_ci#define HDSPM_statusRegister 0 19962306a36Sopenharmony_ci/*#define HDSPM_statusRegister2 96 */ 20062306a36Sopenharmony_ci/* after RME Windows driver sources, status2 is 4-byte word # 48 = word at 20162306a36Sopenharmony_ci * offset 192, for AES32 *and* MADI 20262306a36Sopenharmony_ci * => need to check that offset 192 is working on MADI */ 20362306a36Sopenharmony_ci#define HDSPM_statusRegister2 192 20462306a36Sopenharmony_ci#define HDSPM_timecodeRegister 128 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* AIO, RayDAT */ 20762306a36Sopenharmony_ci#define HDSPM_RD_STATUS_0 0 20862306a36Sopenharmony_ci#define HDSPM_RD_STATUS_1 64 20962306a36Sopenharmony_ci#define HDSPM_RD_STATUS_2 128 21062306a36Sopenharmony_ci#define HDSPM_RD_STATUS_3 192 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci#define HDSPM_RD_TCO 256 21362306a36Sopenharmony_ci#define HDSPM_RD_PLL_FREQ 512 21462306a36Sopenharmony_ci#define HDSPM_WR_TCO 128 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci#define HDSPM_TCO1_TCO_lock 0x00000001 21762306a36Sopenharmony_ci#define HDSPM_TCO1_WCK_Input_Range_LSB 0x00000002 21862306a36Sopenharmony_ci#define HDSPM_TCO1_WCK_Input_Range_MSB 0x00000004 21962306a36Sopenharmony_ci#define HDSPM_TCO1_LTC_Input_valid 0x00000008 22062306a36Sopenharmony_ci#define HDSPM_TCO1_WCK_Input_valid 0x00000010 22162306a36Sopenharmony_ci#define HDSPM_TCO1_Video_Input_Format_NTSC 0x00000020 22262306a36Sopenharmony_ci#define HDSPM_TCO1_Video_Input_Format_PAL 0x00000040 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci#define HDSPM_TCO1_set_TC 0x00000100 22562306a36Sopenharmony_ci#define HDSPM_TCO1_set_drop_frame_flag 0x00000200 22662306a36Sopenharmony_ci#define HDSPM_TCO1_LTC_Format_LSB 0x00000400 22762306a36Sopenharmony_ci#define HDSPM_TCO1_LTC_Format_MSB 0x00000800 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#define HDSPM_TCO2_TC_run 0x00010000 23062306a36Sopenharmony_ci#define HDSPM_TCO2_WCK_IO_ratio_LSB 0x00020000 23162306a36Sopenharmony_ci#define HDSPM_TCO2_WCK_IO_ratio_MSB 0x00040000 23262306a36Sopenharmony_ci#define HDSPM_TCO2_set_num_drop_frames_LSB 0x00080000 23362306a36Sopenharmony_ci#define HDSPM_TCO2_set_num_drop_frames_MSB 0x00100000 23462306a36Sopenharmony_ci#define HDSPM_TCO2_set_jam_sync 0x00200000 23562306a36Sopenharmony_ci#define HDSPM_TCO2_set_flywheel 0x00400000 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci#define HDSPM_TCO2_set_01_4 0x01000000 23862306a36Sopenharmony_ci#define HDSPM_TCO2_set_pull_down 0x02000000 23962306a36Sopenharmony_ci#define HDSPM_TCO2_set_pull_up 0x04000000 24062306a36Sopenharmony_ci#define HDSPM_TCO2_set_freq 0x08000000 24162306a36Sopenharmony_ci#define HDSPM_TCO2_set_term_75R 0x10000000 24262306a36Sopenharmony_ci#define HDSPM_TCO2_set_input_LSB 0x20000000 24362306a36Sopenharmony_ci#define HDSPM_TCO2_set_input_MSB 0x40000000 24462306a36Sopenharmony_ci#define HDSPM_TCO2_set_freq_from_app 0x80000000 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci#define HDSPM_midiDataOut0 352 24862306a36Sopenharmony_ci#define HDSPM_midiDataOut1 356 24962306a36Sopenharmony_ci#define HDSPM_midiDataOut2 368 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci#define HDSPM_midiDataIn0 360 25262306a36Sopenharmony_ci#define HDSPM_midiDataIn1 364 25362306a36Sopenharmony_ci#define HDSPM_midiDataIn2 372 25462306a36Sopenharmony_ci#define HDSPM_midiDataIn3 376 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* status is data bytes in MIDI-FIFO (0-128) */ 25762306a36Sopenharmony_ci#define HDSPM_midiStatusOut0 384 25862306a36Sopenharmony_ci#define HDSPM_midiStatusOut1 388 25962306a36Sopenharmony_ci#define HDSPM_midiStatusOut2 400 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci#define HDSPM_midiStatusIn0 392 26262306a36Sopenharmony_ci#define HDSPM_midiStatusIn1 396 26362306a36Sopenharmony_ci#define HDSPM_midiStatusIn2 404 26462306a36Sopenharmony_ci#define HDSPM_midiStatusIn3 408 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/* the meters are regular i/o-mapped registers, but offset 26862306a36Sopenharmony_ci considerably from the rest. the peak registers are reset 26962306a36Sopenharmony_ci when read; the least-significant 4 bits are full-scale counters; 27062306a36Sopenharmony_ci the actual peak value is in the most-significant 24 bits. 27162306a36Sopenharmony_ci*/ 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci#define HDSPM_MADI_INPUT_PEAK 4096 27462306a36Sopenharmony_ci#define HDSPM_MADI_PLAYBACK_PEAK 4352 27562306a36Sopenharmony_ci#define HDSPM_MADI_OUTPUT_PEAK 4608 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci#define HDSPM_MADI_INPUT_RMS_L 6144 27862306a36Sopenharmony_ci#define HDSPM_MADI_PLAYBACK_RMS_L 6400 27962306a36Sopenharmony_ci#define HDSPM_MADI_OUTPUT_RMS_L 6656 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci#define HDSPM_MADI_INPUT_RMS_H 7168 28262306a36Sopenharmony_ci#define HDSPM_MADI_PLAYBACK_RMS_H 7424 28362306a36Sopenharmony_ci#define HDSPM_MADI_OUTPUT_RMS_H 7680 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci/* --- Control Register bits --------- */ 28662306a36Sopenharmony_ci#define HDSPM_Start (1<<0) /* start engine */ 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci#define HDSPM_Latency0 (1<<1) /* buffer size = 2^n */ 28962306a36Sopenharmony_ci#define HDSPM_Latency1 (1<<2) /* where n is defined */ 29062306a36Sopenharmony_ci#define HDSPM_Latency2 (1<<3) /* by Latency{2,1,0} */ 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci#define HDSPM_ClockModeMaster (1<<4) /* 1=Master, 0=Autosync */ 29362306a36Sopenharmony_ci#define HDSPM_c0Master 0x1 /* Master clock bit in settings 29462306a36Sopenharmony_ci register [RayDAT, AIO] */ 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci#define HDSPM_AudioInterruptEnable (1<<5) /* what do you think ? */ 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci#define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ 29962306a36Sopenharmony_ci#define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */ 30062306a36Sopenharmony_ci#define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ 30162306a36Sopenharmony_ci#define HDSPM_QuadSpeed (1<<31) /* quad speed bit */ 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci#define HDSPM_Professional (1<<9) /* Professional */ /* AES32 ONLY */ 30462306a36Sopenharmony_ci#define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1, 30562306a36Sopenharmony_ci 56channelMODE=0 */ /* MADI ONLY*/ 30662306a36Sopenharmony_ci#define HDSPM_Emphasis (1<<10) /* Emphasis */ /* AES32 ONLY */ 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci#define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode, 30962306a36Sopenharmony_ci 0=off, 1=on */ /* MADI ONLY */ 31062306a36Sopenharmony_ci#define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */ 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax 31362306a36Sopenharmony_ci * -- MADI ONLY 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_ci#define HDSPM_InputSelect1 (1<<15) /* should be 0 */ 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci#define HDSPM_SyncRef2 (1<<13) 31862306a36Sopenharmony_ci#define HDSPM_SyncRef3 (1<<25) 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci#define HDSPM_SMUX (1<<18) /* Frame ??? */ /* MADI ONY */ 32162306a36Sopenharmony_ci#define HDSPM_clr_tms (1<<19) /* clear track marker, do not use 32262306a36Sopenharmony_ci AES additional bits in 32362306a36Sopenharmony_ci lower 5 Audiodatabits ??? */ 32462306a36Sopenharmony_ci#define HDSPM_taxi_reset (1<<20) /* ??? */ /* MADI ONLY ? */ 32562306a36Sopenharmony_ci#define HDSPM_WCK48 (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */ 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci#define HDSPM_Midi0InterruptEnable 0x0400000 32862306a36Sopenharmony_ci#define HDSPM_Midi1InterruptEnable 0x0800000 32962306a36Sopenharmony_ci#define HDSPM_Midi2InterruptEnable 0x0200000 33062306a36Sopenharmony_ci#define HDSPM_Midi3InterruptEnable 0x4000000 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci#define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */ 33362306a36Sopenharmony_ci#define HDSPe_FLOAT_FORMAT 0x2000000 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci#define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */ 33662306a36Sopenharmony_ci#define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */ 33762306a36Sopenharmony_ci#define HDSPM_QS_QuadWire (1<<28) /* AES32 ONLY */ 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci#define HDSPM_wclk_sel (1<<30) 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* additional control register bits for AIO*/ 34262306a36Sopenharmony_ci#define HDSPM_c0_Wck48 0x20 /* also RayDAT */ 34362306a36Sopenharmony_ci#define HDSPM_c0_Input0 0x1000 34462306a36Sopenharmony_ci#define HDSPM_c0_Input1 0x2000 34562306a36Sopenharmony_ci#define HDSPM_c0_Spdif_Opt 0x4000 34662306a36Sopenharmony_ci#define HDSPM_c0_Pro 0x8000 34762306a36Sopenharmony_ci#define HDSPM_c0_clr_tms 0x10000 34862306a36Sopenharmony_ci#define HDSPM_c0_AEB1 0x20000 34962306a36Sopenharmony_ci#define HDSPM_c0_AEB2 0x40000 35062306a36Sopenharmony_ci#define HDSPM_c0_LineOut 0x80000 35162306a36Sopenharmony_ci#define HDSPM_c0_AD_GAIN0 0x100000 35262306a36Sopenharmony_ci#define HDSPM_c0_AD_GAIN1 0x200000 35362306a36Sopenharmony_ci#define HDSPM_c0_DA_GAIN0 0x400000 35462306a36Sopenharmony_ci#define HDSPM_c0_DA_GAIN1 0x800000 35562306a36Sopenharmony_ci#define HDSPM_c0_PH_GAIN0 0x1000000 35662306a36Sopenharmony_ci#define HDSPM_c0_PH_GAIN1 0x2000000 35762306a36Sopenharmony_ci#define HDSPM_c0_Sym6db 0x4000000 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/* --- bit helper defines */ 36162306a36Sopenharmony_ci#define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) 36262306a36Sopenharmony_ci#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ 36362306a36Sopenharmony_ci HDSPM_DoubleSpeed|HDSPM_QuadSpeed) 36462306a36Sopenharmony_ci#define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) 36562306a36Sopenharmony_ci#define HDSPM_InputOptical 0 36662306a36Sopenharmony_ci#define HDSPM_InputCoaxial (HDSPM_InputSelect0) 36762306a36Sopenharmony_ci#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|\ 36862306a36Sopenharmony_ci HDSPM_SyncRef2|HDSPM_SyncRef3) 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci#define HDSPM_c0_SyncRef0 0x2 37162306a36Sopenharmony_ci#define HDSPM_c0_SyncRef1 0x4 37262306a36Sopenharmony_ci#define HDSPM_c0_SyncRef2 0x8 37362306a36Sopenharmony_ci#define HDSPM_c0_SyncRef3 0x10 37462306a36Sopenharmony_ci#define HDSPM_c0_SyncRefMask (HDSPM_c0_SyncRef0 | HDSPM_c0_SyncRef1 |\ 37562306a36Sopenharmony_ci HDSPM_c0_SyncRef2 | HDSPM_c0_SyncRef3) 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci#define HDSPM_SYNC_FROM_WORD 0 /* Preferred sync reference */ 37862306a36Sopenharmony_ci#define HDSPM_SYNC_FROM_MADI 1 /* choices - used by "pref_sync_ref" */ 37962306a36Sopenharmony_ci#define HDSPM_SYNC_FROM_TCO 2 38062306a36Sopenharmony_ci#define HDSPM_SYNC_FROM_SYNC_IN 3 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci#define HDSPM_Frequency32KHz HDSPM_Frequency0 38362306a36Sopenharmony_ci#define HDSPM_Frequency44_1KHz HDSPM_Frequency1 38462306a36Sopenharmony_ci#define HDSPM_Frequency48KHz (HDSPM_Frequency1|HDSPM_Frequency0) 38562306a36Sopenharmony_ci#define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) 38662306a36Sopenharmony_ci#define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) 38762306a36Sopenharmony_ci#define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|\ 38862306a36Sopenharmony_ci HDSPM_Frequency0) 38962306a36Sopenharmony_ci#define HDSPM_Frequency128KHz (HDSPM_QuadSpeed|HDSPM_Frequency0) 39062306a36Sopenharmony_ci#define HDSPM_Frequency176_4KHz (HDSPM_QuadSpeed|HDSPM_Frequency1) 39162306a36Sopenharmony_ci#define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|\ 39262306a36Sopenharmony_ci HDSPM_Frequency0) 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci/* Synccheck Status */ 39662306a36Sopenharmony_ci#define HDSPM_SYNC_CHECK_NO_LOCK 0 39762306a36Sopenharmony_ci#define HDSPM_SYNC_CHECK_LOCK 1 39862306a36Sopenharmony_ci#define HDSPM_SYNC_CHECK_SYNC 2 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/* AutoSync References - used by "autosync_ref" control switch */ 40162306a36Sopenharmony_ci#define HDSPM_AUTOSYNC_FROM_WORD 0 40262306a36Sopenharmony_ci#define HDSPM_AUTOSYNC_FROM_MADI 1 40362306a36Sopenharmony_ci#define HDSPM_AUTOSYNC_FROM_TCO 2 40462306a36Sopenharmony_ci#define HDSPM_AUTOSYNC_FROM_SYNC_IN 3 40562306a36Sopenharmony_ci#define HDSPM_AUTOSYNC_FROM_NONE 4 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci/* Possible sources of MADI input */ 40862306a36Sopenharmony_ci#define HDSPM_OPTICAL 0 /* optical */ 40962306a36Sopenharmony_ci#define HDSPM_COAXIAL 1 /* BNC */ 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci#define hdspm_encode_latency(x) (((x)<<1) & HDSPM_LatencyMask) 41262306a36Sopenharmony_ci#define hdspm_decode_latency(x) ((((x) & HDSPM_LatencyMask)>>1)) 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci#define hdspm_encode_in(x) (((x)&0x3)<<14) 41562306a36Sopenharmony_ci#define hdspm_decode_in(x) (((x)>>14)&0x3) 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* --- control2 register bits --- */ 41862306a36Sopenharmony_ci#define HDSPM_TMS (1<<0) 41962306a36Sopenharmony_ci#define HDSPM_TCK (1<<1) 42062306a36Sopenharmony_ci#define HDSPM_TDI (1<<2) 42162306a36Sopenharmony_ci#define HDSPM_JTAG (1<<3) 42262306a36Sopenharmony_ci#define HDSPM_PWDN (1<<4) 42362306a36Sopenharmony_ci#define HDSPM_PROGRAM (1<<5) 42462306a36Sopenharmony_ci#define HDSPM_CONFIG_MODE_0 (1<<6) 42562306a36Sopenharmony_ci#define HDSPM_CONFIG_MODE_1 (1<<7) 42662306a36Sopenharmony_ci/*#define HDSPM_VERSION_BIT (1<<8) not defined any more*/ 42762306a36Sopenharmony_ci#define HDSPM_BIGENDIAN_MODE (1<<9) 42862306a36Sopenharmony_ci#define HDSPM_RD_MULTIPLE (1<<10) 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci/* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and 43162306a36Sopenharmony_ci that do not conflict with specific bits for AES32 seem to be valid also 43262306a36Sopenharmony_ci for the AES32 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_ci#define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ 43562306a36Sopenharmony_ci#define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn MODE=0 */ 43662306a36Sopenharmony_ci#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 43762306a36Sopenharmony_ci * (like inp0) 43862306a36Sopenharmony_ci */ 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci#define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ 44162306a36Sopenharmony_ci#define HDSPM_madiSync (1<<18) /* MADI is in sync */ 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci#define HDSPM_tcoLockMadi 0x00000020 /* Optional TCO locked status for HDSPe MADI*/ 44462306a36Sopenharmony_ci#define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/ 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci#define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */ 44762306a36Sopenharmony_ci#define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */ 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci#define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ 45062306a36Sopenharmony_ci /* since 64byte accurate, last 6 bits are not used */ 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci#define HDSPM_DoubleSpeedStatus (1<<19) /* (input) card in double speed */ 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci#define HDSPM_madiFreq0 (1<<22) /* system freq 0=error */ 45762306a36Sopenharmony_ci#define HDSPM_madiFreq1 (1<<23) /* 1=32, 2=44.1 3=48 */ 45862306a36Sopenharmony_ci#define HDSPM_madiFreq2 (1<<24) /* 4=64, 5=88.2 6=96 */ 45962306a36Sopenharmony_ci#define HDSPM_madiFreq3 (1<<25) /* 7=128, 8=176.4 9=192 */ 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci#define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with 46262306a36Sopenharmony_ci * Interrupt 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci#define HDSPM_tco_detect 0x08000000 46562306a36Sopenharmony_ci#define HDSPM_tcoLockAes 0x20000000 /* Optional TCO locked status for HDSPe AES */ 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci#define HDSPM_s2_tco_detect 0x00000040 46862306a36Sopenharmony_ci#define HDSPM_s2_AEBO_D 0x00000080 46962306a36Sopenharmony_ci#define HDSPM_s2_AEBI_D 0x00000100 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci#define HDSPM_midi0IRQPending 0x40000000 47362306a36Sopenharmony_ci#define HDSPM_midi1IRQPending 0x80000000 47462306a36Sopenharmony_ci#define HDSPM_midi2IRQPending 0x20000000 47562306a36Sopenharmony_ci#define HDSPM_midi2IRQPendingAES 0x00000020 47662306a36Sopenharmony_ci#define HDSPM_midi3IRQPending 0x00200000 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci/* --- status bit helpers */ 47962306a36Sopenharmony_ci#define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|\ 48062306a36Sopenharmony_ci HDSPM_madiFreq2|HDSPM_madiFreq3) 48162306a36Sopenharmony_ci#define HDSPM_madiFreq32 (HDSPM_madiFreq0) 48262306a36Sopenharmony_ci#define HDSPM_madiFreq44_1 (HDSPM_madiFreq1) 48362306a36Sopenharmony_ci#define HDSPM_madiFreq48 (HDSPM_madiFreq0|HDSPM_madiFreq1) 48462306a36Sopenharmony_ci#define HDSPM_madiFreq64 (HDSPM_madiFreq2) 48562306a36Sopenharmony_ci#define HDSPM_madiFreq88_2 (HDSPM_madiFreq0|HDSPM_madiFreq2) 48662306a36Sopenharmony_ci#define HDSPM_madiFreq96 (HDSPM_madiFreq1|HDSPM_madiFreq2) 48762306a36Sopenharmony_ci#define HDSPM_madiFreq128 (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2) 48862306a36Sopenharmony_ci#define HDSPM_madiFreq176_4 (HDSPM_madiFreq3) 48962306a36Sopenharmony_ci#define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0) 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci/* Status2 Register bits */ /* MADI ONLY */ 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci#define HDSPM_version0 (1<<0) /* not really defined but I guess */ 49462306a36Sopenharmony_ci#define HDSPM_version1 (1<<1) /* in former cards it was ??? */ 49562306a36Sopenharmony_ci#define HDSPM_version2 (1<<2) 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci#define HDSPM_wcLock (1<<3) /* Wordclock is detected and locked */ 49862306a36Sopenharmony_ci#define HDSPM_wcSync (1<<4) /* Wordclock is in sync with systemclock */ 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci#define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */ 50162306a36Sopenharmony_ci#define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */ 50262306a36Sopenharmony_ci#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, 111=128 */ 50362306a36Sopenharmony_ci#define HDSPM_wc_freq3 0x800 /* 1000=176.4, 1001=192 */ 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci#define HDSPM_SyncRef0 0x10000 /* Sync Reference */ 50662306a36Sopenharmony_ci#define HDSPM_SyncRef1 0x20000 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci#define HDSPM_SelSyncRef0 (1<<8) /* AutoSync Source */ 50962306a36Sopenharmony_ci#define HDSPM_SelSyncRef1 (1<<9) /* 000=word, 001=MADI, */ 51062306a36Sopenharmony_ci#define HDSPM_SelSyncRef2 (1<<10) /* 111=no valid signal */ 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci#define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync) 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2|\ 51562306a36Sopenharmony_ci HDSPM_wc_freq3) 51662306a36Sopenharmony_ci#define HDSPM_wcFreq32 (HDSPM_wc_freq0) 51762306a36Sopenharmony_ci#define HDSPM_wcFreq44_1 (HDSPM_wc_freq1) 51862306a36Sopenharmony_ci#define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1) 51962306a36Sopenharmony_ci#define HDSPM_wcFreq64 (HDSPM_wc_freq2) 52062306a36Sopenharmony_ci#define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2) 52162306a36Sopenharmony_ci#define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) 52262306a36Sopenharmony_ci#define HDSPM_wcFreq128 (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) 52362306a36Sopenharmony_ci#define HDSPM_wcFreq176_4 (HDSPM_wc_freq3) 52462306a36Sopenharmony_ci#define HDSPM_wcFreq192 (HDSPM_wc_freq0|HDSPM_wc_freq3) 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci#define HDSPM_status1_F_0 0x0400000 52762306a36Sopenharmony_ci#define HDSPM_status1_F_1 0x0800000 52862306a36Sopenharmony_ci#define HDSPM_status1_F_2 0x1000000 52962306a36Sopenharmony_ci#define HDSPM_status1_F_3 0x2000000 53062306a36Sopenharmony_ci#define HDSPM_status1_freqMask (HDSPM_status1_F_0|HDSPM_status1_F_1|HDSPM_status1_F_2|HDSPM_status1_F_3) 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci#define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ 53462306a36Sopenharmony_ci HDSPM_SelSyncRef2) 53562306a36Sopenharmony_ci#define HDSPM_SelSyncRef_WORD 0 53662306a36Sopenharmony_ci#define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) 53762306a36Sopenharmony_ci#define HDSPM_SelSyncRef_TCO (HDSPM_SelSyncRef1) 53862306a36Sopenharmony_ci#define HDSPM_SelSyncRef_SyncIn (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1) 53962306a36Sopenharmony_ci#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ 54062306a36Sopenharmony_ci HDSPM_SelSyncRef2) 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/* 54362306a36Sopenharmony_ci For AES32, bits for status, status2 and timecode are different 54462306a36Sopenharmony_ci*/ 54562306a36Sopenharmony_ci/* status */ 54662306a36Sopenharmony_ci#define HDSPM_AES32_wcLock 0x0200000 54762306a36Sopenharmony_ci#define HDSPM_AES32_wcSync 0x0100000 54862306a36Sopenharmony_ci#define HDSPM_AES32_wcFreq_bit 22 54962306a36Sopenharmony_ci/* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function 55062306a36Sopenharmony_ci HDSPM_bit2freq */ 55162306a36Sopenharmony_ci#define HDSPM_AES32_syncref_bit 16 55262306a36Sopenharmony_ci/* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */ 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_WORD 0 55562306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES1 1 55662306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES2 2 55762306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES3 3 55862306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES4 4 55962306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES5 5 56062306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 56162306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 56262306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 56362306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_TCO 9 56462306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10 56562306a36Sopenharmony_ci#define HDSPM_AES32_AUTOSYNC_FROM_NONE 11 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci/* status2 */ 56862306a36Sopenharmony_ci/* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ 56962306a36Sopenharmony_ci#define HDSPM_LockAES 0x80 57062306a36Sopenharmony_ci#define HDSPM_LockAES1 0x80 57162306a36Sopenharmony_ci#define HDSPM_LockAES2 0x40 57262306a36Sopenharmony_ci#define HDSPM_LockAES3 0x20 57362306a36Sopenharmony_ci#define HDSPM_LockAES4 0x10 57462306a36Sopenharmony_ci#define HDSPM_LockAES5 0x8 57562306a36Sopenharmony_ci#define HDSPM_LockAES6 0x4 57662306a36Sopenharmony_ci#define HDSPM_LockAES7 0x2 57762306a36Sopenharmony_ci#define HDSPM_LockAES8 0x1 57862306a36Sopenharmony_ci/* 57962306a36Sopenharmony_ci Timecode 58062306a36Sopenharmony_ci After windows driver sources, bits 4*i to 4*i+3 give the input frequency on 58162306a36Sopenharmony_ci AES i+1 58262306a36Sopenharmony_ci bits 3210 58362306a36Sopenharmony_ci 0001 32kHz 58462306a36Sopenharmony_ci 0010 44.1kHz 58562306a36Sopenharmony_ci 0011 48kHz 58662306a36Sopenharmony_ci 0100 64kHz 58762306a36Sopenharmony_ci 0101 88.2kHz 58862306a36Sopenharmony_ci 0110 96kHz 58962306a36Sopenharmony_ci 0111 128kHz 59062306a36Sopenharmony_ci 1000 176.4kHz 59162306a36Sopenharmony_ci 1001 192kHz 59262306a36Sopenharmony_ci NB: Timecode register doesn't seem to work on AES32 card revision 230 59362306a36Sopenharmony_ci*/ 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci/* Mixer Values */ 59662306a36Sopenharmony_ci#define UNITY_GAIN 32768 /* = 65536/2 */ 59762306a36Sopenharmony_ci#define MINUS_INFINITY_GAIN 0 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci/* Number of channels for different Speed Modes */ 60062306a36Sopenharmony_ci#define MADI_SS_CHANNELS 64 60162306a36Sopenharmony_ci#define MADI_DS_CHANNELS 32 60262306a36Sopenharmony_ci#define MADI_QS_CHANNELS 16 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci#define RAYDAT_SS_CHANNELS 36 60562306a36Sopenharmony_ci#define RAYDAT_DS_CHANNELS 20 60662306a36Sopenharmony_ci#define RAYDAT_QS_CHANNELS 12 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci#define AIO_IN_SS_CHANNELS 14 60962306a36Sopenharmony_ci#define AIO_IN_DS_CHANNELS 10 61062306a36Sopenharmony_ci#define AIO_IN_QS_CHANNELS 8 61162306a36Sopenharmony_ci#define AIO_OUT_SS_CHANNELS 16 61262306a36Sopenharmony_ci#define AIO_OUT_DS_CHANNELS 12 61362306a36Sopenharmony_ci#define AIO_OUT_QS_CHANNELS 10 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci#define AES32_CHANNELS 16 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci/* the size of a substream (1 mono data stream) */ 61862306a36Sopenharmony_ci#define HDSPM_CHANNEL_BUFFER_SAMPLES (16*1024) 61962306a36Sopenharmony_ci#define HDSPM_CHANNEL_BUFFER_BYTES (4*HDSPM_CHANNEL_BUFFER_SAMPLES) 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci/* the size of the area we need to allocate for DMA transfers. the 62262306a36Sopenharmony_ci size is the same regardless of the number of channels, and 62362306a36Sopenharmony_ci also the latency to use. 62462306a36Sopenharmony_ci for one direction !!! 62562306a36Sopenharmony_ci*/ 62662306a36Sopenharmony_ci#define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) 62762306a36Sopenharmony_ci#define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci#define HDSPM_RAYDAT_REV 211 63062306a36Sopenharmony_ci#define HDSPM_AIO_REV 212 63162306a36Sopenharmony_ci#define HDSPM_MADIFACE_REV 213 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci/* speed factor modes */ 63462306a36Sopenharmony_ci#define HDSPM_SPEED_SINGLE 0 63562306a36Sopenharmony_ci#define HDSPM_SPEED_DOUBLE 1 63662306a36Sopenharmony_ci#define HDSPM_SPEED_QUAD 2 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci/* names for speed modes */ 63962306a36Sopenharmony_cistatic const char * const hdspm_speed_names[] = { "single", "double", "quad" }; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic const char *const texts_autosync_aes_tco[] = { "Word Clock", 64262306a36Sopenharmony_ci "AES1", "AES2", "AES3", "AES4", 64362306a36Sopenharmony_ci "AES5", "AES6", "AES7", "AES8", 64462306a36Sopenharmony_ci "TCO", "Sync In" 64562306a36Sopenharmony_ci}; 64662306a36Sopenharmony_cistatic const char *const texts_autosync_aes[] = { "Word Clock", 64762306a36Sopenharmony_ci "AES1", "AES2", "AES3", "AES4", 64862306a36Sopenharmony_ci "AES5", "AES6", "AES7", "AES8", 64962306a36Sopenharmony_ci "Sync In" 65062306a36Sopenharmony_ci}; 65162306a36Sopenharmony_cistatic const char *const texts_autosync_madi_tco[] = { "Word Clock", 65262306a36Sopenharmony_ci "MADI", "TCO", "Sync In" }; 65362306a36Sopenharmony_cistatic const char *const texts_autosync_madi[] = { "Word Clock", 65462306a36Sopenharmony_ci "MADI", "Sync In" }; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic const char *const texts_autosync_raydat_tco[] = { 65762306a36Sopenharmony_ci "Word Clock", 65862306a36Sopenharmony_ci "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", 65962306a36Sopenharmony_ci "AES", "SPDIF", "TCO", "Sync In" 66062306a36Sopenharmony_ci}; 66162306a36Sopenharmony_cistatic const char *const texts_autosync_raydat[] = { 66262306a36Sopenharmony_ci "Word Clock", 66362306a36Sopenharmony_ci "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", 66462306a36Sopenharmony_ci "AES", "SPDIF", "Sync In" 66562306a36Sopenharmony_ci}; 66662306a36Sopenharmony_cistatic const char *const texts_autosync_aio_tco[] = { 66762306a36Sopenharmony_ci "Word Clock", 66862306a36Sopenharmony_ci "ADAT", "AES", "SPDIF", "TCO", "Sync In" 66962306a36Sopenharmony_ci}; 67062306a36Sopenharmony_cistatic const char *const texts_autosync_aio[] = { "Word Clock", 67162306a36Sopenharmony_ci "ADAT", "AES", "SPDIF", "Sync In" }; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic const char *const texts_freq[] = { 67462306a36Sopenharmony_ci "No Lock", 67562306a36Sopenharmony_ci "32 kHz", 67662306a36Sopenharmony_ci "44.1 kHz", 67762306a36Sopenharmony_ci "48 kHz", 67862306a36Sopenharmony_ci "64 kHz", 67962306a36Sopenharmony_ci "88.2 kHz", 68062306a36Sopenharmony_ci "96 kHz", 68162306a36Sopenharmony_ci "128 kHz", 68262306a36Sopenharmony_ci "176.4 kHz", 68362306a36Sopenharmony_ci "192 kHz" 68462306a36Sopenharmony_ci}; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic const char * const texts_ports_madi[] = { 68762306a36Sopenharmony_ci "MADI.1", "MADI.2", "MADI.3", "MADI.4", "MADI.5", "MADI.6", 68862306a36Sopenharmony_ci "MADI.7", "MADI.8", "MADI.9", "MADI.10", "MADI.11", "MADI.12", 68962306a36Sopenharmony_ci "MADI.13", "MADI.14", "MADI.15", "MADI.16", "MADI.17", "MADI.18", 69062306a36Sopenharmony_ci "MADI.19", "MADI.20", "MADI.21", "MADI.22", "MADI.23", "MADI.24", 69162306a36Sopenharmony_ci "MADI.25", "MADI.26", "MADI.27", "MADI.28", "MADI.29", "MADI.30", 69262306a36Sopenharmony_ci "MADI.31", "MADI.32", "MADI.33", "MADI.34", "MADI.35", "MADI.36", 69362306a36Sopenharmony_ci "MADI.37", "MADI.38", "MADI.39", "MADI.40", "MADI.41", "MADI.42", 69462306a36Sopenharmony_ci "MADI.43", "MADI.44", "MADI.45", "MADI.46", "MADI.47", "MADI.48", 69562306a36Sopenharmony_ci "MADI.49", "MADI.50", "MADI.51", "MADI.52", "MADI.53", "MADI.54", 69662306a36Sopenharmony_ci "MADI.55", "MADI.56", "MADI.57", "MADI.58", "MADI.59", "MADI.60", 69762306a36Sopenharmony_ci "MADI.61", "MADI.62", "MADI.63", "MADI.64", 69862306a36Sopenharmony_ci}; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic const char * const texts_ports_raydat_ss[] = { 70262306a36Sopenharmony_ci "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4", "ADAT1.5", "ADAT1.6", 70362306a36Sopenharmony_ci "ADAT1.7", "ADAT1.8", "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4", 70462306a36Sopenharmony_ci "ADAT2.5", "ADAT2.6", "ADAT2.7", "ADAT2.8", "ADAT3.1", "ADAT3.2", 70562306a36Sopenharmony_ci "ADAT3.3", "ADAT3.4", "ADAT3.5", "ADAT3.6", "ADAT3.7", "ADAT3.8", 70662306a36Sopenharmony_ci "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4", "ADAT4.5", "ADAT4.6", 70762306a36Sopenharmony_ci "ADAT4.7", "ADAT4.8", 70862306a36Sopenharmony_ci "AES.L", "AES.R", 70962306a36Sopenharmony_ci "SPDIF.L", "SPDIF.R" 71062306a36Sopenharmony_ci}; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic const char * const texts_ports_raydat_ds[] = { 71362306a36Sopenharmony_ci "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4", 71462306a36Sopenharmony_ci "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4", 71562306a36Sopenharmony_ci "ADAT3.1", "ADAT3.2", "ADAT3.3", "ADAT3.4", 71662306a36Sopenharmony_ci "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4", 71762306a36Sopenharmony_ci "AES.L", "AES.R", 71862306a36Sopenharmony_ci "SPDIF.L", "SPDIF.R" 71962306a36Sopenharmony_ci}; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic const char * const texts_ports_raydat_qs[] = { 72262306a36Sopenharmony_ci "ADAT1.1", "ADAT1.2", 72362306a36Sopenharmony_ci "ADAT2.1", "ADAT2.2", 72462306a36Sopenharmony_ci "ADAT3.1", "ADAT3.2", 72562306a36Sopenharmony_ci "ADAT4.1", "ADAT4.2", 72662306a36Sopenharmony_ci "AES.L", "AES.R", 72762306a36Sopenharmony_ci "SPDIF.L", "SPDIF.R" 72862306a36Sopenharmony_ci}; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic const char * const texts_ports_aio_in_ss[] = { 73262306a36Sopenharmony_ci "Analogue.L", "Analogue.R", 73362306a36Sopenharmony_ci "AES.L", "AES.R", 73462306a36Sopenharmony_ci "SPDIF.L", "SPDIF.R", 73562306a36Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", 73662306a36Sopenharmony_ci "ADAT.7", "ADAT.8", 73762306a36Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 73862306a36Sopenharmony_ci}; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic const char * const texts_ports_aio_out_ss[] = { 74162306a36Sopenharmony_ci "Analogue.L", "Analogue.R", 74262306a36Sopenharmony_ci "AES.L", "AES.R", 74362306a36Sopenharmony_ci "SPDIF.L", "SPDIF.R", 74462306a36Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", 74562306a36Sopenharmony_ci "ADAT.7", "ADAT.8", 74662306a36Sopenharmony_ci "Phone.L", "Phone.R", 74762306a36Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 74862306a36Sopenharmony_ci}; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic const char * const texts_ports_aio_in_ds[] = { 75162306a36Sopenharmony_ci "Analogue.L", "Analogue.R", 75262306a36Sopenharmony_ci "AES.L", "AES.R", 75362306a36Sopenharmony_ci "SPDIF.L", "SPDIF.R", 75462306a36Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 75562306a36Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 75662306a36Sopenharmony_ci}; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cistatic const char * const texts_ports_aio_out_ds[] = { 75962306a36Sopenharmony_ci "Analogue.L", "Analogue.R", 76062306a36Sopenharmony_ci "AES.L", "AES.R", 76162306a36Sopenharmony_ci "SPDIF.L", "SPDIF.R", 76262306a36Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 76362306a36Sopenharmony_ci "Phone.L", "Phone.R", 76462306a36Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 76562306a36Sopenharmony_ci}; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic const char * const texts_ports_aio_in_qs[] = { 76862306a36Sopenharmony_ci "Analogue.L", "Analogue.R", 76962306a36Sopenharmony_ci "AES.L", "AES.R", 77062306a36Sopenharmony_ci "SPDIF.L", "SPDIF.R", 77162306a36Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 77262306a36Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 77362306a36Sopenharmony_ci}; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cistatic const char * const texts_ports_aio_out_qs[] = { 77662306a36Sopenharmony_ci "Analogue.L", "Analogue.R", 77762306a36Sopenharmony_ci "AES.L", "AES.R", 77862306a36Sopenharmony_ci "SPDIF.L", "SPDIF.R", 77962306a36Sopenharmony_ci "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", 78062306a36Sopenharmony_ci "Phone.L", "Phone.R", 78162306a36Sopenharmony_ci "AEB.1", "AEB.2", "AEB.3", "AEB.4" 78262306a36Sopenharmony_ci}; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic const char * const texts_ports_aes32[] = { 78562306a36Sopenharmony_ci "AES.1", "AES.2", "AES.3", "AES.4", "AES.5", "AES.6", "AES.7", 78662306a36Sopenharmony_ci "AES.8", "AES.9.", "AES.10", "AES.11", "AES.12", "AES.13", "AES.14", 78762306a36Sopenharmony_ci "AES.15", "AES.16" 78862306a36Sopenharmony_ci}; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci/* These tables map the ALSA channels 1..N to the channels that we 79162306a36Sopenharmony_ci need to use in order to find the relevant channel buffer. RME 79262306a36Sopenharmony_ci refers to this kind of mapping as between "the ADAT channel and 79362306a36Sopenharmony_ci the DMA channel." We index it using the logical audio channel, 79462306a36Sopenharmony_ci and the value is the DMA channel (i.e. channel buffer number) 79562306a36Sopenharmony_ci where the data for that channel can be read/written from/to. 79662306a36Sopenharmony_ci*/ 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic const char channel_map_unity_ss[HDSPM_MAX_CHANNELS] = { 79962306a36Sopenharmony_ci 0, 1, 2, 3, 4, 5, 6, 7, 80062306a36Sopenharmony_ci 8, 9, 10, 11, 12, 13, 14, 15, 80162306a36Sopenharmony_ci 16, 17, 18, 19, 20, 21, 22, 23, 80262306a36Sopenharmony_ci 24, 25, 26, 27, 28, 29, 30, 31, 80362306a36Sopenharmony_ci 32, 33, 34, 35, 36, 37, 38, 39, 80462306a36Sopenharmony_ci 40, 41, 42, 43, 44, 45, 46, 47, 80562306a36Sopenharmony_ci 48, 49, 50, 51, 52, 53, 54, 55, 80662306a36Sopenharmony_ci 56, 57, 58, 59, 60, 61, 62, 63 80762306a36Sopenharmony_ci}; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic const char channel_map_raydat_ss[HDSPM_MAX_CHANNELS] = { 81062306a36Sopenharmony_ci 4, 5, 6, 7, 8, 9, 10, 11, /* ADAT 1 */ 81162306a36Sopenharmony_ci 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT 2 */ 81262306a36Sopenharmony_ci 20, 21, 22, 23, 24, 25, 26, 27, /* ADAT 3 */ 81362306a36Sopenharmony_ci 28, 29, 30, 31, 32, 33, 34, 35, /* ADAT 4 */ 81462306a36Sopenharmony_ci 0, 1, /* AES */ 81562306a36Sopenharmony_ci 2, 3, /* SPDIF */ 81662306a36Sopenharmony_ci -1, -1, -1, -1, 81762306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 81862306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 81962306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 82062306a36Sopenharmony_ci}; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic const char channel_map_raydat_ds[HDSPM_MAX_CHANNELS] = { 82362306a36Sopenharmony_ci 4, 5, 6, 7, /* ADAT 1 */ 82462306a36Sopenharmony_ci 8, 9, 10, 11, /* ADAT 2 */ 82562306a36Sopenharmony_ci 12, 13, 14, 15, /* ADAT 3 */ 82662306a36Sopenharmony_ci 16, 17, 18, 19, /* ADAT 4 */ 82762306a36Sopenharmony_ci 0, 1, /* AES */ 82862306a36Sopenharmony_ci 2, 3, /* SPDIF */ 82962306a36Sopenharmony_ci -1, -1, -1, -1, 83062306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 83162306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 83262306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 83362306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 83462306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 83562306a36Sopenharmony_ci}; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic const char channel_map_raydat_qs[HDSPM_MAX_CHANNELS] = { 83862306a36Sopenharmony_ci 4, 5, /* ADAT 1 */ 83962306a36Sopenharmony_ci 6, 7, /* ADAT 2 */ 84062306a36Sopenharmony_ci 8, 9, /* ADAT 3 */ 84162306a36Sopenharmony_ci 10, 11, /* ADAT 4 */ 84262306a36Sopenharmony_ci 0, 1, /* AES */ 84362306a36Sopenharmony_ci 2, 3, /* SPDIF */ 84462306a36Sopenharmony_ci -1, -1, -1, -1, 84562306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 84662306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 84762306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 84862306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 84962306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 85062306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 85162306a36Sopenharmony_ci}; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic const char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = { 85462306a36Sopenharmony_ci 0, 1, /* line in */ 85562306a36Sopenharmony_ci 8, 9, /* aes in, */ 85662306a36Sopenharmony_ci 10, 11, /* spdif in */ 85762306a36Sopenharmony_ci 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */ 85862306a36Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 85962306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, 86062306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 86162306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 86262306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 86362306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 86462306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 86562306a36Sopenharmony_ci}; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic const char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = { 86862306a36Sopenharmony_ci 0, 1, /* line out */ 86962306a36Sopenharmony_ci 8, 9, /* aes out */ 87062306a36Sopenharmony_ci 10, 11, /* spdif out */ 87162306a36Sopenharmony_ci 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */ 87262306a36Sopenharmony_ci 6, 7, /* phone out */ 87362306a36Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 87462306a36Sopenharmony_ci -1, -1, -1, -1, 87562306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 87662306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 87762306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 87862306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 87962306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 88062306a36Sopenharmony_ci}; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic const char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = { 88362306a36Sopenharmony_ci 0, 1, /* line in */ 88462306a36Sopenharmony_ci 8, 9, /* aes in */ 88562306a36Sopenharmony_ci 10, 11, /* spdif in */ 88662306a36Sopenharmony_ci 12, 14, 16, 18, /* adat in */ 88762306a36Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 88862306a36Sopenharmony_ci -1, -1, 88962306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 89062306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 89162306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 89262306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 89362306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 89462306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 89562306a36Sopenharmony_ci}; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic const char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = { 89862306a36Sopenharmony_ci 0, 1, /* line out */ 89962306a36Sopenharmony_ci 8, 9, /* aes out */ 90062306a36Sopenharmony_ci 10, 11, /* spdif out */ 90162306a36Sopenharmony_ci 12, 14, 16, 18, /* adat out */ 90262306a36Sopenharmony_ci 6, 7, /* phone out */ 90362306a36Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 90462306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 90562306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 90662306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 90762306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 90862306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 90962306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 91062306a36Sopenharmony_ci}; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_cistatic const char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = { 91362306a36Sopenharmony_ci 0, 1, /* line in */ 91462306a36Sopenharmony_ci 8, 9, /* aes in */ 91562306a36Sopenharmony_ci 10, 11, /* spdif in */ 91662306a36Sopenharmony_ci 12, 16, /* adat in */ 91762306a36Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 91862306a36Sopenharmony_ci -1, -1, -1, -1, 91962306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 92062306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 92162306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 92262306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 92362306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 92462306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 92562306a36Sopenharmony_ci}; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic const char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = { 92862306a36Sopenharmony_ci 0, 1, /* line out */ 92962306a36Sopenharmony_ci 8, 9, /* aes out */ 93062306a36Sopenharmony_ci 10, 11, /* spdif out */ 93162306a36Sopenharmony_ci 12, 16, /* adat out */ 93262306a36Sopenharmony_ci 6, 7, /* phone out */ 93362306a36Sopenharmony_ci 2, 3, 4, 5, /* AEB */ 93462306a36Sopenharmony_ci -1, -1, 93562306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 93662306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 93762306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 93862306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 93962306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 94062306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 94162306a36Sopenharmony_ci}; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic const char channel_map_aes32[HDSPM_MAX_CHANNELS] = { 94462306a36Sopenharmony_ci 0, 1, 2, 3, 4, 5, 6, 7, 94562306a36Sopenharmony_ci 8, 9, 10, 11, 12, 13, 14, 15, 94662306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 94762306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 94862306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 94962306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 95062306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 95162306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 95262306a36Sopenharmony_ci}; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistruct hdspm_midi { 95562306a36Sopenharmony_ci struct hdspm *hdspm; 95662306a36Sopenharmony_ci int id; 95762306a36Sopenharmony_ci struct snd_rawmidi *rmidi; 95862306a36Sopenharmony_ci struct snd_rawmidi_substream *input; 95962306a36Sopenharmony_ci struct snd_rawmidi_substream *output; 96062306a36Sopenharmony_ci char istimer; /* timer in use */ 96162306a36Sopenharmony_ci struct timer_list timer; 96262306a36Sopenharmony_ci spinlock_t lock; 96362306a36Sopenharmony_ci int pending; 96462306a36Sopenharmony_ci int dataIn; 96562306a36Sopenharmony_ci int statusIn; 96662306a36Sopenharmony_ci int dataOut; 96762306a36Sopenharmony_ci int statusOut; 96862306a36Sopenharmony_ci int ie; 96962306a36Sopenharmony_ci int irq; 97062306a36Sopenharmony_ci}; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_cistruct hdspm_tco { 97362306a36Sopenharmony_ci int input; /* 0: LTC, 1:Video, 2: WC*/ 97462306a36Sopenharmony_ci int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */ 97562306a36Sopenharmony_ci int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */ 97662306a36Sopenharmony_ci int samplerate; /* 0=44.1, 1=48, 2= freq from app */ 97762306a36Sopenharmony_ci int pull; /* 0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/ 97862306a36Sopenharmony_ci int term; /* 0 = off, 1 = on */ 97962306a36Sopenharmony_ci}; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cistruct hdspm { 98262306a36Sopenharmony_ci spinlock_t lock; 98362306a36Sopenharmony_ci /* only one playback and/or capture stream */ 98462306a36Sopenharmony_ci struct snd_pcm_substream *capture_substream; 98562306a36Sopenharmony_ci struct snd_pcm_substream *playback_substream; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci char *card_name; /* for procinfo */ 98862306a36Sopenharmony_ci unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/ 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci uint8_t io_type; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci int monitor_outs; /* set up monitoring outs init flag */ 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci u32 control_register; /* cached value */ 99562306a36Sopenharmony_ci u32 control2_register; /* cached value */ 99662306a36Sopenharmony_ci u32 settings_register; /* cached value for AIO / RayDat (sync reference, master/slave) */ 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci struct hdspm_midi midi[4]; 99962306a36Sopenharmony_ci struct work_struct midi_work; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci size_t period_bytes; 100262306a36Sopenharmony_ci unsigned char ss_in_channels; 100362306a36Sopenharmony_ci unsigned char ds_in_channels; 100462306a36Sopenharmony_ci unsigned char qs_in_channels; 100562306a36Sopenharmony_ci unsigned char ss_out_channels; 100662306a36Sopenharmony_ci unsigned char ds_out_channels; 100762306a36Sopenharmony_ci unsigned char qs_out_channels; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci unsigned char max_channels_in; 101062306a36Sopenharmony_ci unsigned char max_channels_out; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci const signed char *channel_map_in; 101362306a36Sopenharmony_ci const signed char *channel_map_out; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci const signed char *channel_map_in_ss, *channel_map_in_ds, *channel_map_in_qs; 101662306a36Sopenharmony_ci const signed char *channel_map_out_ss, *channel_map_out_ds, *channel_map_out_qs; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci const char * const *port_names_in; 101962306a36Sopenharmony_ci const char * const *port_names_out; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci const char * const *port_names_in_ss; 102262306a36Sopenharmony_ci const char * const *port_names_in_ds; 102362306a36Sopenharmony_ci const char * const *port_names_in_qs; 102462306a36Sopenharmony_ci const char * const *port_names_out_ss; 102562306a36Sopenharmony_ci const char * const *port_names_out_ds; 102662306a36Sopenharmony_ci const char * const *port_names_out_qs; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci unsigned char *playback_buffer; /* suitably aligned address */ 102962306a36Sopenharmony_ci unsigned char *capture_buffer; /* suitably aligned address */ 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci pid_t capture_pid; /* process id which uses capture */ 103262306a36Sopenharmony_ci pid_t playback_pid; /* process id which uses capture */ 103362306a36Sopenharmony_ci int running; /* running status */ 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci int last_external_sample_rate; /* samplerate mystic ... */ 103662306a36Sopenharmony_ci int last_internal_sample_rate; 103762306a36Sopenharmony_ci int system_sample_rate; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci int dev; /* Hardware vars... */ 104062306a36Sopenharmony_ci int irq; 104162306a36Sopenharmony_ci unsigned long port; 104262306a36Sopenharmony_ci void __iomem *iobase; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci int irq_count; /* for debug */ 104562306a36Sopenharmony_ci int midiPorts; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci struct snd_card *card; /* one card */ 104862306a36Sopenharmony_ci struct snd_pcm *pcm; /* has one pcm */ 104962306a36Sopenharmony_ci struct snd_hwdep *hwdep; /* and a hwdep for additional ioctl */ 105062306a36Sopenharmony_ci struct pci_dev *pci; /* and an pci info */ 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci /* Mixer vars */ 105362306a36Sopenharmony_ci /* fast alsa mixer */ 105462306a36Sopenharmony_ci struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; 105562306a36Sopenharmony_ci /* but input to much, so not used */ 105662306a36Sopenharmony_ci struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS]; 105762306a36Sopenharmony_ci /* full mixer accessible over mixer ioctl or hwdep-device */ 105862306a36Sopenharmony_ci struct hdspm_mixer *mixer; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci struct hdspm_tco *tco; /* NULL if no TCO detected */ 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci const char *const *texts_autosync; 106362306a36Sopenharmony_ci int texts_autosync_items; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci cycles_t last_interrupt; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci unsigned int serial; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci struct hdspm_peak_rms peak_rms; 107062306a36Sopenharmony_ci}; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_cistatic const struct pci_device_id snd_hdspm_ids[] = { 107462306a36Sopenharmony_ci { 107562306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_XILINX, 107662306a36Sopenharmony_ci .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, 107762306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 107862306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 107962306a36Sopenharmony_ci .class = 0, 108062306a36Sopenharmony_ci .class_mask = 0, 108162306a36Sopenharmony_ci .driver_data = 0}, 108262306a36Sopenharmony_ci {0,} 108362306a36Sopenharmony_ci}; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_hdspm_ids); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci/* prototypes */ 108862306a36Sopenharmony_cistatic int snd_hdspm_create_alsa_devices(struct snd_card *card, 108962306a36Sopenharmony_ci struct hdspm *hdspm); 109062306a36Sopenharmony_cistatic int snd_hdspm_create_pcm(struct snd_card *card, 109162306a36Sopenharmony_ci struct hdspm *hdspm); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistatic inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm); 109462306a36Sopenharmony_cistatic inline int hdspm_get_pll_freq(struct hdspm *hdspm); 109562306a36Sopenharmony_cistatic int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); 109662306a36Sopenharmony_cistatic int hdspm_autosync_ref(struct hdspm *hdspm); 109762306a36Sopenharmony_cistatic int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out); 109862306a36Sopenharmony_cistatic int snd_hdspm_set_defaults(struct hdspm *hdspm); 109962306a36Sopenharmony_cistatic int hdspm_system_clock_mode(struct hdspm *hdspm); 110062306a36Sopenharmony_cistatic void hdspm_set_channel_dma_addr(struct hdspm *hdspm, 110162306a36Sopenharmony_ci struct snd_pcm_substream *substream, 110262306a36Sopenharmony_ci unsigned int reg, int channels); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistatic int hdspm_aes_sync_check(struct hdspm *hdspm, int idx); 110562306a36Sopenharmony_cistatic int hdspm_wc_sync_check(struct hdspm *hdspm); 110662306a36Sopenharmony_cistatic int hdspm_tco_sync_check(struct hdspm *hdspm); 110762306a36Sopenharmony_cistatic int hdspm_sync_in_sync_check(struct hdspm *hdspm); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_cistatic int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index); 111062306a36Sopenharmony_cistatic int hdspm_get_tco_sample_rate(struct hdspm *hdspm); 111162306a36Sopenharmony_cistatic int hdspm_get_wc_sample_rate(struct hdspm *hdspm); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_cistatic inline int HDSPM_bit2freq(int n) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci static const int bit2freq_tab[] = { 111862306a36Sopenharmony_ci 0, 32000, 44100, 48000, 64000, 88200, 111962306a36Sopenharmony_ci 96000, 128000, 176400, 192000 }; 112062306a36Sopenharmony_ci if (n < 1 || n > 9) 112162306a36Sopenharmony_ci return 0; 112262306a36Sopenharmony_ci return bit2freq_tab[n]; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic bool hdspm_is_raydat_or_aio(struct hdspm *hdspm) 112662306a36Sopenharmony_ci{ 112762306a36Sopenharmony_ci return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type)); 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci/* Write/read to/from HDSPM with Adresses in Bytes 113262306a36Sopenharmony_ci not words but only 32Bit writes are allowed */ 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic inline void hdspm_write(struct hdspm * hdspm, unsigned int reg, 113562306a36Sopenharmony_ci unsigned int val) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci writel(val, hdspm->iobase + reg); 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cistatic inline unsigned int hdspm_read(struct hdspm * hdspm, unsigned int reg) 114162306a36Sopenharmony_ci{ 114262306a36Sopenharmony_ci return readl(hdspm->iobase + reg); 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci/* for each output channel (chan) I have an Input (in) and Playback (pb) Fader 114662306a36Sopenharmony_ci mixer is write only on hardware so we have to cache him for read 114762306a36Sopenharmony_ci each fader is a u32, but uses only the first 16 bit */ 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_cistatic inline int hdspm_read_in_gain(struct hdspm * hdspm, unsigned int chan, 115062306a36Sopenharmony_ci unsigned int in) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) 115362306a36Sopenharmony_ci return 0; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci return hdspm->mixer->ch[chan].in[in]; 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_cistatic inline int hdspm_read_pb_gain(struct hdspm * hdspm, unsigned int chan, 115962306a36Sopenharmony_ci unsigned int pb) 116062306a36Sopenharmony_ci{ 116162306a36Sopenharmony_ci if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) 116262306a36Sopenharmony_ci return 0; 116362306a36Sopenharmony_ci return hdspm->mixer->ch[chan].pb[pb]; 116462306a36Sopenharmony_ci} 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cistatic int hdspm_write_in_gain(struct hdspm *hdspm, unsigned int chan, 116762306a36Sopenharmony_ci unsigned int in, unsigned short data) 116862306a36Sopenharmony_ci{ 116962306a36Sopenharmony_ci if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) 117062306a36Sopenharmony_ci return -1; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci hdspm_write(hdspm, 117362306a36Sopenharmony_ci HDSPM_MADI_mixerBase + 117462306a36Sopenharmony_ci ((in + 128 * chan) * sizeof(u32)), 117562306a36Sopenharmony_ci (hdspm->mixer->ch[chan].in[in] = data & 0xFFFF)); 117662306a36Sopenharmony_ci return 0; 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic int hdspm_write_pb_gain(struct hdspm *hdspm, unsigned int chan, 118062306a36Sopenharmony_ci unsigned int pb, unsigned short data) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) 118362306a36Sopenharmony_ci return -1; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci hdspm_write(hdspm, 118662306a36Sopenharmony_ci HDSPM_MADI_mixerBase + 118762306a36Sopenharmony_ci ((64 + pb + 128 * chan) * sizeof(u32)), 118862306a36Sopenharmony_ci (hdspm->mixer->ch[chan].pb[pb] = data & 0xFFFF)); 118962306a36Sopenharmony_ci return 0; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci/* enable DMA for specific channels, now available for DSP-MADI */ 119462306a36Sopenharmony_cistatic inline void snd_hdspm_enable_in(struct hdspm * hdspm, int i, int v) 119562306a36Sopenharmony_ci{ 119662306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_inputEnableBase + (4 * i), v); 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic inline void snd_hdspm_enable_out(struct hdspm * hdspm, int i, int v) 120062306a36Sopenharmony_ci{ 120162306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_outputEnableBase + (4 * i), v); 120262306a36Sopenharmony_ci} 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci/* check if same process is writing and reading */ 120562306a36Sopenharmony_cistatic int snd_hdspm_use_is_exclusive(struct hdspm *hdspm) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci unsigned long flags; 120862306a36Sopenharmony_ci int ret = 1; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci spin_lock_irqsave(&hdspm->lock, flags); 121162306a36Sopenharmony_ci if ((hdspm->playback_pid != hdspm->capture_pid) && 121262306a36Sopenharmony_ci (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) { 121362306a36Sopenharmony_ci ret = 0; 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci spin_unlock_irqrestore(&hdspm->lock, flags); 121662306a36Sopenharmony_ci return ret; 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci/* round arbitrary sample rates to commonly known rates */ 122062306a36Sopenharmony_cistatic int hdspm_round_frequency(int rate) 122162306a36Sopenharmony_ci{ 122262306a36Sopenharmony_ci if (rate < 38050) 122362306a36Sopenharmony_ci return 32000; 122462306a36Sopenharmony_ci if (rate < 46008) 122562306a36Sopenharmony_ci return 44100; 122662306a36Sopenharmony_ci else 122762306a36Sopenharmony_ci return 48000; 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci/* QS and DS rates normally can not be detected 123162306a36Sopenharmony_ci * automatically by the card. Only exception is MADI 123262306a36Sopenharmony_ci * in 96k frame mode. 123362306a36Sopenharmony_ci * 123462306a36Sopenharmony_ci * So if we read SS values (32 .. 48k), check for 123562306a36Sopenharmony_ci * user-provided DS/QS bits in the control register 123662306a36Sopenharmony_ci * and multiply the base frequency accordingly. 123762306a36Sopenharmony_ci */ 123862306a36Sopenharmony_cistatic int hdspm_rate_multiplier(struct hdspm *hdspm, int rate) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci if (rate <= 48000) { 124162306a36Sopenharmony_ci if (hdspm->control_register & HDSPM_QuadSpeed) 124262306a36Sopenharmony_ci return rate * 4; 124362306a36Sopenharmony_ci else if (hdspm->control_register & 124462306a36Sopenharmony_ci HDSPM_DoubleSpeed) 124562306a36Sopenharmony_ci return rate * 2; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci return rate; 124862306a36Sopenharmony_ci} 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci/* check for external sample rate, returns the sample rate in Hz*/ 125162306a36Sopenharmony_cistatic int hdspm_external_sample_rate(struct hdspm *hdspm) 125262306a36Sopenharmony_ci{ 125362306a36Sopenharmony_ci unsigned int status, status2; 125462306a36Sopenharmony_ci int syncref, rate = 0, rate_bits; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci switch (hdspm->io_type) { 125762306a36Sopenharmony_ci case AES32: 125862306a36Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 125962306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci syncref = hdspm_autosync_ref(hdspm); 126262306a36Sopenharmony_ci switch (syncref) { 126362306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_WORD: 126462306a36Sopenharmony_ci /* Check WC sync and get sample rate */ 126562306a36Sopenharmony_ci if (hdspm_wc_sync_check(hdspm)) 126662306a36Sopenharmony_ci return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm)); 126762306a36Sopenharmony_ci break; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES1: 127062306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES2: 127162306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES3: 127262306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES4: 127362306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES5: 127462306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES6: 127562306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES7: 127662306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES8: 127762306a36Sopenharmony_ci /* Check AES sync and get sample rate */ 127862306a36Sopenharmony_ci if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)) 127962306a36Sopenharmony_ci return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm, 128062306a36Sopenharmony_ci syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)); 128162306a36Sopenharmony_ci break; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_TCO: 128562306a36Sopenharmony_ci /* Check TCO sync and get sample rate */ 128662306a36Sopenharmony_ci if (hdspm_tco_sync_check(hdspm)) 128762306a36Sopenharmony_ci return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm)); 128862306a36Sopenharmony_ci break; 128962306a36Sopenharmony_ci default: 129062306a36Sopenharmony_ci return 0; 129162306a36Sopenharmony_ci } /* end switch(syncref) */ 129262306a36Sopenharmony_ci break; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci case MADIface: 129562306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (!(status & HDSPM_madiLock)) { 129862306a36Sopenharmony_ci rate = 0; /* no lock */ 129962306a36Sopenharmony_ci } else { 130062306a36Sopenharmony_ci switch (status & (HDSPM_status1_freqMask)) { 130162306a36Sopenharmony_ci case HDSPM_status1_F_0*1: 130262306a36Sopenharmony_ci rate = 32000; break; 130362306a36Sopenharmony_ci case HDSPM_status1_F_0*2: 130462306a36Sopenharmony_ci rate = 44100; break; 130562306a36Sopenharmony_ci case HDSPM_status1_F_0*3: 130662306a36Sopenharmony_ci rate = 48000; break; 130762306a36Sopenharmony_ci case HDSPM_status1_F_0*4: 130862306a36Sopenharmony_ci rate = 64000; break; 130962306a36Sopenharmony_ci case HDSPM_status1_F_0*5: 131062306a36Sopenharmony_ci rate = 88200; break; 131162306a36Sopenharmony_ci case HDSPM_status1_F_0*6: 131262306a36Sopenharmony_ci rate = 96000; break; 131362306a36Sopenharmony_ci case HDSPM_status1_F_0*7: 131462306a36Sopenharmony_ci rate = 128000; break; 131562306a36Sopenharmony_ci case HDSPM_status1_F_0*8: 131662306a36Sopenharmony_ci rate = 176400; break; 131762306a36Sopenharmony_ci case HDSPM_status1_F_0*9: 131862306a36Sopenharmony_ci rate = 192000; break; 131962306a36Sopenharmony_ci default: 132062306a36Sopenharmony_ci rate = 0; break; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci break; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci case MADI: 132762306a36Sopenharmony_ci case AIO: 132862306a36Sopenharmony_ci case RayDAT: 132962306a36Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 133062306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 133162306a36Sopenharmony_ci rate = 0; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci /* if wordclock has synced freq and wordclock is valid */ 133462306a36Sopenharmony_ci if ((status2 & HDSPM_wcLock) != 0 && 133562306a36Sopenharmony_ci (status2 & HDSPM_SelSyncRef0) == 0) { 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci rate_bits = status2 & HDSPM_wcFreqMask; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci switch (rate_bits) { 134162306a36Sopenharmony_ci case HDSPM_wcFreq32: 134262306a36Sopenharmony_ci rate = 32000; 134362306a36Sopenharmony_ci break; 134462306a36Sopenharmony_ci case HDSPM_wcFreq44_1: 134562306a36Sopenharmony_ci rate = 44100; 134662306a36Sopenharmony_ci break; 134762306a36Sopenharmony_ci case HDSPM_wcFreq48: 134862306a36Sopenharmony_ci rate = 48000; 134962306a36Sopenharmony_ci break; 135062306a36Sopenharmony_ci case HDSPM_wcFreq64: 135162306a36Sopenharmony_ci rate = 64000; 135262306a36Sopenharmony_ci break; 135362306a36Sopenharmony_ci case HDSPM_wcFreq88_2: 135462306a36Sopenharmony_ci rate = 88200; 135562306a36Sopenharmony_ci break; 135662306a36Sopenharmony_ci case HDSPM_wcFreq96: 135762306a36Sopenharmony_ci rate = 96000; 135862306a36Sopenharmony_ci break; 135962306a36Sopenharmony_ci case HDSPM_wcFreq128: 136062306a36Sopenharmony_ci rate = 128000; 136162306a36Sopenharmony_ci break; 136262306a36Sopenharmony_ci case HDSPM_wcFreq176_4: 136362306a36Sopenharmony_ci rate = 176400; 136462306a36Sopenharmony_ci break; 136562306a36Sopenharmony_ci case HDSPM_wcFreq192: 136662306a36Sopenharmony_ci rate = 192000; 136762306a36Sopenharmony_ci break; 136862306a36Sopenharmony_ci default: 136962306a36Sopenharmony_ci rate = 0; 137062306a36Sopenharmony_ci break; 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci /* if rate detected and Syncref is Word than have it, 137562306a36Sopenharmony_ci * word has priority to MADI 137662306a36Sopenharmony_ci */ 137762306a36Sopenharmony_ci if (rate != 0 && 137862306a36Sopenharmony_ci (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) 137962306a36Sopenharmony_ci return hdspm_rate_multiplier(hdspm, rate); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci /* maybe a madi input (which is taken if sel sync is madi) */ 138262306a36Sopenharmony_ci if (status & HDSPM_madiLock) { 138362306a36Sopenharmony_ci rate_bits = status & HDSPM_madiFreqMask; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci switch (rate_bits) { 138662306a36Sopenharmony_ci case HDSPM_madiFreq32: 138762306a36Sopenharmony_ci rate = 32000; 138862306a36Sopenharmony_ci break; 138962306a36Sopenharmony_ci case HDSPM_madiFreq44_1: 139062306a36Sopenharmony_ci rate = 44100; 139162306a36Sopenharmony_ci break; 139262306a36Sopenharmony_ci case HDSPM_madiFreq48: 139362306a36Sopenharmony_ci rate = 48000; 139462306a36Sopenharmony_ci break; 139562306a36Sopenharmony_ci case HDSPM_madiFreq64: 139662306a36Sopenharmony_ci rate = 64000; 139762306a36Sopenharmony_ci break; 139862306a36Sopenharmony_ci case HDSPM_madiFreq88_2: 139962306a36Sopenharmony_ci rate = 88200; 140062306a36Sopenharmony_ci break; 140162306a36Sopenharmony_ci case HDSPM_madiFreq96: 140262306a36Sopenharmony_ci rate = 96000; 140362306a36Sopenharmony_ci break; 140462306a36Sopenharmony_ci case HDSPM_madiFreq128: 140562306a36Sopenharmony_ci rate = 128000; 140662306a36Sopenharmony_ci break; 140762306a36Sopenharmony_ci case HDSPM_madiFreq176_4: 140862306a36Sopenharmony_ci rate = 176400; 140962306a36Sopenharmony_ci break; 141062306a36Sopenharmony_ci case HDSPM_madiFreq192: 141162306a36Sopenharmony_ci rate = 192000; 141262306a36Sopenharmony_ci break; 141362306a36Sopenharmony_ci default: 141462306a36Sopenharmony_ci rate = 0; 141562306a36Sopenharmony_ci break; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci } /* endif HDSPM_madiLock */ 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci /* check sample rate from TCO or SYNC_IN */ 142162306a36Sopenharmony_ci { 142262306a36Sopenharmony_ci bool is_valid_input = 0; 142362306a36Sopenharmony_ci bool has_sync = 0; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci syncref = hdspm_autosync_ref(hdspm); 142662306a36Sopenharmony_ci if (HDSPM_AUTOSYNC_FROM_TCO == syncref) { 142762306a36Sopenharmony_ci is_valid_input = 1; 142862306a36Sopenharmony_ci has_sync = (HDSPM_SYNC_CHECK_SYNC == 142962306a36Sopenharmony_ci hdspm_tco_sync_check(hdspm)); 143062306a36Sopenharmony_ci } else if (HDSPM_AUTOSYNC_FROM_SYNC_IN == syncref) { 143162306a36Sopenharmony_ci is_valid_input = 1; 143262306a36Sopenharmony_ci has_sync = (HDSPM_SYNC_CHECK_SYNC == 143362306a36Sopenharmony_ci hdspm_sync_in_sync_check(hdspm)); 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci if (is_valid_input && has_sync) { 143762306a36Sopenharmony_ci rate = hdspm_round_frequency( 143862306a36Sopenharmony_ci hdspm_get_pll_freq(hdspm)); 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci rate = hdspm_rate_multiplier(hdspm, rate); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci break; 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci return rate; 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci/* return latency in samples per period */ 145162306a36Sopenharmony_cistatic int hdspm_get_latency(struct hdspm *hdspm) 145262306a36Sopenharmony_ci{ 145362306a36Sopenharmony_ci int n; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci n = hdspm_decode_latency(hdspm->control_register); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci /* Special case for new RME cards with 32 samples period size. 145862306a36Sopenharmony_ci * The three latency bits in the control register 145962306a36Sopenharmony_ci * (HDSP_LatencyMask) encode latency values of 64 samples as 146062306a36Sopenharmony_ci * 0, 128 samples as 1 ... 4096 samples as 6. For old cards, 7 146162306a36Sopenharmony_ci * denotes 8192 samples, but on new cards like RayDAT or AIO, 146262306a36Sopenharmony_ci * it corresponds to 32 samples. 146362306a36Sopenharmony_ci */ 146462306a36Sopenharmony_ci if ((7 == n) && (RayDAT == hdspm->io_type || AIO == hdspm->io_type)) 146562306a36Sopenharmony_ci n = -1; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci return 1 << (n + 6); 146862306a36Sopenharmony_ci} 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci/* Latency function */ 147162306a36Sopenharmony_cistatic inline void hdspm_compute_period_size(struct hdspm *hdspm) 147262306a36Sopenharmony_ci{ 147362306a36Sopenharmony_ci hdspm->period_bytes = 4 * hdspm_get_latency(hdspm); 147462306a36Sopenharmony_ci} 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_cistatic snd_pcm_uframes_t hdspm_hw_pointer(struct hdspm *hdspm) 147862306a36Sopenharmony_ci{ 147962306a36Sopenharmony_ci int position; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci position = hdspm_read(hdspm, HDSPM_statusRegister); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci switch (hdspm->io_type) { 148462306a36Sopenharmony_ci case RayDAT: 148562306a36Sopenharmony_ci case AIO: 148662306a36Sopenharmony_ci position &= HDSPM_BufferPositionMask; 148762306a36Sopenharmony_ci position /= 4; /* Bytes per sample */ 148862306a36Sopenharmony_ci break; 148962306a36Sopenharmony_ci default: 149062306a36Sopenharmony_ci position = (position & HDSPM_BufferID) ? 149162306a36Sopenharmony_ci (hdspm->period_bytes / 4) : 0; 149262306a36Sopenharmony_ci } 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci return position; 149562306a36Sopenharmony_ci} 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_cistatic inline void hdspm_start_audio(struct hdspm * s) 149962306a36Sopenharmony_ci{ 150062306a36Sopenharmony_ci s->control_register |= (HDSPM_AudioInterruptEnable | HDSPM_Start); 150162306a36Sopenharmony_ci hdspm_write(s, HDSPM_controlRegister, s->control_register); 150262306a36Sopenharmony_ci} 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_cistatic inline void hdspm_stop_audio(struct hdspm * s) 150562306a36Sopenharmony_ci{ 150662306a36Sopenharmony_ci s->control_register &= ~(HDSPM_Start | HDSPM_AudioInterruptEnable); 150762306a36Sopenharmony_ci hdspm_write(s, HDSPM_controlRegister, s->control_register); 150862306a36Sopenharmony_ci} 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci/* should I silence all or only opened ones ? doit all for first even is 4MB*/ 151162306a36Sopenharmony_cistatic void hdspm_silence_playback(struct hdspm *hdspm) 151262306a36Sopenharmony_ci{ 151362306a36Sopenharmony_ci int i; 151462306a36Sopenharmony_ci int n = hdspm->period_bytes; 151562306a36Sopenharmony_ci void *buf = hdspm->playback_buffer; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if (!buf) 151862306a36Sopenharmony_ci return; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { 152162306a36Sopenharmony_ci memset(buf, 0, n); 152262306a36Sopenharmony_ci buf += HDSPM_CHANNEL_BUFFER_BYTES; 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_cistatic int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames) 152762306a36Sopenharmony_ci{ 152862306a36Sopenharmony_ci int n; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci spin_lock_irq(&s->lock); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci if (32 == frames) { 153362306a36Sopenharmony_ci /* Special case for new RME cards like RayDAT/AIO which 153462306a36Sopenharmony_ci * support period sizes of 32 samples. Since latency is 153562306a36Sopenharmony_ci * encoded in the three bits of HDSP_LatencyMask, we can only 153662306a36Sopenharmony_ci * have values from 0 .. 7. While 0 still means 64 samples and 153762306a36Sopenharmony_ci * 6 represents 4096 samples on all cards, 7 represents 8192 153862306a36Sopenharmony_ci * on older cards and 32 samples on new cards. 153962306a36Sopenharmony_ci * 154062306a36Sopenharmony_ci * In other words, period size in samples is calculated by 154162306a36Sopenharmony_ci * 2^(n+6) with n ranging from 0 .. 7. 154262306a36Sopenharmony_ci */ 154362306a36Sopenharmony_ci n = 7; 154462306a36Sopenharmony_ci } else { 154562306a36Sopenharmony_ci frames >>= 7; 154662306a36Sopenharmony_ci n = 0; 154762306a36Sopenharmony_ci while (frames) { 154862306a36Sopenharmony_ci n++; 154962306a36Sopenharmony_ci frames >>= 1; 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci s->control_register &= ~HDSPM_LatencyMask; 155462306a36Sopenharmony_ci s->control_register |= hdspm_encode_latency(n); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci hdspm_write(s, HDSPM_controlRegister, s->control_register); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci hdspm_compute_period_size(s); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci spin_unlock_irq(&s->lock); 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci return 0; 156362306a36Sopenharmony_ci} 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_cistatic u64 hdspm_calc_dds_value(struct hdspm *hdspm, u64 period) 156662306a36Sopenharmony_ci{ 156762306a36Sopenharmony_ci u64 freq_const; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci if (period == 0) 157062306a36Sopenharmony_ci return 0; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci switch (hdspm->io_type) { 157362306a36Sopenharmony_ci case MADI: 157462306a36Sopenharmony_ci case AES32: 157562306a36Sopenharmony_ci freq_const = 110069313433624ULL; 157662306a36Sopenharmony_ci break; 157762306a36Sopenharmony_ci case RayDAT: 157862306a36Sopenharmony_ci case AIO: 157962306a36Sopenharmony_ci freq_const = 104857600000000ULL; 158062306a36Sopenharmony_ci break; 158162306a36Sopenharmony_ci case MADIface: 158262306a36Sopenharmony_ci freq_const = 131072000000000ULL; 158362306a36Sopenharmony_ci break; 158462306a36Sopenharmony_ci default: 158562306a36Sopenharmony_ci snd_BUG(); 158662306a36Sopenharmony_ci return 0; 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci return div_u64(freq_const, period); 159062306a36Sopenharmony_ci} 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_cistatic void hdspm_set_dds_value(struct hdspm *hdspm, int rate) 159462306a36Sopenharmony_ci{ 159562306a36Sopenharmony_ci u64 n; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci if (snd_BUG_ON(rate <= 0)) 159862306a36Sopenharmony_ci return; 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci if (rate >= 112000) 160162306a36Sopenharmony_ci rate /= 4; 160262306a36Sopenharmony_ci else if (rate >= 56000) 160362306a36Sopenharmony_ci rate /= 2; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci switch (hdspm->io_type) { 160662306a36Sopenharmony_ci case MADIface: 160762306a36Sopenharmony_ci n = 131072000000000ULL; /* 125 MHz */ 160862306a36Sopenharmony_ci break; 160962306a36Sopenharmony_ci case MADI: 161062306a36Sopenharmony_ci case AES32: 161162306a36Sopenharmony_ci n = 110069313433624ULL; /* 105 MHz */ 161262306a36Sopenharmony_ci break; 161362306a36Sopenharmony_ci case RayDAT: 161462306a36Sopenharmony_ci case AIO: 161562306a36Sopenharmony_ci n = 104857600000000ULL; /* 100 MHz */ 161662306a36Sopenharmony_ci break; 161762306a36Sopenharmony_ci default: 161862306a36Sopenharmony_ci snd_BUG(); 161962306a36Sopenharmony_ci return; 162062306a36Sopenharmony_ci } 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci n = div_u64(n, rate); 162362306a36Sopenharmony_ci /* n should be less than 2^32 for being written to FREQ register */ 162462306a36Sopenharmony_ci snd_BUG_ON(n >> 32); 162562306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_freqReg, (u32)n); 162662306a36Sopenharmony_ci} 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci/* dummy set rate lets see what happens */ 162962306a36Sopenharmony_cistatic int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) 163062306a36Sopenharmony_ci{ 163162306a36Sopenharmony_ci int current_rate; 163262306a36Sopenharmony_ci int rate_bits; 163362306a36Sopenharmony_ci int not_set = 0; 163462306a36Sopenharmony_ci int current_speed, target_speed; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci /* ASSUMPTION: hdspm->lock is either set, or there is no need for 163762306a36Sopenharmony_ci it (e.g. during module initialization). 163862306a36Sopenharmony_ci */ 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci /* SLAVE --- */ 164362306a36Sopenharmony_ci if (called_internally) { 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci /* request from ctl or card initialization 164662306a36Sopenharmony_ci just make a warning an remember setting 164762306a36Sopenharmony_ci for future master mode switching */ 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci dev_warn(hdspm->card->dev, 165062306a36Sopenharmony_ci "Warning: device is not running as a clock master.\n"); 165162306a36Sopenharmony_ci not_set = 1; 165262306a36Sopenharmony_ci } else { 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci /* hw_param request while in AutoSync mode */ 165562306a36Sopenharmony_ci int external_freq = 165662306a36Sopenharmony_ci hdspm_external_sample_rate(hdspm); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci if (hdspm_autosync_ref(hdspm) == 165962306a36Sopenharmony_ci HDSPM_AUTOSYNC_FROM_NONE) { 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci dev_warn(hdspm->card->dev, 166262306a36Sopenharmony_ci "Detected no External Sync\n"); 166362306a36Sopenharmony_ci not_set = 1; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci } else if (rate != external_freq) { 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci dev_warn(hdspm->card->dev, 166862306a36Sopenharmony_ci "Warning: No AutoSync source for requested rate\n"); 166962306a36Sopenharmony_ci not_set = 1; 167062306a36Sopenharmony_ci } 167162306a36Sopenharmony_ci } 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci current_rate = hdspm->system_sample_rate; 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci /* Changing between Singe, Double and Quad speed is not 167762306a36Sopenharmony_ci allowed if any substreams are open. This is because such a change 167862306a36Sopenharmony_ci causes a shift in the location of the DMA buffers and a reduction 167962306a36Sopenharmony_ci in the number of available buffers. 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci Note that a similar but essentially insoluble problem exists for 168262306a36Sopenharmony_ci externally-driven rate changes. All we can do is to flag rate 168362306a36Sopenharmony_ci changes in the read/write routines. 168462306a36Sopenharmony_ci */ 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci if (current_rate <= 48000) 168762306a36Sopenharmony_ci current_speed = HDSPM_SPEED_SINGLE; 168862306a36Sopenharmony_ci else if (current_rate <= 96000) 168962306a36Sopenharmony_ci current_speed = HDSPM_SPEED_DOUBLE; 169062306a36Sopenharmony_ci else 169162306a36Sopenharmony_ci current_speed = HDSPM_SPEED_QUAD; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci if (rate <= 48000) 169462306a36Sopenharmony_ci target_speed = HDSPM_SPEED_SINGLE; 169562306a36Sopenharmony_ci else if (rate <= 96000) 169662306a36Sopenharmony_ci target_speed = HDSPM_SPEED_DOUBLE; 169762306a36Sopenharmony_ci else 169862306a36Sopenharmony_ci target_speed = HDSPM_SPEED_QUAD; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci switch (rate) { 170162306a36Sopenharmony_ci case 32000: 170262306a36Sopenharmony_ci rate_bits = HDSPM_Frequency32KHz; 170362306a36Sopenharmony_ci break; 170462306a36Sopenharmony_ci case 44100: 170562306a36Sopenharmony_ci rate_bits = HDSPM_Frequency44_1KHz; 170662306a36Sopenharmony_ci break; 170762306a36Sopenharmony_ci case 48000: 170862306a36Sopenharmony_ci rate_bits = HDSPM_Frequency48KHz; 170962306a36Sopenharmony_ci break; 171062306a36Sopenharmony_ci case 64000: 171162306a36Sopenharmony_ci rate_bits = HDSPM_Frequency64KHz; 171262306a36Sopenharmony_ci break; 171362306a36Sopenharmony_ci case 88200: 171462306a36Sopenharmony_ci rate_bits = HDSPM_Frequency88_2KHz; 171562306a36Sopenharmony_ci break; 171662306a36Sopenharmony_ci case 96000: 171762306a36Sopenharmony_ci rate_bits = HDSPM_Frequency96KHz; 171862306a36Sopenharmony_ci break; 171962306a36Sopenharmony_ci case 128000: 172062306a36Sopenharmony_ci rate_bits = HDSPM_Frequency128KHz; 172162306a36Sopenharmony_ci break; 172262306a36Sopenharmony_ci case 176400: 172362306a36Sopenharmony_ci rate_bits = HDSPM_Frequency176_4KHz; 172462306a36Sopenharmony_ci break; 172562306a36Sopenharmony_ci case 192000: 172662306a36Sopenharmony_ci rate_bits = HDSPM_Frequency192KHz; 172762306a36Sopenharmony_ci break; 172862306a36Sopenharmony_ci default: 172962306a36Sopenharmony_ci return -EINVAL; 173062306a36Sopenharmony_ci } 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci if (current_speed != target_speed 173362306a36Sopenharmony_ci && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { 173462306a36Sopenharmony_ci dev_err(hdspm->card->dev, 173562306a36Sopenharmony_ci "cannot change from %s speed to %s speed mode (capture PID = %d, playback PID = %d)\n", 173662306a36Sopenharmony_ci hdspm_speed_names[current_speed], 173762306a36Sopenharmony_ci hdspm_speed_names[target_speed], 173862306a36Sopenharmony_ci hdspm->capture_pid, hdspm->playback_pid); 173962306a36Sopenharmony_ci return -EBUSY; 174062306a36Sopenharmony_ci } 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci hdspm->control_register &= ~HDSPM_FrequencyMask; 174362306a36Sopenharmony_ci hdspm->control_register |= rate_bits; 174462306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci /* For AES32, need to set DDS value in FREQ register 174762306a36Sopenharmony_ci For MADI, also apparently */ 174862306a36Sopenharmony_ci hdspm_set_dds_value(hdspm, rate); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci if (AES32 == hdspm->io_type && rate != current_rate) 175162306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_eeprom_wr, 0); 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci hdspm->system_sample_rate = rate; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci if (rate <= 48000) { 175662306a36Sopenharmony_ci hdspm->channel_map_in = hdspm->channel_map_in_ss; 175762306a36Sopenharmony_ci hdspm->channel_map_out = hdspm->channel_map_out_ss; 175862306a36Sopenharmony_ci hdspm->max_channels_in = hdspm->ss_in_channels; 175962306a36Sopenharmony_ci hdspm->max_channels_out = hdspm->ss_out_channels; 176062306a36Sopenharmony_ci hdspm->port_names_in = hdspm->port_names_in_ss; 176162306a36Sopenharmony_ci hdspm->port_names_out = hdspm->port_names_out_ss; 176262306a36Sopenharmony_ci } else if (rate <= 96000) { 176362306a36Sopenharmony_ci hdspm->channel_map_in = hdspm->channel_map_in_ds; 176462306a36Sopenharmony_ci hdspm->channel_map_out = hdspm->channel_map_out_ds; 176562306a36Sopenharmony_ci hdspm->max_channels_in = hdspm->ds_in_channels; 176662306a36Sopenharmony_ci hdspm->max_channels_out = hdspm->ds_out_channels; 176762306a36Sopenharmony_ci hdspm->port_names_in = hdspm->port_names_in_ds; 176862306a36Sopenharmony_ci hdspm->port_names_out = hdspm->port_names_out_ds; 176962306a36Sopenharmony_ci } else { 177062306a36Sopenharmony_ci hdspm->channel_map_in = hdspm->channel_map_in_qs; 177162306a36Sopenharmony_ci hdspm->channel_map_out = hdspm->channel_map_out_qs; 177262306a36Sopenharmony_ci hdspm->max_channels_in = hdspm->qs_in_channels; 177362306a36Sopenharmony_ci hdspm->max_channels_out = hdspm->qs_out_channels; 177462306a36Sopenharmony_ci hdspm->port_names_in = hdspm->port_names_in_qs; 177562306a36Sopenharmony_ci hdspm->port_names_out = hdspm->port_names_out_qs; 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci if (not_set != 0) 177962306a36Sopenharmony_ci return -1; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci return 0; 178262306a36Sopenharmony_ci} 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci/* mainly for init to 0 on load */ 178562306a36Sopenharmony_cistatic void all_in_all_mixer(struct hdspm * hdspm, int sgain) 178662306a36Sopenharmony_ci{ 178762306a36Sopenharmony_ci int i, j; 178862306a36Sopenharmony_ci unsigned int gain; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci if (sgain > UNITY_GAIN) 179162306a36Sopenharmony_ci gain = UNITY_GAIN; 179262306a36Sopenharmony_ci else if (sgain < 0) 179362306a36Sopenharmony_ci gain = 0; 179462306a36Sopenharmony_ci else 179562306a36Sopenharmony_ci gain = sgain; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) 179862306a36Sopenharmony_ci for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) { 179962306a36Sopenharmony_ci hdspm_write_in_gain(hdspm, i, j, gain); 180062306a36Sopenharmony_ci hdspm_write_pb_gain(hdspm, i, j, gain); 180162306a36Sopenharmony_ci } 180262306a36Sopenharmony_ci} 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci/*---------------------------------------------------------------------------- 180562306a36Sopenharmony_ci MIDI 180662306a36Sopenharmony_ci ----------------------------------------------------------------------------*/ 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_cistatic inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm, 180962306a36Sopenharmony_ci int id) 181062306a36Sopenharmony_ci{ 181162306a36Sopenharmony_ci /* the hardware already does the relevant bit-mask with 0xff */ 181262306a36Sopenharmony_ci return hdspm_read(hdspm, hdspm->midi[id].dataIn); 181362306a36Sopenharmony_ci} 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_cistatic inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id, 181662306a36Sopenharmony_ci int val) 181762306a36Sopenharmony_ci{ 181862306a36Sopenharmony_ci /* the hardware already does the relevant bit-mask with 0xff */ 181962306a36Sopenharmony_ci return hdspm_write(hdspm, hdspm->midi[id].dataOut, val); 182062306a36Sopenharmony_ci} 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_cistatic inline int snd_hdspm_midi_input_available (struct hdspm *hdspm, int id) 182362306a36Sopenharmony_ci{ 182462306a36Sopenharmony_ci return hdspm_read(hdspm, hdspm->midi[id].statusIn) & 0xFF; 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_cistatic inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id) 182862306a36Sopenharmony_ci{ 182962306a36Sopenharmony_ci int fifo_bytes_used; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci fifo_bytes_used = hdspm_read(hdspm, hdspm->midi[id].statusOut) & 0xFF; 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci if (fifo_bytes_used < 128) 183462306a36Sopenharmony_ci return 128 - fifo_bytes_used; 183562306a36Sopenharmony_ci else 183662306a36Sopenharmony_ci return 0; 183762306a36Sopenharmony_ci} 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_cistatic void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id) 184062306a36Sopenharmony_ci{ 184162306a36Sopenharmony_ci while (snd_hdspm_midi_input_available (hdspm, id)) 184262306a36Sopenharmony_ci snd_hdspm_midi_read_byte (hdspm, id); 184362306a36Sopenharmony_ci} 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_cistatic int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) 184662306a36Sopenharmony_ci{ 184762306a36Sopenharmony_ci unsigned long flags; 184862306a36Sopenharmony_ci int n_pending; 184962306a36Sopenharmony_ci int to_write; 185062306a36Sopenharmony_ci int i; 185162306a36Sopenharmony_ci unsigned char buf[128]; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci /* Output is not interrupt driven */ 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci spin_lock_irqsave (&hmidi->lock, flags); 185662306a36Sopenharmony_ci if (hmidi->output && 185762306a36Sopenharmony_ci !snd_rawmidi_transmit_empty (hmidi->output)) { 185862306a36Sopenharmony_ci n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, 185962306a36Sopenharmony_ci hmidi->id); 186062306a36Sopenharmony_ci if (n_pending > 0) { 186162306a36Sopenharmony_ci if (n_pending > (int)sizeof (buf)) 186262306a36Sopenharmony_ci n_pending = sizeof (buf); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci to_write = snd_rawmidi_transmit (hmidi->output, buf, 186562306a36Sopenharmony_ci n_pending); 186662306a36Sopenharmony_ci if (to_write > 0) { 186762306a36Sopenharmony_ci for (i = 0; i < to_write; ++i) 186862306a36Sopenharmony_ci snd_hdspm_midi_write_byte (hmidi->hdspm, 186962306a36Sopenharmony_ci hmidi->id, 187062306a36Sopenharmony_ci buf[i]); 187162306a36Sopenharmony_ci } 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci spin_unlock_irqrestore (&hmidi->lock, flags); 187562306a36Sopenharmony_ci return 0; 187662306a36Sopenharmony_ci} 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_cistatic int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi) 187962306a36Sopenharmony_ci{ 188062306a36Sopenharmony_ci unsigned char buf[128]; /* this buffer is designed to match the MIDI 188162306a36Sopenharmony_ci * input FIFO size 188262306a36Sopenharmony_ci */ 188362306a36Sopenharmony_ci unsigned long flags; 188462306a36Sopenharmony_ci int n_pending; 188562306a36Sopenharmony_ci int i; 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci spin_lock_irqsave (&hmidi->lock, flags); 188862306a36Sopenharmony_ci n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id); 188962306a36Sopenharmony_ci if (n_pending > 0) { 189062306a36Sopenharmony_ci if (hmidi->input) { 189162306a36Sopenharmony_ci if (n_pending > (int)sizeof (buf)) 189262306a36Sopenharmony_ci n_pending = sizeof (buf); 189362306a36Sopenharmony_ci for (i = 0; i < n_pending; ++i) 189462306a36Sopenharmony_ci buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, 189562306a36Sopenharmony_ci hmidi->id); 189662306a36Sopenharmony_ci if (n_pending) 189762306a36Sopenharmony_ci snd_rawmidi_receive (hmidi->input, buf, 189862306a36Sopenharmony_ci n_pending); 189962306a36Sopenharmony_ci } else { 190062306a36Sopenharmony_ci /* flush the MIDI input FIFO */ 190162306a36Sopenharmony_ci while (n_pending--) 190262306a36Sopenharmony_ci snd_hdspm_midi_read_byte (hmidi->hdspm, 190362306a36Sopenharmony_ci hmidi->id); 190462306a36Sopenharmony_ci } 190562306a36Sopenharmony_ci } 190662306a36Sopenharmony_ci hmidi->pending = 0; 190762306a36Sopenharmony_ci spin_unlock_irqrestore(&hmidi->lock, flags); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci spin_lock_irqsave(&hmidi->hdspm->lock, flags); 191062306a36Sopenharmony_ci hmidi->hdspm->control_register |= hmidi->ie; 191162306a36Sopenharmony_ci hdspm_write(hmidi->hdspm, HDSPM_controlRegister, 191262306a36Sopenharmony_ci hmidi->hdspm->control_register); 191362306a36Sopenharmony_ci spin_unlock_irqrestore(&hmidi->hdspm->lock, flags); 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci return snd_hdspm_midi_output_write (hmidi); 191662306a36Sopenharmony_ci} 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_cistatic void 191962306a36Sopenharmony_cisnd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) 192062306a36Sopenharmony_ci{ 192162306a36Sopenharmony_ci struct hdspm *hdspm; 192262306a36Sopenharmony_ci struct hdspm_midi *hmidi; 192362306a36Sopenharmony_ci unsigned long flags; 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci hmidi = substream->rmidi->private_data; 192662306a36Sopenharmony_ci hdspm = hmidi->hdspm; 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci spin_lock_irqsave (&hdspm->lock, flags); 192962306a36Sopenharmony_ci if (up) { 193062306a36Sopenharmony_ci if (!(hdspm->control_register & hmidi->ie)) { 193162306a36Sopenharmony_ci snd_hdspm_flush_midi_input (hdspm, hmidi->id); 193262306a36Sopenharmony_ci hdspm->control_register |= hmidi->ie; 193362306a36Sopenharmony_ci } 193462306a36Sopenharmony_ci } else { 193562306a36Sopenharmony_ci hdspm->control_register &= ~hmidi->ie; 193662306a36Sopenharmony_ci } 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 193962306a36Sopenharmony_ci spin_unlock_irqrestore (&hdspm->lock, flags); 194062306a36Sopenharmony_ci} 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_cistatic void snd_hdspm_midi_output_timer(struct timer_list *t) 194362306a36Sopenharmony_ci{ 194462306a36Sopenharmony_ci struct hdspm_midi *hmidi = from_timer(hmidi, t, timer); 194562306a36Sopenharmony_ci unsigned long flags; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci snd_hdspm_midi_output_write(hmidi); 194862306a36Sopenharmony_ci spin_lock_irqsave (&hmidi->lock, flags); 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci /* this does not bump hmidi->istimer, because the 195162306a36Sopenharmony_ci kernel automatically removed the timer when it 195262306a36Sopenharmony_ci expired, and we are now adding it back, thus 195362306a36Sopenharmony_ci leaving istimer wherever it was set before. 195462306a36Sopenharmony_ci */ 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci if (hmidi->istimer) 195762306a36Sopenharmony_ci mod_timer(&hmidi->timer, 1 + jiffies); 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci spin_unlock_irqrestore (&hmidi->lock, flags); 196062306a36Sopenharmony_ci} 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_cistatic void 196362306a36Sopenharmony_cisnd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) 196462306a36Sopenharmony_ci{ 196562306a36Sopenharmony_ci struct hdspm_midi *hmidi; 196662306a36Sopenharmony_ci unsigned long flags; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci hmidi = substream->rmidi->private_data; 196962306a36Sopenharmony_ci spin_lock_irqsave (&hmidi->lock, flags); 197062306a36Sopenharmony_ci if (up) { 197162306a36Sopenharmony_ci if (!hmidi->istimer) { 197262306a36Sopenharmony_ci timer_setup(&hmidi->timer, 197362306a36Sopenharmony_ci snd_hdspm_midi_output_timer, 0); 197462306a36Sopenharmony_ci mod_timer(&hmidi->timer, 1 + jiffies); 197562306a36Sopenharmony_ci hmidi->istimer++; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci } else { 197862306a36Sopenharmony_ci if (hmidi->istimer && --hmidi->istimer <= 0) 197962306a36Sopenharmony_ci del_timer (&hmidi->timer); 198062306a36Sopenharmony_ci } 198162306a36Sopenharmony_ci spin_unlock_irqrestore (&hmidi->lock, flags); 198262306a36Sopenharmony_ci if (up) 198362306a36Sopenharmony_ci snd_hdspm_midi_output_write(hmidi); 198462306a36Sopenharmony_ci} 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_cistatic int snd_hdspm_midi_input_open(struct snd_rawmidi_substream *substream) 198762306a36Sopenharmony_ci{ 198862306a36Sopenharmony_ci struct hdspm_midi *hmidi; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci hmidi = substream->rmidi->private_data; 199162306a36Sopenharmony_ci spin_lock_irq (&hmidi->lock); 199262306a36Sopenharmony_ci snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id); 199362306a36Sopenharmony_ci hmidi->input = substream; 199462306a36Sopenharmony_ci spin_unlock_irq (&hmidi->lock); 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci return 0; 199762306a36Sopenharmony_ci} 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_cistatic int snd_hdspm_midi_output_open(struct snd_rawmidi_substream *substream) 200062306a36Sopenharmony_ci{ 200162306a36Sopenharmony_ci struct hdspm_midi *hmidi; 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci hmidi = substream->rmidi->private_data; 200462306a36Sopenharmony_ci spin_lock_irq (&hmidi->lock); 200562306a36Sopenharmony_ci hmidi->output = substream; 200662306a36Sopenharmony_ci spin_unlock_irq (&hmidi->lock); 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci return 0; 200962306a36Sopenharmony_ci} 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_cistatic int snd_hdspm_midi_input_close(struct snd_rawmidi_substream *substream) 201262306a36Sopenharmony_ci{ 201362306a36Sopenharmony_ci struct hdspm_midi *hmidi; 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci snd_hdspm_midi_input_trigger (substream, 0); 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci hmidi = substream->rmidi->private_data; 201862306a36Sopenharmony_ci spin_lock_irq (&hmidi->lock); 201962306a36Sopenharmony_ci hmidi->input = NULL; 202062306a36Sopenharmony_ci spin_unlock_irq (&hmidi->lock); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci return 0; 202362306a36Sopenharmony_ci} 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_cistatic int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream) 202662306a36Sopenharmony_ci{ 202762306a36Sopenharmony_ci struct hdspm_midi *hmidi; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci snd_hdspm_midi_output_trigger (substream, 0); 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci hmidi = substream->rmidi->private_data; 203262306a36Sopenharmony_ci spin_lock_irq (&hmidi->lock); 203362306a36Sopenharmony_ci hmidi->output = NULL; 203462306a36Sopenharmony_ci spin_unlock_irq (&hmidi->lock); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci return 0; 203762306a36Sopenharmony_ci} 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_cistatic const struct snd_rawmidi_ops snd_hdspm_midi_output = 204062306a36Sopenharmony_ci{ 204162306a36Sopenharmony_ci .open = snd_hdspm_midi_output_open, 204262306a36Sopenharmony_ci .close = snd_hdspm_midi_output_close, 204362306a36Sopenharmony_ci .trigger = snd_hdspm_midi_output_trigger, 204462306a36Sopenharmony_ci}; 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_cistatic const struct snd_rawmidi_ops snd_hdspm_midi_input = 204762306a36Sopenharmony_ci{ 204862306a36Sopenharmony_ci .open = snd_hdspm_midi_input_open, 204962306a36Sopenharmony_ci .close = snd_hdspm_midi_input_close, 205062306a36Sopenharmony_ci .trigger = snd_hdspm_midi_input_trigger, 205162306a36Sopenharmony_ci}; 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_cistatic int snd_hdspm_create_midi(struct snd_card *card, 205462306a36Sopenharmony_ci struct hdspm *hdspm, int id) 205562306a36Sopenharmony_ci{ 205662306a36Sopenharmony_ci int err; 205762306a36Sopenharmony_ci char buf[64]; 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci hdspm->midi[id].id = id; 206062306a36Sopenharmony_ci hdspm->midi[id].hdspm = hdspm; 206162306a36Sopenharmony_ci spin_lock_init (&hdspm->midi[id].lock); 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci if (0 == id) { 206462306a36Sopenharmony_ci if (MADIface == hdspm->io_type) { 206562306a36Sopenharmony_ci /* MIDI-over-MADI on HDSPe MADIface */ 206662306a36Sopenharmony_ci hdspm->midi[0].dataIn = HDSPM_midiDataIn2; 206762306a36Sopenharmony_ci hdspm->midi[0].statusIn = HDSPM_midiStatusIn2; 206862306a36Sopenharmony_ci hdspm->midi[0].dataOut = HDSPM_midiDataOut2; 206962306a36Sopenharmony_ci hdspm->midi[0].statusOut = HDSPM_midiStatusOut2; 207062306a36Sopenharmony_ci hdspm->midi[0].ie = HDSPM_Midi2InterruptEnable; 207162306a36Sopenharmony_ci hdspm->midi[0].irq = HDSPM_midi2IRQPending; 207262306a36Sopenharmony_ci } else { 207362306a36Sopenharmony_ci hdspm->midi[0].dataIn = HDSPM_midiDataIn0; 207462306a36Sopenharmony_ci hdspm->midi[0].statusIn = HDSPM_midiStatusIn0; 207562306a36Sopenharmony_ci hdspm->midi[0].dataOut = HDSPM_midiDataOut0; 207662306a36Sopenharmony_ci hdspm->midi[0].statusOut = HDSPM_midiStatusOut0; 207762306a36Sopenharmony_ci hdspm->midi[0].ie = HDSPM_Midi0InterruptEnable; 207862306a36Sopenharmony_ci hdspm->midi[0].irq = HDSPM_midi0IRQPending; 207962306a36Sopenharmony_ci } 208062306a36Sopenharmony_ci } else if (1 == id) { 208162306a36Sopenharmony_ci hdspm->midi[1].dataIn = HDSPM_midiDataIn1; 208262306a36Sopenharmony_ci hdspm->midi[1].statusIn = HDSPM_midiStatusIn1; 208362306a36Sopenharmony_ci hdspm->midi[1].dataOut = HDSPM_midiDataOut1; 208462306a36Sopenharmony_ci hdspm->midi[1].statusOut = HDSPM_midiStatusOut1; 208562306a36Sopenharmony_ci hdspm->midi[1].ie = HDSPM_Midi1InterruptEnable; 208662306a36Sopenharmony_ci hdspm->midi[1].irq = HDSPM_midi1IRQPending; 208762306a36Sopenharmony_ci } else if ((2 == id) && (MADI == hdspm->io_type)) { 208862306a36Sopenharmony_ci /* MIDI-over-MADI on HDSPe MADI */ 208962306a36Sopenharmony_ci hdspm->midi[2].dataIn = HDSPM_midiDataIn2; 209062306a36Sopenharmony_ci hdspm->midi[2].statusIn = HDSPM_midiStatusIn2; 209162306a36Sopenharmony_ci hdspm->midi[2].dataOut = HDSPM_midiDataOut2; 209262306a36Sopenharmony_ci hdspm->midi[2].statusOut = HDSPM_midiStatusOut2; 209362306a36Sopenharmony_ci hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable; 209462306a36Sopenharmony_ci hdspm->midi[2].irq = HDSPM_midi2IRQPending; 209562306a36Sopenharmony_ci } else if (2 == id) { 209662306a36Sopenharmony_ci /* TCO MTC, read only */ 209762306a36Sopenharmony_ci hdspm->midi[2].dataIn = HDSPM_midiDataIn2; 209862306a36Sopenharmony_ci hdspm->midi[2].statusIn = HDSPM_midiStatusIn2; 209962306a36Sopenharmony_ci hdspm->midi[2].dataOut = -1; 210062306a36Sopenharmony_ci hdspm->midi[2].statusOut = -1; 210162306a36Sopenharmony_ci hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable; 210262306a36Sopenharmony_ci hdspm->midi[2].irq = HDSPM_midi2IRQPendingAES; 210362306a36Sopenharmony_ci } else if (3 == id) { 210462306a36Sopenharmony_ci /* TCO MTC on HDSPe MADI */ 210562306a36Sopenharmony_ci hdspm->midi[3].dataIn = HDSPM_midiDataIn3; 210662306a36Sopenharmony_ci hdspm->midi[3].statusIn = HDSPM_midiStatusIn3; 210762306a36Sopenharmony_ci hdspm->midi[3].dataOut = -1; 210862306a36Sopenharmony_ci hdspm->midi[3].statusOut = -1; 210962306a36Sopenharmony_ci hdspm->midi[3].ie = HDSPM_Midi3InterruptEnable; 211062306a36Sopenharmony_ci hdspm->midi[3].irq = HDSPM_midi3IRQPending; 211162306a36Sopenharmony_ci } 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci if ((id < 2) || ((2 == id) && ((MADI == hdspm->io_type) || 211462306a36Sopenharmony_ci (MADIface == hdspm->io_type)))) { 211562306a36Sopenharmony_ci if ((id == 0) && (MADIface == hdspm->io_type)) { 211662306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "%s MIDIoverMADI", 211762306a36Sopenharmony_ci card->shortname); 211862306a36Sopenharmony_ci } else if ((id == 2) && (MADI == hdspm->io_type)) { 211962306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "%s MIDIoverMADI", 212062306a36Sopenharmony_ci card->shortname); 212162306a36Sopenharmony_ci } else { 212262306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "%s MIDI %d", 212362306a36Sopenharmony_ci card->shortname, id+1); 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci err = snd_rawmidi_new(card, buf, id, 1, 1, 212662306a36Sopenharmony_ci &hdspm->midi[id].rmidi); 212762306a36Sopenharmony_ci if (err < 0) 212862306a36Sopenharmony_ci return err; 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci snprintf(hdspm->midi[id].rmidi->name, 213162306a36Sopenharmony_ci sizeof(hdspm->midi[id].rmidi->name), 213262306a36Sopenharmony_ci "%s MIDI %d", card->id, id+1); 213362306a36Sopenharmony_ci hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 213662306a36Sopenharmony_ci SNDRV_RAWMIDI_STREAM_OUTPUT, 213762306a36Sopenharmony_ci &snd_hdspm_midi_output); 213862306a36Sopenharmony_ci snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 213962306a36Sopenharmony_ci SNDRV_RAWMIDI_STREAM_INPUT, 214062306a36Sopenharmony_ci &snd_hdspm_midi_input); 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci hdspm->midi[id].rmidi->info_flags |= 214362306a36Sopenharmony_ci SNDRV_RAWMIDI_INFO_OUTPUT | 214462306a36Sopenharmony_ci SNDRV_RAWMIDI_INFO_INPUT | 214562306a36Sopenharmony_ci SNDRV_RAWMIDI_INFO_DUPLEX; 214662306a36Sopenharmony_ci } else { 214762306a36Sopenharmony_ci /* TCO MTC, read only */ 214862306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "%s MTC %d", 214962306a36Sopenharmony_ci card->shortname, id+1); 215062306a36Sopenharmony_ci err = snd_rawmidi_new(card, buf, id, 1, 1, 215162306a36Sopenharmony_ci &hdspm->midi[id].rmidi); 215262306a36Sopenharmony_ci if (err < 0) 215362306a36Sopenharmony_ci return err; 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci snprintf(hdspm->midi[id].rmidi->name, 215662306a36Sopenharmony_ci sizeof(hdspm->midi[id].rmidi->name), 215762306a36Sopenharmony_ci "%s MTC %d", card->id, id+1); 215862306a36Sopenharmony_ci hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci snd_rawmidi_set_ops(hdspm->midi[id].rmidi, 216162306a36Sopenharmony_ci SNDRV_RAWMIDI_STREAM_INPUT, 216262306a36Sopenharmony_ci &snd_hdspm_midi_input); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; 216562306a36Sopenharmony_ci } 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci return 0; 216862306a36Sopenharmony_ci} 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_cistatic void hdspm_midi_work(struct work_struct *work) 217262306a36Sopenharmony_ci{ 217362306a36Sopenharmony_ci struct hdspm *hdspm = container_of(work, struct hdspm, midi_work); 217462306a36Sopenharmony_ci int i = 0; 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci while (i < hdspm->midiPorts) { 217762306a36Sopenharmony_ci if (hdspm->midi[i].pending) 217862306a36Sopenharmony_ci snd_hdspm_midi_input_read(&hdspm->midi[i]); 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci i++; 218162306a36Sopenharmony_ci } 218262306a36Sopenharmony_ci} 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci/*----------------------------------------------------------------------------- 218662306a36Sopenharmony_ci Status Interface 218762306a36Sopenharmony_ci ----------------------------------------------------------------------------*/ 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci/* get the system sample rate which is set */ 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_cistatic inline int hdspm_get_pll_freq(struct hdspm *hdspm) 219362306a36Sopenharmony_ci{ 219462306a36Sopenharmony_ci unsigned int period, rate; 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 219762306a36Sopenharmony_ci rate = hdspm_calc_dds_value(hdspm, period); 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci return rate; 220062306a36Sopenharmony_ci} 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_ci/* 220362306a36Sopenharmony_ci * Calculate the real sample rate from the 220462306a36Sopenharmony_ci * current DDS value. 220562306a36Sopenharmony_ci */ 220662306a36Sopenharmony_cistatic int hdspm_get_system_sample_rate(struct hdspm *hdspm) 220762306a36Sopenharmony_ci{ 220862306a36Sopenharmony_ci unsigned int rate; 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci rate = hdspm_get_pll_freq(hdspm); 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci if (rate > 207000) { 221362306a36Sopenharmony_ci /* Unreasonable high sample rate as seen on PCI MADI cards. */ 221462306a36Sopenharmony_ci if (0 == hdspm_system_clock_mode(hdspm)) { 221562306a36Sopenharmony_ci /* master mode, return internal sample rate */ 221662306a36Sopenharmony_ci rate = hdspm->system_sample_rate; 221762306a36Sopenharmony_ci } else { 221862306a36Sopenharmony_ci /* slave mode, return external sample rate */ 221962306a36Sopenharmony_ci rate = hdspm_external_sample_rate(hdspm); 222062306a36Sopenharmony_ci if (!rate) 222162306a36Sopenharmony_ci rate = hdspm->system_sample_rate; 222262306a36Sopenharmony_ci } 222362306a36Sopenharmony_ci } 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci return rate; 222662306a36Sopenharmony_ci} 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci#define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \ 223062306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 223162306a36Sopenharmony_ci .name = xname, \ 223262306a36Sopenharmony_ci .index = xindex, \ 223362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 223462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 223562306a36Sopenharmony_ci .info = snd_hdspm_info_system_sample_rate, \ 223662306a36Sopenharmony_ci .put = snd_hdspm_put_system_sample_rate, \ 223762306a36Sopenharmony_ci .get = snd_hdspm_get_system_sample_rate \ 223862306a36Sopenharmony_ci} 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_cistatic int snd_hdspm_info_system_sample_rate(struct snd_kcontrol *kcontrol, 224162306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 224262306a36Sopenharmony_ci{ 224362306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 224462306a36Sopenharmony_ci uinfo->count = 1; 224562306a36Sopenharmony_ci uinfo->value.integer.min = 27000; 224662306a36Sopenharmony_ci uinfo->value.integer.max = 207000; 224762306a36Sopenharmony_ci uinfo->value.integer.step = 1; 224862306a36Sopenharmony_ci return 0; 224962306a36Sopenharmony_ci} 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_cistatic int snd_hdspm_get_system_sample_rate(struct snd_kcontrol *kcontrol, 225362306a36Sopenharmony_ci struct snd_ctl_elem_value * 225462306a36Sopenharmony_ci ucontrol) 225562306a36Sopenharmony_ci{ 225662306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = hdspm_get_system_sample_rate(hdspm); 225962306a36Sopenharmony_ci return 0; 226062306a36Sopenharmony_ci} 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_cistatic int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol, 226362306a36Sopenharmony_ci struct snd_ctl_elem_value * 226462306a36Sopenharmony_ci ucontrol) 226562306a36Sopenharmony_ci{ 226662306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 226762306a36Sopenharmony_ci int rate = ucontrol->value.integer.value[0]; 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci if (rate < 27000 || rate > 207000) 227062306a36Sopenharmony_ci return -EINVAL; 227162306a36Sopenharmony_ci hdspm_set_dds_value(hdspm, ucontrol->value.integer.value[0]); 227262306a36Sopenharmony_ci return 0; 227362306a36Sopenharmony_ci} 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci/* 227762306a36Sopenharmony_ci * Returns the WordClock sample rate class for the given card. 227862306a36Sopenharmony_ci */ 227962306a36Sopenharmony_cistatic int hdspm_get_wc_sample_rate(struct hdspm *hdspm) 228062306a36Sopenharmony_ci{ 228162306a36Sopenharmony_ci int status; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci switch (hdspm->io_type) { 228462306a36Sopenharmony_ci case RayDAT: 228562306a36Sopenharmony_ci case AIO: 228662306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 228762306a36Sopenharmony_ci return (status >> 16) & 0xF; 228862306a36Sopenharmony_ci case AES32: 228962306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 229062306a36Sopenharmony_ci return (status >> HDSPM_AES32_wcFreq_bit) & 0xF; 229162306a36Sopenharmony_ci default: 229262306a36Sopenharmony_ci break; 229362306a36Sopenharmony_ci } 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci return 0; 229762306a36Sopenharmony_ci} 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci/* 230162306a36Sopenharmony_ci * Returns the TCO sample rate class for the given card. 230262306a36Sopenharmony_ci */ 230362306a36Sopenharmony_cistatic int hdspm_get_tco_sample_rate(struct hdspm *hdspm) 230462306a36Sopenharmony_ci{ 230562306a36Sopenharmony_ci int status; 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci if (hdspm->tco) { 230862306a36Sopenharmony_ci switch (hdspm->io_type) { 230962306a36Sopenharmony_ci case RayDAT: 231062306a36Sopenharmony_ci case AIO: 231162306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 231262306a36Sopenharmony_ci return (status >> 20) & 0xF; 231362306a36Sopenharmony_ci case AES32: 231462306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 231562306a36Sopenharmony_ci return (status >> 1) & 0xF; 231662306a36Sopenharmony_ci default: 231762306a36Sopenharmony_ci break; 231862306a36Sopenharmony_ci } 231962306a36Sopenharmony_ci } 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci return 0; 232262306a36Sopenharmony_ci} 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci/* 232662306a36Sopenharmony_ci * Returns the SYNC_IN sample rate class for the given card. 232762306a36Sopenharmony_ci */ 232862306a36Sopenharmony_cistatic int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) 232962306a36Sopenharmony_ci{ 233062306a36Sopenharmony_ci int status; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci if (hdspm->tco) { 233362306a36Sopenharmony_ci switch (hdspm->io_type) { 233462306a36Sopenharmony_ci case RayDAT: 233562306a36Sopenharmony_ci case AIO: 233662306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_2); 233762306a36Sopenharmony_ci return (status >> 12) & 0xF; 233862306a36Sopenharmony_ci default: 233962306a36Sopenharmony_ci break; 234062306a36Sopenharmony_ci } 234162306a36Sopenharmony_ci } 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci return 0; 234462306a36Sopenharmony_ci} 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci/* 234762306a36Sopenharmony_ci * Returns the AES sample rate class for the given card. 234862306a36Sopenharmony_ci */ 234962306a36Sopenharmony_cistatic int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index) 235062306a36Sopenharmony_ci{ 235162306a36Sopenharmony_ci int timecode; 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci switch (hdspm->io_type) { 235462306a36Sopenharmony_ci case AES32: 235562306a36Sopenharmony_ci timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); 235662306a36Sopenharmony_ci return (timecode >> (4*index)) & 0xF; 235762306a36Sopenharmony_ci default: 235862306a36Sopenharmony_ci break; 235962306a36Sopenharmony_ci } 236062306a36Sopenharmony_ci return 0; 236162306a36Sopenharmony_ci} 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci/* 236462306a36Sopenharmony_ci * Returns the sample rate class for input source <idx> for 236562306a36Sopenharmony_ci * 'new style' cards like the AIO and RayDAT. 236662306a36Sopenharmony_ci */ 236762306a36Sopenharmony_cistatic int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) 236862306a36Sopenharmony_ci{ 236962306a36Sopenharmony_ci int status = hdspm_read(hdspm, HDSPM_RD_STATUS_2); 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci return (status >> (idx*4)) & 0xF; 237262306a36Sopenharmony_ci} 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci#define ENUMERATED_CTL_INFO(info, texts) \ 237562306a36Sopenharmony_ci snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts) 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci/* Helper function to query the external sample rate and return the 237962306a36Sopenharmony_ci * corresponding enum to be returned to userspace. 238062306a36Sopenharmony_ci */ 238162306a36Sopenharmony_cistatic int hdspm_external_rate_to_enum(struct hdspm *hdspm) 238262306a36Sopenharmony_ci{ 238362306a36Sopenharmony_ci int rate = hdspm_external_sample_rate(hdspm); 238462306a36Sopenharmony_ci int i, selected_rate = 0; 238562306a36Sopenharmony_ci for (i = 1; i < 10; i++) 238662306a36Sopenharmony_ci if (HDSPM_bit2freq(i) == rate) { 238762306a36Sopenharmony_ci selected_rate = i; 238862306a36Sopenharmony_ci break; 238962306a36Sopenharmony_ci } 239062306a36Sopenharmony_ci return selected_rate; 239162306a36Sopenharmony_ci} 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci#define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ 239562306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 239662306a36Sopenharmony_ci .name = xname, \ 239762306a36Sopenharmony_ci .private_value = xindex, \ 239862306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, \ 239962306a36Sopenharmony_ci .info = snd_hdspm_info_autosync_sample_rate, \ 240062306a36Sopenharmony_ci .get = snd_hdspm_get_autosync_sample_rate \ 240162306a36Sopenharmony_ci} 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_cistatic int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, 240562306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 240662306a36Sopenharmony_ci{ 240762306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts_freq); 240862306a36Sopenharmony_ci return 0; 240962306a36Sopenharmony_ci} 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_cistatic int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, 241362306a36Sopenharmony_ci struct snd_ctl_elem_value * 241462306a36Sopenharmony_ci ucontrol) 241562306a36Sopenharmony_ci{ 241662306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci switch (hdspm->io_type) { 241962306a36Sopenharmony_ci case RayDAT: 242062306a36Sopenharmony_ci switch (kcontrol->private_value) { 242162306a36Sopenharmony_ci case 0: 242262306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 242362306a36Sopenharmony_ci hdspm_get_wc_sample_rate(hdspm); 242462306a36Sopenharmony_ci break; 242562306a36Sopenharmony_ci case 7: 242662306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 242762306a36Sopenharmony_ci hdspm_get_tco_sample_rate(hdspm); 242862306a36Sopenharmony_ci break; 242962306a36Sopenharmony_ci case 8: 243062306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 243162306a36Sopenharmony_ci hdspm_get_sync_in_sample_rate(hdspm); 243262306a36Sopenharmony_ci break; 243362306a36Sopenharmony_ci default: 243462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 243562306a36Sopenharmony_ci hdspm_get_s1_sample_rate(hdspm, 243662306a36Sopenharmony_ci kcontrol->private_value-1); 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci break; 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci case AIO: 244162306a36Sopenharmony_ci switch (kcontrol->private_value) { 244262306a36Sopenharmony_ci case 0: /* WC */ 244362306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 244462306a36Sopenharmony_ci hdspm_get_wc_sample_rate(hdspm); 244562306a36Sopenharmony_ci break; 244662306a36Sopenharmony_ci case 4: /* TCO */ 244762306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 244862306a36Sopenharmony_ci hdspm_get_tco_sample_rate(hdspm); 244962306a36Sopenharmony_ci break; 245062306a36Sopenharmony_ci case 5: /* SYNC_IN */ 245162306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 245262306a36Sopenharmony_ci hdspm_get_sync_in_sample_rate(hdspm); 245362306a36Sopenharmony_ci break; 245462306a36Sopenharmony_ci default: 245562306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 245662306a36Sopenharmony_ci hdspm_get_s1_sample_rate(hdspm, 245762306a36Sopenharmony_ci kcontrol->private_value-1); 245862306a36Sopenharmony_ci } 245962306a36Sopenharmony_ci break; 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci case AES32: 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci switch (kcontrol->private_value) { 246462306a36Sopenharmony_ci case 0: /* WC */ 246562306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 246662306a36Sopenharmony_ci hdspm_get_wc_sample_rate(hdspm); 246762306a36Sopenharmony_ci break; 246862306a36Sopenharmony_ci case 9: /* TCO */ 246962306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 247062306a36Sopenharmony_ci hdspm_get_tco_sample_rate(hdspm); 247162306a36Sopenharmony_ci break; 247262306a36Sopenharmony_ci case 10: /* SYNC_IN */ 247362306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 247462306a36Sopenharmony_ci hdspm_get_sync_in_sample_rate(hdspm); 247562306a36Sopenharmony_ci break; 247662306a36Sopenharmony_ci case 11: /* External Rate */ 247762306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 247862306a36Sopenharmony_ci hdspm_external_rate_to_enum(hdspm); 247962306a36Sopenharmony_ci break; 248062306a36Sopenharmony_ci default: /* AES1 to AES8 */ 248162306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 248262306a36Sopenharmony_ci hdspm_get_aes_sample_rate(hdspm, 248362306a36Sopenharmony_ci kcontrol->private_value - 248462306a36Sopenharmony_ci HDSPM_AES32_AUTOSYNC_FROM_AES1); 248562306a36Sopenharmony_ci break; 248662306a36Sopenharmony_ci } 248762306a36Sopenharmony_ci break; 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci case MADI: 249062306a36Sopenharmony_ci case MADIface: 249162306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 249262306a36Sopenharmony_ci hdspm_external_rate_to_enum(hdspm); 249362306a36Sopenharmony_ci break; 249462306a36Sopenharmony_ci default: 249562306a36Sopenharmony_ci break; 249662306a36Sopenharmony_ci } 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci return 0; 249962306a36Sopenharmony_ci} 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci#define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \ 250362306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 250462306a36Sopenharmony_ci .name = xname, \ 250562306a36Sopenharmony_ci .index = xindex, \ 250662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 250762306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 250862306a36Sopenharmony_ci .info = snd_hdspm_info_system_clock_mode, \ 250962306a36Sopenharmony_ci .get = snd_hdspm_get_system_clock_mode, \ 251062306a36Sopenharmony_ci .put = snd_hdspm_put_system_clock_mode, \ 251162306a36Sopenharmony_ci} 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci/* 251562306a36Sopenharmony_ci * Returns the system clock mode for the given card. 251662306a36Sopenharmony_ci * @returns 0 - master, 1 - slave 251762306a36Sopenharmony_ci */ 251862306a36Sopenharmony_cistatic int hdspm_system_clock_mode(struct hdspm *hdspm) 251962306a36Sopenharmony_ci{ 252062306a36Sopenharmony_ci switch (hdspm->io_type) { 252162306a36Sopenharmony_ci case AIO: 252262306a36Sopenharmony_ci case RayDAT: 252362306a36Sopenharmony_ci if (hdspm->settings_register & HDSPM_c0Master) 252462306a36Sopenharmony_ci return 0; 252562306a36Sopenharmony_ci break; 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci default: 252862306a36Sopenharmony_ci if (hdspm->control_register & HDSPM_ClockModeMaster) 252962306a36Sopenharmony_ci return 0; 253062306a36Sopenharmony_ci } 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci return 1; 253362306a36Sopenharmony_ci} 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_ci/* 253762306a36Sopenharmony_ci * Sets the system clock mode. 253862306a36Sopenharmony_ci * @param mode 0 - master, 1 - slave 253962306a36Sopenharmony_ci */ 254062306a36Sopenharmony_cistatic void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) 254162306a36Sopenharmony_ci{ 254262306a36Sopenharmony_ci hdspm_set_toggle_setting(hdspm, 254362306a36Sopenharmony_ci (hdspm_is_raydat_or_aio(hdspm)) ? 254462306a36Sopenharmony_ci HDSPM_c0Master : HDSPM_ClockModeMaster, 254562306a36Sopenharmony_ci (0 == mode)); 254662306a36Sopenharmony_ci} 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_cistatic int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, 255062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 255162306a36Sopenharmony_ci{ 255262306a36Sopenharmony_ci static const char *const texts[] = { "Master", "AutoSync" }; 255362306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 255462306a36Sopenharmony_ci return 0; 255562306a36Sopenharmony_ci} 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_cistatic int snd_hdspm_get_system_clock_mode(struct snd_kcontrol *kcontrol, 255862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 255962306a36Sopenharmony_ci{ 256062306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_system_clock_mode(hdspm); 256362306a36Sopenharmony_ci return 0; 256462306a36Sopenharmony_ci} 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_cistatic int snd_hdspm_put_system_clock_mode(struct snd_kcontrol *kcontrol, 256762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 256862306a36Sopenharmony_ci{ 256962306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 257062306a36Sopenharmony_ci int val; 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 257362306a36Sopenharmony_ci return -EBUSY; 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 257662306a36Sopenharmony_ci if (val < 0) 257762306a36Sopenharmony_ci val = 0; 257862306a36Sopenharmony_ci else if (val > 1) 257962306a36Sopenharmony_ci val = 1; 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci hdspm_set_system_clock_mode(hdspm, val); 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci return 0; 258462306a36Sopenharmony_ci} 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci#define HDSPM_INTERNAL_CLOCK(xname, xindex) \ 258862306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 258962306a36Sopenharmony_ci .name = xname, \ 259062306a36Sopenharmony_ci .index = xindex, \ 259162306a36Sopenharmony_ci .info = snd_hdspm_info_clock_source, \ 259262306a36Sopenharmony_ci .get = snd_hdspm_get_clock_source, \ 259362306a36Sopenharmony_ci .put = snd_hdspm_put_clock_source \ 259462306a36Sopenharmony_ci} 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_cistatic int hdspm_clock_source(struct hdspm * hdspm) 259862306a36Sopenharmony_ci{ 259962306a36Sopenharmony_ci switch (hdspm->system_sample_rate) { 260062306a36Sopenharmony_ci case 32000: return 0; 260162306a36Sopenharmony_ci case 44100: return 1; 260262306a36Sopenharmony_ci case 48000: return 2; 260362306a36Sopenharmony_ci case 64000: return 3; 260462306a36Sopenharmony_ci case 88200: return 4; 260562306a36Sopenharmony_ci case 96000: return 5; 260662306a36Sopenharmony_ci case 128000: return 6; 260762306a36Sopenharmony_ci case 176400: return 7; 260862306a36Sopenharmony_ci case 192000: return 8; 260962306a36Sopenharmony_ci } 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci return -1; 261262306a36Sopenharmony_ci} 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_cistatic int hdspm_set_clock_source(struct hdspm * hdspm, int mode) 261562306a36Sopenharmony_ci{ 261662306a36Sopenharmony_ci int rate; 261762306a36Sopenharmony_ci switch (mode) { 261862306a36Sopenharmony_ci case 0: 261962306a36Sopenharmony_ci rate = 32000; break; 262062306a36Sopenharmony_ci case 1: 262162306a36Sopenharmony_ci rate = 44100; break; 262262306a36Sopenharmony_ci case 2: 262362306a36Sopenharmony_ci rate = 48000; break; 262462306a36Sopenharmony_ci case 3: 262562306a36Sopenharmony_ci rate = 64000; break; 262662306a36Sopenharmony_ci case 4: 262762306a36Sopenharmony_ci rate = 88200; break; 262862306a36Sopenharmony_ci case 5: 262962306a36Sopenharmony_ci rate = 96000; break; 263062306a36Sopenharmony_ci case 6: 263162306a36Sopenharmony_ci rate = 128000; break; 263262306a36Sopenharmony_ci case 7: 263362306a36Sopenharmony_ci rate = 176400; break; 263462306a36Sopenharmony_ci case 8: 263562306a36Sopenharmony_ci rate = 192000; break; 263662306a36Sopenharmony_ci default: 263762306a36Sopenharmony_ci rate = 48000; 263862306a36Sopenharmony_ci } 263962306a36Sopenharmony_ci hdspm_set_rate(hdspm, rate, 1); 264062306a36Sopenharmony_ci return 0; 264162306a36Sopenharmony_ci} 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_cistatic int snd_hdspm_info_clock_source(struct snd_kcontrol *kcontrol, 264462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 264562306a36Sopenharmony_ci{ 264662306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 9, texts_freq + 1); 264762306a36Sopenharmony_ci} 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_cistatic int snd_hdspm_get_clock_source(struct snd_kcontrol *kcontrol, 265062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 265162306a36Sopenharmony_ci{ 265262306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_clock_source(hdspm); 265562306a36Sopenharmony_ci return 0; 265662306a36Sopenharmony_ci} 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_cistatic int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol, 265962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 266062306a36Sopenharmony_ci{ 266162306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 266262306a36Sopenharmony_ci int change; 266362306a36Sopenharmony_ci int val; 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 266662306a36Sopenharmony_ci return -EBUSY; 266762306a36Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 266862306a36Sopenharmony_ci if (val < 0) 266962306a36Sopenharmony_ci val = 0; 267062306a36Sopenharmony_ci if (val > 9) 267162306a36Sopenharmony_ci val = 9; 267262306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 267362306a36Sopenharmony_ci if (val != hdspm_clock_source(hdspm)) 267462306a36Sopenharmony_ci change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0; 267562306a36Sopenharmony_ci else 267662306a36Sopenharmony_ci change = 0; 267762306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 267862306a36Sopenharmony_ci return change; 267962306a36Sopenharmony_ci} 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci#define HDSPM_PREF_SYNC_REF(xname, xindex) \ 268362306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 268462306a36Sopenharmony_ci .name = xname, \ 268562306a36Sopenharmony_ci .index = xindex, \ 268662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 268762306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 268862306a36Sopenharmony_ci .info = snd_hdspm_info_pref_sync_ref, \ 268962306a36Sopenharmony_ci .get = snd_hdspm_get_pref_sync_ref, \ 269062306a36Sopenharmony_ci .put = snd_hdspm_put_pref_sync_ref \ 269162306a36Sopenharmony_ci} 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci 269462306a36Sopenharmony_ci/* 269562306a36Sopenharmony_ci * Returns the current preferred sync reference setting. 269662306a36Sopenharmony_ci * The semantics of the return value are depending on the 269762306a36Sopenharmony_ci * card, please see the comments for clarification. 269862306a36Sopenharmony_ci */ 269962306a36Sopenharmony_cistatic int hdspm_pref_sync_ref(struct hdspm * hdspm) 270062306a36Sopenharmony_ci{ 270162306a36Sopenharmony_ci switch (hdspm->io_type) { 270262306a36Sopenharmony_ci case AES32: 270362306a36Sopenharmony_ci switch (hdspm->control_register & HDSPM_SyncRefMask) { 270462306a36Sopenharmony_ci case 0: return 0; /* WC */ 270562306a36Sopenharmony_ci case HDSPM_SyncRef0: return 1; /* AES 1 */ 270662306a36Sopenharmony_ci case HDSPM_SyncRef1: return 2; /* AES 2 */ 270762306a36Sopenharmony_ci case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3; /* AES 3 */ 270862306a36Sopenharmony_ci case HDSPM_SyncRef2: return 4; /* AES 4 */ 270962306a36Sopenharmony_ci case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5; /* AES 5 */ 271062306a36Sopenharmony_ci case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6; /* AES 6 */ 271162306a36Sopenharmony_ci case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0: 271262306a36Sopenharmony_ci return 7; /* AES 7 */ 271362306a36Sopenharmony_ci case HDSPM_SyncRef3: return 8; /* AES 8 */ 271462306a36Sopenharmony_ci case HDSPM_SyncRef3+HDSPM_SyncRef0: return 9; /* TCO */ 271562306a36Sopenharmony_ci } 271662306a36Sopenharmony_ci break; 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci case MADI: 271962306a36Sopenharmony_ci case MADIface: 272062306a36Sopenharmony_ci if (hdspm->tco) { 272162306a36Sopenharmony_ci switch (hdspm->control_register & HDSPM_SyncRefMask) { 272262306a36Sopenharmony_ci case 0: return 0; /* WC */ 272362306a36Sopenharmony_ci case HDSPM_SyncRef0: return 1; /* MADI */ 272462306a36Sopenharmony_ci case HDSPM_SyncRef1: return 2; /* TCO */ 272562306a36Sopenharmony_ci case HDSPM_SyncRef1+HDSPM_SyncRef0: 272662306a36Sopenharmony_ci return 3; /* SYNC_IN */ 272762306a36Sopenharmony_ci } 272862306a36Sopenharmony_ci } else { 272962306a36Sopenharmony_ci switch (hdspm->control_register & HDSPM_SyncRefMask) { 273062306a36Sopenharmony_ci case 0: return 0; /* WC */ 273162306a36Sopenharmony_ci case HDSPM_SyncRef0: return 1; /* MADI */ 273262306a36Sopenharmony_ci case HDSPM_SyncRef1+HDSPM_SyncRef0: 273362306a36Sopenharmony_ci return 2; /* SYNC_IN */ 273462306a36Sopenharmony_ci } 273562306a36Sopenharmony_ci } 273662306a36Sopenharmony_ci break; 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci case RayDAT: 273962306a36Sopenharmony_ci if (hdspm->tco) { 274062306a36Sopenharmony_ci switch ((hdspm->settings_register & 274162306a36Sopenharmony_ci HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 274262306a36Sopenharmony_ci case 0: return 0; /* WC */ 274362306a36Sopenharmony_ci case 3: return 1; /* ADAT 1 */ 274462306a36Sopenharmony_ci case 4: return 2; /* ADAT 2 */ 274562306a36Sopenharmony_ci case 5: return 3; /* ADAT 3 */ 274662306a36Sopenharmony_ci case 6: return 4; /* ADAT 4 */ 274762306a36Sopenharmony_ci case 1: return 5; /* AES */ 274862306a36Sopenharmony_ci case 2: return 6; /* SPDIF */ 274962306a36Sopenharmony_ci case 9: return 7; /* TCO */ 275062306a36Sopenharmony_ci case 10: return 8; /* SYNC_IN */ 275162306a36Sopenharmony_ci } 275262306a36Sopenharmony_ci } else { 275362306a36Sopenharmony_ci switch ((hdspm->settings_register & 275462306a36Sopenharmony_ci HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 275562306a36Sopenharmony_ci case 0: return 0; /* WC */ 275662306a36Sopenharmony_ci case 3: return 1; /* ADAT 1 */ 275762306a36Sopenharmony_ci case 4: return 2; /* ADAT 2 */ 275862306a36Sopenharmony_ci case 5: return 3; /* ADAT 3 */ 275962306a36Sopenharmony_ci case 6: return 4; /* ADAT 4 */ 276062306a36Sopenharmony_ci case 1: return 5; /* AES */ 276162306a36Sopenharmony_ci case 2: return 6; /* SPDIF */ 276262306a36Sopenharmony_ci case 10: return 7; /* SYNC_IN */ 276362306a36Sopenharmony_ci } 276462306a36Sopenharmony_ci } 276562306a36Sopenharmony_ci 276662306a36Sopenharmony_ci break; 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci case AIO: 276962306a36Sopenharmony_ci if (hdspm->tco) { 277062306a36Sopenharmony_ci switch ((hdspm->settings_register & 277162306a36Sopenharmony_ci HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 277262306a36Sopenharmony_ci case 0: return 0; /* WC */ 277362306a36Sopenharmony_ci case 3: return 1; /* ADAT */ 277462306a36Sopenharmony_ci case 1: return 2; /* AES */ 277562306a36Sopenharmony_ci case 2: return 3; /* SPDIF */ 277662306a36Sopenharmony_ci case 9: return 4; /* TCO */ 277762306a36Sopenharmony_ci case 10: return 5; /* SYNC_IN */ 277862306a36Sopenharmony_ci } 277962306a36Sopenharmony_ci } else { 278062306a36Sopenharmony_ci switch ((hdspm->settings_register & 278162306a36Sopenharmony_ci HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) { 278262306a36Sopenharmony_ci case 0: return 0; /* WC */ 278362306a36Sopenharmony_ci case 3: return 1; /* ADAT */ 278462306a36Sopenharmony_ci case 1: return 2; /* AES */ 278562306a36Sopenharmony_ci case 2: return 3; /* SPDIF */ 278662306a36Sopenharmony_ci case 10: return 4; /* SYNC_IN */ 278762306a36Sopenharmony_ci } 278862306a36Sopenharmony_ci } 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci break; 279162306a36Sopenharmony_ci } 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci return -1; 279462306a36Sopenharmony_ci} 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ci/* 279862306a36Sopenharmony_ci * Set the preferred sync reference to <pref>. The semantics 279962306a36Sopenharmony_ci * of <pref> are depending on the card type, see the comments 280062306a36Sopenharmony_ci * for clarification. 280162306a36Sopenharmony_ci */ 280262306a36Sopenharmony_cistatic int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref) 280362306a36Sopenharmony_ci{ 280462306a36Sopenharmony_ci int p = 0; 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci switch (hdspm->io_type) { 280762306a36Sopenharmony_ci case AES32: 280862306a36Sopenharmony_ci hdspm->control_register &= ~HDSPM_SyncRefMask; 280962306a36Sopenharmony_ci switch (pref) { 281062306a36Sopenharmony_ci case 0: /* WC */ 281162306a36Sopenharmony_ci break; 281262306a36Sopenharmony_ci case 1: /* AES 1 */ 281362306a36Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef0; 281462306a36Sopenharmony_ci break; 281562306a36Sopenharmony_ci case 2: /* AES 2 */ 281662306a36Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef1; 281762306a36Sopenharmony_ci break; 281862306a36Sopenharmony_ci case 3: /* AES 3 */ 281962306a36Sopenharmony_ci hdspm->control_register |= 282062306a36Sopenharmony_ci HDSPM_SyncRef1+HDSPM_SyncRef0; 282162306a36Sopenharmony_ci break; 282262306a36Sopenharmony_ci case 4: /* AES 4 */ 282362306a36Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef2; 282462306a36Sopenharmony_ci break; 282562306a36Sopenharmony_ci case 5: /* AES 5 */ 282662306a36Sopenharmony_ci hdspm->control_register |= 282762306a36Sopenharmony_ci HDSPM_SyncRef2+HDSPM_SyncRef0; 282862306a36Sopenharmony_ci break; 282962306a36Sopenharmony_ci case 6: /* AES 6 */ 283062306a36Sopenharmony_ci hdspm->control_register |= 283162306a36Sopenharmony_ci HDSPM_SyncRef2+HDSPM_SyncRef1; 283262306a36Sopenharmony_ci break; 283362306a36Sopenharmony_ci case 7: /* AES 7 */ 283462306a36Sopenharmony_ci hdspm->control_register |= 283562306a36Sopenharmony_ci HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0; 283662306a36Sopenharmony_ci break; 283762306a36Sopenharmony_ci case 8: /* AES 8 */ 283862306a36Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef3; 283962306a36Sopenharmony_ci break; 284062306a36Sopenharmony_ci case 9: /* TCO */ 284162306a36Sopenharmony_ci hdspm->control_register |= 284262306a36Sopenharmony_ci HDSPM_SyncRef3+HDSPM_SyncRef0; 284362306a36Sopenharmony_ci break; 284462306a36Sopenharmony_ci default: 284562306a36Sopenharmony_ci return -1; 284662306a36Sopenharmony_ci } 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci break; 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci case MADI: 285162306a36Sopenharmony_ci case MADIface: 285262306a36Sopenharmony_ci hdspm->control_register &= ~HDSPM_SyncRefMask; 285362306a36Sopenharmony_ci if (hdspm->tco) { 285462306a36Sopenharmony_ci switch (pref) { 285562306a36Sopenharmony_ci case 0: /* WC */ 285662306a36Sopenharmony_ci break; 285762306a36Sopenharmony_ci case 1: /* MADI */ 285862306a36Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef0; 285962306a36Sopenharmony_ci break; 286062306a36Sopenharmony_ci case 2: /* TCO */ 286162306a36Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef1; 286262306a36Sopenharmony_ci break; 286362306a36Sopenharmony_ci case 3: /* SYNC_IN */ 286462306a36Sopenharmony_ci hdspm->control_register |= 286562306a36Sopenharmony_ci HDSPM_SyncRef0+HDSPM_SyncRef1; 286662306a36Sopenharmony_ci break; 286762306a36Sopenharmony_ci default: 286862306a36Sopenharmony_ci return -1; 286962306a36Sopenharmony_ci } 287062306a36Sopenharmony_ci } else { 287162306a36Sopenharmony_ci switch (pref) { 287262306a36Sopenharmony_ci case 0: /* WC */ 287362306a36Sopenharmony_ci break; 287462306a36Sopenharmony_ci case 1: /* MADI */ 287562306a36Sopenharmony_ci hdspm->control_register |= HDSPM_SyncRef0; 287662306a36Sopenharmony_ci break; 287762306a36Sopenharmony_ci case 2: /* SYNC_IN */ 287862306a36Sopenharmony_ci hdspm->control_register |= 287962306a36Sopenharmony_ci HDSPM_SyncRef0+HDSPM_SyncRef1; 288062306a36Sopenharmony_ci break; 288162306a36Sopenharmony_ci default: 288262306a36Sopenharmony_ci return -1; 288362306a36Sopenharmony_ci } 288462306a36Sopenharmony_ci } 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci break; 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci case RayDAT: 288962306a36Sopenharmony_ci if (hdspm->tco) { 289062306a36Sopenharmony_ci switch (pref) { 289162306a36Sopenharmony_ci case 0: p = 0; break; /* WC */ 289262306a36Sopenharmony_ci case 1: p = 3; break; /* ADAT 1 */ 289362306a36Sopenharmony_ci case 2: p = 4; break; /* ADAT 2 */ 289462306a36Sopenharmony_ci case 3: p = 5; break; /* ADAT 3 */ 289562306a36Sopenharmony_ci case 4: p = 6; break; /* ADAT 4 */ 289662306a36Sopenharmony_ci case 5: p = 1; break; /* AES */ 289762306a36Sopenharmony_ci case 6: p = 2; break; /* SPDIF */ 289862306a36Sopenharmony_ci case 7: p = 9; break; /* TCO */ 289962306a36Sopenharmony_ci case 8: p = 10; break; /* SYNC_IN */ 290062306a36Sopenharmony_ci default: return -1; 290162306a36Sopenharmony_ci } 290262306a36Sopenharmony_ci } else { 290362306a36Sopenharmony_ci switch (pref) { 290462306a36Sopenharmony_ci case 0: p = 0; break; /* WC */ 290562306a36Sopenharmony_ci case 1: p = 3; break; /* ADAT 1 */ 290662306a36Sopenharmony_ci case 2: p = 4; break; /* ADAT 2 */ 290762306a36Sopenharmony_ci case 3: p = 5; break; /* ADAT 3 */ 290862306a36Sopenharmony_ci case 4: p = 6; break; /* ADAT 4 */ 290962306a36Sopenharmony_ci case 5: p = 1; break; /* AES */ 291062306a36Sopenharmony_ci case 6: p = 2; break; /* SPDIF */ 291162306a36Sopenharmony_ci case 7: p = 10; break; /* SYNC_IN */ 291262306a36Sopenharmony_ci default: return -1; 291362306a36Sopenharmony_ci } 291462306a36Sopenharmony_ci } 291562306a36Sopenharmony_ci break; 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci case AIO: 291862306a36Sopenharmony_ci if (hdspm->tco) { 291962306a36Sopenharmony_ci switch (pref) { 292062306a36Sopenharmony_ci case 0: p = 0; break; /* WC */ 292162306a36Sopenharmony_ci case 1: p = 3; break; /* ADAT */ 292262306a36Sopenharmony_ci case 2: p = 1; break; /* AES */ 292362306a36Sopenharmony_ci case 3: p = 2; break; /* SPDIF */ 292462306a36Sopenharmony_ci case 4: p = 9; break; /* TCO */ 292562306a36Sopenharmony_ci case 5: p = 10; break; /* SYNC_IN */ 292662306a36Sopenharmony_ci default: return -1; 292762306a36Sopenharmony_ci } 292862306a36Sopenharmony_ci } else { 292962306a36Sopenharmony_ci switch (pref) { 293062306a36Sopenharmony_ci case 0: p = 0; break; /* WC */ 293162306a36Sopenharmony_ci case 1: p = 3; break; /* ADAT */ 293262306a36Sopenharmony_ci case 2: p = 1; break; /* AES */ 293362306a36Sopenharmony_ci case 3: p = 2; break; /* SPDIF */ 293462306a36Sopenharmony_ci case 4: p = 10; break; /* SYNC_IN */ 293562306a36Sopenharmony_ci default: return -1; 293662306a36Sopenharmony_ci } 293762306a36Sopenharmony_ci } 293862306a36Sopenharmony_ci break; 293962306a36Sopenharmony_ci } 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ci switch (hdspm->io_type) { 294262306a36Sopenharmony_ci case RayDAT: 294362306a36Sopenharmony_ci case AIO: 294462306a36Sopenharmony_ci hdspm->settings_register &= ~HDSPM_c0_SyncRefMask; 294562306a36Sopenharmony_ci hdspm->settings_register |= HDSPM_c0_SyncRef0 * p; 294662306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 294762306a36Sopenharmony_ci break; 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_ci case MADI: 295062306a36Sopenharmony_ci case MADIface: 295162306a36Sopenharmony_ci case AES32: 295262306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, 295362306a36Sopenharmony_ci hdspm->control_register); 295462306a36Sopenharmony_ci } 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci return 0; 295762306a36Sopenharmony_ci} 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_cistatic int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, 296162306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 296262306a36Sopenharmony_ci{ 296362306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync); 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci return 0; 296862306a36Sopenharmony_ci} 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_cistatic int snd_hdspm_get_pref_sync_ref(struct snd_kcontrol *kcontrol, 297162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 297262306a36Sopenharmony_ci{ 297362306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 297462306a36Sopenharmony_ci int psf = hdspm_pref_sync_ref(hdspm); 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_ci if (psf >= 0) { 297762306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = psf; 297862306a36Sopenharmony_ci return 0; 297962306a36Sopenharmony_ci } 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci return -1; 298262306a36Sopenharmony_ci} 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_cistatic int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, 298562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 298662306a36Sopenharmony_ci{ 298762306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 298862306a36Sopenharmony_ci int val, change = 0; 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 299162306a36Sopenharmony_ci return -EBUSY; 299262306a36Sopenharmony_ci 299362306a36Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci if (val < 0) 299662306a36Sopenharmony_ci val = 0; 299762306a36Sopenharmony_ci else if (val >= hdspm->texts_autosync_items) 299862306a36Sopenharmony_ci val = hdspm->texts_autosync_items-1; 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 300162306a36Sopenharmony_ci if (val != hdspm_pref_sync_ref(hdspm)) 300262306a36Sopenharmony_ci change = (0 == hdspm_set_pref_sync_ref(hdspm, val)) ? 1 : 0; 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 300562306a36Sopenharmony_ci return change; 300662306a36Sopenharmony_ci} 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci#define HDSPM_AUTOSYNC_REF(xname, xindex) \ 301062306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 301162306a36Sopenharmony_ci .name = xname, \ 301262306a36Sopenharmony_ci .index = xindex, \ 301362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, \ 301462306a36Sopenharmony_ci .info = snd_hdspm_info_autosync_ref, \ 301562306a36Sopenharmony_ci .get = snd_hdspm_get_autosync_ref, \ 301662306a36Sopenharmony_ci} 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_cistatic int hdspm_autosync_ref(struct hdspm *hdspm) 301962306a36Sopenharmony_ci{ 302062306a36Sopenharmony_ci /* This looks at the autosync selected sync reference */ 302162306a36Sopenharmony_ci if (AES32 == hdspm->io_type) { 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); 302462306a36Sopenharmony_ci unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; 302562306a36Sopenharmony_ci /* syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD is always true */ 302662306a36Sopenharmony_ci if (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN) { 302762306a36Sopenharmony_ci return syncref; 302862306a36Sopenharmony_ci } 302962306a36Sopenharmony_ci return HDSPM_AES32_AUTOSYNC_FROM_NONE; 303062306a36Sopenharmony_ci 303162306a36Sopenharmony_ci } else if (MADI == hdspm->io_type) { 303262306a36Sopenharmony_ci 303362306a36Sopenharmony_ci unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 303462306a36Sopenharmony_ci switch (status2 & HDSPM_SelSyncRefMask) { 303562306a36Sopenharmony_ci case HDSPM_SelSyncRef_WORD: 303662306a36Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_WORD; 303762306a36Sopenharmony_ci case HDSPM_SelSyncRef_MADI: 303862306a36Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_MADI; 303962306a36Sopenharmony_ci case HDSPM_SelSyncRef_TCO: 304062306a36Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_TCO; 304162306a36Sopenharmony_ci case HDSPM_SelSyncRef_SyncIn: 304262306a36Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_SYNC_IN; 304362306a36Sopenharmony_ci case HDSPM_SelSyncRef_NVALID: 304462306a36Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_NONE; 304562306a36Sopenharmony_ci default: 304662306a36Sopenharmony_ci return HDSPM_AUTOSYNC_FROM_NONE; 304762306a36Sopenharmony_ci } 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci } 305062306a36Sopenharmony_ci return 0; 305162306a36Sopenharmony_ci} 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_cistatic int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, 305562306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 305662306a36Sopenharmony_ci{ 305762306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 305862306a36Sopenharmony_ci 305962306a36Sopenharmony_ci if (AES32 == hdspm->io_type) { 306062306a36Sopenharmony_ci static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3", 306162306a36Sopenharmony_ci "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"}; 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 306462306a36Sopenharmony_ci } else if (MADI == hdspm->io_type) { 306562306a36Sopenharmony_ci static const char *const texts[] = {"Word Clock", "MADI", "TCO", 306662306a36Sopenharmony_ci "Sync In", "None" }; 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 306962306a36Sopenharmony_ci } 307062306a36Sopenharmony_ci return 0; 307162306a36Sopenharmony_ci} 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_cistatic int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, 307462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 307562306a36Sopenharmony_ci{ 307662306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_autosync_ref(hdspm); 307962306a36Sopenharmony_ci return 0; 308062306a36Sopenharmony_ci} 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci#define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname, xindex) \ 308562306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 308662306a36Sopenharmony_ci .name = xname, \ 308762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ |\ 308862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 308962306a36Sopenharmony_ci .info = snd_hdspm_info_tco_video_input_format, \ 309062306a36Sopenharmony_ci .get = snd_hdspm_get_tco_video_input_format, \ 309162306a36Sopenharmony_ci} 309262306a36Sopenharmony_ci 309362306a36Sopenharmony_cistatic int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol, 309462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 309562306a36Sopenharmony_ci{ 309662306a36Sopenharmony_ci static const char *const texts[] = {"No video", "NTSC", "PAL"}; 309762306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 309862306a36Sopenharmony_ci return 0; 309962306a36Sopenharmony_ci} 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_cistatic int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol, 310262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 310362306a36Sopenharmony_ci{ 310462306a36Sopenharmony_ci u32 status; 310562306a36Sopenharmony_ci int ret = 0; 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 310862306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 310962306a36Sopenharmony_ci switch (status & (HDSPM_TCO1_Video_Input_Format_NTSC | 311062306a36Sopenharmony_ci HDSPM_TCO1_Video_Input_Format_PAL)) { 311162306a36Sopenharmony_ci case HDSPM_TCO1_Video_Input_Format_NTSC: 311262306a36Sopenharmony_ci /* ntsc */ 311362306a36Sopenharmony_ci ret = 1; 311462306a36Sopenharmony_ci break; 311562306a36Sopenharmony_ci case HDSPM_TCO1_Video_Input_Format_PAL: 311662306a36Sopenharmony_ci /* pal */ 311762306a36Sopenharmony_ci ret = 2; 311862306a36Sopenharmony_ci break; 311962306a36Sopenharmony_ci default: 312062306a36Sopenharmony_ci /* no video */ 312162306a36Sopenharmony_ci ret = 0; 312262306a36Sopenharmony_ci break; 312362306a36Sopenharmony_ci } 312462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = ret; 312562306a36Sopenharmony_ci return 0; 312662306a36Sopenharmony_ci} 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci#define HDSPM_TCO_LTC_FRAMES(xname, xindex) \ 313162306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 313262306a36Sopenharmony_ci .name = xname, \ 313362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ |\ 313462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 313562306a36Sopenharmony_ci .info = snd_hdspm_info_tco_ltc_frames, \ 313662306a36Sopenharmony_ci .get = snd_hdspm_get_tco_ltc_frames, \ 313762306a36Sopenharmony_ci} 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_cistatic int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol, 314062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 314162306a36Sopenharmony_ci{ 314262306a36Sopenharmony_ci static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", 314362306a36Sopenharmony_ci "30 fps"}; 314462306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 314562306a36Sopenharmony_ci return 0; 314662306a36Sopenharmony_ci} 314762306a36Sopenharmony_ci 314862306a36Sopenharmony_cistatic int hdspm_tco_ltc_frames(struct hdspm *hdspm) 314962306a36Sopenharmony_ci{ 315062306a36Sopenharmony_ci u32 status; 315162306a36Sopenharmony_ci int ret = 0; 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 315462306a36Sopenharmony_ci if (status & HDSPM_TCO1_LTC_Input_valid) { 315562306a36Sopenharmony_ci switch (status & (HDSPM_TCO1_LTC_Format_LSB | 315662306a36Sopenharmony_ci HDSPM_TCO1_LTC_Format_MSB)) { 315762306a36Sopenharmony_ci case 0: 315862306a36Sopenharmony_ci /* 24 fps */ 315962306a36Sopenharmony_ci ret = fps_24; 316062306a36Sopenharmony_ci break; 316162306a36Sopenharmony_ci case HDSPM_TCO1_LTC_Format_LSB: 316262306a36Sopenharmony_ci /* 25 fps */ 316362306a36Sopenharmony_ci ret = fps_25; 316462306a36Sopenharmony_ci break; 316562306a36Sopenharmony_ci case HDSPM_TCO1_LTC_Format_MSB: 316662306a36Sopenharmony_ci /* 29.97 fps */ 316762306a36Sopenharmony_ci ret = fps_2997; 316862306a36Sopenharmony_ci break; 316962306a36Sopenharmony_ci default: 317062306a36Sopenharmony_ci /* 30 fps */ 317162306a36Sopenharmony_ci ret = fps_30; 317262306a36Sopenharmony_ci break; 317362306a36Sopenharmony_ci } 317462306a36Sopenharmony_ci } 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci return ret; 317762306a36Sopenharmony_ci} 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_cistatic int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol, 318062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 318162306a36Sopenharmony_ci{ 318262306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 318362306a36Sopenharmony_ci 318462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_tco_ltc_frames(hdspm); 318562306a36Sopenharmony_ci return 0; 318662306a36Sopenharmony_ci} 318762306a36Sopenharmony_ci 318862306a36Sopenharmony_ci#define HDSPM_TOGGLE_SETTING(xname, xindex) \ 318962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 319062306a36Sopenharmony_ci .name = xname, \ 319162306a36Sopenharmony_ci .private_value = xindex, \ 319262306a36Sopenharmony_ci .info = snd_hdspm_info_toggle_setting, \ 319362306a36Sopenharmony_ci .get = snd_hdspm_get_toggle_setting, \ 319462306a36Sopenharmony_ci .put = snd_hdspm_put_toggle_setting \ 319562306a36Sopenharmony_ci} 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_cistatic int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask) 319862306a36Sopenharmony_ci{ 319962306a36Sopenharmony_ci u32 reg; 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ci if (hdspm_is_raydat_or_aio(hdspm)) 320262306a36Sopenharmony_ci reg = hdspm->settings_register; 320362306a36Sopenharmony_ci else 320462306a36Sopenharmony_ci reg = hdspm->control_register; 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci return (reg & regmask) ? 1 : 0; 320762306a36Sopenharmony_ci} 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_cistatic int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out) 321062306a36Sopenharmony_ci{ 321162306a36Sopenharmony_ci u32 *reg; 321262306a36Sopenharmony_ci u32 target_reg; 321362306a36Sopenharmony_ci 321462306a36Sopenharmony_ci if (hdspm_is_raydat_or_aio(hdspm)) { 321562306a36Sopenharmony_ci reg = &(hdspm->settings_register); 321662306a36Sopenharmony_ci target_reg = HDSPM_WR_SETTINGS; 321762306a36Sopenharmony_ci } else { 321862306a36Sopenharmony_ci reg = &(hdspm->control_register); 321962306a36Sopenharmony_ci target_reg = HDSPM_controlRegister; 322062306a36Sopenharmony_ci } 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci if (out) 322362306a36Sopenharmony_ci *reg |= regmask; 322462306a36Sopenharmony_ci else 322562306a36Sopenharmony_ci *reg &= ~regmask; 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_ci hdspm_write(hdspm, target_reg, *reg); 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ci return 0; 323062306a36Sopenharmony_ci} 323162306a36Sopenharmony_ci 323262306a36Sopenharmony_ci#define snd_hdspm_info_toggle_setting snd_ctl_boolean_mono_info 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_cistatic int snd_hdspm_get_toggle_setting(struct snd_kcontrol *kcontrol, 323562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 323662306a36Sopenharmony_ci{ 323762306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 323862306a36Sopenharmony_ci u32 regmask = kcontrol->private_value; 323962306a36Sopenharmony_ci 324062306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 324162306a36Sopenharmony_ci ucontrol->value.integer.value[0] = hdspm_toggle_setting(hdspm, regmask); 324262306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 324362306a36Sopenharmony_ci return 0; 324462306a36Sopenharmony_ci} 324562306a36Sopenharmony_ci 324662306a36Sopenharmony_cistatic int snd_hdspm_put_toggle_setting(struct snd_kcontrol *kcontrol, 324762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 324862306a36Sopenharmony_ci{ 324962306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 325062306a36Sopenharmony_ci u32 regmask = kcontrol->private_value; 325162306a36Sopenharmony_ci int change; 325262306a36Sopenharmony_ci unsigned int val; 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 325562306a36Sopenharmony_ci return -EBUSY; 325662306a36Sopenharmony_ci val = ucontrol->value.integer.value[0] & 1; 325762306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 325862306a36Sopenharmony_ci change = (int) val != hdspm_toggle_setting(hdspm, regmask); 325962306a36Sopenharmony_ci hdspm_set_toggle_setting(hdspm, regmask, val); 326062306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 326162306a36Sopenharmony_ci return change; 326262306a36Sopenharmony_ci} 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ci#define HDSPM_INPUT_SELECT(xname, xindex) \ 326562306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 326662306a36Sopenharmony_ci .name = xname, \ 326762306a36Sopenharmony_ci .index = xindex, \ 326862306a36Sopenharmony_ci .info = snd_hdspm_info_input_select, \ 326962306a36Sopenharmony_ci .get = snd_hdspm_get_input_select, \ 327062306a36Sopenharmony_ci .put = snd_hdspm_put_input_select \ 327162306a36Sopenharmony_ci} 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_cistatic int hdspm_input_select(struct hdspm * hdspm) 327462306a36Sopenharmony_ci{ 327562306a36Sopenharmony_ci return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0; 327662306a36Sopenharmony_ci} 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_cistatic int hdspm_set_input_select(struct hdspm * hdspm, int out) 327962306a36Sopenharmony_ci{ 328062306a36Sopenharmony_ci if (out) 328162306a36Sopenharmony_ci hdspm->control_register |= HDSPM_InputSelect0; 328262306a36Sopenharmony_ci else 328362306a36Sopenharmony_ci hdspm->control_register &= ~HDSPM_InputSelect0; 328462306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 328562306a36Sopenharmony_ci 328662306a36Sopenharmony_ci return 0; 328762306a36Sopenharmony_ci} 328862306a36Sopenharmony_ci 328962306a36Sopenharmony_cistatic int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, 329062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 329162306a36Sopenharmony_ci{ 329262306a36Sopenharmony_ci static const char *const texts[] = { "optical", "coaxial" }; 329362306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 329462306a36Sopenharmony_ci return 0; 329562306a36Sopenharmony_ci} 329662306a36Sopenharmony_ci 329762306a36Sopenharmony_cistatic int snd_hdspm_get_input_select(struct snd_kcontrol *kcontrol, 329862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 329962306a36Sopenharmony_ci{ 330062306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 330162306a36Sopenharmony_ci 330262306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 330362306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm); 330462306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 330562306a36Sopenharmony_ci return 0; 330662306a36Sopenharmony_ci} 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_cistatic int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol, 330962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 331062306a36Sopenharmony_ci{ 331162306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 331262306a36Sopenharmony_ci int change; 331362306a36Sopenharmony_ci unsigned int val; 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 331662306a36Sopenharmony_ci return -EBUSY; 331762306a36Sopenharmony_ci val = ucontrol->value.integer.value[0] & 1; 331862306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 331962306a36Sopenharmony_ci change = (int) val != hdspm_input_select(hdspm); 332062306a36Sopenharmony_ci hdspm_set_input_select(hdspm, val); 332162306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 332262306a36Sopenharmony_ci return change; 332362306a36Sopenharmony_ci} 332462306a36Sopenharmony_ci 332562306a36Sopenharmony_ci 332662306a36Sopenharmony_ci#define HDSPM_DS_WIRE(xname, xindex) \ 332762306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 332862306a36Sopenharmony_ci .name = xname, \ 332962306a36Sopenharmony_ci .index = xindex, \ 333062306a36Sopenharmony_ci .info = snd_hdspm_info_ds_wire, \ 333162306a36Sopenharmony_ci .get = snd_hdspm_get_ds_wire, \ 333262306a36Sopenharmony_ci .put = snd_hdspm_put_ds_wire \ 333362306a36Sopenharmony_ci} 333462306a36Sopenharmony_ci 333562306a36Sopenharmony_cistatic int hdspm_ds_wire(struct hdspm * hdspm) 333662306a36Sopenharmony_ci{ 333762306a36Sopenharmony_ci return (hdspm->control_register & HDSPM_DS_DoubleWire) ? 1 : 0; 333862306a36Sopenharmony_ci} 333962306a36Sopenharmony_ci 334062306a36Sopenharmony_cistatic int hdspm_set_ds_wire(struct hdspm * hdspm, int ds) 334162306a36Sopenharmony_ci{ 334262306a36Sopenharmony_ci if (ds) 334362306a36Sopenharmony_ci hdspm->control_register |= HDSPM_DS_DoubleWire; 334462306a36Sopenharmony_ci else 334562306a36Sopenharmony_ci hdspm->control_register &= ~HDSPM_DS_DoubleWire; 334662306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci return 0; 334962306a36Sopenharmony_ci} 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_cistatic int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, 335262306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 335362306a36Sopenharmony_ci{ 335462306a36Sopenharmony_ci static const char *const texts[] = { "Single", "Double" }; 335562306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 335662306a36Sopenharmony_ci return 0; 335762306a36Sopenharmony_ci} 335862306a36Sopenharmony_ci 335962306a36Sopenharmony_cistatic int snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol, 336062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 336162306a36Sopenharmony_ci{ 336262306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 336562306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm); 336662306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 336762306a36Sopenharmony_ci return 0; 336862306a36Sopenharmony_ci} 336962306a36Sopenharmony_ci 337062306a36Sopenharmony_cistatic int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol, 337162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 337262306a36Sopenharmony_ci{ 337362306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 337462306a36Sopenharmony_ci int change; 337562306a36Sopenharmony_ci unsigned int val; 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 337862306a36Sopenharmony_ci return -EBUSY; 337962306a36Sopenharmony_ci val = ucontrol->value.integer.value[0] & 1; 338062306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 338162306a36Sopenharmony_ci change = (int) val != hdspm_ds_wire(hdspm); 338262306a36Sopenharmony_ci hdspm_set_ds_wire(hdspm, val); 338362306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 338462306a36Sopenharmony_ci return change; 338562306a36Sopenharmony_ci} 338662306a36Sopenharmony_ci 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci#define HDSPM_QS_WIRE(xname, xindex) \ 338962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 339062306a36Sopenharmony_ci .name = xname, \ 339162306a36Sopenharmony_ci .index = xindex, \ 339262306a36Sopenharmony_ci .info = snd_hdspm_info_qs_wire, \ 339362306a36Sopenharmony_ci .get = snd_hdspm_get_qs_wire, \ 339462306a36Sopenharmony_ci .put = snd_hdspm_put_qs_wire \ 339562306a36Sopenharmony_ci} 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_cistatic int hdspm_qs_wire(struct hdspm * hdspm) 339862306a36Sopenharmony_ci{ 339962306a36Sopenharmony_ci if (hdspm->control_register & HDSPM_QS_DoubleWire) 340062306a36Sopenharmony_ci return 1; 340162306a36Sopenharmony_ci if (hdspm->control_register & HDSPM_QS_QuadWire) 340262306a36Sopenharmony_ci return 2; 340362306a36Sopenharmony_ci return 0; 340462306a36Sopenharmony_ci} 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_cistatic int hdspm_set_qs_wire(struct hdspm * hdspm, int mode) 340762306a36Sopenharmony_ci{ 340862306a36Sopenharmony_ci hdspm->control_register &= ~(HDSPM_QS_DoubleWire | HDSPM_QS_QuadWire); 340962306a36Sopenharmony_ci switch (mode) { 341062306a36Sopenharmony_ci case 0: 341162306a36Sopenharmony_ci break; 341262306a36Sopenharmony_ci case 1: 341362306a36Sopenharmony_ci hdspm->control_register |= HDSPM_QS_DoubleWire; 341462306a36Sopenharmony_ci break; 341562306a36Sopenharmony_ci case 2: 341662306a36Sopenharmony_ci hdspm->control_register |= HDSPM_QS_QuadWire; 341762306a36Sopenharmony_ci break; 341862306a36Sopenharmony_ci } 341962306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci return 0; 342262306a36Sopenharmony_ci} 342362306a36Sopenharmony_ci 342462306a36Sopenharmony_cistatic int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, 342562306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 342662306a36Sopenharmony_ci{ 342762306a36Sopenharmony_ci static const char *const texts[] = { "Single", "Double", "Quad" }; 342862306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 342962306a36Sopenharmony_ci return 0; 343062306a36Sopenharmony_ci} 343162306a36Sopenharmony_ci 343262306a36Sopenharmony_cistatic int snd_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol, 343362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 343462306a36Sopenharmony_ci{ 343562306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 343862306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm); 343962306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 344062306a36Sopenharmony_ci return 0; 344162306a36Sopenharmony_ci} 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_cistatic int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, 344462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 344562306a36Sopenharmony_ci{ 344662306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 344762306a36Sopenharmony_ci int change; 344862306a36Sopenharmony_ci int val; 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 345162306a36Sopenharmony_ci return -EBUSY; 345262306a36Sopenharmony_ci val = ucontrol->value.integer.value[0]; 345362306a36Sopenharmony_ci if (val < 0) 345462306a36Sopenharmony_ci val = 0; 345562306a36Sopenharmony_ci if (val > 2) 345662306a36Sopenharmony_ci val = 2; 345762306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 345862306a36Sopenharmony_ci change = val != hdspm_qs_wire(hdspm); 345962306a36Sopenharmony_ci hdspm_set_qs_wire(hdspm, val); 346062306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 346162306a36Sopenharmony_ci return change; 346262306a36Sopenharmony_ci} 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci#define HDSPM_CONTROL_TRISTATE(xname, xindex) \ 346562306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 346662306a36Sopenharmony_ci .name = xname, \ 346762306a36Sopenharmony_ci .private_value = xindex, \ 346862306a36Sopenharmony_ci .info = snd_hdspm_info_tristate, \ 346962306a36Sopenharmony_ci .get = snd_hdspm_get_tristate, \ 347062306a36Sopenharmony_ci .put = snd_hdspm_put_tristate \ 347162306a36Sopenharmony_ci} 347262306a36Sopenharmony_ci 347362306a36Sopenharmony_cistatic int hdspm_tristate(struct hdspm *hdspm, u32 regmask) 347462306a36Sopenharmony_ci{ 347562306a36Sopenharmony_ci u32 reg = hdspm->settings_register & (regmask * 3); 347662306a36Sopenharmony_ci return reg / regmask; 347762306a36Sopenharmony_ci} 347862306a36Sopenharmony_ci 347962306a36Sopenharmony_cistatic int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask) 348062306a36Sopenharmony_ci{ 348162306a36Sopenharmony_ci hdspm->settings_register &= ~(regmask * 3); 348262306a36Sopenharmony_ci hdspm->settings_register |= (regmask * mode); 348362306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_ci return 0; 348662306a36Sopenharmony_ci} 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_cistatic int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol, 348962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 349062306a36Sopenharmony_ci{ 349162306a36Sopenharmony_ci u32 regmask = kcontrol->private_value; 349262306a36Sopenharmony_ci 349362306a36Sopenharmony_ci static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" }; 349462306a36Sopenharmony_ci static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" }; 349562306a36Sopenharmony_ci 349662306a36Sopenharmony_ci switch (regmask) { 349762306a36Sopenharmony_ci case HDSPM_c0_Input0: 349862306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts_spdif); 349962306a36Sopenharmony_ci break; 350062306a36Sopenharmony_ci default: 350162306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts_levels); 350262306a36Sopenharmony_ci break; 350362306a36Sopenharmony_ci } 350462306a36Sopenharmony_ci return 0; 350562306a36Sopenharmony_ci} 350662306a36Sopenharmony_ci 350762306a36Sopenharmony_cistatic int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol, 350862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 350962306a36Sopenharmony_ci{ 351062306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 351162306a36Sopenharmony_ci u32 regmask = kcontrol->private_value; 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 351462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask); 351562306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 351662306a36Sopenharmony_ci return 0; 351762306a36Sopenharmony_ci} 351862306a36Sopenharmony_ci 351962306a36Sopenharmony_cistatic int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol, 352062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 352162306a36Sopenharmony_ci{ 352262306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 352362306a36Sopenharmony_ci u32 regmask = kcontrol->private_value; 352462306a36Sopenharmony_ci int change; 352562306a36Sopenharmony_ci int val; 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 352862306a36Sopenharmony_ci return -EBUSY; 352962306a36Sopenharmony_ci val = ucontrol->value.integer.value[0]; 353062306a36Sopenharmony_ci if (val < 0) 353162306a36Sopenharmony_ci val = 0; 353262306a36Sopenharmony_ci if (val > 2) 353362306a36Sopenharmony_ci val = 2; 353462306a36Sopenharmony_ci 353562306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 353662306a36Sopenharmony_ci change = val != hdspm_tristate(hdspm, regmask); 353762306a36Sopenharmony_ci hdspm_set_tristate(hdspm, val, regmask); 353862306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 353962306a36Sopenharmony_ci return change; 354062306a36Sopenharmony_ci} 354162306a36Sopenharmony_ci 354262306a36Sopenharmony_ci#define HDSPM_MADI_SPEEDMODE(xname, xindex) \ 354362306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 354462306a36Sopenharmony_ci .name = xname, \ 354562306a36Sopenharmony_ci .index = xindex, \ 354662306a36Sopenharmony_ci .info = snd_hdspm_info_madi_speedmode, \ 354762306a36Sopenharmony_ci .get = snd_hdspm_get_madi_speedmode, \ 354862306a36Sopenharmony_ci .put = snd_hdspm_put_madi_speedmode \ 354962306a36Sopenharmony_ci} 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_cistatic int hdspm_madi_speedmode(struct hdspm *hdspm) 355262306a36Sopenharmony_ci{ 355362306a36Sopenharmony_ci if (hdspm->control_register & HDSPM_QuadSpeed) 355462306a36Sopenharmony_ci return 2; 355562306a36Sopenharmony_ci if (hdspm->control_register & HDSPM_DoubleSpeed) 355662306a36Sopenharmony_ci return 1; 355762306a36Sopenharmony_ci return 0; 355862306a36Sopenharmony_ci} 355962306a36Sopenharmony_ci 356062306a36Sopenharmony_cistatic int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode) 356162306a36Sopenharmony_ci{ 356262306a36Sopenharmony_ci hdspm->control_register &= ~(HDSPM_DoubleSpeed | HDSPM_QuadSpeed); 356362306a36Sopenharmony_ci switch (mode) { 356462306a36Sopenharmony_ci case 0: 356562306a36Sopenharmony_ci break; 356662306a36Sopenharmony_ci case 1: 356762306a36Sopenharmony_ci hdspm->control_register |= HDSPM_DoubleSpeed; 356862306a36Sopenharmony_ci break; 356962306a36Sopenharmony_ci case 2: 357062306a36Sopenharmony_ci hdspm->control_register |= HDSPM_QuadSpeed; 357162306a36Sopenharmony_ci break; 357262306a36Sopenharmony_ci } 357362306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci return 0; 357662306a36Sopenharmony_ci} 357762306a36Sopenharmony_ci 357862306a36Sopenharmony_cistatic int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, 357962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 358062306a36Sopenharmony_ci{ 358162306a36Sopenharmony_ci static const char *const texts[] = { "Single", "Double", "Quad" }; 358262306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 358362306a36Sopenharmony_ci return 0; 358462306a36Sopenharmony_ci} 358562306a36Sopenharmony_ci 358662306a36Sopenharmony_cistatic int snd_hdspm_get_madi_speedmode(struct snd_kcontrol *kcontrol, 358762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 358862306a36Sopenharmony_ci{ 358962306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 359062306a36Sopenharmony_ci 359162306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 359262306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm_madi_speedmode(hdspm); 359362306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 359462306a36Sopenharmony_ci return 0; 359562306a36Sopenharmony_ci} 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_cistatic int snd_hdspm_put_madi_speedmode(struct snd_kcontrol *kcontrol, 359862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 359962306a36Sopenharmony_ci{ 360062306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 360162306a36Sopenharmony_ci int change; 360262306a36Sopenharmony_ci int val; 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 360562306a36Sopenharmony_ci return -EBUSY; 360662306a36Sopenharmony_ci val = ucontrol->value.integer.value[0]; 360762306a36Sopenharmony_ci if (val < 0) 360862306a36Sopenharmony_ci val = 0; 360962306a36Sopenharmony_ci if (val > 2) 361062306a36Sopenharmony_ci val = 2; 361162306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 361262306a36Sopenharmony_ci change = val != hdspm_madi_speedmode(hdspm); 361362306a36Sopenharmony_ci hdspm_set_madi_speedmode(hdspm, val); 361462306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 361562306a36Sopenharmony_ci return change; 361662306a36Sopenharmony_ci} 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_ci#define HDSPM_MIXER(xname, xindex) \ 361962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ 362062306a36Sopenharmony_ci .name = xname, \ 362162306a36Sopenharmony_ci .index = xindex, \ 362262306a36Sopenharmony_ci .device = 0, \ 362362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 362462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 362562306a36Sopenharmony_ci .info = snd_hdspm_info_mixer, \ 362662306a36Sopenharmony_ci .get = snd_hdspm_get_mixer, \ 362762306a36Sopenharmony_ci .put = snd_hdspm_put_mixer \ 362862306a36Sopenharmony_ci} 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_cistatic int snd_hdspm_info_mixer(struct snd_kcontrol *kcontrol, 363162306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 363262306a36Sopenharmony_ci{ 363362306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 363462306a36Sopenharmony_ci uinfo->count = 3; 363562306a36Sopenharmony_ci uinfo->value.integer.min = 0; 363662306a36Sopenharmony_ci uinfo->value.integer.max = 65535; 363762306a36Sopenharmony_ci uinfo->value.integer.step = 1; 363862306a36Sopenharmony_ci return 0; 363962306a36Sopenharmony_ci} 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_cistatic int snd_hdspm_get_mixer(struct snd_kcontrol *kcontrol, 364262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 364362306a36Sopenharmony_ci{ 364462306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 364562306a36Sopenharmony_ci int source; 364662306a36Sopenharmony_ci int destination; 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci source = ucontrol->value.integer.value[0]; 364962306a36Sopenharmony_ci if (source < 0) 365062306a36Sopenharmony_ci source = 0; 365162306a36Sopenharmony_ci else if (source >= 2 * HDSPM_MAX_CHANNELS) 365262306a36Sopenharmony_ci source = 2 * HDSPM_MAX_CHANNELS - 1; 365362306a36Sopenharmony_ci 365462306a36Sopenharmony_ci destination = ucontrol->value.integer.value[1]; 365562306a36Sopenharmony_ci if (destination < 0) 365662306a36Sopenharmony_ci destination = 0; 365762306a36Sopenharmony_ci else if (destination >= HDSPM_MAX_CHANNELS) 365862306a36Sopenharmony_ci destination = HDSPM_MAX_CHANNELS - 1; 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 366162306a36Sopenharmony_ci if (source >= HDSPM_MAX_CHANNELS) 366262306a36Sopenharmony_ci ucontrol->value.integer.value[2] = 366362306a36Sopenharmony_ci hdspm_read_pb_gain(hdspm, destination, 366462306a36Sopenharmony_ci source - HDSPM_MAX_CHANNELS); 366562306a36Sopenharmony_ci else 366662306a36Sopenharmony_ci ucontrol->value.integer.value[2] = 366762306a36Sopenharmony_ci hdspm_read_in_gain(hdspm, destination, source); 366862306a36Sopenharmony_ci 366962306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 367062306a36Sopenharmony_ci 367162306a36Sopenharmony_ci return 0; 367262306a36Sopenharmony_ci} 367362306a36Sopenharmony_ci 367462306a36Sopenharmony_cistatic int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol, 367562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 367662306a36Sopenharmony_ci{ 367762306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 367862306a36Sopenharmony_ci int change; 367962306a36Sopenharmony_ci int source; 368062306a36Sopenharmony_ci int destination; 368162306a36Sopenharmony_ci int gain; 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 368462306a36Sopenharmony_ci return -EBUSY; 368562306a36Sopenharmony_ci 368662306a36Sopenharmony_ci source = ucontrol->value.integer.value[0]; 368762306a36Sopenharmony_ci destination = ucontrol->value.integer.value[1]; 368862306a36Sopenharmony_ci 368962306a36Sopenharmony_ci if (source < 0 || source >= 2 * HDSPM_MAX_CHANNELS) 369062306a36Sopenharmony_ci return -1; 369162306a36Sopenharmony_ci if (destination < 0 || destination >= HDSPM_MAX_CHANNELS) 369262306a36Sopenharmony_ci return -1; 369362306a36Sopenharmony_ci 369462306a36Sopenharmony_ci gain = ucontrol->value.integer.value[2]; 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 369762306a36Sopenharmony_ci 369862306a36Sopenharmony_ci if (source >= HDSPM_MAX_CHANNELS) 369962306a36Sopenharmony_ci change = gain != hdspm_read_pb_gain(hdspm, destination, 370062306a36Sopenharmony_ci source - 370162306a36Sopenharmony_ci HDSPM_MAX_CHANNELS); 370262306a36Sopenharmony_ci else 370362306a36Sopenharmony_ci change = gain != hdspm_read_in_gain(hdspm, destination, 370462306a36Sopenharmony_ci source); 370562306a36Sopenharmony_ci 370662306a36Sopenharmony_ci if (change) { 370762306a36Sopenharmony_ci if (source >= HDSPM_MAX_CHANNELS) 370862306a36Sopenharmony_ci hdspm_write_pb_gain(hdspm, destination, 370962306a36Sopenharmony_ci source - HDSPM_MAX_CHANNELS, 371062306a36Sopenharmony_ci gain); 371162306a36Sopenharmony_ci else 371262306a36Sopenharmony_ci hdspm_write_in_gain(hdspm, destination, source, 371362306a36Sopenharmony_ci gain); 371462306a36Sopenharmony_ci } 371562306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 371662306a36Sopenharmony_ci 371762306a36Sopenharmony_ci return change; 371862306a36Sopenharmony_ci} 371962306a36Sopenharmony_ci 372062306a36Sopenharmony_ci/* The simple mixer control(s) provide gain control for the 372162306a36Sopenharmony_ci basic 1:1 mappings of playback streams to output 372262306a36Sopenharmony_ci streams. 372362306a36Sopenharmony_ci*/ 372462306a36Sopenharmony_ci 372562306a36Sopenharmony_ci#define HDSPM_PLAYBACK_MIXER \ 372662306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 372762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ 372862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 372962306a36Sopenharmony_ci .info = snd_hdspm_info_playback_mixer, \ 373062306a36Sopenharmony_ci .get = snd_hdspm_get_playback_mixer, \ 373162306a36Sopenharmony_ci .put = snd_hdspm_put_playback_mixer \ 373262306a36Sopenharmony_ci} 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_cistatic int snd_hdspm_info_playback_mixer(struct snd_kcontrol *kcontrol, 373562306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 373662306a36Sopenharmony_ci{ 373762306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 373862306a36Sopenharmony_ci uinfo->count = 1; 373962306a36Sopenharmony_ci uinfo->value.integer.min = 0; 374062306a36Sopenharmony_ci uinfo->value.integer.max = 64; 374162306a36Sopenharmony_ci uinfo->value.integer.step = 1; 374262306a36Sopenharmony_ci return 0; 374362306a36Sopenharmony_ci} 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_cistatic int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol, 374662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 374762306a36Sopenharmony_ci{ 374862306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 374962306a36Sopenharmony_ci int channel; 375062306a36Sopenharmony_ci 375162306a36Sopenharmony_ci channel = ucontrol->id.index - 1; 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_ci if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS)) 375462306a36Sopenharmony_ci return -EINVAL; 375562306a36Sopenharmony_ci 375662306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 375762306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 375862306a36Sopenharmony_ci (hdspm_read_pb_gain(hdspm, channel, channel)*64)/UNITY_GAIN; 375962306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 376062306a36Sopenharmony_ci 376162306a36Sopenharmony_ci return 0; 376262306a36Sopenharmony_ci} 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_cistatic int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, 376562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 376662306a36Sopenharmony_ci{ 376762306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 376862306a36Sopenharmony_ci int change; 376962306a36Sopenharmony_ci int channel; 377062306a36Sopenharmony_ci int gain; 377162306a36Sopenharmony_ci 377262306a36Sopenharmony_ci if (!snd_hdspm_use_is_exclusive(hdspm)) 377362306a36Sopenharmony_ci return -EBUSY; 377462306a36Sopenharmony_ci 377562306a36Sopenharmony_ci channel = ucontrol->id.index - 1; 377662306a36Sopenharmony_ci 377762306a36Sopenharmony_ci if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS)) 377862306a36Sopenharmony_ci return -EINVAL; 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci gain = ucontrol->value.integer.value[0]*UNITY_GAIN/64; 378162306a36Sopenharmony_ci 378262306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 378362306a36Sopenharmony_ci change = 378462306a36Sopenharmony_ci gain != hdspm_read_pb_gain(hdspm, channel, 378562306a36Sopenharmony_ci channel); 378662306a36Sopenharmony_ci if (change) 378762306a36Sopenharmony_ci hdspm_write_pb_gain(hdspm, channel, channel, 378862306a36Sopenharmony_ci gain); 378962306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 379062306a36Sopenharmony_ci return change; 379162306a36Sopenharmony_ci} 379262306a36Sopenharmony_ci 379362306a36Sopenharmony_ci#define HDSPM_SYNC_CHECK(xname, xindex) \ 379462306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 379562306a36Sopenharmony_ci .name = xname, \ 379662306a36Sopenharmony_ci .private_value = xindex, \ 379762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 379862306a36Sopenharmony_ci .info = snd_hdspm_info_sync_check, \ 379962306a36Sopenharmony_ci .get = snd_hdspm_get_sync_check \ 380062306a36Sopenharmony_ci} 380162306a36Sopenharmony_ci 380262306a36Sopenharmony_ci#define HDSPM_TCO_LOCK_CHECK(xname, xindex) \ 380362306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 380462306a36Sopenharmony_ci .name = xname, \ 380562306a36Sopenharmony_ci .private_value = xindex, \ 380662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 380762306a36Sopenharmony_ci .info = snd_hdspm_tco_info_lock_check, \ 380862306a36Sopenharmony_ci .get = snd_hdspm_get_sync_check \ 380962306a36Sopenharmony_ci} 381062306a36Sopenharmony_ci 381162306a36Sopenharmony_ci 381262306a36Sopenharmony_ci 381362306a36Sopenharmony_cistatic int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, 381462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 381562306a36Sopenharmony_ci{ 381662306a36Sopenharmony_ci static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" }; 381762306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 381862306a36Sopenharmony_ci return 0; 381962306a36Sopenharmony_ci} 382062306a36Sopenharmony_ci 382162306a36Sopenharmony_cistatic int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol, 382262306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 382362306a36Sopenharmony_ci{ 382462306a36Sopenharmony_ci static const char *const texts[] = { "No Lock", "Lock" }; 382562306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 382662306a36Sopenharmony_ci return 0; 382762306a36Sopenharmony_ci} 382862306a36Sopenharmony_ci 382962306a36Sopenharmony_cistatic int hdspm_wc_sync_check(struct hdspm *hdspm) 383062306a36Sopenharmony_ci{ 383162306a36Sopenharmony_ci int status, status2; 383262306a36Sopenharmony_ci 383362306a36Sopenharmony_ci switch (hdspm->io_type) { 383462306a36Sopenharmony_ci case AES32: 383562306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 383662306a36Sopenharmony_ci if (status & HDSPM_AES32_wcLock) { 383762306a36Sopenharmony_ci if (status & HDSPM_AES32_wcSync) 383862306a36Sopenharmony_ci return 2; 383962306a36Sopenharmony_ci else 384062306a36Sopenharmony_ci return 1; 384162306a36Sopenharmony_ci } 384262306a36Sopenharmony_ci return 0; 384362306a36Sopenharmony_ci 384462306a36Sopenharmony_ci case MADI: 384562306a36Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 384662306a36Sopenharmony_ci if (status2 & HDSPM_wcLock) { 384762306a36Sopenharmony_ci if (status2 & HDSPM_wcSync) 384862306a36Sopenharmony_ci return 2; 384962306a36Sopenharmony_ci else 385062306a36Sopenharmony_ci return 1; 385162306a36Sopenharmony_ci } 385262306a36Sopenharmony_ci return 0; 385362306a36Sopenharmony_ci 385462306a36Sopenharmony_ci case RayDAT: 385562306a36Sopenharmony_ci case AIO: 385662306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 385762306a36Sopenharmony_ci 385862306a36Sopenharmony_ci if (status & 0x2000000) 385962306a36Sopenharmony_ci return 2; 386062306a36Sopenharmony_ci else if (status & 0x1000000) 386162306a36Sopenharmony_ci return 1; 386262306a36Sopenharmony_ci return 0; 386362306a36Sopenharmony_ci 386462306a36Sopenharmony_ci case MADIface: 386562306a36Sopenharmony_ci break; 386662306a36Sopenharmony_ci } 386762306a36Sopenharmony_ci 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_ci return 3; 387062306a36Sopenharmony_ci} 387162306a36Sopenharmony_ci 387262306a36Sopenharmony_ci 387362306a36Sopenharmony_cistatic int hdspm_madi_sync_check(struct hdspm *hdspm) 387462306a36Sopenharmony_ci{ 387562306a36Sopenharmony_ci int status = hdspm_read(hdspm, HDSPM_statusRegister); 387662306a36Sopenharmony_ci if (status & HDSPM_madiLock) { 387762306a36Sopenharmony_ci if (status & HDSPM_madiSync) 387862306a36Sopenharmony_ci return 2; 387962306a36Sopenharmony_ci else 388062306a36Sopenharmony_ci return 1; 388162306a36Sopenharmony_ci } 388262306a36Sopenharmony_ci return 0; 388362306a36Sopenharmony_ci} 388462306a36Sopenharmony_ci 388562306a36Sopenharmony_ci 388662306a36Sopenharmony_cistatic int hdspm_s1_sync_check(struct hdspm *hdspm, int idx) 388762306a36Sopenharmony_ci{ 388862306a36Sopenharmony_ci int status, lock, sync; 388962306a36Sopenharmony_ci 389062306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 389162306a36Sopenharmony_ci 389262306a36Sopenharmony_ci lock = (status & (0x1<<idx)) ? 1 : 0; 389362306a36Sopenharmony_ci sync = (status & (0x100<<idx)) ? 1 : 0; 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ci if (lock && sync) 389662306a36Sopenharmony_ci return 2; 389762306a36Sopenharmony_ci else if (lock) 389862306a36Sopenharmony_ci return 1; 389962306a36Sopenharmony_ci return 0; 390062306a36Sopenharmony_ci} 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_ci 390362306a36Sopenharmony_cistatic int hdspm_sync_in_sync_check(struct hdspm *hdspm) 390462306a36Sopenharmony_ci{ 390562306a36Sopenharmony_ci int status, lock = 0, sync = 0; 390662306a36Sopenharmony_ci 390762306a36Sopenharmony_ci switch (hdspm->io_type) { 390862306a36Sopenharmony_ci case RayDAT: 390962306a36Sopenharmony_ci case AIO: 391062306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_3); 391162306a36Sopenharmony_ci lock = (status & 0x400) ? 1 : 0; 391262306a36Sopenharmony_ci sync = (status & 0x800) ? 1 : 0; 391362306a36Sopenharmony_ci break; 391462306a36Sopenharmony_ci 391562306a36Sopenharmony_ci case MADI: 391662306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 391762306a36Sopenharmony_ci lock = (status & HDSPM_syncInLock) ? 1 : 0; 391862306a36Sopenharmony_ci sync = (status & HDSPM_syncInSync) ? 1 : 0; 391962306a36Sopenharmony_ci break; 392062306a36Sopenharmony_ci 392162306a36Sopenharmony_ci case AES32: 392262306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister2); 392362306a36Sopenharmony_ci lock = (status & 0x100000) ? 1 : 0; 392462306a36Sopenharmony_ci sync = (status & 0x200000) ? 1 : 0; 392562306a36Sopenharmony_ci break; 392662306a36Sopenharmony_ci 392762306a36Sopenharmony_ci case MADIface: 392862306a36Sopenharmony_ci break; 392962306a36Sopenharmony_ci } 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ci if (lock && sync) 393262306a36Sopenharmony_ci return 2; 393362306a36Sopenharmony_ci else if (lock) 393462306a36Sopenharmony_ci return 1; 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci return 0; 393762306a36Sopenharmony_ci} 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_cistatic int hdspm_aes_sync_check(struct hdspm *hdspm, int idx) 394062306a36Sopenharmony_ci{ 394162306a36Sopenharmony_ci int status2, lock, sync; 394262306a36Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ci lock = (status2 & (0x0080 >> idx)) ? 1 : 0; 394562306a36Sopenharmony_ci sync = (status2 & (0x8000 >> idx)) ? 1 : 0; 394662306a36Sopenharmony_ci 394762306a36Sopenharmony_ci if (sync) 394862306a36Sopenharmony_ci return 2; 394962306a36Sopenharmony_ci else if (lock) 395062306a36Sopenharmony_ci return 1; 395162306a36Sopenharmony_ci return 0; 395262306a36Sopenharmony_ci} 395362306a36Sopenharmony_ci 395462306a36Sopenharmony_cistatic int hdspm_tco_input_check(struct hdspm *hdspm, u32 mask) 395562306a36Sopenharmony_ci{ 395662306a36Sopenharmony_ci u32 status; 395762306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 395862306a36Sopenharmony_ci 395962306a36Sopenharmony_ci return (status & mask) ? 1 : 0; 396062306a36Sopenharmony_ci} 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci 396362306a36Sopenharmony_cistatic int hdspm_tco_sync_check(struct hdspm *hdspm) 396462306a36Sopenharmony_ci{ 396562306a36Sopenharmony_ci int status; 396662306a36Sopenharmony_ci 396762306a36Sopenharmony_ci if (hdspm->tco) { 396862306a36Sopenharmony_ci switch (hdspm->io_type) { 396962306a36Sopenharmony_ci case MADI: 397062306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 397162306a36Sopenharmony_ci if (status & HDSPM_tcoLockMadi) { 397262306a36Sopenharmony_ci if (status & HDSPM_tcoSync) 397362306a36Sopenharmony_ci return 2; 397462306a36Sopenharmony_ci else 397562306a36Sopenharmony_ci return 1; 397662306a36Sopenharmony_ci } 397762306a36Sopenharmony_ci return 0; 397862306a36Sopenharmony_ci case AES32: 397962306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 398062306a36Sopenharmony_ci if (status & HDSPM_tcoLockAes) { 398162306a36Sopenharmony_ci if (status & HDSPM_tcoSync) 398262306a36Sopenharmony_ci return 2; 398362306a36Sopenharmony_ci else 398462306a36Sopenharmony_ci return 1; 398562306a36Sopenharmony_ci } 398662306a36Sopenharmony_ci return 0; 398762306a36Sopenharmony_ci case RayDAT: 398862306a36Sopenharmony_ci case AIO: 398962306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); 399062306a36Sopenharmony_ci 399162306a36Sopenharmony_ci if (status & 0x8000000) 399262306a36Sopenharmony_ci return 2; /* Sync */ 399362306a36Sopenharmony_ci if (status & 0x4000000) 399462306a36Sopenharmony_ci return 1; /* Lock */ 399562306a36Sopenharmony_ci return 0; /* No signal */ 399662306a36Sopenharmony_ci 399762306a36Sopenharmony_ci default: 399862306a36Sopenharmony_ci break; 399962306a36Sopenharmony_ci } 400062306a36Sopenharmony_ci } 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci return 3; /* N/A */ 400362306a36Sopenharmony_ci} 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci 400662306a36Sopenharmony_cistatic int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, 400762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 400862306a36Sopenharmony_ci{ 400962306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 401062306a36Sopenharmony_ci int val = -1; 401162306a36Sopenharmony_ci 401262306a36Sopenharmony_ci switch (hdspm->io_type) { 401362306a36Sopenharmony_ci case RayDAT: 401462306a36Sopenharmony_ci switch (kcontrol->private_value) { 401562306a36Sopenharmony_ci case 0: /* WC */ 401662306a36Sopenharmony_ci val = hdspm_wc_sync_check(hdspm); break; 401762306a36Sopenharmony_ci case 7: /* TCO */ 401862306a36Sopenharmony_ci val = hdspm_tco_sync_check(hdspm); break; 401962306a36Sopenharmony_ci case 8: /* SYNC IN */ 402062306a36Sopenharmony_ci val = hdspm_sync_in_sync_check(hdspm); break; 402162306a36Sopenharmony_ci default: 402262306a36Sopenharmony_ci val = hdspm_s1_sync_check(hdspm, 402362306a36Sopenharmony_ci kcontrol->private_value-1); 402462306a36Sopenharmony_ci } 402562306a36Sopenharmony_ci break; 402662306a36Sopenharmony_ci 402762306a36Sopenharmony_ci case AIO: 402862306a36Sopenharmony_ci switch (kcontrol->private_value) { 402962306a36Sopenharmony_ci case 0: /* WC */ 403062306a36Sopenharmony_ci val = hdspm_wc_sync_check(hdspm); break; 403162306a36Sopenharmony_ci case 4: /* TCO */ 403262306a36Sopenharmony_ci val = hdspm_tco_sync_check(hdspm); break; 403362306a36Sopenharmony_ci case 5: /* SYNC IN */ 403462306a36Sopenharmony_ci val = hdspm_sync_in_sync_check(hdspm); break; 403562306a36Sopenharmony_ci default: 403662306a36Sopenharmony_ci val = hdspm_s1_sync_check(hdspm, 403762306a36Sopenharmony_ci kcontrol->private_value-1); 403862306a36Sopenharmony_ci } 403962306a36Sopenharmony_ci break; 404062306a36Sopenharmony_ci 404162306a36Sopenharmony_ci case MADI: 404262306a36Sopenharmony_ci switch (kcontrol->private_value) { 404362306a36Sopenharmony_ci case 0: /* WC */ 404462306a36Sopenharmony_ci val = hdspm_wc_sync_check(hdspm); break; 404562306a36Sopenharmony_ci case 1: /* MADI */ 404662306a36Sopenharmony_ci val = hdspm_madi_sync_check(hdspm); break; 404762306a36Sopenharmony_ci case 2: /* TCO */ 404862306a36Sopenharmony_ci val = hdspm_tco_sync_check(hdspm); break; 404962306a36Sopenharmony_ci case 3: /* SYNC_IN */ 405062306a36Sopenharmony_ci val = hdspm_sync_in_sync_check(hdspm); break; 405162306a36Sopenharmony_ci } 405262306a36Sopenharmony_ci break; 405362306a36Sopenharmony_ci 405462306a36Sopenharmony_ci case MADIface: 405562306a36Sopenharmony_ci val = hdspm_madi_sync_check(hdspm); /* MADI */ 405662306a36Sopenharmony_ci break; 405762306a36Sopenharmony_ci 405862306a36Sopenharmony_ci case AES32: 405962306a36Sopenharmony_ci switch (kcontrol->private_value) { 406062306a36Sopenharmony_ci case 0: /* WC */ 406162306a36Sopenharmony_ci val = hdspm_wc_sync_check(hdspm); break; 406262306a36Sopenharmony_ci case 9: /* TCO */ 406362306a36Sopenharmony_ci val = hdspm_tco_sync_check(hdspm); break; 406462306a36Sopenharmony_ci case 10 /* SYNC IN */: 406562306a36Sopenharmony_ci val = hdspm_sync_in_sync_check(hdspm); break; 406662306a36Sopenharmony_ci default: /* AES1 to AES8 */ 406762306a36Sopenharmony_ci val = hdspm_aes_sync_check(hdspm, 406862306a36Sopenharmony_ci kcontrol->private_value-1); 406962306a36Sopenharmony_ci } 407062306a36Sopenharmony_ci break; 407162306a36Sopenharmony_ci 407262306a36Sopenharmony_ci } 407362306a36Sopenharmony_ci 407462306a36Sopenharmony_ci if (hdspm->tco) { 407562306a36Sopenharmony_ci switch (kcontrol->private_value) { 407662306a36Sopenharmony_ci case 11: 407762306a36Sopenharmony_ci /* Check TCO for lock state of its current input */ 407862306a36Sopenharmony_ci val = hdspm_tco_input_check(hdspm, HDSPM_TCO1_TCO_lock); 407962306a36Sopenharmony_ci break; 408062306a36Sopenharmony_ci case 12: 408162306a36Sopenharmony_ci /* Check TCO for valid time code on LTC input. */ 408262306a36Sopenharmony_ci val = hdspm_tco_input_check(hdspm, 408362306a36Sopenharmony_ci HDSPM_TCO1_LTC_Input_valid); 408462306a36Sopenharmony_ci break; 408562306a36Sopenharmony_ci default: 408662306a36Sopenharmony_ci break; 408762306a36Sopenharmony_ci } 408862306a36Sopenharmony_ci } 408962306a36Sopenharmony_ci 409062306a36Sopenharmony_ci if (-1 == val) 409162306a36Sopenharmony_ci val = 3; 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = val; 409462306a36Sopenharmony_ci return 0; 409562306a36Sopenharmony_ci} 409662306a36Sopenharmony_ci 409762306a36Sopenharmony_ci 409862306a36Sopenharmony_ci 409962306a36Sopenharmony_ci/* 410062306a36Sopenharmony_ci * TCO controls 410162306a36Sopenharmony_ci */ 410262306a36Sopenharmony_cistatic void hdspm_tco_write(struct hdspm *hdspm) 410362306a36Sopenharmony_ci{ 410462306a36Sopenharmony_ci unsigned int tc[4] = { 0, 0, 0, 0}; 410562306a36Sopenharmony_ci 410662306a36Sopenharmony_ci switch (hdspm->tco->input) { 410762306a36Sopenharmony_ci case 0: 410862306a36Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_input_MSB; 410962306a36Sopenharmony_ci break; 411062306a36Sopenharmony_ci case 1: 411162306a36Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_input_LSB; 411262306a36Sopenharmony_ci break; 411362306a36Sopenharmony_ci default: 411462306a36Sopenharmony_ci break; 411562306a36Sopenharmony_ci } 411662306a36Sopenharmony_ci 411762306a36Sopenharmony_ci switch (hdspm->tco->framerate) { 411862306a36Sopenharmony_ci case 1: 411962306a36Sopenharmony_ci tc[1] |= HDSPM_TCO1_LTC_Format_LSB; 412062306a36Sopenharmony_ci break; 412162306a36Sopenharmony_ci case 2: 412262306a36Sopenharmony_ci tc[1] |= HDSPM_TCO1_LTC_Format_MSB; 412362306a36Sopenharmony_ci break; 412462306a36Sopenharmony_ci case 3: 412562306a36Sopenharmony_ci tc[1] |= HDSPM_TCO1_LTC_Format_MSB + 412662306a36Sopenharmony_ci HDSPM_TCO1_set_drop_frame_flag; 412762306a36Sopenharmony_ci break; 412862306a36Sopenharmony_ci case 4: 412962306a36Sopenharmony_ci tc[1] |= HDSPM_TCO1_LTC_Format_LSB + 413062306a36Sopenharmony_ci HDSPM_TCO1_LTC_Format_MSB; 413162306a36Sopenharmony_ci break; 413262306a36Sopenharmony_ci case 5: 413362306a36Sopenharmony_ci tc[1] |= HDSPM_TCO1_LTC_Format_LSB + 413462306a36Sopenharmony_ci HDSPM_TCO1_LTC_Format_MSB + 413562306a36Sopenharmony_ci HDSPM_TCO1_set_drop_frame_flag; 413662306a36Sopenharmony_ci break; 413762306a36Sopenharmony_ci default: 413862306a36Sopenharmony_ci break; 413962306a36Sopenharmony_ci } 414062306a36Sopenharmony_ci 414162306a36Sopenharmony_ci switch (hdspm->tco->wordclock) { 414262306a36Sopenharmony_ci case 1: 414362306a36Sopenharmony_ci tc[2] |= HDSPM_TCO2_WCK_IO_ratio_LSB; 414462306a36Sopenharmony_ci break; 414562306a36Sopenharmony_ci case 2: 414662306a36Sopenharmony_ci tc[2] |= HDSPM_TCO2_WCK_IO_ratio_MSB; 414762306a36Sopenharmony_ci break; 414862306a36Sopenharmony_ci default: 414962306a36Sopenharmony_ci break; 415062306a36Sopenharmony_ci } 415162306a36Sopenharmony_ci 415262306a36Sopenharmony_ci switch (hdspm->tco->samplerate) { 415362306a36Sopenharmony_ci case 1: 415462306a36Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_freq; 415562306a36Sopenharmony_ci break; 415662306a36Sopenharmony_ci case 2: 415762306a36Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_freq_from_app; 415862306a36Sopenharmony_ci break; 415962306a36Sopenharmony_ci default: 416062306a36Sopenharmony_ci break; 416162306a36Sopenharmony_ci } 416262306a36Sopenharmony_ci 416362306a36Sopenharmony_ci switch (hdspm->tco->pull) { 416462306a36Sopenharmony_ci case 1: 416562306a36Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_pull_up; 416662306a36Sopenharmony_ci break; 416762306a36Sopenharmony_ci case 2: 416862306a36Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_pull_down; 416962306a36Sopenharmony_ci break; 417062306a36Sopenharmony_ci case 3: 417162306a36Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_pull_up + HDSPM_TCO2_set_01_4; 417262306a36Sopenharmony_ci break; 417362306a36Sopenharmony_ci case 4: 417462306a36Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_pull_down + HDSPM_TCO2_set_01_4; 417562306a36Sopenharmony_ci break; 417662306a36Sopenharmony_ci default: 417762306a36Sopenharmony_ci break; 417862306a36Sopenharmony_ci } 417962306a36Sopenharmony_ci 418062306a36Sopenharmony_ci if (1 == hdspm->tco->term) { 418162306a36Sopenharmony_ci tc[2] |= HDSPM_TCO2_set_term_75R; 418262306a36Sopenharmony_ci } 418362306a36Sopenharmony_ci 418462306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_TCO, tc[0]); 418562306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_TCO+4, tc[1]); 418662306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_TCO+8, tc[2]); 418762306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_TCO+12, tc[3]); 418862306a36Sopenharmony_ci} 418962306a36Sopenharmony_ci 419062306a36Sopenharmony_ci 419162306a36Sopenharmony_ci#define HDSPM_TCO_SAMPLE_RATE(xname, xindex) \ 419262306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 419362306a36Sopenharmony_ci .name = xname, \ 419462306a36Sopenharmony_ci .index = xindex, \ 419562306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 419662306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 419762306a36Sopenharmony_ci .info = snd_hdspm_info_tco_sample_rate, \ 419862306a36Sopenharmony_ci .get = snd_hdspm_get_tco_sample_rate, \ 419962306a36Sopenharmony_ci .put = snd_hdspm_put_tco_sample_rate \ 420062306a36Sopenharmony_ci} 420162306a36Sopenharmony_ci 420262306a36Sopenharmony_cistatic int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, 420362306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 420462306a36Sopenharmony_ci{ 420562306a36Sopenharmony_ci /* TODO freq from app could be supported here, see tco->samplerate */ 420662306a36Sopenharmony_ci static const char *const texts[] = { "44.1 kHz", "48 kHz" }; 420762306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 420862306a36Sopenharmony_ci return 0; 420962306a36Sopenharmony_ci} 421062306a36Sopenharmony_ci 421162306a36Sopenharmony_cistatic int snd_hdspm_get_tco_sample_rate(struct snd_kcontrol *kcontrol, 421262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 421362306a36Sopenharmony_ci{ 421462306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 421562306a36Sopenharmony_ci 421662306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm->tco->samplerate; 421762306a36Sopenharmony_ci 421862306a36Sopenharmony_ci return 0; 421962306a36Sopenharmony_ci} 422062306a36Sopenharmony_ci 422162306a36Sopenharmony_cistatic int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol, 422262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 422362306a36Sopenharmony_ci{ 422462306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 422562306a36Sopenharmony_ci 422662306a36Sopenharmony_ci if (hdspm->tco->samplerate != ucontrol->value.enumerated.item[0]) { 422762306a36Sopenharmony_ci hdspm->tco->samplerate = ucontrol->value.enumerated.item[0]; 422862306a36Sopenharmony_ci 422962306a36Sopenharmony_ci hdspm_tco_write(hdspm); 423062306a36Sopenharmony_ci 423162306a36Sopenharmony_ci return 1; 423262306a36Sopenharmony_ci } 423362306a36Sopenharmony_ci 423462306a36Sopenharmony_ci return 0; 423562306a36Sopenharmony_ci} 423662306a36Sopenharmony_ci 423762306a36Sopenharmony_ci 423862306a36Sopenharmony_ci#define HDSPM_TCO_PULL(xname, xindex) \ 423962306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 424062306a36Sopenharmony_ci .name = xname, \ 424162306a36Sopenharmony_ci .index = xindex, \ 424262306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 424362306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 424462306a36Sopenharmony_ci .info = snd_hdspm_info_tco_pull, \ 424562306a36Sopenharmony_ci .get = snd_hdspm_get_tco_pull, \ 424662306a36Sopenharmony_ci .put = snd_hdspm_put_tco_pull \ 424762306a36Sopenharmony_ci} 424862306a36Sopenharmony_ci 424962306a36Sopenharmony_cistatic int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, 425062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 425162306a36Sopenharmony_ci{ 425262306a36Sopenharmony_ci static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %", 425362306a36Sopenharmony_ci "+ 4 %", "- 4 %" }; 425462306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 425562306a36Sopenharmony_ci return 0; 425662306a36Sopenharmony_ci} 425762306a36Sopenharmony_ci 425862306a36Sopenharmony_cistatic int snd_hdspm_get_tco_pull(struct snd_kcontrol *kcontrol, 425962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 426062306a36Sopenharmony_ci{ 426162306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 426262306a36Sopenharmony_ci 426362306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm->tco->pull; 426462306a36Sopenharmony_ci 426562306a36Sopenharmony_ci return 0; 426662306a36Sopenharmony_ci} 426762306a36Sopenharmony_ci 426862306a36Sopenharmony_cistatic int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol, 426962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 427062306a36Sopenharmony_ci{ 427162306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 427262306a36Sopenharmony_ci 427362306a36Sopenharmony_ci if (hdspm->tco->pull != ucontrol->value.enumerated.item[0]) { 427462306a36Sopenharmony_ci hdspm->tco->pull = ucontrol->value.enumerated.item[0]; 427562306a36Sopenharmony_ci 427662306a36Sopenharmony_ci hdspm_tco_write(hdspm); 427762306a36Sopenharmony_ci 427862306a36Sopenharmony_ci return 1; 427962306a36Sopenharmony_ci } 428062306a36Sopenharmony_ci 428162306a36Sopenharmony_ci return 0; 428262306a36Sopenharmony_ci} 428362306a36Sopenharmony_ci 428462306a36Sopenharmony_ci#define HDSPM_TCO_WCK_CONVERSION(xname, xindex) \ 428562306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 428662306a36Sopenharmony_ci .name = xname, \ 428762306a36Sopenharmony_ci .index = xindex, \ 428862306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 428962306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 429062306a36Sopenharmony_ci .info = snd_hdspm_info_tco_wck_conversion, \ 429162306a36Sopenharmony_ci .get = snd_hdspm_get_tco_wck_conversion, \ 429262306a36Sopenharmony_ci .put = snd_hdspm_put_tco_wck_conversion \ 429362306a36Sopenharmony_ci} 429462306a36Sopenharmony_ci 429562306a36Sopenharmony_cistatic int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, 429662306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 429762306a36Sopenharmony_ci{ 429862306a36Sopenharmony_ci static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; 429962306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 430062306a36Sopenharmony_ci return 0; 430162306a36Sopenharmony_ci} 430262306a36Sopenharmony_ci 430362306a36Sopenharmony_cistatic int snd_hdspm_get_tco_wck_conversion(struct snd_kcontrol *kcontrol, 430462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 430562306a36Sopenharmony_ci{ 430662306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm->tco->wordclock; 430962306a36Sopenharmony_ci 431062306a36Sopenharmony_ci return 0; 431162306a36Sopenharmony_ci} 431262306a36Sopenharmony_ci 431362306a36Sopenharmony_cistatic int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol, 431462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 431562306a36Sopenharmony_ci{ 431662306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 431762306a36Sopenharmony_ci 431862306a36Sopenharmony_ci if (hdspm->tco->wordclock != ucontrol->value.enumerated.item[0]) { 431962306a36Sopenharmony_ci hdspm->tco->wordclock = ucontrol->value.enumerated.item[0]; 432062306a36Sopenharmony_ci 432162306a36Sopenharmony_ci hdspm_tco_write(hdspm); 432262306a36Sopenharmony_ci 432362306a36Sopenharmony_ci return 1; 432462306a36Sopenharmony_ci } 432562306a36Sopenharmony_ci 432662306a36Sopenharmony_ci return 0; 432762306a36Sopenharmony_ci} 432862306a36Sopenharmony_ci 432962306a36Sopenharmony_ci 433062306a36Sopenharmony_ci#define HDSPM_TCO_FRAME_RATE(xname, xindex) \ 433162306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 433262306a36Sopenharmony_ci .name = xname, \ 433362306a36Sopenharmony_ci .index = xindex, \ 433462306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 433562306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 433662306a36Sopenharmony_ci .info = snd_hdspm_info_tco_frame_rate, \ 433762306a36Sopenharmony_ci .get = snd_hdspm_get_tco_frame_rate, \ 433862306a36Sopenharmony_ci .put = snd_hdspm_put_tco_frame_rate \ 433962306a36Sopenharmony_ci} 434062306a36Sopenharmony_ci 434162306a36Sopenharmony_cistatic int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, 434262306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 434362306a36Sopenharmony_ci{ 434462306a36Sopenharmony_ci static const char *const texts[] = { "24 fps", "25 fps", "29.97fps", 434562306a36Sopenharmony_ci "29.97 dfps", "30 fps", "30 dfps" }; 434662306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 434762306a36Sopenharmony_ci return 0; 434862306a36Sopenharmony_ci} 434962306a36Sopenharmony_ci 435062306a36Sopenharmony_cistatic int snd_hdspm_get_tco_frame_rate(struct snd_kcontrol *kcontrol, 435162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 435262306a36Sopenharmony_ci{ 435362306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 435462306a36Sopenharmony_ci 435562306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm->tco->framerate; 435662306a36Sopenharmony_ci 435762306a36Sopenharmony_ci return 0; 435862306a36Sopenharmony_ci} 435962306a36Sopenharmony_ci 436062306a36Sopenharmony_cistatic int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol, 436162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 436262306a36Sopenharmony_ci{ 436362306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 436462306a36Sopenharmony_ci 436562306a36Sopenharmony_ci if (hdspm->tco->framerate != ucontrol->value.enumerated.item[0]) { 436662306a36Sopenharmony_ci hdspm->tco->framerate = ucontrol->value.enumerated.item[0]; 436762306a36Sopenharmony_ci 436862306a36Sopenharmony_ci hdspm_tco_write(hdspm); 436962306a36Sopenharmony_ci 437062306a36Sopenharmony_ci return 1; 437162306a36Sopenharmony_ci } 437262306a36Sopenharmony_ci 437362306a36Sopenharmony_ci return 0; 437462306a36Sopenharmony_ci} 437562306a36Sopenharmony_ci 437662306a36Sopenharmony_ci 437762306a36Sopenharmony_ci#define HDSPM_TCO_SYNC_SOURCE(xname, xindex) \ 437862306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 437962306a36Sopenharmony_ci .name = xname, \ 438062306a36Sopenharmony_ci .index = xindex, \ 438162306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 438262306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 438362306a36Sopenharmony_ci .info = snd_hdspm_info_tco_sync_source, \ 438462306a36Sopenharmony_ci .get = snd_hdspm_get_tco_sync_source, \ 438562306a36Sopenharmony_ci .put = snd_hdspm_put_tco_sync_source \ 438662306a36Sopenharmony_ci} 438762306a36Sopenharmony_ci 438862306a36Sopenharmony_cistatic int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, 438962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 439062306a36Sopenharmony_ci{ 439162306a36Sopenharmony_ci static const char *const texts[] = { "LTC", "Video", "WCK" }; 439262306a36Sopenharmony_ci ENUMERATED_CTL_INFO(uinfo, texts); 439362306a36Sopenharmony_ci return 0; 439462306a36Sopenharmony_ci} 439562306a36Sopenharmony_ci 439662306a36Sopenharmony_cistatic int snd_hdspm_get_tco_sync_source(struct snd_kcontrol *kcontrol, 439762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 439862306a36Sopenharmony_ci{ 439962306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 440062306a36Sopenharmony_ci 440162306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = hdspm->tco->input; 440262306a36Sopenharmony_ci 440362306a36Sopenharmony_ci return 0; 440462306a36Sopenharmony_ci} 440562306a36Sopenharmony_ci 440662306a36Sopenharmony_cistatic int snd_hdspm_put_tco_sync_source(struct snd_kcontrol *kcontrol, 440762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 440862306a36Sopenharmony_ci{ 440962306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 441062306a36Sopenharmony_ci 441162306a36Sopenharmony_ci if (hdspm->tco->input != ucontrol->value.enumerated.item[0]) { 441262306a36Sopenharmony_ci hdspm->tco->input = ucontrol->value.enumerated.item[0]; 441362306a36Sopenharmony_ci 441462306a36Sopenharmony_ci hdspm_tco_write(hdspm); 441562306a36Sopenharmony_ci 441662306a36Sopenharmony_ci return 1; 441762306a36Sopenharmony_ci } 441862306a36Sopenharmony_ci 441962306a36Sopenharmony_ci return 0; 442062306a36Sopenharmony_ci} 442162306a36Sopenharmony_ci 442262306a36Sopenharmony_ci 442362306a36Sopenharmony_ci#define HDSPM_TCO_WORD_TERM(xname, xindex) \ 442462306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 442562306a36Sopenharmony_ci .name = xname, \ 442662306a36Sopenharmony_ci .index = xindex, \ 442762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ 442862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ 442962306a36Sopenharmony_ci .info = snd_hdspm_info_tco_word_term, \ 443062306a36Sopenharmony_ci .get = snd_hdspm_get_tco_word_term, \ 443162306a36Sopenharmony_ci .put = snd_hdspm_put_tco_word_term \ 443262306a36Sopenharmony_ci} 443362306a36Sopenharmony_ci 443462306a36Sopenharmony_cistatic int snd_hdspm_info_tco_word_term(struct snd_kcontrol *kcontrol, 443562306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 443662306a36Sopenharmony_ci{ 443762306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 443862306a36Sopenharmony_ci uinfo->count = 1; 443962306a36Sopenharmony_ci uinfo->value.integer.min = 0; 444062306a36Sopenharmony_ci uinfo->value.integer.max = 1; 444162306a36Sopenharmony_ci 444262306a36Sopenharmony_ci return 0; 444362306a36Sopenharmony_ci} 444462306a36Sopenharmony_ci 444562306a36Sopenharmony_ci 444662306a36Sopenharmony_cistatic int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol, 444762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 444862306a36Sopenharmony_ci{ 444962306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 445062306a36Sopenharmony_ci 445162306a36Sopenharmony_ci ucontrol->value.integer.value[0] = hdspm->tco->term; 445262306a36Sopenharmony_ci 445362306a36Sopenharmony_ci return 0; 445462306a36Sopenharmony_ci} 445562306a36Sopenharmony_ci 445662306a36Sopenharmony_ci 445762306a36Sopenharmony_cistatic int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol, 445862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 445962306a36Sopenharmony_ci{ 446062306a36Sopenharmony_ci struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); 446162306a36Sopenharmony_ci 446262306a36Sopenharmony_ci if (hdspm->tco->term != ucontrol->value.integer.value[0]) { 446362306a36Sopenharmony_ci hdspm->tco->term = ucontrol->value.integer.value[0]; 446462306a36Sopenharmony_ci 446562306a36Sopenharmony_ci hdspm_tco_write(hdspm); 446662306a36Sopenharmony_ci 446762306a36Sopenharmony_ci return 1; 446862306a36Sopenharmony_ci } 446962306a36Sopenharmony_ci 447062306a36Sopenharmony_ci return 0; 447162306a36Sopenharmony_ci} 447262306a36Sopenharmony_ci 447362306a36Sopenharmony_ci 447462306a36Sopenharmony_ci 447562306a36Sopenharmony_ci 447662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_madi[] = { 447762306a36Sopenharmony_ci HDSPM_MIXER("Mixer", 0), 447862306a36Sopenharmony_ci HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 447962306a36Sopenharmony_ci HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 448062306a36Sopenharmony_ci HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 448162306a36Sopenharmony_ci HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), 448262306a36Sopenharmony_ci HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 448362306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 448462306a36Sopenharmony_ci HDSPM_SYNC_CHECK("WC SyncCheck", 0), 448562306a36Sopenharmony_ci HDSPM_SYNC_CHECK("MADI SyncCheck", 1), 448662306a36Sopenharmony_ci HDSPM_SYNC_CHECK("TCO SyncCheck", 2), 448762306a36Sopenharmony_ci HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3), 448862306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut), 448962306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch), 449062306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Disable 96K frames", HDSPM_SMUX), 449162306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), 449262306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp), 449362306a36Sopenharmony_ci HDSPM_INPUT_SELECT("Input Select", 0), 449462306a36Sopenharmony_ci HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) 449562306a36Sopenharmony_ci}; 449662306a36Sopenharmony_ci 449762306a36Sopenharmony_ci 449862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_madiface[] = { 449962306a36Sopenharmony_ci HDSPM_MIXER("Mixer", 0), 450062306a36Sopenharmony_ci HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 450162306a36Sopenharmony_ci HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 450262306a36Sopenharmony_ci HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 450362306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 450462306a36Sopenharmony_ci HDSPM_SYNC_CHECK("MADI SyncCheck", 0), 450562306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch), 450662306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), 450762306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp), 450862306a36Sopenharmony_ci HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) 450962306a36Sopenharmony_ci}; 451062306a36Sopenharmony_ci 451162306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_aio[] = { 451262306a36Sopenharmony_ci HDSPM_MIXER("Mixer", 0), 451362306a36Sopenharmony_ci HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 451462306a36Sopenharmony_ci HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 451562306a36Sopenharmony_ci HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 451662306a36Sopenharmony_ci HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 451762306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), 451862306a36Sopenharmony_ci HDSPM_SYNC_CHECK("WC SyncCheck", 0), 451962306a36Sopenharmony_ci HDSPM_SYNC_CHECK("AES SyncCheck", 1), 452062306a36Sopenharmony_ci HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2), 452162306a36Sopenharmony_ci HDSPM_SYNC_CHECK("ADAT SyncCheck", 3), 452262306a36Sopenharmony_ci HDSPM_SYNC_CHECK("TCO SyncCheck", 4), 452362306a36Sopenharmony_ci HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 5), 452462306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 452562306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1), 452662306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), 452762306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), 452862306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), 452962306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5), 453062306a36Sopenharmony_ci HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0), 453162306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt), 453262306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), 453362306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1), 453462306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db), 453562306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48), 453662306a36Sopenharmony_ci HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0), 453762306a36Sopenharmony_ci HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0), 453862306a36Sopenharmony_ci HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0) 453962306a36Sopenharmony_ci 454062306a36Sopenharmony_ci /* 454162306a36Sopenharmony_ci HDSPM_INPUT_SELECT("Input Select", 0), 454262306a36Sopenharmony_ci HDSPM_SPDIF_OPTICAL("SPDIF Out Optical", 0), 454362306a36Sopenharmony_ci HDSPM_PROFESSIONAL("SPDIF Out Professional", 0); 454462306a36Sopenharmony_ci HDSPM_SPDIF_IN("SPDIF In", 0); 454562306a36Sopenharmony_ci HDSPM_BREAKOUT_CABLE("Breakout Cable", 0); 454662306a36Sopenharmony_ci HDSPM_INPUT_LEVEL("Input Level", 0); 454762306a36Sopenharmony_ci HDSPM_OUTPUT_LEVEL("Output Level", 0); 454862306a36Sopenharmony_ci HDSPM_PHONES("Phones", 0); 454962306a36Sopenharmony_ci */ 455062306a36Sopenharmony_ci}; 455162306a36Sopenharmony_ci 455262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_raydat[] = { 455362306a36Sopenharmony_ci HDSPM_MIXER("Mixer", 0), 455462306a36Sopenharmony_ci HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 455562306a36Sopenharmony_ci HDSPM_SYSTEM_CLOCK_MODE("Clock Mode", 0), 455662306a36Sopenharmony_ci HDSPM_PREF_SYNC_REF("Pref Sync Ref", 0), 455762306a36Sopenharmony_ci HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 455862306a36Sopenharmony_ci HDSPM_SYNC_CHECK("WC SyncCheck", 0), 455962306a36Sopenharmony_ci HDSPM_SYNC_CHECK("AES SyncCheck", 1), 456062306a36Sopenharmony_ci HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2), 456162306a36Sopenharmony_ci HDSPM_SYNC_CHECK("ADAT1 SyncCheck", 3), 456262306a36Sopenharmony_ci HDSPM_SYNC_CHECK("ADAT2 SyncCheck", 4), 456362306a36Sopenharmony_ci HDSPM_SYNC_CHECK("ADAT3 SyncCheck", 5), 456462306a36Sopenharmony_ci HDSPM_SYNC_CHECK("ADAT4 SyncCheck", 6), 456562306a36Sopenharmony_ci HDSPM_SYNC_CHECK("TCO SyncCheck", 7), 456662306a36Sopenharmony_ci HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 8), 456762306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 456862306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1), 456962306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), 457062306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT1 Frequency", 3), 457162306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT2 Frequency", 4), 457262306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5), 457362306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6), 457462306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7), 457562306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8), 457662306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), 457762306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48) 457862306a36Sopenharmony_ci}; 457962306a36Sopenharmony_ci 458062306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { 458162306a36Sopenharmony_ci HDSPM_MIXER("Mixer", 0), 458262306a36Sopenharmony_ci HDSPM_INTERNAL_CLOCK("Internal Clock", 0), 458362306a36Sopenharmony_ci HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), 458462306a36Sopenharmony_ci HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), 458562306a36Sopenharmony_ci HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), 458662306a36Sopenharmony_ci HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), 458762306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11), 458862306a36Sopenharmony_ci HDSPM_SYNC_CHECK("WC Sync Check", 0), 458962306a36Sopenharmony_ci HDSPM_SYNC_CHECK("AES1 Sync Check", 1), 459062306a36Sopenharmony_ci HDSPM_SYNC_CHECK("AES2 Sync Check", 2), 459162306a36Sopenharmony_ci HDSPM_SYNC_CHECK("AES3 Sync Check", 3), 459262306a36Sopenharmony_ci HDSPM_SYNC_CHECK("AES4 Sync Check", 4), 459362306a36Sopenharmony_ci HDSPM_SYNC_CHECK("AES5 Sync Check", 5), 459462306a36Sopenharmony_ci HDSPM_SYNC_CHECK("AES6 Sync Check", 6), 459562306a36Sopenharmony_ci HDSPM_SYNC_CHECK("AES7 Sync Check", 7), 459662306a36Sopenharmony_ci HDSPM_SYNC_CHECK("AES8 Sync Check", 8), 459762306a36Sopenharmony_ci HDSPM_SYNC_CHECK("TCO Sync Check", 9), 459862306a36Sopenharmony_ci HDSPM_SYNC_CHECK("SYNC IN Sync Check", 10), 459962306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0), 460062306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES1 Frequency", 1), 460162306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES2 Frequency", 2), 460262306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES3 Frequency", 3), 460362306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES4 Frequency", 4), 460462306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES5 Frequency", 5), 460562306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES6 Frequency", 6), 460662306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES7 Frequency", 7), 460762306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("AES8 Frequency", 8), 460862306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 9), 460962306a36Sopenharmony_ci HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 10), 461062306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut), 461162306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Emphasis", HDSPM_Emphasis), 461262306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Non Audio", HDSPM_Dolby), 461362306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Professional", HDSPM_Professional), 461462306a36Sopenharmony_ci HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), 461562306a36Sopenharmony_ci HDSPM_DS_WIRE("Double Speed Wire Mode", 0), 461662306a36Sopenharmony_ci HDSPM_QS_WIRE("Quad Speed Wire Mode", 0), 461762306a36Sopenharmony_ci}; 461862306a36Sopenharmony_ci 461962306a36Sopenharmony_ci 462062306a36Sopenharmony_ci 462162306a36Sopenharmony_ci/* Control elements for the optional TCO module */ 462262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdspm_controls_tco[] = { 462362306a36Sopenharmony_ci HDSPM_TCO_SAMPLE_RATE("TCO Sample Rate", 0), 462462306a36Sopenharmony_ci HDSPM_TCO_PULL("TCO Pull", 0), 462562306a36Sopenharmony_ci HDSPM_TCO_WCK_CONVERSION("TCO WCK Conversion", 0), 462662306a36Sopenharmony_ci HDSPM_TCO_FRAME_RATE("TCO Frame Rate", 0), 462762306a36Sopenharmony_ci HDSPM_TCO_SYNC_SOURCE("TCO Sync Source", 0), 462862306a36Sopenharmony_ci HDSPM_TCO_WORD_TERM("TCO Word Term", 0), 462962306a36Sopenharmony_ci HDSPM_TCO_LOCK_CHECK("TCO Input Check", 11), 463062306a36Sopenharmony_ci HDSPM_TCO_LOCK_CHECK("TCO LTC Valid", 12), 463162306a36Sopenharmony_ci HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate", 0), 463262306a36Sopenharmony_ci HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format", 0) 463362306a36Sopenharmony_ci}; 463462306a36Sopenharmony_ci 463562306a36Sopenharmony_ci 463662306a36Sopenharmony_cistatic struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER; 463762306a36Sopenharmony_ci 463862306a36Sopenharmony_ci 463962306a36Sopenharmony_cistatic int hdspm_update_simple_mixer_controls(struct hdspm * hdspm) 464062306a36Sopenharmony_ci{ 464162306a36Sopenharmony_ci int i; 464262306a36Sopenharmony_ci 464362306a36Sopenharmony_ci for (i = hdspm->ds_out_channels; i < hdspm->ss_out_channels; ++i) { 464462306a36Sopenharmony_ci if (hdspm->system_sample_rate > 48000) { 464562306a36Sopenharmony_ci hdspm->playback_mixer_ctls[i]->vd[0].access = 464662306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_INACTIVE | 464762306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_READ | 464862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE; 464962306a36Sopenharmony_ci } else { 465062306a36Sopenharmony_ci hdspm->playback_mixer_ctls[i]->vd[0].access = 465162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_READWRITE | 465262306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE; 465362306a36Sopenharmony_ci } 465462306a36Sopenharmony_ci snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE | 465562306a36Sopenharmony_ci SNDRV_CTL_EVENT_MASK_INFO, 465662306a36Sopenharmony_ci &hdspm->playback_mixer_ctls[i]->id); 465762306a36Sopenharmony_ci } 465862306a36Sopenharmony_ci 465962306a36Sopenharmony_ci return 0; 466062306a36Sopenharmony_ci} 466162306a36Sopenharmony_ci 466262306a36Sopenharmony_ci 466362306a36Sopenharmony_cistatic int snd_hdspm_create_controls(struct snd_card *card, 466462306a36Sopenharmony_ci struct hdspm *hdspm) 466562306a36Sopenharmony_ci{ 466662306a36Sopenharmony_ci unsigned int idx, limit; 466762306a36Sopenharmony_ci int err; 466862306a36Sopenharmony_ci struct snd_kcontrol *kctl; 466962306a36Sopenharmony_ci const struct snd_kcontrol_new *list = NULL; 467062306a36Sopenharmony_ci 467162306a36Sopenharmony_ci switch (hdspm->io_type) { 467262306a36Sopenharmony_ci case MADI: 467362306a36Sopenharmony_ci list = snd_hdspm_controls_madi; 467462306a36Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_madi); 467562306a36Sopenharmony_ci break; 467662306a36Sopenharmony_ci case MADIface: 467762306a36Sopenharmony_ci list = snd_hdspm_controls_madiface; 467862306a36Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_madiface); 467962306a36Sopenharmony_ci break; 468062306a36Sopenharmony_ci case AIO: 468162306a36Sopenharmony_ci list = snd_hdspm_controls_aio; 468262306a36Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_aio); 468362306a36Sopenharmony_ci break; 468462306a36Sopenharmony_ci case RayDAT: 468562306a36Sopenharmony_ci list = snd_hdspm_controls_raydat; 468662306a36Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_raydat); 468762306a36Sopenharmony_ci break; 468862306a36Sopenharmony_ci case AES32: 468962306a36Sopenharmony_ci list = snd_hdspm_controls_aes32; 469062306a36Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_aes32); 469162306a36Sopenharmony_ci break; 469262306a36Sopenharmony_ci } 469362306a36Sopenharmony_ci 469462306a36Sopenharmony_ci if (list) { 469562306a36Sopenharmony_ci for (idx = 0; idx < limit; idx++) { 469662306a36Sopenharmony_ci err = snd_ctl_add(card, 469762306a36Sopenharmony_ci snd_ctl_new1(&list[idx], hdspm)); 469862306a36Sopenharmony_ci if (err < 0) 469962306a36Sopenharmony_ci return err; 470062306a36Sopenharmony_ci } 470162306a36Sopenharmony_ci } 470262306a36Sopenharmony_ci 470362306a36Sopenharmony_ci 470462306a36Sopenharmony_ci /* create simple 1:1 playback mixer controls */ 470562306a36Sopenharmony_ci snd_hdspm_playback_mixer.name = "Chn"; 470662306a36Sopenharmony_ci if (hdspm->system_sample_rate >= 128000) { 470762306a36Sopenharmony_ci limit = hdspm->qs_out_channels; 470862306a36Sopenharmony_ci } else if (hdspm->system_sample_rate >= 64000) { 470962306a36Sopenharmony_ci limit = hdspm->ds_out_channels; 471062306a36Sopenharmony_ci } else { 471162306a36Sopenharmony_ci limit = hdspm->ss_out_channels; 471262306a36Sopenharmony_ci } 471362306a36Sopenharmony_ci for (idx = 0; idx < limit; ++idx) { 471462306a36Sopenharmony_ci snd_hdspm_playback_mixer.index = idx + 1; 471562306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_hdspm_playback_mixer, hdspm); 471662306a36Sopenharmony_ci err = snd_ctl_add(card, kctl); 471762306a36Sopenharmony_ci if (err < 0) 471862306a36Sopenharmony_ci return err; 471962306a36Sopenharmony_ci hdspm->playback_mixer_ctls[idx] = kctl; 472062306a36Sopenharmony_ci } 472162306a36Sopenharmony_ci 472262306a36Sopenharmony_ci 472362306a36Sopenharmony_ci if (hdspm->tco) { 472462306a36Sopenharmony_ci /* add tco control elements */ 472562306a36Sopenharmony_ci list = snd_hdspm_controls_tco; 472662306a36Sopenharmony_ci limit = ARRAY_SIZE(snd_hdspm_controls_tco); 472762306a36Sopenharmony_ci for (idx = 0; idx < limit; idx++) { 472862306a36Sopenharmony_ci err = snd_ctl_add(card, 472962306a36Sopenharmony_ci snd_ctl_new1(&list[idx], hdspm)); 473062306a36Sopenharmony_ci if (err < 0) 473162306a36Sopenharmony_ci return err; 473262306a36Sopenharmony_ci } 473362306a36Sopenharmony_ci } 473462306a36Sopenharmony_ci 473562306a36Sopenharmony_ci return 0; 473662306a36Sopenharmony_ci} 473762306a36Sopenharmony_ci 473862306a36Sopenharmony_ci/*------------------------------------------------------------ 473962306a36Sopenharmony_ci /proc interface 474062306a36Sopenharmony_ci ------------------------------------------------------------*/ 474162306a36Sopenharmony_ci 474262306a36Sopenharmony_cistatic void 474362306a36Sopenharmony_cisnd_hdspm_proc_read_tco(struct snd_info_entry *entry, 474462306a36Sopenharmony_ci struct snd_info_buffer *buffer) 474562306a36Sopenharmony_ci{ 474662306a36Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 474762306a36Sopenharmony_ci unsigned int status, control; 474862306a36Sopenharmony_ci int a, ltc, frames, seconds, minutes, hours; 474962306a36Sopenharmony_ci unsigned int period; 475062306a36Sopenharmony_ci u64 freq_const = 0; 475162306a36Sopenharmony_ci u32 rate; 475262306a36Sopenharmony_ci 475362306a36Sopenharmony_ci snd_iprintf(buffer, "--- TCO ---\n"); 475462306a36Sopenharmony_ci 475562306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 475662306a36Sopenharmony_ci control = hdspm->control_register; 475762306a36Sopenharmony_ci 475862306a36Sopenharmony_ci 475962306a36Sopenharmony_ci if (status & HDSPM_tco_detect) { 476062306a36Sopenharmony_ci snd_iprintf(buffer, "TCO module detected.\n"); 476162306a36Sopenharmony_ci a = hdspm_read(hdspm, HDSPM_RD_TCO+4); 476262306a36Sopenharmony_ci if (a & HDSPM_TCO1_LTC_Input_valid) { 476362306a36Sopenharmony_ci snd_iprintf(buffer, " LTC valid, "); 476462306a36Sopenharmony_ci switch (a & (HDSPM_TCO1_LTC_Format_LSB | 476562306a36Sopenharmony_ci HDSPM_TCO1_LTC_Format_MSB)) { 476662306a36Sopenharmony_ci case 0: 476762306a36Sopenharmony_ci snd_iprintf(buffer, "24 fps, "); 476862306a36Sopenharmony_ci break; 476962306a36Sopenharmony_ci case HDSPM_TCO1_LTC_Format_LSB: 477062306a36Sopenharmony_ci snd_iprintf(buffer, "25 fps, "); 477162306a36Sopenharmony_ci break; 477262306a36Sopenharmony_ci case HDSPM_TCO1_LTC_Format_MSB: 477362306a36Sopenharmony_ci snd_iprintf(buffer, "29.97 fps, "); 477462306a36Sopenharmony_ci break; 477562306a36Sopenharmony_ci default: 477662306a36Sopenharmony_ci snd_iprintf(buffer, "30 fps, "); 477762306a36Sopenharmony_ci break; 477862306a36Sopenharmony_ci } 477962306a36Sopenharmony_ci if (a & HDSPM_TCO1_set_drop_frame_flag) { 478062306a36Sopenharmony_ci snd_iprintf(buffer, "drop frame\n"); 478162306a36Sopenharmony_ci } else { 478262306a36Sopenharmony_ci snd_iprintf(buffer, "full frame\n"); 478362306a36Sopenharmony_ci } 478462306a36Sopenharmony_ci } else { 478562306a36Sopenharmony_ci snd_iprintf(buffer, " no LTC\n"); 478662306a36Sopenharmony_ci } 478762306a36Sopenharmony_ci if (a & HDSPM_TCO1_Video_Input_Format_NTSC) { 478862306a36Sopenharmony_ci snd_iprintf(buffer, " Video: NTSC\n"); 478962306a36Sopenharmony_ci } else if (a & HDSPM_TCO1_Video_Input_Format_PAL) { 479062306a36Sopenharmony_ci snd_iprintf(buffer, " Video: PAL\n"); 479162306a36Sopenharmony_ci } else { 479262306a36Sopenharmony_ci snd_iprintf(buffer, " No video\n"); 479362306a36Sopenharmony_ci } 479462306a36Sopenharmony_ci if (a & HDSPM_TCO1_TCO_lock) { 479562306a36Sopenharmony_ci snd_iprintf(buffer, " Sync: lock\n"); 479662306a36Sopenharmony_ci } else { 479762306a36Sopenharmony_ci snd_iprintf(buffer, " Sync: no lock\n"); 479862306a36Sopenharmony_ci } 479962306a36Sopenharmony_ci 480062306a36Sopenharmony_ci switch (hdspm->io_type) { 480162306a36Sopenharmony_ci case MADI: 480262306a36Sopenharmony_ci case AES32: 480362306a36Sopenharmony_ci freq_const = 110069313433624ULL; 480462306a36Sopenharmony_ci break; 480562306a36Sopenharmony_ci case RayDAT: 480662306a36Sopenharmony_ci case AIO: 480762306a36Sopenharmony_ci freq_const = 104857600000000ULL; 480862306a36Sopenharmony_ci break; 480962306a36Sopenharmony_ci case MADIface: 481062306a36Sopenharmony_ci break; /* no TCO possible */ 481162306a36Sopenharmony_ci } 481262306a36Sopenharmony_ci 481362306a36Sopenharmony_ci period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 481462306a36Sopenharmony_ci snd_iprintf(buffer, " period: %u\n", period); 481562306a36Sopenharmony_ci 481662306a36Sopenharmony_ci 481762306a36Sopenharmony_ci /* rate = freq_const/period; */ 481862306a36Sopenharmony_ci rate = div_u64(freq_const, period); 481962306a36Sopenharmony_ci 482062306a36Sopenharmony_ci if (control & HDSPM_QuadSpeed) { 482162306a36Sopenharmony_ci rate *= 4; 482262306a36Sopenharmony_ci } else if (control & HDSPM_DoubleSpeed) { 482362306a36Sopenharmony_ci rate *= 2; 482462306a36Sopenharmony_ci } 482562306a36Sopenharmony_ci 482662306a36Sopenharmony_ci snd_iprintf(buffer, " Frequency: %u Hz\n", 482762306a36Sopenharmony_ci (unsigned int) rate); 482862306a36Sopenharmony_ci 482962306a36Sopenharmony_ci ltc = hdspm_read(hdspm, HDSPM_RD_TCO); 483062306a36Sopenharmony_ci frames = ltc & 0xF; 483162306a36Sopenharmony_ci ltc >>= 4; 483262306a36Sopenharmony_ci frames += (ltc & 0x3) * 10; 483362306a36Sopenharmony_ci ltc >>= 4; 483462306a36Sopenharmony_ci seconds = ltc & 0xF; 483562306a36Sopenharmony_ci ltc >>= 4; 483662306a36Sopenharmony_ci seconds += (ltc & 0x7) * 10; 483762306a36Sopenharmony_ci ltc >>= 4; 483862306a36Sopenharmony_ci minutes = ltc & 0xF; 483962306a36Sopenharmony_ci ltc >>= 4; 484062306a36Sopenharmony_ci minutes += (ltc & 0x7) * 10; 484162306a36Sopenharmony_ci ltc >>= 4; 484262306a36Sopenharmony_ci hours = ltc & 0xF; 484362306a36Sopenharmony_ci ltc >>= 4; 484462306a36Sopenharmony_ci hours += (ltc & 0x3) * 10; 484562306a36Sopenharmony_ci snd_iprintf(buffer, 484662306a36Sopenharmony_ci " LTC In: %02d:%02d:%02d:%02d\n", 484762306a36Sopenharmony_ci hours, minutes, seconds, frames); 484862306a36Sopenharmony_ci 484962306a36Sopenharmony_ci } else { 485062306a36Sopenharmony_ci snd_iprintf(buffer, "No TCO module detected.\n"); 485162306a36Sopenharmony_ci } 485262306a36Sopenharmony_ci} 485362306a36Sopenharmony_ci 485462306a36Sopenharmony_cistatic void 485562306a36Sopenharmony_cisnd_hdspm_proc_read_madi(struct snd_info_entry *entry, 485662306a36Sopenharmony_ci struct snd_info_buffer *buffer) 485762306a36Sopenharmony_ci{ 485862306a36Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 485962306a36Sopenharmony_ci unsigned int status, status2; 486062306a36Sopenharmony_ci 486162306a36Sopenharmony_ci char *pref_sync_ref; 486262306a36Sopenharmony_ci char *autosync_ref; 486362306a36Sopenharmony_ci char *system_clock_mode; 486462306a36Sopenharmony_ci int x, x2; 486562306a36Sopenharmony_ci 486662306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 486762306a36Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 486862306a36Sopenharmony_ci 486962306a36Sopenharmony_ci snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", 487062306a36Sopenharmony_ci hdspm->card_name, hdspm->card->number + 1, 487162306a36Sopenharmony_ci hdspm->firmware_rev, 487262306a36Sopenharmony_ci (status2 & HDSPM_version0) | 487362306a36Sopenharmony_ci (status2 & HDSPM_version1) | (status2 & 487462306a36Sopenharmony_ci HDSPM_version2)); 487562306a36Sopenharmony_ci 487662306a36Sopenharmony_ci snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", 487762306a36Sopenharmony_ci (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, 487862306a36Sopenharmony_ci hdspm->serial); 487962306a36Sopenharmony_ci 488062306a36Sopenharmony_ci snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", 488162306a36Sopenharmony_ci hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); 488262306a36Sopenharmony_ci 488362306a36Sopenharmony_ci snd_iprintf(buffer, "--- System ---\n"); 488462306a36Sopenharmony_ci 488562306a36Sopenharmony_ci snd_iprintf(buffer, 488662306a36Sopenharmony_ci "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", 488762306a36Sopenharmony_ci status & HDSPM_audioIRQPending, 488862306a36Sopenharmony_ci (status & HDSPM_midi0IRQPending) ? 1 : 0, 488962306a36Sopenharmony_ci (status & HDSPM_midi1IRQPending) ? 1 : 0, 489062306a36Sopenharmony_ci hdspm->irq_count); 489162306a36Sopenharmony_ci snd_iprintf(buffer, 489262306a36Sopenharmony_ci "HW pointer: id = %d, rawptr = %d (%d->%d) " 489362306a36Sopenharmony_ci "estimated= %ld (bytes)\n", 489462306a36Sopenharmony_ci ((status & HDSPM_BufferID) ? 1 : 0), 489562306a36Sopenharmony_ci (status & HDSPM_BufferPositionMask), 489662306a36Sopenharmony_ci (status & HDSPM_BufferPositionMask) % 489762306a36Sopenharmony_ci (2 * (int)hdspm->period_bytes), 489862306a36Sopenharmony_ci ((status & HDSPM_BufferPositionMask) - 64) % 489962306a36Sopenharmony_ci (2 * (int)hdspm->period_bytes), 490062306a36Sopenharmony_ci (long) hdspm_hw_pointer(hdspm) * 4); 490162306a36Sopenharmony_ci 490262306a36Sopenharmony_ci snd_iprintf(buffer, 490362306a36Sopenharmony_ci "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", 490462306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, 490562306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, 490662306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, 490762306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); 490862306a36Sopenharmony_ci snd_iprintf(buffer, 490962306a36Sopenharmony_ci "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", 491062306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, 491162306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); 491262306a36Sopenharmony_ci snd_iprintf(buffer, 491362306a36Sopenharmony_ci "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " 491462306a36Sopenharmony_ci "status2=0x%x\n", 491562306a36Sopenharmony_ci hdspm->control_register, hdspm->control2_register, 491662306a36Sopenharmony_ci status, status2); 491762306a36Sopenharmony_ci 491862306a36Sopenharmony_ci 491962306a36Sopenharmony_ci snd_iprintf(buffer, "--- Settings ---\n"); 492062306a36Sopenharmony_ci 492162306a36Sopenharmony_ci x = hdspm_get_latency(hdspm); 492262306a36Sopenharmony_ci 492362306a36Sopenharmony_ci snd_iprintf(buffer, 492462306a36Sopenharmony_ci "Size (Latency): %d samples (2 periods of %lu bytes)\n", 492562306a36Sopenharmony_ci x, (unsigned long) hdspm->period_bytes); 492662306a36Sopenharmony_ci 492762306a36Sopenharmony_ci snd_iprintf(buffer, "Line out: %s\n", 492862306a36Sopenharmony_ci (hdspm->control_register & HDSPM_LineOut) ? "on " : "off"); 492962306a36Sopenharmony_ci 493062306a36Sopenharmony_ci snd_iprintf(buffer, 493162306a36Sopenharmony_ci "ClearTrackMarker = %s, Transmit in %s Channel Mode, " 493262306a36Sopenharmony_ci "Auto Input %s\n", 493362306a36Sopenharmony_ci (hdspm->control_register & HDSPM_clr_tms) ? "on" : "off", 493462306a36Sopenharmony_ci (hdspm->control_register & HDSPM_TX_64ch) ? "64" : "56", 493562306a36Sopenharmony_ci (hdspm->control_register & HDSPM_AutoInp) ? "on" : "off"); 493662306a36Sopenharmony_ci 493762306a36Sopenharmony_ci 493862306a36Sopenharmony_ci if (!(hdspm->control_register & HDSPM_ClockModeMaster)) 493962306a36Sopenharmony_ci system_clock_mode = "AutoSync"; 494062306a36Sopenharmony_ci else 494162306a36Sopenharmony_ci system_clock_mode = "Master"; 494262306a36Sopenharmony_ci snd_iprintf(buffer, "AutoSync Reference: %s\n", system_clock_mode); 494362306a36Sopenharmony_ci 494462306a36Sopenharmony_ci switch (hdspm_pref_sync_ref(hdspm)) { 494562306a36Sopenharmony_ci case HDSPM_SYNC_FROM_WORD: 494662306a36Sopenharmony_ci pref_sync_ref = "Word Clock"; 494762306a36Sopenharmony_ci break; 494862306a36Sopenharmony_ci case HDSPM_SYNC_FROM_MADI: 494962306a36Sopenharmony_ci pref_sync_ref = "MADI Sync"; 495062306a36Sopenharmony_ci break; 495162306a36Sopenharmony_ci case HDSPM_SYNC_FROM_TCO: 495262306a36Sopenharmony_ci pref_sync_ref = "TCO"; 495362306a36Sopenharmony_ci break; 495462306a36Sopenharmony_ci case HDSPM_SYNC_FROM_SYNC_IN: 495562306a36Sopenharmony_ci pref_sync_ref = "Sync In"; 495662306a36Sopenharmony_ci break; 495762306a36Sopenharmony_ci default: 495862306a36Sopenharmony_ci pref_sync_ref = "XXXX Clock"; 495962306a36Sopenharmony_ci break; 496062306a36Sopenharmony_ci } 496162306a36Sopenharmony_ci snd_iprintf(buffer, "Preferred Sync Reference: %s\n", 496262306a36Sopenharmony_ci pref_sync_ref); 496362306a36Sopenharmony_ci 496462306a36Sopenharmony_ci snd_iprintf(buffer, "System Clock Frequency: %d\n", 496562306a36Sopenharmony_ci hdspm->system_sample_rate); 496662306a36Sopenharmony_ci 496762306a36Sopenharmony_ci 496862306a36Sopenharmony_ci snd_iprintf(buffer, "--- Status:\n"); 496962306a36Sopenharmony_ci 497062306a36Sopenharmony_ci x = status & HDSPM_madiSync; 497162306a36Sopenharmony_ci x2 = status2 & HDSPM_wcSync; 497262306a36Sopenharmony_ci 497362306a36Sopenharmony_ci snd_iprintf(buffer, "Inputs MADI=%s, WordClock=%s\n", 497462306a36Sopenharmony_ci (status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") : 497562306a36Sopenharmony_ci "NoLock", 497662306a36Sopenharmony_ci (status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") : 497762306a36Sopenharmony_ci "NoLock"); 497862306a36Sopenharmony_ci 497962306a36Sopenharmony_ci switch (hdspm_autosync_ref(hdspm)) { 498062306a36Sopenharmony_ci case HDSPM_AUTOSYNC_FROM_SYNC_IN: 498162306a36Sopenharmony_ci autosync_ref = "Sync In"; 498262306a36Sopenharmony_ci break; 498362306a36Sopenharmony_ci case HDSPM_AUTOSYNC_FROM_TCO: 498462306a36Sopenharmony_ci autosync_ref = "TCO"; 498562306a36Sopenharmony_ci break; 498662306a36Sopenharmony_ci case HDSPM_AUTOSYNC_FROM_WORD: 498762306a36Sopenharmony_ci autosync_ref = "Word Clock"; 498862306a36Sopenharmony_ci break; 498962306a36Sopenharmony_ci case HDSPM_AUTOSYNC_FROM_MADI: 499062306a36Sopenharmony_ci autosync_ref = "MADI Sync"; 499162306a36Sopenharmony_ci break; 499262306a36Sopenharmony_ci case HDSPM_AUTOSYNC_FROM_NONE: 499362306a36Sopenharmony_ci autosync_ref = "Input not valid"; 499462306a36Sopenharmony_ci break; 499562306a36Sopenharmony_ci default: 499662306a36Sopenharmony_ci autosync_ref = "---"; 499762306a36Sopenharmony_ci break; 499862306a36Sopenharmony_ci } 499962306a36Sopenharmony_ci snd_iprintf(buffer, 500062306a36Sopenharmony_ci "AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n", 500162306a36Sopenharmony_ci autosync_ref, hdspm_external_sample_rate(hdspm), 500262306a36Sopenharmony_ci (status & HDSPM_madiFreqMask) >> 22, 500362306a36Sopenharmony_ci (status2 & HDSPM_wcFreqMask) >> 5); 500462306a36Sopenharmony_ci 500562306a36Sopenharmony_ci snd_iprintf(buffer, "Input: %s, Mode=%s\n", 500662306a36Sopenharmony_ci (status & HDSPM_AB_int) ? "Coax" : "Optical", 500762306a36Sopenharmony_ci (status & HDSPM_RX_64ch) ? "64 channels" : 500862306a36Sopenharmony_ci "56 channels"); 500962306a36Sopenharmony_ci 501062306a36Sopenharmony_ci /* call readout function for TCO specific status */ 501162306a36Sopenharmony_ci snd_hdspm_proc_read_tco(entry, buffer); 501262306a36Sopenharmony_ci 501362306a36Sopenharmony_ci snd_iprintf(buffer, "\n"); 501462306a36Sopenharmony_ci} 501562306a36Sopenharmony_ci 501662306a36Sopenharmony_cistatic void 501762306a36Sopenharmony_cisnd_hdspm_proc_read_aes32(struct snd_info_entry * entry, 501862306a36Sopenharmony_ci struct snd_info_buffer *buffer) 501962306a36Sopenharmony_ci{ 502062306a36Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 502162306a36Sopenharmony_ci unsigned int status; 502262306a36Sopenharmony_ci unsigned int status2; 502362306a36Sopenharmony_ci unsigned int timecode; 502462306a36Sopenharmony_ci unsigned int wcLock, wcSync; 502562306a36Sopenharmony_ci int pref_syncref; 502662306a36Sopenharmony_ci char *autosync_ref; 502762306a36Sopenharmony_ci int x; 502862306a36Sopenharmony_ci 502962306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 503062306a36Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 503162306a36Sopenharmony_ci timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); 503262306a36Sopenharmony_ci 503362306a36Sopenharmony_ci snd_iprintf(buffer, "%s (Card #%d) Rev.%x\n", 503462306a36Sopenharmony_ci hdspm->card_name, hdspm->card->number + 1, 503562306a36Sopenharmony_ci hdspm->firmware_rev); 503662306a36Sopenharmony_ci 503762306a36Sopenharmony_ci snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", 503862306a36Sopenharmony_ci hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); 503962306a36Sopenharmony_ci 504062306a36Sopenharmony_ci snd_iprintf(buffer, "--- System ---\n"); 504162306a36Sopenharmony_ci 504262306a36Sopenharmony_ci snd_iprintf(buffer, 504362306a36Sopenharmony_ci "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", 504462306a36Sopenharmony_ci status & HDSPM_audioIRQPending, 504562306a36Sopenharmony_ci (status & HDSPM_midi0IRQPending) ? 1 : 0, 504662306a36Sopenharmony_ci (status & HDSPM_midi1IRQPending) ? 1 : 0, 504762306a36Sopenharmony_ci hdspm->irq_count); 504862306a36Sopenharmony_ci snd_iprintf(buffer, 504962306a36Sopenharmony_ci "HW pointer: id = %d, rawptr = %d (%d->%d) " 505062306a36Sopenharmony_ci "estimated= %ld (bytes)\n", 505162306a36Sopenharmony_ci ((status & HDSPM_BufferID) ? 1 : 0), 505262306a36Sopenharmony_ci (status & HDSPM_BufferPositionMask), 505362306a36Sopenharmony_ci (status & HDSPM_BufferPositionMask) % 505462306a36Sopenharmony_ci (2 * (int)hdspm->period_bytes), 505562306a36Sopenharmony_ci ((status & HDSPM_BufferPositionMask) - 64) % 505662306a36Sopenharmony_ci (2 * (int)hdspm->period_bytes), 505762306a36Sopenharmony_ci (long) hdspm_hw_pointer(hdspm) * 4); 505862306a36Sopenharmony_ci 505962306a36Sopenharmony_ci snd_iprintf(buffer, 506062306a36Sopenharmony_ci "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", 506162306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, 506262306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, 506362306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, 506462306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); 506562306a36Sopenharmony_ci snd_iprintf(buffer, 506662306a36Sopenharmony_ci "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", 506762306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, 506862306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); 506962306a36Sopenharmony_ci snd_iprintf(buffer, 507062306a36Sopenharmony_ci "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " 507162306a36Sopenharmony_ci "status2=0x%x\n", 507262306a36Sopenharmony_ci hdspm->control_register, hdspm->control2_register, 507362306a36Sopenharmony_ci status, status2); 507462306a36Sopenharmony_ci 507562306a36Sopenharmony_ci snd_iprintf(buffer, "--- Settings ---\n"); 507662306a36Sopenharmony_ci 507762306a36Sopenharmony_ci x = hdspm_get_latency(hdspm); 507862306a36Sopenharmony_ci 507962306a36Sopenharmony_ci snd_iprintf(buffer, 508062306a36Sopenharmony_ci "Size (Latency): %d samples (2 periods of %lu bytes)\n", 508162306a36Sopenharmony_ci x, (unsigned long) hdspm->period_bytes); 508262306a36Sopenharmony_ci 508362306a36Sopenharmony_ci snd_iprintf(buffer, "Line out: %s\n", 508462306a36Sopenharmony_ci (hdspm-> 508562306a36Sopenharmony_ci control_register & HDSPM_LineOut) ? "on " : "off"); 508662306a36Sopenharmony_ci 508762306a36Sopenharmony_ci snd_iprintf(buffer, 508862306a36Sopenharmony_ci "ClearTrackMarker %s, Emphasis %s, Dolby %s\n", 508962306a36Sopenharmony_ci (hdspm-> 509062306a36Sopenharmony_ci control_register & HDSPM_clr_tms) ? "on" : "off", 509162306a36Sopenharmony_ci (hdspm-> 509262306a36Sopenharmony_ci control_register & HDSPM_Emphasis) ? "on" : "off", 509362306a36Sopenharmony_ci (hdspm-> 509462306a36Sopenharmony_ci control_register & HDSPM_Dolby) ? "on" : "off"); 509562306a36Sopenharmony_ci 509662306a36Sopenharmony_ci 509762306a36Sopenharmony_ci pref_syncref = hdspm_pref_sync_ref(hdspm); 509862306a36Sopenharmony_ci if (pref_syncref == 0) 509962306a36Sopenharmony_ci snd_iprintf(buffer, "Preferred Sync Reference: Word Clock\n"); 510062306a36Sopenharmony_ci else 510162306a36Sopenharmony_ci snd_iprintf(buffer, "Preferred Sync Reference: AES%d\n", 510262306a36Sopenharmony_ci pref_syncref); 510362306a36Sopenharmony_ci 510462306a36Sopenharmony_ci snd_iprintf(buffer, "System Clock Frequency: %d\n", 510562306a36Sopenharmony_ci hdspm->system_sample_rate); 510662306a36Sopenharmony_ci 510762306a36Sopenharmony_ci snd_iprintf(buffer, "Double speed: %s\n", 510862306a36Sopenharmony_ci hdspm->control_register & HDSPM_DS_DoubleWire? 510962306a36Sopenharmony_ci "Double wire" : "Single wire"); 511062306a36Sopenharmony_ci snd_iprintf(buffer, "Quad speed: %s\n", 511162306a36Sopenharmony_ci hdspm->control_register & HDSPM_QS_DoubleWire? 511262306a36Sopenharmony_ci "Double wire" : 511362306a36Sopenharmony_ci hdspm->control_register & HDSPM_QS_QuadWire? 511462306a36Sopenharmony_ci "Quad wire" : "Single wire"); 511562306a36Sopenharmony_ci 511662306a36Sopenharmony_ci snd_iprintf(buffer, "--- Status:\n"); 511762306a36Sopenharmony_ci 511862306a36Sopenharmony_ci wcLock = status & HDSPM_AES32_wcLock; 511962306a36Sopenharmony_ci wcSync = wcLock && (status & HDSPM_AES32_wcSync); 512062306a36Sopenharmony_ci 512162306a36Sopenharmony_ci snd_iprintf(buffer, "Word: %s Frequency: %d\n", 512262306a36Sopenharmony_ci (wcLock) ? (wcSync ? "Sync " : "Lock ") : "No Lock", 512362306a36Sopenharmony_ci HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); 512462306a36Sopenharmony_ci 512562306a36Sopenharmony_ci for (x = 0; x < 8; x++) { 512662306a36Sopenharmony_ci snd_iprintf(buffer, "AES%d: %s Frequency: %d\n", 512762306a36Sopenharmony_ci x+1, 512862306a36Sopenharmony_ci (status2 & (HDSPM_LockAES >> x)) ? 512962306a36Sopenharmony_ci "Sync " : "No Lock", 513062306a36Sopenharmony_ci HDSPM_bit2freq((timecode >> (4*x)) & 0xF)); 513162306a36Sopenharmony_ci } 513262306a36Sopenharmony_ci 513362306a36Sopenharmony_ci switch (hdspm_autosync_ref(hdspm)) { 513462306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_NONE: 513562306a36Sopenharmony_ci autosync_ref = "None"; break; 513662306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_WORD: 513762306a36Sopenharmony_ci autosync_ref = "Word Clock"; break; 513862306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES1: 513962306a36Sopenharmony_ci autosync_ref = "AES1"; break; 514062306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES2: 514162306a36Sopenharmony_ci autosync_ref = "AES2"; break; 514262306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES3: 514362306a36Sopenharmony_ci autosync_ref = "AES3"; break; 514462306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES4: 514562306a36Sopenharmony_ci autosync_ref = "AES4"; break; 514662306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES5: 514762306a36Sopenharmony_ci autosync_ref = "AES5"; break; 514862306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES6: 514962306a36Sopenharmony_ci autosync_ref = "AES6"; break; 515062306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES7: 515162306a36Sopenharmony_ci autosync_ref = "AES7"; break; 515262306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_AES8: 515362306a36Sopenharmony_ci autosync_ref = "AES8"; break; 515462306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_TCO: 515562306a36Sopenharmony_ci autosync_ref = "TCO"; break; 515662306a36Sopenharmony_ci case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN: 515762306a36Sopenharmony_ci autosync_ref = "Sync In"; break; 515862306a36Sopenharmony_ci default: 515962306a36Sopenharmony_ci autosync_ref = "---"; break; 516062306a36Sopenharmony_ci } 516162306a36Sopenharmony_ci snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); 516262306a36Sopenharmony_ci 516362306a36Sopenharmony_ci /* call readout function for TCO specific status */ 516462306a36Sopenharmony_ci snd_hdspm_proc_read_tco(entry, buffer); 516562306a36Sopenharmony_ci 516662306a36Sopenharmony_ci snd_iprintf(buffer, "\n"); 516762306a36Sopenharmony_ci} 516862306a36Sopenharmony_ci 516962306a36Sopenharmony_cistatic void 517062306a36Sopenharmony_cisnd_hdspm_proc_read_raydat(struct snd_info_entry *entry, 517162306a36Sopenharmony_ci struct snd_info_buffer *buffer) 517262306a36Sopenharmony_ci{ 517362306a36Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 517462306a36Sopenharmony_ci unsigned int status1, status2, status3, i; 517562306a36Sopenharmony_ci unsigned int lock, sync; 517662306a36Sopenharmony_ci 517762306a36Sopenharmony_ci status1 = hdspm_read(hdspm, HDSPM_RD_STATUS_1); /* s1 */ 517862306a36Sopenharmony_ci status2 = hdspm_read(hdspm, HDSPM_RD_STATUS_2); /* freq */ 517962306a36Sopenharmony_ci status3 = hdspm_read(hdspm, HDSPM_RD_STATUS_3); /* s2 */ 518062306a36Sopenharmony_ci 518162306a36Sopenharmony_ci snd_iprintf(buffer, "STATUS1: 0x%08x\n", status1); 518262306a36Sopenharmony_ci snd_iprintf(buffer, "STATUS2: 0x%08x\n", status2); 518362306a36Sopenharmony_ci snd_iprintf(buffer, "STATUS3: 0x%08x\n", status3); 518462306a36Sopenharmony_ci 518562306a36Sopenharmony_ci 518662306a36Sopenharmony_ci snd_iprintf(buffer, "\n*** CLOCK MODE\n\n"); 518762306a36Sopenharmony_ci 518862306a36Sopenharmony_ci snd_iprintf(buffer, "Clock mode : %s\n", 518962306a36Sopenharmony_ci (hdspm_system_clock_mode(hdspm) == 0) ? "master" : "slave"); 519062306a36Sopenharmony_ci snd_iprintf(buffer, "System frequency: %d Hz\n", 519162306a36Sopenharmony_ci hdspm_get_system_sample_rate(hdspm)); 519262306a36Sopenharmony_ci 519362306a36Sopenharmony_ci snd_iprintf(buffer, "\n*** INPUT STATUS\n\n"); 519462306a36Sopenharmony_ci 519562306a36Sopenharmony_ci lock = 0x1; 519662306a36Sopenharmony_ci sync = 0x100; 519762306a36Sopenharmony_ci 519862306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 519962306a36Sopenharmony_ci snd_iprintf(buffer, "s1_input %d: Lock %d, Sync %d, Freq %s\n", 520062306a36Sopenharmony_ci i, 520162306a36Sopenharmony_ci (status1 & lock) ? 1 : 0, 520262306a36Sopenharmony_ci (status1 & sync) ? 1 : 0, 520362306a36Sopenharmony_ci texts_freq[(status2 >> (i * 4)) & 0xF]); 520462306a36Sopenharmony_ci 520562306a36Sopenharmony_ci lock = lock<<1; 520662306a36Sopenharmony_ci sync = sync<<1; 520762306a36Sopenharmony_ci } 520862306a36Sopenharmony_ci 520962306a36Sopenharmony_ci snd_iprintf(buffer, "WC input: Lock %d, Sync %d, Freq %s\n", 521062306a36Sopenharmony_ci (status1 & 0x1000000) ? 1 : 0, 521162306a36Sopenharmony_ci (status1 & 0x2000000) ? 1 : 0, 521262306a36Sopenharmony_ci texts_freq[(status1 >> 16) & 0xF]); 521362306a36Sopenharmony_ci 521462306a36Sopenharmony_ci snd_iprintf(buffer, "TCO input: Lock %d, Sync %d, Freq %s\n", 521562306a36Sopenharmony_ci (status1 & 0x4000000) ? 1 : 0, 521662306a36Sopenharmony_ci (status1 & 0x8000000) ? 1 : 0, 521762306a36Sopenharmony_ci texts_freq[(status1 >> 20) & 0xF]); 521862306a36Sopenharmony_ci 521962306a36Sopenharmony_ci snd_iprintf(buffer, "SYNC IN: Lock %d, Sync %d, Freq %s\n", 522062306a36Sopenharmony_ci (status3 & 0x400) ? 1 : 0, 522162306a36Sopenharmony_ci (status3 & 0x800) ? 1 : 0, 522262306a36Sopenharmony_ci texts_freq[(status2 >> 12) & 0xF]); 522362306a36Sopenharmony_ci 522462306a36Sopenharmony_ci} 522562306a36Sopenharmony_ci 522662306a36Sopenharmony_ci#ifdef CONFIG_SND_DEBUG 522762306a36Sopenharmony_cistatic void 522862306a36Sopenharmony_cisnd_hdspm_proc_read_debug(struct snd_info_entry *entry, 522962306a36Sopenharmony_ci struct snd_info_buffer *buffer) 523062306a36Sopenharmony_ci{ 523162306a36Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 523262306a36Sopenharmony_ci 523362306a36Sopenharmony_ci int j,i; 523462306a36Sopenharmony_ci 523562306a36Sopenharmony_ci for (i = 0; i < 256 /* 1024*64 */; i += j) { 523662306a36Sopenharmony_ci snd_iprintf(buffer, "0x%08X: ", i); 523762306a36Sopenharmony_ci for (j = 0; j < 16; j += 4) 523862306a36Sopenharmony_ci snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j)); 523962306a36Sopenharmony_ci snd_iprintf(buffer, "\n"); 524062306a36Sopenharmony_ci } 524162306a36Sopenharmony_ci} 524262306a36Sopenharmony_ci#endif 524362306a36Sopenharmony_ci 524462306a36Sopenharmony_ci 524562306a36Sopenharmony_cistatic void snd_hdspm_proc_ports_in(struct snd_info_entry *entry, 524662306a36Sopenharmony_ci struct snd_info_buffer *buffer) 524762306a36Sopenharmony_ci{ 524862306a36Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 524962306a36Sopenharmony_ci int i; 525062306a36Sopenharmony_ci 525162306a36Sopenharmony_ci snd_iprintf(buffer, "# generated by hdspm\n"); 525262306a36Sopenharmony_ci 525362306a36Sopenharmony_ci for (i = 0; i < hdspm->max_channels_in; i++) { 525462306a36Sopenharmony_ci snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_in[i]); 525562306a36Sopenharmony_ci } 525662306a36Sopenharmony_ci} 525762306a36Sopenharmony_ci 525862306a36Sopenharmony_cistatic void snd_hdspm_proc_ports_out(struct snd_info_entry *entry, 525962306a36Sopenharmony_ci struct snd_info_buffer *buffer) 526062306a36Sopenharmony_ci{ 526162306a36Sopenharmony_ci struct hdspm *hdspm = entry->private_data; 526262306a36Sopenharmony_ci int i; 526362306a36Sopenharmony_ci 526462306a36Sopenharmony_ci snd_iprintf(buffer, "# generated by hdspm\n"); 526562306a36Sopenharmony_ci 526662306a36Sopenharmony_ci for (i = 0; i < hdspm->max_channels_out; i++) { 526762306a36Sopenharmony_ci snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_out[i]); 526862306a36Sopenharmony_ci } 526962306a36Sopenharmony_ci} 527062306a36Sopenharmony_ci 527162306a36Sopenharmony_ci 527262306a36Sopenharmony_cistatic void snd_hdspm_proc_init(struct hdspm *hdspm) 527362306a36Sopenharmony_ci{ 527462306a36Sopenharmony_ci void (*read)(struct snd_info_entry *, struct snd_info_buffer *) = NULL; 527562306a36Sopenharmony_ci 527662306a36Sopenharmony_ci switch (hdspm->io_type) { 527762306a36Sopenharmony_ci case AES32: 527862306a36Sopenharmony_ci read = snd_hdspm_proc_read_aes32; 527962306a36Sopenharmony_ci break; 528062306a36Sopenharmony_ci case MADI: 528162306a36Sopenharmony_ci read = snd_hdspm_proc_read_madi; 528262306a36Sopenharmony_ci break; 528362306a36Sopenharmony_ci case MADIface: 528462306a36Sopenharmony_ci /* read = snd_hdspm_proc_read_madiface; */ 528562306a36Sopenharmony_ci break; 528662306a36Sopenharmony_ci case RayDAT: 528762306a36Sopenharmony_ci read = snd_hdspm_proc_read_raydat; 528862306a36Sopenharmony_ci break; 528962306a36Sopenharmony_ci case AIO: 529062306a36Sopenharmony_ci break; 529162306a36Sopenharmony_ci } 529262306a36Sopenharmony_ci 529362306a36Sopenharmony_ci snd_card_ro_proc_new(hdspm->card, "hdspm", hdspm, read); 529462306a36Sopenharmony_ci snd_card_ro_proc_new(hdspm->card, "ports.in", hdspm, 529562306a36Sopenharmony_ci snd_hdspm_proc_ports_in); 529662306a36Sopenharmony_ci snd_card_ro_proc_new(hdspm->card, "ports.out", hdspm, 529762306a36Sopenharmony_ci snd_hdspm_proc_ports_out); 529862306a36Sopenharmony_ci 529962306a36Sopenharmony_ci#ifdef CONFIG_SND_DEBUG 530062306a36Sopenharmony_ci /* debug file to read all hdspm registers */ 530162306a36Sopenharmony_ci snd_card_ro_proc_new(hdspm->card, "debug", hdspm, 530262306a36Sopenharmony_ci snd_hdspm_proc_read_debug); 530362306a36Sopenharmony_ci#endif 530462306a36Sopenharmony_ci} 530562306a36Sopenharmony_ci 530662306a36Sopenharmony_ci/*------------------------------------------------------------ 530762306a36Sopenharmony_ci hdspm intitialize 530862306a36Sopenharmony_ci ------------------------------------------------------------*/ 530962306a36Sopenharmony_ci 531062306a36Sopenharmony_cistatic int snd_hdspm_set_defaults(struct hdspm * hdspm) 531162306a36Sopenharmony_ci{ 531262306a36Sopenharmony_ci /* ASSUMPTION: hdspm->lock is either held, or there is no need to 531362306a36Sopenharmony_ci hold it (e.g. during module initialization). 531462306a36Sopenharmony_ci */ 531562306a36Sopenharmony_ci 531662306a36Sopenharmony_ci /* set defaults: */ 531762306a36Sopenharmony_ci 531862306a36Sopenharmony_ci hdspm->settings_register = 0; 531962306a36Sopenharmony_ci 532062306a36Sopenharmony_ci switch (hdspm->io_type) { 532162306a36Sopenharmony_ci case MADI: 532262306a36Sopenharmony_ci case MADIface: 532362306a36Sopenharmony_ci hdspm->control_register = 532462306a36Sopenharmony_ci 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000; 532562306a36Sopenharmony_ci break; 532662306a36Sopenharmony_ci 532762306a36Sopenharmony_ci case RayDAT: 532862306a36Sopenharmony_ci case AIO: 532962306a36Sopenharmony_ci hdspm->settings_register = 0x1 + 0x1000; 533062306a36Sopenharmony_ci /* Magic values are: LAT_0, LAT_2, Master, freq1, tx64ch, inp_0, 533162306a36Sopenharmony_ci * line_out */ 533262306a36Sopenharmony_ci hdspm->control_register = 533362306a36Sopenharmony_ci 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000; 533462306a36Sopenharmony_ci break; 533562306a36Sopenharmony_ci 533662306a36Sopenharmony_ci case AES32: 533762306a36Sopenharmony_ci hdspm->control_register = 533862306a36Sopenharmony_ci HDSPM_ClockModeMaster | /* Master Clock Mode on */ 533962306a36Sopenharmony_ci hdspm_encode_latency(7) | /* latency max=8192samples */ 534062306a36Sopenharmony_ci HDSPM_SyncRef0 | /* AES1 is syncclock */ 534162306a36Sopenharmony_ci HDSPM_LineOut | /* Analog output in */ 534262306a36Sopenharmony_ci HDSPM_Professional; /* Professional mode */ 534362306a36Sopenharmony_ci break; 534462306a36Sopenharmony_ci } 534562306a36Sopenharmony_ci 534662306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 534762306a36Sopenharmony_ci 534862306a36Sopenharmony_ci if (AES32 == hdspm->io_type) { 534962306a36Sopenharmony_ci /* No control2 register for AES32 */ 535062306a36Sopenharmony_ci#ifdef SNDRV_BIG_ENDIAN 535162306a36Sopenharmony_ci hdspm->control2_register = HDSPM_BIGENDIAN_MODE; 535262306a36Sopenharmony_ci#else 535362306a36Sopenharmony_ci hdspm->control2_register = 0; 535462306a36Sopenharmony_ci#endif 535562306a36Sopenharmony_ci 535662306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register); 535762306a36Sopenharmony_ci } 535862306a36Sopenharmony_ci hdspm_compute_period_size(hdspm); 535962306a36Sopenharmony_ci 536062306a36Sopenharmony_ci /* silence everything */ 536162306a36Sopenharmony_ci 536262306a36Sopenharmony_ci all_in_all_mixer(hdspm, 0 * UNITY_GAIN); 536362306a36Sopenharmony_ci 536462306a36Sopenharmony_ci if (hdspm_is_raydat_or_aio(hdspm)) 536562306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); 536662306a36Sopenharmony_ci 536762306a36Sopenharmony_ci /* set a default rate so that the channel map is set up. */ 536862306a36Sopenharmony_ci hdspm_set_rate(hdspm, 48000, 1); 536962306a36Sopenharmony_ci 537062306a36Sopenharmony_ci return 0; 537162306a36Sopenharmony_ci} 537262306a36Sopenharmony_ci 537362306a36Sopenharmony_ci 537462306a36Sopenharmony_ci/*------------------------------------------------------------ 537562306a36Sopenharmony_ci interrupt 537662306a36Sopenharmony_ci ------------------------------------------------------------*/ 537762306a36Sopenharmony_ci 537862306a36Sopenharmony_cistatic irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) 537962306a36Sopenharmony_ci{ 538062306a36Sopenharmony_ci struct hdspm *hdspm = (struct hdspm *) dev_id; 538162306a36Sopenharmony_ci unsigned int status; 538262306a36Sopenharmony_ci int i, audio, midi, schedule = 0; 538362306a36Sopenharmony_ci /* cycles_t now; */ 538462306a36Sopenharmony_ci 538562306a36Sopenharmony_ci status = hdspm_read(hdspm, HDSPM_statusRegister); 538662306a36Sopenharmony_ci 538762306a36Sopenharmony_ci audio = status & HDSPM_audioIRQPending; 538862306a36Sopenharmony_ci midi = status & (HDSPM_midi0IRQPending | HDSPM_midi1IRQPending | 538962306a36Sopenharmony_ci HDSPM_midi2IRQPending | HDSPM_midi3IRQPending); 539062306a36Sopenharmony_ci 539162306a36Sopenharmony_ci /* now = get_cycles(); */ 539262306a36Sopenharmony_ci /* 539362306a36Sopenharmony_ci * LAT_2..LAT_0 period counter (win) counter (mac) 539462306a36Sopenharmony_ci * 6 4096 ~256053425 ~514672358 539562306a36Sopenharmony_ci * 5 2048 ~128024983 ~257373821 539662306a36Sopenharmony_ci * 4 1024 ~64023706 ~128718089 539762306a36Sopenharmony_ci * 3 512 ~32005945 ~64385999 539862306a36Sopenharmony_ci * 2 256 ~16003039 ~32260176 539962306a36Sopenharmony_ci * 1 128 ~7998738 ~16194507 540062306a36Sopenharmony_ci * 0 64 ~3998231 ~8191558 540162306a36Sopenharmony_ci */ 540262306a36Sopenharmony_ci /* 540362306a36Sopenharmony_ci dev_info(hdspm->card->dev, "snd_hdspm_interrupt %llu @ %llx\n", 540462306a36Sopenharmony_ci now-hdspm->last_interrupt, status & 0xFFC0); 540562306a36Sopenharmony_ci hdspm->last_interrupt = now; 540662306a36Sopenharmony_ci */ 540762306a36Sopenharmony_ci 540862306a36Sopenharmony_ci if (!audio && !midi) 540962306a36Sopenharmony_ci return IRQ_NONE; 541062306a36Sopenharmony_ci 541162306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_interruptConfirmation, 0); 541262306a36Sopenharmony_ci hdspm->irq_count++; 541362306a36Sopenharmony_ci 541462306a36Sopenharmony_ci 541562306a36Sopenharmony_ci if (audio) { 541662306a36Sopenharmony_ci if (hdspm->capture_substream) 541762306a36Sopenharmony_ci snd_pcm_period_elapsed(hdspm->capture_substream); 541862306a36Sopenharmony_ci 541962306a36Sopenharmony_ci if (hdspm->playback_substream) 542062306a36Sopenharmony_ci snd_pcm_period_elapsed(hdspm->playback_substream); 542162306a36Sopenharmony_ci } 542262306a36Sopenharmony_ci 542362306a36Sopenharmony_ci if (midi) { 542462306a36Sopenharmony_ci i = 0; 542562306a36Sopenharmony_ci while (i < hdspm->midiPorts) { 542662306a36Sopenharmony_ci if ((hdspm_read(hdspm, 542762306a36Sopenharmony_ci hdspm->midi[i].statusIn) & 0xff) && 542862306a36Sopenharmony_ci (status & hdspm->midi[i].irq)) { 542962306a36Sopenharmony_ci /* we disable interrupts for this input until 543062306a36Sopenharmony_ci * processing is done 543162306a36Sopenharmony_ci */ 543262306a36Sopenharmony_ci hdspm->control_register &= ~hdspm->midi[i].ie; 543362306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, 543462306a36Sopenharmony_ci hdspm->control_register); 543562306a36Sopenharmony_ci hdspm->midi[i].pending = 1; 543662306a36Sopenharmony_ci schedule = 1; 543762306a36Sopenharmony_ci } 543862306a36Sopenharmony_ci 543962306a36Sopenharmony_ci i++; 544062306a36Sopenharmony_ci } 544162306a36Sopenharmony_ci 544262306a36Sopenharmony_ci if (schedule) 544362306a36Sopenharmony_ci queue_work(system_highpri_wq, &hdspm->midi_work); 544462306a36Sopenharmony_ci } 544562306a36Sopenharmony_ci 544662306a36Sopenharmony_ci return IRQ_HANDLED; 544762306a36Sopenharmony_ci} 544862306a36Sopenharmony_ci 544962306a36Sopenharmony_ci/*------------------------------------------------------------ 545062306a36Sopenharmony_ci pcm interface 545162306a36Sopenharmony_ci ------------------------------------------------------------*/ 545262306a36Sopenharmony_ci 545362306a36Sopenharmony_ci 545462306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_hdspm_hw_pointer(struct snd_pcm_substream 545562306a36Sopenharmony_ci *substream) 545662306a36Sopenharmony_ci{ 545762306a36Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 545862306a36Sopenharmony_ci return hdspm_hw_pointer(hdspm); 545962306a36Sopenharmony_ci} 546062306a36Sopenharmony_ci 546162306a36Sopenharmony_ci 546262306a36Sopenharmony_cistatic int snd_hdspm_reset(struct snd_pcm_substream *substream) 546362306a36Sopenharmony_ci{ 546462306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 546562306a36Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 546662306a36Sopenharmony_ci struct snd_pcm_substream *other; 546762306a36Sopenharmony_ci 546862306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 546962306a36Sopenharmony_ci other = hdspm->capture_substream; 547062306a36Sopenharmony_ci else 547162306a36Sopenharmony_ci other = hdspm->playback_substream; 547262306a36Sopenharmony_ci 547362306a36Sopenharmony_ci if (hdspm->running) 547462306a36Sopenharmony_ci runtime->status->hw_ptr = hdspm_hw_pointer(hdspm); 547562306a36Sopenharmony_ci else 547662306a36Sopenharmony_ci runtime->status->hw_ptr = 0; 547762306a36Sopenharmony_ci if (other) { 547862306a36Sopenharmony_ci struct snd_pcm_substream *s; 547962306a36Sopenharmony_ci struct snd_pcm_runtime *oruntime = other->runtime; 548062306a36Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 548162306a36Sopenharmony_ci if (s == other) { 548262306a36Sopenharmony_ci oruntime->status->hw_ptr = 548362306a36Sopenharmony_ci runtime->status->hw_ptr; 548462306a36Sopenharmony_ci break; 548562306a36Sopenharmony_ci } 548662306a36Sopenharmony_ci } 548762306a36Sopenharmony_ci } 548862306a36Sopenharmony_ci return 0; 548962306a36Sopenharmony_ci} 549062306a36Sopenharmony_ci 549162306a36Sopenharmony_cistatic int snd_hdspm_hw_params(struct snd_pcm_substream *substream, 549262306a36Sopenharmony_ci struct snd_pcm_hw_params *params) 549362306a36Sopenharmony_ci{ 549462306a36Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 549562306a36Sopenharmony_ci int err; 549662306a36Sopenharmony_ci int i; 549762306a36Sopenharmony_ci pid_t this_pid; 549862306a36Sopenharmony_ci pid_t other_pid; 549962306a36Sopenharmony_ci 550062306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 550162306a36Sopenharmony_ci 550262306a36Sopenharmony_ci if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { 550362306a36Sopenharmony_ci this_pid = hdspm->playback_pid; 550462306a36Sopenharmony_ci other_pid = hdspm->capture_pid; 550562306a36Sopenharmony_ci } else { 550662306a36Sopenharmony_ci this_pid = hdspm->capture_pid; 550762306a36Sopenharmony_ci other_pid = hdspm->playback_pid; 550862306a36Sopenharmony_ci } 550962306a36Sopenharmony_ci 551062306a36Sopenharmony_ci if (other_pid > 0 && this_pid != other_pid) { 551162306a36Sopenharmony_ci 551262306a36Sopenharmony_ci /* The other stream is open, and not by the same 551362306a36Sopenharmony_ci task as this one. Make sure that the parameters 551462306a36Sopenharmony_ci that matter are the same. 551562306a36Sopenharmony_ci */ 551662306a36Sopenharmony_ci 551762306a36Sopenharmony_ci if (params_rate(params) != hdspm->system_sample_rate) { 551862306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 551962306a36Sopenharmony_ci _snd_pcm_hw_param_setempty(params, 552062306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE); 552162306a36Sopenharmony_ci return -EBUSY; 552262306a36Sopenharmony_ci } 552362306a36Sopenharmony_ci 552462306a36Sopenharmony_ci if (params_period_size(params) != hdspm->period_bytes / 4) { 552562306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 552662306a36Sopenharmony_ci _snd_pcm_hw_param_setempty(params, 552762306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 552862306a36Sopenharmony_ci return -EBUSY; 552962306a36Sopenharmony_ci } 553062306a36Sopenharmony_ci 553162306a36Sopenharmony_ci } 553262306a36Sopenharmony_ci /* We're fine. */ 553362306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 553462306a36Sopenharmony_ci 553562306a36Sopenharmony_ci /* how to make sure that the rate matches an externally-set one ? */ 553662306a36Sopenharmony_ci 553762306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 553862306a36Sopenharmony_ci err = hdspm_set_rate(hdspm, params_rate(params), 0); 553962306a36Sopenharmony_ci if (err < 0) { 554062306a36Sopenharmony_ci dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err); 554162306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 554262306a36Sopenharmony_ci _snd_pcm_hw_param_setempty(params, 554362306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE); 554462306a36Sopenharmony_ci return err; 554562306a36Sopenharmony_ci } 554662306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 554762306a36Sopenharmony_ci 554862306a36Sopenharmony_ci err = hdspm_set_interrupt_interval(hdspm, 554962306a36Sopenharmony_ci params_period_size(params)); 555062306a36Sopenharmony_ci if (err < 0) { 555162306a36Sopenharmony_ci dev_info(hdspm->card->dev, 555262306a36Sopenharmony_ci "err on hdspm_set_interrupt_interval: %d\n", err); 555362306a36Sopenharmony_ci _snd_pcm_hw_param_setempty(params, 555462306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 555562306a36Sopenharmony_ci return err; 555662306a36Sopenharmony_ci } 555762306a36Sopenharmony_ci 555862306a36Sopenharmony_ci /* Memory allocation, takashi's method, dont know if we should 555962306a36Sopenharmony_ci * spinlock 556062306a36Sopenharmony_ci */ 556162306a36Sopenharmony_ci /* malloc all buffer even if not enabled to get sure */ 556262306a36Sopenharmony_ci /* Update for MADI rev 204: we need to allocate for all channels, 556362306a36Sopenharmony_ci * otherwise it doesn't work at 96kHz */ 556462306a36Sopenharmony_ci 556562306a36Sopenharmony_ci err = 556662306a36Sopenharmony_ci snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES); 556762306a36Sopenharmony_ci if (err < 0) { 556862306a36Sopenharmony_ci dev_info(hdspm->card->dev, 556962306a36Sopenharmony_ci "err on snd_pcm_lib_malloc_pages: %d\n", err); 557062306a36Sopenharmony_ci return err; 557162306a36Sopenharmony_ci } 557262306a36Sopenharmony_ci 557362306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 557462306a36Sopenharmony_ci 557562306a36Sopenharmony_ci for (i = 0; i < params_channels(params); ++i) { 557662306a36Sopenharmony_ci int c = hdspm->channel_map_out[i]; 557762306a36Sopenharmony_ci 557862306a36Sopenharmony_ci if (c < 0) 557962306a36Sopenharmony_ci continue; /* just make sure */ 558062306a36Sopenharmony_ci hdspm_set_channel_dma_addr(hdspm, substream, 558162306a36Sopenharmony_ci HDSPM_pageAddressBufferOut, 558262306a36Sopenharmony_ci c); 558362306a36Sopenharmony_ci snd_hdspm_enable_out(hdspm, c, 1); 558462306a36Sopenharmony_ci } 558562306a36Sopenharmony_ci 558662306a36Sopenharmony_ci hdspm->playback_buffer = 558762306a36Sopenharmony_ci (unsigned char *) substream->runtime->dma_area; 558862306a36Sopenharmony_ci dev_dbg(hdspm->card->dev, 558962306a36Sopenharmony_ci "Allocated sample buffer for playback at %p\n", 559062306a36Sopenharmony_ci hdspm->playback_buffer); 559162306a36Sopenharmony_ci } else { 559262306a36Sopenharmony_ci for (i = 0; i < params_channels(params); ++i) { 559362306a36Sopenharmony_ci int c = hdspm->channel_map_in[i]; 559462306a36Sopenharmony_ci 559562306a36Sopenharmony_ci if (c < 0) 559662306a36Sopenharmony_ci continue; 559762306a36Sopenharmony_ci hdspm_set_channel_dma_addr(hdspm, substream, 559862306a36Sopenharmony_ci HDSPM_pageAddressBufferIn, 559962306a36Sopenharmony_ci c); 560062306a36Sopenharmony_ci snd_hdspm_enable_in(hdspm, c, 1); 560162306a36Sopenharmony_ci } 560262306a36Sopenharmony_ci 560362306a36Sopenharmony_ci hdspm->capture_buffer = 560462306a36Sopenharmony_ci (unsigned char *) substream->runtime->dma_area; 560562306a36Sopenharmony_ci dev_dbg(hdspm->card->dev, 560662306a36Sopenharmony_ci "Allocated sample buffer for capture at %p\n", 560762306a36Sopenharmony_ci hdspm->capture_buffer); 560862306a36Sopenharmony_ci } 560962306a36Sopenharmony_ci 561062306a36Sopenharmony_ci /* 561162306a36Sopenharmony_ci dev_dbg(hdspm->card->dev, 561262306a36Sopenharmony_ci "Allocated sample buffer for %s at 0x%08X\n", 561362306a36Sopenharmony_ci substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 561462306a36Sopenharmony_ci "playback" : "capture", 561562306a36Sopenharmony_ci snd_pcm_sgbuf_get_addr(substream, 0)); 561662306a36Sopenharmony_ci */ 561762306a36Sopenharmony_ci /* 561862306a36Sopenharmony_ci dev_dbg(hdspm->card->dev, 561962306a36Sopenharmony_ci "set_hwparams: %s %d Hz, %d channels, bs = %d\n", 562062306a36Sopenharmony_ci substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 562162306a36Sopenharmony_ci "playback" : "capture", 562262306a36Sopenharmony_ci params_rate(params), params_channels(params), 562362306a36Sopenharmony_ci params_buffer_size(params)); 562462306a36Sopenharmony_ci */ 562562306a36Sopenharmony_ci 562662306a36Sopenharmony_ci 562762306a36Sopenharmony_ci /* For AES cards, the float format bit is the same as the 562862306a36Sopenharmony_ci * preferred sync reference. Since we don't want to break 562962306a36Sopenharmony_ci * sync settings, we have to skip the remaining part of this 563062306a36Sopenharmony_ci * function. 563162306a36Sopenharmony_ci */ 563262306a36Sopenharmony_ci if (hdspm->io_type == AES32) { 563362306a36Sopenharmony_ci return 0; 563462306a36Sopenharmony_ci } 563562306a36Sopenharmony_ci 563662306a36Sopenharmony_ci 563762306a36Sopenharmony_ci /* Switch to native float format if requested */ 563862306a36Sopenharmony_ci if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) { 563962306a36Sopenharmony_ci if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT)) 564062306a36Sopenharmony_ci dev_info(hdspm->card->dev, 564162306a36Sopenharmony_ci "Switching to native 32bit LE float format.\n"); 564262306a36Sopenharmony_ci 564362306a36Sopenharmony_ci hdspm->control_register |= HDSPe_FLOAT_FORMAT; 564462306a36Sopenharmony_ci } else if (SNDRV_PCM_FORMAT_S32_LE == params_format(params)) { 564562306a36Sopenharmony_ci if (hdspm->control_register & HDSPe_FLOAT_FORMAT) 564662306a36Sopenharmony_ci dev_info(hdspm->card->dev, 564762306a36Sopenharmony_ci "Switching to native 32bit LE integer format.\n"); 564862306a36Sopenharmony_ci 564962306a36Sopenharmony_ci hdspm->control_register &= ~HDSPe_FLOAT_FORMAT; 565062306a36Sopenharmony_ci } 565162306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); 565262306a36Sopenharmony_ci 565362306a36Sopenharmony_ci return 0; 565462306a36Sopenharmony_ci} 565562306a36Sopenharmony_ci 565662306a36Sopenharmony_cistatic int snd_hdspm_hw_free(struct snd_pcm_substream *substream) 565762306a36Sopenharmony_ci{ 565862306a36Sopenharmony_ci int i; 565962306a36Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 566062306a36Sopenharmony_ci 566162306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 566262306a36Sopenharmony_ci /* Just disable all channels. The saving when disabling a */ 566362306a36Sopenharmony_ci /* smaller set is not worth the trouble. */ 566462306a36Sopenharmony_ci for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) 566562306a36Sopenharmony_ci snd_hdspm_enable_out(hdspm, i, 0); 566662306a36Sopenharmony_ci 566762306a36Sopenharmony_ci hdspm->playback_buffer = NULL; 566862306a36Sopenharmony_ci } else { 566962306a36Sopenharmony_ci for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) 567062306a36Sopenharmony_ci snd_hdspm_enable_in(hdspm, i, 0); 567162306a36Sopenharmony_ci 567262306a36Sopenharmony_ci hdspm->capture_buffer = NULL; 567362306a36Sopenharmony_ci } 567462306a36Sopenharmony_ci 567562306a36Sopenharmony_ci snd_pcm_lib_free_pages(substream); 567662306a36Sopenharmony_ci 567762306a36Sopenharmony_ci return 0; 567862306a36Sopenharmony_ci} 567962306a36Sopenharmony_ci 568062306a36Sopenharmony_ci 568162306a36Sopenharmony_cistatic int snd_hdspm_channel_info(struct snd_pcm_substream *substream, 568262306a36Sopenharmony_ci struct snd_pcm_channel_info *info) 568362306a36Sopenharmony_ci{ 568462306a36Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 568562306a36Sopenharmony_ci unsigned int channel = info->channel; 568662306a36Sopenharmony_ci 568762306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 568862306a36Sopenharmony_ci if (snd_BUG_ON(channel >= hdspm->max_channels_out)) { 568962306a36Sopenharmony_ci dev_info(hdspm->card->dev, 569062306a36Sopenharmony_ci "snd_hdspm_channel_info: output channel out of range (%d)\n", 569162306a36Sopenharmony_ci channel); 569262306a36Sopenharmony_ci return -EINVAL; 569362306a36Sopenharmony_ci } 569462306a36Sopenharmony_ci 569562306a36Sopenharmony_ci channel = array_index_nospec(channel, hdspm->max_channels_out); 569662306a36Sopenharmony_ci if (hdspm->channel_map_out[channel] < 0) { 569762306a36Sopenharmony_ci dev_info(hdspm->card->dev, 569862306a36Sopenharmony_ci "snd_hdspm_channel_info: output channel %d mapped out\n", 569962306a36Sopenharmony_ci channel); 570062306a36Sopenharmony_ci return -EINVAL; 570162306a36Sopenharmony_ci } 570262306a36Sopenharmony_ci 570362306a36Sopenharmony_ci info->offset = hdspm->channel_map_out[channel] * 570462306a36Sopenharmony_ci HDSPM_CHANNEL_BUFFER_BYTES; 570562306a36Sopenharmony_ci } else { 570662306a36Sopenharmony_ci if (snd_BUG_ON(channel >= hdspm->max_channels_in)) { 570762306a36Sopenharmony_ci dev_info(hdspm->card->dev, 570862306a36Sopenharmony_ci "snd_hdspm_channel_info: input channel out of range (%d)\n", 570962306a36Sopenharmony_ci channel); 571062306a36Sopenharmony_ci return -EINVAL; 571162306a36Sopenharmony_ci } 571262306a36Sopenharmony_ci 571362306a36Sopenharmony_ci channel = array_index_nospec(channel, hdspm->max_channels_in); 571462306a36Sopenharmony_ci if (hdspm->channel_map_in[channel] < 0) { 571562306a36Sopenharmony_ci dev_info(hdspm->card->dev, 571662306a36Sopenharmony_ci "snd_hdspm_channel_info: input channel %d mapped out\n", 571762306a36Sopenharmony_ci channel); 571862306a36Sopenharmony_ci return -EINVAL; 571962306a36Sopenharmony_ci } 572062306a36Sopenharmony_ci 572162306a36Sopenharmony_ci info->offset = hdspm->channel_map_in[channel] * 572262306a36Sopenharmony_ci HDSPM_CHANNEL_BUFFER_BYTES; 572362306a36Sopenharmony_ci } 572462306a36Sopenharmony_ci 572562306a36Sopenharmony_ci info->first = 0; 572662306a36Sopenharmony_ci info->step = 32; 572762306a36Sopenharmony_ci return 0; 572862306a36Sopenharmony_ci} 572962306a36Sopenharmony_ci 573062306a36Sopenharmony_ci 573162306a36Sopenharmony_cistatic int snd_hdspm_ioctl(struct snd_pcm_substream *substream, 573262306a36Sopenharmony_ci unsigned int cmd, void *arg) 573362306a36Sopenharmony_ci{ 573462306a36Sopenharmony_ci switch (cmd) { 573562306a36Sopenharmony_ci case SNDRV_PCM_IOCTL1_RESET: 573662306a36Sopenharmony_ci return snd_hdspm_reset(substream); 573762306a36Sopenharmony_ci 573862306a36Sopenharmony_ci case SNDRV_PCM_IOCTL1_CHANNEL_INFO: 573962306a36Sopenharmony_ci { 574062306a36Sopenharmony_ci struct snd_pcm_channel_info *info = arg; 574162306a36Sopenharmony_ci return snd_hdspm_channel_info(substream, info); 574262306a36Sopenharmony_ci } 574362306a36Sopenharmony_ci default: 574462306a36Sopenharmony_ci break; 574562306a36Sopenharmony_ci } 574662306a36Sopenharmony_ci 574762306a36Sopenharmony_ci return snd_pcm_lib_ioctl(substream, cmd, arg); 574862306a36Sopenharmony_ci} 574962306a36Sopenharmony_ci 575062306a36Sopenharmony_cistatic int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd) 575162306a36Sopenharmony_ci{ 575262306a36Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 575362306a36Sopenharmony_ci struct snd_pcm_substream *other; 575462306a36Sopenharmony_ci int running; 575562306a36Sopenharmony_ci 575662306a36Sopenharmony_ci spin_lock(&hdspm->lock); 575762306a36Sopenharmony_ci running = hdspm->running; 575862306a36Sopenharmony_ci switch (cmd) { 575962306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 576062306a36Sopenharmony_ci running |= 1 << substream->stream; 576162306a36Sopenharmony_ci break; 576262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 576362306a36Sopenharmony_ci running &= ~(1 << substream->stream); 576462306a36Sopenharmony_ci break; 576562306a36Sopenharmony_ci default: 576662306a36Sopenharmony_ci snd_BUG(); 576762306a36Sopenharmony_ci spin_unlock(&hdspm->lock); 576862306a36Sopenharmony_ci return -EINVAL; 576962306a36Sopenharmony_ci } 577062306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 577162306a36Sopenharmony_ci other = hdspm->capture_substream; 577262306a36Sopenharmony_ci else 577362306a36Sopenharmony_ci other = hdspm->playback_substream; 577462306a36Sopenharmony_ci 577562306a36Sopenharmony_ci if (other) { 577662306a36Sopenharmony_ci struct snd_pcm_substream *s; 577762306a36Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 577862306a36Sopenharmony_ci if (s == other) { 577962306a36Sopenharmony_ci snd_pcm_trigger_done(s, substream); 578062306a36Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) 578162306a36Sopenharmony_ci running |= 1 << s->stream; 578262306a36Sopenharmony_ci else 578362306a36Sopenharmony_ci running &= ~(1 << s->stream); 578462306a36Sopenharmony_ci goto _ok; 578562306a36Sopenharmony_ci } 578662306a36Sopenharmony_ci } 578762306a36Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) { 578862306a36Sopenharmony_ci if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) 578962306a36Sopenharmony_ci && substream->stream == 579062306a36Sopenharmony_ci SNDRV_PCM_STREAM_CAPTURE) 579162306a36Sopenharmony_ci hdspm_silence_playback(hdspm); 579262306a36Sopenharmony_ci } else { 579362306a36Sopenharmony_ci if (running && 579462306a36Sopenharmony_ci substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 579562306a36Sopenharmony_ci hdspm_silence_playback(hdspm); 579662306a36Sopenharmony_ci } 579762306a36Sopenharmony_ci } else { 579862306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 579962306a36Sopenharmony_ci hdspm_silence_playback(hdspm); 580062306a36Sopenharmony_ci } 580162306a36Sopenharmony_ci_ok: 580262306a36Sopenharmony_ci snd_pcm_trigger_done(substream, substream); 580362306a36Sopenharmony_ci if (!hdspm->running && running) 580462306a36Sopenharmony_ci hdspm_start_audio(hdspm); 580562306a36Sopenharmony_ci else if (hdspm->running && !running) 580662306a36Sopenharmony_ci hdspm_stop_audio(hdspm); 580762306a36Sopenharmony_ci hdspm->running = running; 580862306a36Sopenharmony_ci spin_unlock(&hdspm->lock); 580962306a36Sopenharmony_ci 581062306a36Sopenharmony_ci return 0; 581162306a36Sopenharmony_ci} 581262306a36Sopenharmony_ci 581362306a36Sopenharmony_cistatic int snd_hdspm_prepare(struct snd_pcm_substream *substream) 581462306a36Sopenharmony_ci{ 581562306a36Sopenharmony_ci return 0; 581662306a36Sopenharmony_ci} 581762306a36Sopenharmony_ci 581862306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_hdspm_playback_subinfo = { 581962306a36Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 582062306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 582162306a36Sopenharmony_ci SNDRV_PCM_INFO_NONINTERLEAVED | 582262306a36Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_DOUBLE), 582362306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 582462306a36Sopenharmony_ci .rates = (SNDRV_PCM_RATE_32000 | 582562306a36Sopenharmony_ci SNDRV_PCM_RATE_44100 | 582662306a36Sopenharmony_ci SNDRV_PCM_RATE_48000 | 582762306a36Sopenharmony_ci SNDRV_PCM_RATE_64000 | 582862306a36Sopenharmony_ci SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 582962306a36Sopenharmony_ci SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ), 583062306a36Sopenharmony_ci .rate_min = 32000, 583162306a36Sopenharmony_ci .rate_max = 192000, 583262306a36Sopenharmony_ci .channels_min = 1, 583362306a36Sopenharmony_ci .channels_max = HDSPM_MAX_CHANNELS, 583462306a36Sopenharmony_ci .buffer_bytes_max = 583562306a36Sopenharmony_ci HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, 583662306a36Sopenharmony_ci .period_bytes_min = (32 * 4), 583762306a36Sopenharmony_ci .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, 583862306a36Sopenharmony_ci .periods_min = 2, 583962306a36Sopenharmony_ci .periods_max = 512, 584062306a36Sopenharmony_ci .fifo_size = 0 584162306a36Sopenharmony_ci}; 584262306a36Sopenharmony_ci 584362306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_hdspm_capture_subinfo = { 584462306a36Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 584562306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 584662306a36Sopenharmony_ci SNDRV_PCM_INFO_NONINTERLEAVED | 584762306a36Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START), 584862306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 584962306a36Sopenharmony_ci .rates = (SNDRV_PCM_RATE_32000 | 585062306a36Sopenharmony_ci SNDRV_PCM_RATE_44100 | 585162306a36Sopenharmony_ci SNDRV_PCM_RATE_48000 | 585262306a36Sopenharmony_ci SNDRV_PCM_RATE_64000 | 585362306a36Sopenharmony_ci SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 585462306a36Sopenharmony_ci SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000), 585562306a36Sopenharmony_ci .rate_min = 32000, 585662306a36Sopenharmony_ci .rate_max = 192000, 585762306a36Sopenharmony_ci .channels_min = 1, 585862306a36Sopenharmony_ci .channels_max = HDSPM_MAX_CHANNELS, 585962306a36Sopenharmony_ci .buffer_bytes_max = 586062306a36Sopenharmony_ci HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, 586162306a36Sopenharmony_ci .period_bytes_min = (32 * 4), 586262306a36Sopenharmony_ci .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, 586362306a36Sopenharmony_ci .periods_min = 2, 586462306a36Sopenharmony_ci .periods_max = 512, 586562306a36Sopenharmony_ci .fifo_size = 0 586662306a36Sopenharmony_ci}; 586762306a36Sopenharmony_ci 586862306a36Sopenharmony_cistatic int snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params, 586962306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 587062306a36Sopenharmony_ci{ 587162306a36Sopenharmony_ci struct hdspm *hdspm = rule->private; 587262306a36Sopenharmony_ci struct snd_interval *c = 587362306a36Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 587462306a36Sopenharmony_ci struct snd_interval *r = 587562306a36Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 587662306a36Sopenharmony_ci 587762306a36Sopenharmony_ci if (r->min > 96000 && r->max <= 192000) { 587862306a36Sopenharmony_ci struct snd_interval t = { 587962306a36Sopenharmony_ci .min = hdspm->qs_in_channels, 588062306a36Sopenharmony_ci .max = hdspm->qs_in_channels, 588162306a36Sopenharmony_ci .integer = 1, 588262306a36Sopenharmony_ci }; 588362306a36Sopenharmony_ci return snd_interval_refine(c, &t); 588462306a36Sopenharmony_ci } else if (r->min > 48000 && r->max <= 96000) { 588562306a36Sopenharmony_ci struct snd_interval t = { 588662306a36Sopenharmony_ci .min = hdspm->ds_in_channels, 588762306a36Sopenharmony_ci .max = hdspm->ds_in_channels, 588862306a36Sopenharmony_ci .integer = 1, 588962306a36Sopenharmony_ci }; 589062306a36Sopenharmony_ci return snd_interval_refine(c, &t); 589162306a36Sopenharmony_ci } else if (r->max < 64000) { 589262306a36Sopenharmony_ci struct snd_interval t = { 589362306a36Sopenharmony_ci .min = hdspm->ss_in_channels, 589462306a36Sopenharmony_ci .max = hdspm->ss_in_channels, 589562306a36Sopenharmony_ci .integer = 1, 589662306a36Sopenharmony_ci }; 589762306a36Sopenharmony_ci return snd_interval_refine(c, &t); 589862306a36Sopenharmony_ci } 589962306a36Sopenharmony_ci 590062306a36Sopenharmony_ci return 0; 590162306a36Sopenharmony_ci} 590262306a36Sopenharmony_ci 590362306a36Sopenharmony_cistatic int snd_hdspm_hw_rule_out_channels_rate(struct snd_pcm_hw_params *params, 590462306a36Sopenharmony_ci struct snd_pcm_hw_rule * rule) 590562306a36Sopenharmony_ci{ 590662306a36Sopenharmony_ci struct hdspm *hdspm = rule->private; 590762306a36Sopenharmony_ci struct snd_interval *c = 590862306a36Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 590962306a36Sopenharmony_ci struct snd_interval *r = 591062306a36Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 591162306a36Sopenharmony_ci 591262306a36Sopenharmony_ci if (r->min > 96000 && r->max <= 192000) { 591362306a36Sopenharmony_ci struct snd_interval t = { 591462306a36Sopenharmony_ci .min = hdspm->qs_out_channels, 591562306a36Sopenharmony_ci .max = hdspm->qs_out_channels, 591662306a36Sopenharmony_ci .integer = 1, 591762306a36Sopenharmony_ci }; 591862306a36Sopenharmony_ci return snd_interval_refine(c, &t); 591962306a36Sopenharmony_ci } else if (r->min > 48000 && r->max <= 96000) { 592062306a36Sopenharmony_ci struct snd_interval t = { 592162306a36Sopenharmony_ci .min = hdspm->ds_out_channels, 592262306a36Sopenharmony_ci .max = hdspm->ds_out_channels, 592362306a36Sopenharmony_ci .integer = 1, 592462306a36Sopenharmony_ci }; 592562306a36Sopenharmony_ci return snd_interval_refine(c, &t); 592662306a36Sopenharmony_ci } else if (r->max < 64000) { 592762306a36Sopenharmony_ci struct snd_interval t = { 592862306a36Sopenharmony_ci .min = hdspm->ss_out_channels, 592962306a36Sopenharmony_ci .max = hdspm->ss_out_channels, 593062306a36Sopenharmony_ci .integer = 1, 593162306a36Sopenharmony_ci }; 593262306a36Sopenharmony_ci return snd_interval_refine(c, &t); 593362306a36Sopenharmony_ci } else { 593462306a36Sopenharmony_ci } 593562306a36Sopenharmony_ci return 0; 593662306a36Sopenharmony_ci} 593762306a36Sopenharmony_ci 593862306a36Sopenharmony_cistatic int snd_hdspm_hw_rule_rate_in_channels(struct snd_pcm_hw_params *params, 593962306a36Sopenharmony_ci struct snd_pcm_hw_rule * rule) 594062306a36Sopenharmony_ci{ 594162306a36Sopenharmony_ci struct hdspm *hdspm = rule->private; 594262306a36Sopenharmony_ci struct snd_interval *c = 594362306a36Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 594462306a36Sopenharmony_ci struct snd_interval *r = 594562306a36Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 594662306a36Sopenharmony_ci 594762306a36Sopenharmony_ci if (c->min >= hdspm->ss_in_channels) { 594862306a36Sopenharmony_ci struct snd_interval t = { 594962306a36Sopenharmony_ci .min = 32000, 595062306a36Sopenharmony_ci .max = 48000, 595162306a36Sopenharmony_ci .integer = 1, 595262306a36Sopenharmony_ci }; 595362306a36Sopenharmony_ci return snd_interval_refine(r, &t); 595462306a36Sopenharmony_ci } else if (c->max <= hdspm->qs_in_channels) { 595562306a36Sopenharmony_ci struct snd_interval t = { 595662306a36Sopenharmony_ci .min = 128000, 595762306a36Sopenharmony_ci .max = 192000, 595862306a36Sopenharmony_ci .integer = 1, 595962306a36Sopenharmony_ci }; 596062306a36Sopenharmony_ci return snd_interval_refine(r, &t); 596162306a36Sopenharmony_ci } else if (c->max <= hdspm->ds_in_channels) { 596262306a36Sopenharmony_ci struct snd_interval t = { 596362306a36Sopenharmony_ci .min = 64000, 596462306a36Sopenharmony_ci .max = 96000, 596562306a36Sopenharmony_ci .integer = 1, 596662306a36Sopenharmony_ci }; 596762306a36Sopenharmony_ci return snd_interval_refine(r, &t); 596862306a36Sopenharmony_ci } 596962306a36Sopenharmony_ci 597062306a36Sopenharmony_ci return 0; 597162306a36Sopenharmony_ci} 597262306a36Sopenharmony_cistatic int snd_hdspm_hw_rule_rate_out_channels(struct snd_pcm_hw_params *params, 597362306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 597462306a36Sopenharmony_ci{ 597562306a36Sopenharmony_ci struct hdspm *hdspm = rule->private; 597662306a36Sopenharmony_ci struct snd_interval *c = 597762306a36Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 597862306a36Sopenharmony_ci struct snd_interval *r = 597962306a36Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 598062306a36Sopenharmony_ci 598162306a36Sopenharmony_ci if (c->min >= hdspm->ss_out_channels) { 598262306a36Sopenharmony_ci struct snd_interval t = { 598362306a36Sopenharmony_ci .min = 32000, 598462306a36Sopenharmony_ci .max = 48000, 598562306a36Sopenharmony_ci .integer = 1, 598662306a36Sopenharmony_ci }; 598762306a36Sopenharmony_ci return snd_interval_refine(r, &t); 598862306a36Sopenharmony_ci } else if (c->max <= hdspm->qs_out_channels) { 598962306a36Sopenharmony_ci struct snd_interval t = { 599062306a36Sopenharmony_ci .min = 128000, 599162306a36Sopenharmony_ci .max = 192000, 599262306a36Sopenharmony_ci .integer = 1, 599362306a36Sopenharmony_ci }; 599462306a36Sopenharmony_ci return snd_interval_refine(r, &t); 599562306a36Sopenharmony_ci } else if (c->max <= hdspm->ds_out_channels) { 599662306a36Sopenharmony_ci struct snd_interval t = { 599762306a36Sopenharmony_ci .min = 64000, 599862306a36Sopenharmony_ci .max = 96000, 599962306a36Sopenharmony_ci .integer = 1, 600062306a36Sopenharmony_ci }; 600162306a36Sopenharmony_ci return snd_interval_refine(r, &t); 600262306a36Sopenharmony_ci } 600362306a36Sopenharmony_ci 600462306a36Sopenharmony_ci return 0; 600562306a36Sopenharmony_ci} 600662306a36Sopenharmony_ci 600762306a36Sopenharmony_cistatic int snd_hdspm_hw_rule_in_channels(struct snd_pcm_hw_params *params, 600862306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 600962306a36Sopenharmony_ci{ 601062306a36Sopenharmony_ci unsigned int list[3]; 601162306a36Sopenharmony_ci struct hdspm *hdspm = rule->private; 601262306a36Sopenharmony_ci struct snd_interval *c = hw_param_interval(params, 601362306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS); 601462306a36Sopenharmony_ci 601562306a36Sopenharmony_ci list[0] = hdspm->qs_in_channels; 601662306a36Sopenharmony_ci list[1] = hdspm->ds_in_channels; 601762306a36Sopenharmony_ci list[2] = hdspm->ss_in_channels; 601862306a36Sopenharmony_ci return snd_interval_list(c, 3, list, 0); 601962306a36Sopenharmony_ci} 602062306a36Sopenharmony_ci 602162306a36Sopenharmony_cistatic int snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params *params, 602262306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 602362306a36Sopenharmony_ci{ 602462306a36Sopenharmony_ci unsigned int list[3]; 602562306a36Sopenharmony_ci struct hdspm *hdspm = rule->private; 602662306a36Sopenharmony_ci struct snd_interval *c = hw_param_interval(params, 602762306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS); 602862306a36Sopenharmony_ci 602962306a36Sopenharmony_ci list[0] = hdspm->qs_out_channels; 603062306a36Sopenharmony_ci list[1] = hdspm->ds_out_channels; 603162306a36Sopenharmony_ci list[2] = hdspm->ss_out_channels; 603262306a36Sopenharmony_ci return snd_interval_list(c, 3, list, 0); 603362306a36Sopenharmony_ci} 603462306a36Sopenharmony_ci 603562306a36Sopenharmony_ci 603662306a36Sopenharmony_cistatic const unsigned int hdspm_aes32_sample_rates[] = { 603762306a36Sopenharmony_ci 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 603862306a36Sopenharmony_ci}; 603962306a36Sopenharmony_ci 604062306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list 604162306a36Sopenharmony_cihdspm_hw_constraints_aes32_sample_rates = { 604262306a36Sopenharmony_ci .count = ARRAY_SIZE(hdspm_aes32_sample_rates), 604362306a36Sopenharmony_ci .list = hdspm_aes32_sample_rates, 604462306a36Sopenharmony_ci .mask = 0 604562306a36Sopenharmony_ci}; 604662306a36Sopenharmony_ci 604762306a36Sopenharmony_cistatic int snd_hdspm_open(struct snd_pcm_substream *substream) 604862306a36Sopenharmony_ci{ 604962306a36Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 605062306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 605162306a36Sopenharmony_ci bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 605262306a36Sopenharmony_ci 605362306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 605462306a36Sopenharmony_ci snd_pcm_set_sync(substream); 605562306a36Sopenharmony_ci runtime->hw = (playback) ? snd_hdspm_playback_subinfo : 605662306a36Sopenharmony_ci snd_hdspm_capture_subinfo; 605762306a36Sopenharmony_ci 605862306a36Sopenharmony_ci if (playback) { 605962306a36Sopenharmony_ci if (!hdspm->capture_substream) 606062306a36Sopenharmony_ci hdspm_stop_audio(hdspm); 606162306a36Sopenharmony_ci 606262306a36Sopenharmony_ci hdspm->playback_pid = current->pid; 606362306a36Sopenharmony_ci hdspm->playback_substream = substream; 606462306a36Sopenharmony_ci } else { 606562306a36Sopenharmony_ci if (!hdspm->playback_substream) 606662306a36Sopenharmony_ci hdspm_stop_audio(hdspm); 606762306a36Sopenharmony_ci 606862306a36Sopenharmony_ci hdspm->capture_pid = current->pid; 606962306a36Sopenharmony_ci hdspm->capture_substream = substream; 607062306a36Sopenharmony_ci } 607162306a36Sopenharmony_ci 607262306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 607362306a36Sopenharmony_ci 607462306a36Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 607562306a36Sopenharmony_ci snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 607662306a36Sopenharmony_ci 607762306a36Sopenharmony_ci switch (hdspm->io_type) { 607862306a36Sopenharmony_ci case AIO: 607962306a36Sopenharmony_ci case RayDAT: 608062306a36Sopenharmony_ci snd_pcm_hw_constraint_minmax(runtime, 608162306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 608262306a36Sopenharmony_ci 32, 4096); 608362306a36Sopenharmony_ci /* RayDAT & AIO have a fixed buffer of 16384 samples per channel */ 608462306a36Sopenharmony_ci snd_pcm_hw_constraint_single(runtime, 608562306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 608662306a36Sopenharmony_ci 16384); 608762306a36Sopenharmony_ci break; 608862306a36Sopenharmony_ci 608962306a36Sopenharmony_ci default: 609062306a36Sopenharmony_ci snd_pcm_hw_constraint_minmax(runtime, 609162306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 609262306a36Sopenharmony_ci 64, 8192); 609362306a36Sopenharmony_ci snd_pcm_hw_constraint_single(runtime, 609462306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS, 2); 609562306a36Sopenharmony_ci break; 609662306a36Sopenharmony_ci } 609762306a36Sopenharmony_ci 609862306a36Sopenharmony_ci if (AES32 == hdspm->io_type) { 609962306a36Sopenharmony_ci runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; 610062306a36Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 610162306a36Sopenharmony_ci &hdspm_hw_constraints_aes32_sample_rates); 610262306a36Sopenharmony_ci } else { 610362306a36Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 610462306a36Sopenharmony_ci (playback ? 610562306a36Sopenharmony_ci snd_hdspm_hw_rule_rate_out_channels : 610662306a36Sopenharmony_ci snd_hdspm_hw_rule_rate_in_channels), hdspm, 610762306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 610862306a36Sopenharmony_ci } 610962306a36Sopenharmony_ci 611062306a36Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 611162306a36Sopenharmony_ci (playback ? snd_hdspm_hw_rule_out_channels : 611262306a36Sopenharmony_ci snd_hdspm_hw_rule_in_channels), hdspm, 611362306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 611462306a36Sopenharmony_ci 611562306a36Sopenharmony_ci snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 611662306a36Sopenharmony_ci (playback ? snd_hdspm_hw_rule_out_channels_rate : 611762306a36Sopenharmony_ci snd_hdspm_hw_rule_in_channels_rate), hdspm, 611862306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, -1); 611962306a36Sopenharmony_ci 612062306a36Sopenharmony_ci return 0; 612162306a36Sopenharmony_ci} 612262306a36Sopenharmony_ci 612362306a36Sopenharmony_cistatic int snd_hdspm_release(struct snd_pcm_substream *substream) 612462306a36Sopenharmony_ci{ 612562306a36Sopenharmony_ci struct hdspm *hdspm = snd_pcm_substream_chip(substream); 612662306a36Sopenharmony_ci bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 612762306a36Sopenharmony_ci 612862306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 612962306a36Sopenharmony_ci 613062306a36Sopenharmony_ci if (playback) { 613162306a36Sopenharmony_ci hdspm->playback_pid = -1; 613262306a36Sopenharmony_ci hdspm->playback_substream = NULL; 613362306a36Sopenharmony_ci } else { 613462306a36Sopenharmony_ci hdspm->capture_pid = -1; 613562306a36Sopenharmony_ci hdspm->capture_substream = NULL; 613662306a36Sopenharmony_ci } 613762306a36Sopenharmony_ci 613862306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 613962306a36Sopenharmony_ci 614062306a36Sopenharmony_ci return 0; 614162306a36Sopenharmony_ci} 614262306a36Sopenharmony_ci 614362306a36Sopenharmony_cistatic int snd_hdspm_hwdep_dummy_op(struct snd_hwdep *hw, struct file *file) 614462306a36Sopenharmony_ci{ 614562306a36Sopenharmony_ci /* we have nothing to initialize but the call is required */ 614662306a36Sopenharmony_ci return 0; 614762306a36Sopenharmony_ci} 614862306a36Sopenharmony_ci 614962306a36Sopenharmony_cistatic int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, 615062306a36Sopenharmony_ci unsigned int cmd, unsigned long arg) 615162306a36Sopenharmony_ci{ 615262306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 615362306a36Sopenharmony_ci struct hdspm *hdspm = hw->private_data; 615462306a36Sopenharmony_ci struct hdspm_mixer_ioctl mixer; 615562306a36Sopenharmony_ci struct hdspm_config info; 615662306a36Sopenharmony_ci struct hdspm_status status; 615762306a36Sopenharmony_ci struct hdspm_version hdspm_version; 615862306a36Sopenharmony_ci struct hdspm_peak_rms *levels; 615962306a36Sopenharmony_ci struct hdspm_ltc ltc; 616062306a36Sopenharmony_ci unsigned int statusregister; 616162306a36Sopenharmony_ci long unsigned int s; 616262306a36Sopenharmony_ci int i = 0; 616362306a36Sopenharmony_ci 616462306a36Sopenharmony_ci switch (cmd) { 616562306a36Sopenharmony_ci 616662306a36Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS: 616762306a36Sopenharmony_ci levels = &hdspm->peak_rms; 616862306a36Sopenharmony_ci for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { 616962306a36Sopenharmony_ci levels->input_peaks[i] = 617062306a36Sopenharmony_ci readl(hdspm->iobase + 617162306a36Sopenharmony_ci HDSPM_MADI_INPUT_PEAK + i*4); 617262306a36Sopenharmony_ci levels->playback_peaks[i] = 617362306a36Sopenharmony_ci readl(hdspm->iobase + 617462306a36Sopenharmony_ci HDSPM_MADI_PLAYBACK_PEAK + i*4); 617562306a36Sopenharmony_ci levels->output_peaks[i] = 617662306a36Sopenharmony_ci readl(hdspm->iobase + 617762306a36Sopenharmony_ci HDSPM_MADI_OUTPUT_PEAK + i*4); 617862306a36Sopenharmony_ci 617962306a36Sopenharmony_ci levels->input_rms[i] = 618062306a36Sopenharmony_ci ((uint64_t) readl(hdspm->iobase + 618162306a36Sopenharmony_ci HDSPM_MADI_INPUT_RMS_H + i*4) << 32) | 618262306a36Sopenharmony_ci (uint64_t) readl(hdspm->iobase + 618362306a36Sopenharmony_ci HDSPM_MADI_INPUT_RMS_L + i*4); 618462306a36Sopenharmony_ci levels->playback_rms[i] = 618562306a36Sopenharmony_ci ((uint64_t)readl(hdspm->iobase + 618662306a36Sopenharmony_ci HDSPM_MADI_PLAYBACK_RMS_H+i*4) << 32) | 618762306a36Sopenharmony_ci (uint64_t)readl(hdspm->iobase + 618862306a36Sopenharmony_ci HDSPM_MADI_PLAYBACK_RMS_L + i*4); 618962306a36Sopenharmony_ci levels->output_rms[i] = 619062306a36Sopenharmony_ci ((uint64_t)readl(hdspm->iobase + 619162306a36Sopenharmony_ci HDSPM_MADI_OUTPUT_RMS_H + i*4) << 32) | 619262306a36Sopenharmony_ci (uint64_t)readl(hdspm->iobase + 619362306a36Sopenharmony_ci HDSPM_MADI_OUTPUT_RMS_L + i*4); 619462306a36Sopenharmony_ci } 619562306a36Sopenharmony_ci 619662306a36Sopenharmony_ci if (hdspm->system_sample_rate > 96000) { 619762306a36Sopenharmony_ci levels->speed = qs; 619862306a36Sopenharmony_ci } else if (hdspm->system_sample_rate > 48000) { 619962306a36Sopenharmony_ci levels->speed = ds; 620062306a36Sopenharmony_ci } else { 620162306a36Sopenharmony_ci levels->speed = ss; 620262306a36Sopenharmony_ci } 620362306a36Sopenharmony_ci levels->status2 = hdspm_read(hdspm, HDSPM_statusRegister2); 620462306a36Sopenharmony_ci 620562306a36Sopenharmony_ci s = copy_to_user(argp, levels, sizeof(*levels)); 620662306a36Sopenharmony_ci if (0 != s) { 620762306a36Sopenharmony_ci /* dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu 620862306a36Sopenharmony_ci [Levels]\n", sizeof(struct hdspm_peak_rms), s); 620962306a36Sopenharmony_ci */ 621062306a36Sopenharmony_ci return -EFAULT; 621162306a36Sopenharmony_ci } 621262306a36Sopenharmony_ci break; 621362306a36Sopenharmony_ci 621462306a36Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_LTC: 621562306a36Sopenharmony_ci ltc.ltc = hdspm_read(hdspm, HDSPM_RD_TCO); 621662306a36Sopenharmony_ci i = hdspm_read(hdspm, HDSPM_RD_TCO + 4); 621762306a36Sopenharmony_ci if (i & HDSPM_TCO1_LTC_Input_valid) { 621862306a36Sopenharmony_ci switch (i & (HDSPM_TCO1_LTC_Format_LSB | 621962306a36Sopenharmony_ci HDSPM_TCO1_LTC_Format_MSB)) { 622062306a36Sopenharmony_ci case 0: 622162306a36Sopenharmony_ci ltc.format = fps_24; 622262306a36Sopenharmony_ci break; 622362306a36Sopenharmony_ci case HDSPM_TCO1_LTC_Format_LSB: 622462306a36Sopenharmony_ci ltc.format = fps_25; 622562306a36Sopenharmony_ci break; 622662306a36Sopenharmony_ci case HDSPM_TCO1_LTC_Format_MSB: 622762306a36Sopenharmony_ci ltc.format = fps_2997; 622862306a36Sopenharmony_ci break; 622962306a36Sopenharmony_ci default: 623062306a36Sopenharmony_ci ltc.format = fps_30; 623162306a36Sopenharmony_ci break; 623262306a36Sopenharmony_ci } 623362306a36Sopenharmony_ci if (i & HDSPM_TCO1_set_drop_frame_flag) { 623462306a36Sopenharmony_ci ltc.frame = drop_frame; 623562306a36Sopenharmony_ci } else { 623662306a36Sopenharmony_ci ltc.frame = full_frame; 623762306a36Sopenharmony_ci } 623862306a36Sopenharmony_ci } else { 623962306a36Sopenharmony_ci ltc.format = format_invalid; 624062306a36Sopenharmony_ci ltc.frame = frame_invalid; 624162306a36Sopenharmony_ci } 624262306a36Sopenharmony_ci if (i & HDSPM_TCO1_Video_Input_Format_NTSC) { 624362306a36Sopenharmony_ci ltc.input_format = ntsc; 624462306a36Sopenharmony_ci } else if (i & HDSPM_TCO1_Video_Input_Format_PAL) { 624562306a36Sopenharmony_ci ltc.input_format = pal; 624662306a36Sopenharmony_ci } else { 624762306a36Sopenharmony_ci ltc.input_format = no_video; 624862306a36Sopenharmony_ci } 624962306a36Sopenharmony_ci 625062306a36Sopenharmony_ci s = copy_to_user(argp, <c, sizeof(ltc)); 625162306a36Sopenharmony_ci if (0 != s) { 625262306a36Sopenharmony_ci /* 625362306a36Sopenharmony_ci dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */ 625462306a36Sopenharmony_ci return -EFAULT; 625562306a36Sopenharmony_ci } 625662306a36Sopenharmony_ci 625762306a36Sopenharmony_ci break; 625862306a36Sopenharmony_ci 625962306a36Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_CONFIG: 626062306a36Sopenharmony_ci 626162306a36Sopenharmony_ci memset(&info, 0, sizeof(info)); 626262306a36Sopenharmony_ci spin_lock_irq(&hdspm->lock); 626362306a36Sopenharmony_ci info.pref_sync_ref = hdspm_pref_sync_ref(hdspm); 626462306a36Sopenharmony_ci info.wordclock_sync_check = hdspm_wc_sync_check(hdspm); 626562306a36Sopenharmony_ci 626662306a36Sopenharmony_ci info.system_sample_rate = hdspm->system_sample_rate; 626762306a36Sopenharmony_ci info.autosync_sample_rate = 626862306a36Sopenharmony_ci hdspm_external_sample_rate(hdspm); 626962306a36Sopenharmony_ci info.system_clock_mode = hdspm_system_clock_mode(hdspm); 627062306a36Sopenharmony_ci info.clock_source = hdspm_clock_source(hdspm); 627162306a36Sopenharmony_ci info.autosync_ref = hdspm_autosync_ref(hdspm); 627262306a36Sopenharmony_ci info.line_out = hdspm_toggle_setting(hdspm, HDSPM_LineOut); 627362306a36Sopenharmony_ci info.passthru = 0; 627462306a36Sopenharmony_ci spin_unlock_irq(&hdspm->lock); 627562306a36Sopenharmony_ci if (copy_to_user(argp, &info, sizeof(info))) 627662306a36Sopenharmony_ci return -EFAULT; 627762306a36Sopenharmony_ci break; 627862306a36Sopenharmony_ci 627962306a36Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_STATUS: 628062306a36Sopenharmony_ci memset(&status, 0, sizeof(status)); 628162306a36Sopenharmony_ci 628262306a36Sopenharmony_ci status.card_type = hdspm->io_type; 628362306a36Sopenharmony_ci 628462306a36Sopenharmony_ci status.autosync_source = hdspm_autosync_ref(hdspm); 628562306a36Sopenharmony_ci 628662306a36Sopenharmony_ci status.card_clock = 110069313433624ULL; 628762306a36Sopenharmony_ci status.master_period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); 628862306a36Sopenharmony_ci 628962306a36Sopenharmony_ci switch (hdspm->io_type) { 629062306a36Sopenharmony_ci case MADI: 629162306a36Sopenharmony_ci case MADIface: 629262306a36Sopenharmony_ci status.card_specific.madi.sync_wc = 629362306a36Sopenharmony_ci hdspm_wc_sync_check(hdspm); 629462306a36Sopenharmony_ci status.card_specific.madi.sync_madi = 629562306a36Sopenharmony_ci hdspm_madi_sync_check(hdspm); 629662306a36Sopenharmony_ci status.card_specific.madi.sync_tco = 629762306a36Sopenharmony_ci hdspm_tco_sync_check(hdspm); 629862306a36Sopenharmony_ci status.card_specific.madi.sync_in = 629962306a36Sopenharmony_ci hdspm_sync_in_sync_check(hdspm); 630062306a36Sopenharmony_ci 630162306a36Sopenharmony_ci statusregister = 630262306a36Sopenharmony_ci hdspm_read(hdspm, HDSPM_statusRegister); 630362306a36Sopenharmony_ci status.card_specific.madi.madi_input = 630462306a36Sopenharmony_ci (statusregister & HDSPM_AB_int) ? 1 : 0; 630562306a36Sopenharmony_ci status.card_specific.madi.channel_format = 630662306a36Sopenharmony_ci (statusregister & HDSPM_RX_64ch) ? 1 : 0; 630762306a36Sopenharmony_ci /* TODO: Mac driver sets it when f_s>48kHz */ 630862306a36Sopenharmony_ci status.card_specific.madi.frame_format = 0; 630962306a36Sopenharmony_ci break; 631062306a36Sopenharmony_ci 631162306a36Sopenharmony_ci default: 631262306a36Sopenharmony_ci break; 631362306a36Sopenharmony_ci } 631462306a36Sopenharmony_ci 631562306a36Sopenharmony_ci if (copy_to_user(argp, &status, sizeof(status))) 631662306a36Sopenharmony_ci return -EFAULT; 631762306a36Sopenharmony_ci 631862306a36Sopenharmony_ci 631962306a36Sopenharmony_ci break; 632062306a36Sopenharmony_ci 632162306a36Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_VERSION: 632262306a36Sopenharmony_ci memset(&hdspm_version, 0, sizeof(hdspm_version)); 632362306a36Sopenharmony_ci 632462306a36Sopenharmony_ci hdspm_version.card_type = hdspm->io_type; 632562306a36Sopenharmony_ci strscpy(hdspm_version.cardname, hdspm->card_name, 632662306a36Sopenharmony_ci sizeof(hdspm_version.cardname)); 632762306a36Sopenharmony_ci hdspm_version.serial = hdspm->serial; 632862306a36Sopenharmony_ci hdspm_version.firmware_rev = hdspm->firmware_rev; 632962306a36Sopenharmony_ci hdspm_version.addons = 0; 633062306a36Sopenharmony_ci if (hdspm->tco) 633162306a36Sopenharmony_ci hdspm_version.addons |= HDSPM_ADDON_TCO; 633262306a36Sopenharmony_ci 633362306a36Sopenharmony_ci if (copy_to_user(argp, &hdspm_version, 633462306a36Sopenharmony_ci sizeof(hdspm_version))) 633562306a36Sopenharmony_ci return -EFAULT; 633662306a36Sopenharmony_ci break; 633762306a36Sopenharmony_ci 633862306a36Sopenharmony_ci case SNDRV_HDSPM_IOCTL_GET_MIXER: 633962306a36Sopenharmony_ci if (copy_from_user(&mixer, argp, sizeof(mixer))) 634062306a36Sopenharmony_ci return -EFAULT; 634162306a36Sopenharmony_ci if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer, 634262306a36Sopenharmony_ci sizeof(*mixer.mixer))) 634362306a36Sopenharmony_ci return -EFAULT; 634462306a36Sopenharmony_ci break; 634562306a36Sopenharmony_ci 634662306a36Sopenharmony_ci default: 634762306a36Sopenharmony_ci return -EINVAL; 634862306a36Sopenharmony_ci } 634962306a36Sopenharmony_ci return 0; 635062306a36Sopenharmony_ci} 635162306a36Sopenharmony_ci 635262306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_hdspm_ops = { 635362306a36Sopenharmony_ci .open = snd_hdspm_open, 635462306a36Sopenharmony_ci .close = snd_hdspm_release, 635562306a36Sopenharmony_ci .ioctl = snd_hdspm_ioctl, 635662306a36Sopenharmony_ci .hw_params = snd_hdspm_hw_params, 635762306a36Sopenharmony_ci .hw_free = snd_hdspm_hw_free, 635862306a36Sopenharmony_ci .prepare = snd_hdspm_prepare, 635962306a36Sopenharmony_ci .trigger = snd_hdspm_trigger, 636062306a36Sopenharmony_ci .pointer = snd_hdspm_hw_pointer, 636162306a36Sopenharmony_ci}; 636262306a36Sopenharmony_ci 636362306a36Sopenharmony_cistatic int snd_hdspm_create_hwdep(struct snd_card *card, 636462306a36Sopenharmony_ci struct hdspm *hdspm) 636562306a36Sopenharmony_ci{ 636662306a36Sopenharmony_ci struct snd_hwdep *hw; 636762306a36Sopenharmony_ci int err; 636862306a36Sopenharmony_ci 636962306a36Sopenharmony_ci err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw); 637062306a36Sopenharmony_ci if (err < 0) 637162306a36Sopenharmony_ci return err; 637262306a36Sopenharmony_ci 637362306a36Sopenharmony_ci hdspm->hwdep = hw; 637462306a36Sopenharmony_ci hw->private_data = hdspm; 637562306a36Sopenharmony_ci strcpy(hw->name, "HDSPM hwdep interface"); 637662306a36Sopenharmony_ci 637762306a36Sopenharmony_ci hw->ops.open = snd_hdspm_hwdep_dummy_op; 637862306a36Sopenharmony_ci hw->ops.ioctl = snd_hdspm_hwdep_ioctl; 637962306a36Sopenharmony_ci hw->ops.ioctl_compat = snd_hdspm_hwdep_ioctl; 638062306a36Sopenharmony_ci hw->ops.release = snd_hdspm_hwdep_dummy_op; 638162306a36Sopenharmony_ci 638262306a36Sopenharmony_ci return 0; 638362306a36Sopenharmony_ci} 638462306a36Sopenharmony_ci 638562306a36Sopenharmony_ci 638662306a36Sopenharmony_ci/*------------------------------------------------------------ 638762306a36Sopenharmony_ci memory interface 638862306a36Sopenharmony_ci ------------------------------------------------------------*/ 638962306a36Sopenharmony_cistatic int snd_hdspm_preallocate_memory(struct hdspm *hdspm) 639062306a36Sopenharmony_ci{ 639162306a36Sopenharmony_ci struct snd_pcm *pcm; 639262306a36Sopenharmony_ci size_t wanted; 639362306a36Sopenharmony_ci 639462306a36Sopenharmony_ci pcm = hdspm->pcm; 639562306a36Sopenharmony_ci 639662306a36Sopenharmony_ci wanted = HDSPM_DMA_AREA_BYTES; 639762306a36Sopenharmony_ci 639862306a36Sopenharmony_ci snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, 639962306a36Sopenharmony_ci &hdspm->pci->dev, 640062306a36Sopenharmony_ci wanted, wanted); 640162306a36Sopenharmony_ci dev_dbg(hdspm->card->dev, " Preallocated %zd Bytes\n", wanted); 640262306a36Sopenharmony_ci return 0; 640362306a36Sopenharmony_ci} 640462306a36Sopenharmony_ci 640562306a36Sopenharmony_ci/* Inform the card what DMA addresses to use for the indicated channel. */ 640662306a36Sopenharmony_ci/* Each channel got 16 4K pages allocated for DMA transfers. */ 640762306a36Sopenharmony_cistatic void hdspm_set_channel_dma_addr(struct hdspm *hdspm, 640862306a36Sopenharmony_ci struct snd_pcm_substream *substream, 640962306a36Sopenharmony_ci unsigned int reg, int channel) 641062306a36Sopenharmony_ci{ 641162306a36Sopenharmony_ci int i; 641262306a36Sopenharmony_ci 641362306a36Sopenharmony_ci for (i = channel * 16; i < channel * 16 + 16; i++) 641462306a36Sopenharmony_ci hdspm_write(hdspm, reg + 4 * i, 641562306a36Sopenharmony_ci snd_pcm_sgbuf_get_addr(substream, 4096 * i)); 641662306a36Sopenharmony_ci} 641762306a36Sopenharmony_ci 641862306a36Sopenharmony_ci 641962306a36Sopenharmony_ci/* ------------- ALSA Devices ---------------------------- */ 642062306a36Sopenharmony_cistatic int snd_hdspm_create_pcm(struct snd_card *card, 642162306a36Sopenharmony_ci struct hdspm *hdspm) 642262306a36Sopenharmony_ci{ 642362306a36Sopenharmony_ci struct snd_pcm *pcm; 642462306a36Sopenharmony_ci int err; 642562306a36Sopenharmony_ci 642662306a36Sopenharmony_ci err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm); 642762306a36Sopenharmony_ci if (err < 0) 642862306a36Sopenharmony_ci return err; 642962306a36Sopenharmony_ci 643062306a36Sopenharmony_ci hdspm->pcm = pcm; 643162306a36Sopenharmony_ci pcm->private_data = hdspm; 643262306a36Sopenharmony_ci strcpy(pcm->name, hdspm->card_name); 643362306a36Sopenharmony_ci 643462306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 643562306a36Sopenharmony_ci &snd_hdspm_ops); 643662306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 643762306a36Sopenharmony_ci &snd_hdspm_ops); 643862306a36Sopenharmony_ci 643962306a36Sopenharmony_ci pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; 644062306a36Sopenharmony_ci 644162306a36Sopenharmony_ci err = snd_hdspm_preallocate_memory(hdspm); 644262306a36Sopenharmony_ci if (err < 0) 644362306a36Sopenharmony_ci return err; 644462306a36Sopenharmony_ci 644562306a36Sopenharmony_ci return 0; 644662306a36Sopenharmony_ci} 644762306a36Sopenharmony_ci 644862306a36Sopenharmony_cistatic inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm) 644962306a36Sopenharmony_ci{ 645062306a36Sopenharmony_ci int i; 645162306a36Sopenharmony_ci 645262306a36Sopenharmony_ci for (i = 0; i < hdspm->midiPorts; i++) 645362306a36Sopenharmony_ci snd_hdspm_flush_midi_input(hdspm, i); 645462306a36Sopenharmony_ci} 645562306a36Sopenharmony_ci 645662306a36Sopenharmony_cistatic int snd_hdspm_create_alsa_devices(struct snd_card *card, 645762306a36Sopenharmony_ci struct hdspm *hdspm) 645862306a36Sopenharmony_ci{ 645962306a36Sopenharmony_ci int err, i; 646062306a36Sopenharmony_ci 646162306a36Sopenharmony_ci dev_dbg(card->dev, "Create card...\n"); 646262306a36Sopenharmony_ci err = snd_hdspm_create_pcm(card, hdspm); 646362306a36Sopenharmony_ci if (err < 0) 646462306a36Sopenharmony_ci return err; 646562306a36Sopenharmony_ci 646662306a36Sopenharmony_ci i = 0; 646762306a36Sopenharmony_ci while (i < hdspm->midiPorts) { 646862306a36Sopenharmony_ci err = snd_hdspm_create_midi(card, hdspm, i); 646962306a36Sopenharmony_ci if (err < 0) { 647062306a36Sopenharmony_ci return err; 647162306a36Sopenharmony_ci } 647262306a36Sopenharmony_ci i++; 647362306a36Sopenharmony_ci } 647462306a36Sopenharmony_ci 647562306a36Sopenharmony_ci err = snd_hdspm_create_controls(card, hdspm); 647662306a36Sopenharmony_ci if (err < 0) 647762306a36Sopenharmony_ci return err; 647862306a36Sopenharmony_ci 647962306a36Sopenharmony_ci err = snd_hdspm_create_hwdep(card, hdspm); 648062306a36Sopenharmony_ci if (err < 0) 648162306a36Sopenharmony_ci return err; 648262306a36Sopenharmony_ci 648362306a36Sopenharmony_ci dev_dbg(card->dev, "proc init...\n"); 648462306a36Sopenharmony_ci snd_hdspm_proc_init(hdspm); 648562306a36Sopenharmony_ci 648662306a36Sopenharmony_ci hdspm->system_sample_rate = -1; 648762306a36Sopenharmony_ci hdspm->last_external_sample_rate = -1; 648862306a36Sopenharmony_ci hdspm->last_internal_sample_rate = -1; 648962306a36Sopenharmony_ci hdspm->playback_pid = -1; 649062306a36Sopenharmony_ci hdspm->capture_pid = -1; 649162306a36Sopenharmony_ci hdspm->capture_substream = NULL; 649262306a36Sopenharmony_ci hdspm->playback_substream = NULL; 649362306a36Sopenharmony_ci 649462306a36Sopenharmony_ci dev_dbg(card->dev, "Set defaults...\n"); 649562306a36Sopenharmony_ci err = snd_hdspm_set_defaults(hdspm); 649662306a36Sopenharmony_ci if (err < 0) 649762306a36Sopenharmony_ci return err; 649862306a36Sopenharmony_ci 649962306a36Sopenharmony_ci dev_dbg(card->dev, "Update mixer controls...\n"); 650062306a36Sopenharmony_ci hdspm_update_simple_mixer_controls(hdspm); 650162306a36Sopenharmony_ci 650262306a36Sopenharmony_ci dev_dbg(card->dev, "Initializing complete?\n"); 650362306a36Sopenharmony_ci 650462306a36Sopenharmony_ci err = snd_card_register(card); 650562306a36Sopenharmony_ci if (err < 0) { 650662306a36Sopenharmony_ci dev_err(card->dev, "error registering card\n"); 650762306a36Sopenharmony_ci return err; 650862306a36Sopenharmony_ci } 650962306a36Sopenharmony_ci 651062306a36Sopenharmony_ci dev_dbg(card->dev, "... yes now\n"); 651162306a36Sopenharmony_ci 651262306a36Sopenharmony_ci return 0; 651362306a36Sopenharmony_ci} 651462306a36Sopenharmony_ci 651562306a36Sopenharmony_cistatic int snd_hdspm_create(struct snd_card *card, 651662306a36Sopenharmony_ci struct hdspm *hdspm) 651762306a36Sopenharmony_ci{ 651862306a36Sopenharmony_ci 651962306a36Sopenharmony_ci struct pci_dev *pci = hdspm->pci; 652062306a36Sopenharmony_ci int err; 652162306a36Sopenharmony_ci unsigned long io_extent; 652262306a36Sopenharmony_ci 652362306a36Sopenharmony_ci hdspm->irq = -1; 652462306a36Sopenharmony_ci hdspm->card = card; 652562306a36Sopenharmony_ci 652662306a36Sopenharmony_ci spin_lock_init(&hdspm->lock); 652762306a36Sopenharmony_ci INIT_WORK(&hdspm->midi_work, hdspm_midi_work); 652862306a36Sopenharmony_ci 652962306a36Sopenharmony_ci pci_read_config_word(hdspm->pci, 653062306a36Sopenharmony_ci PCI_CLASS_REVISION, &hdspm->firmware_rev); 653162306a36Sopenharmony_ci 653262306a36Sopenharmony_ci strcpy(card->mixername, "Xilinx FPGA"); 653362306a36Sopenharmony_ci strcpy(card->driver, "HDSPM"); 653462306a36Sopenharmony_ci 653562306a36Sopenharmony_ci switch (hdspm->firmware_rev) { 653662306a36Sopenharmony_ci case HDSPM_RAYDAT_REV: 653762306a36Sopenharmony_ci hdspm->io_type = RayDAT; 653862306a36Sopenharmony_ci hdspm->card_name = "RME RayDAT"; 653962306a36Sopenharmony_ci hdspm->midiPorts = 2; 654062306a36Sopenharmony_ci break; 654162306a36Sopenharmony_ci case HDSPM_AIO_REV: 654262306a36Sopenharmony_ci hdspm->io_type = AIO; 654362306a36Sopenharmony_ci hdspm->card_name = "RME AIO"; 654462306a36Sopenharmony_ci hdspm->midiPorts = 1; 654562306a36Sopenharmony_ci break; 654662306a36Sopenharmony_ci case HDSPM_MADIFACE_REV: 654762306a36Sopenharmony_ci hdspm->io_type = MADIface; 654862306a36Sopenharmony_ci hdspm->card_name = "RME MADIface"; 654962306a36Sopenharmony_ci hdspm->midiPorts = 1; 655062306a36Sopenharmony_ci break; 655162306a36Sopenharmony_ci default: 655262306a36Sopenharmony_ci if ((hdspm->firmware_rev == 0xf0) || 655362306a36Sopenharmony_ci ((hdspm->firmware_rev >= 0xe6) && 655462306a36Sopenharmony_ci (hdspm->firmware_rev <= 0xea))) { 655562306a36Sopenharmony_ci hdspm->io_type = AES32; 655662306a36Sopenharmony_ci hdspm->card_name = "RME AES32"; 655762306a36Sopenharmony_ci hdspm->midiPorts = 2; 655862306a36Sopenharmony_ci } else if ((hdspm->firmware_rev == 0xd2) || 655962306a36Sopenharmony_ci ((hdspm->firmware_rev >= 0xc8) && 656062306a36Sopenharmony_ci (hdspm->firmware_rev <= 0xcf))) { 656162306a36Sopenharmony_ci hdspm->io_type = MADI; 656262306a36Sopenharmony_ci hdspm->card_name = "RME MADI"; 656362306a36Sopenharmony_ci hdspm->midiPorts = 3; 656462306a36Sopenharmony_ci } else { 656562306a36Sopenharmony_ci dev_err(card->dev, 656662306a36Sopenharmony_ci "unknown firmware revision %x\n", 656762306a36Sopenharmony_ci hdspm->firmware_rev); 656862306a36Sopenharmony_ci return -ENODEV; 656962306a36Sopenharmony_ci } 657062306a36Sopenharmony_ci } 657162306a36Sopenharmony_ci 657262306a36Sopenharmony_ci err = pcim_enable_device(pci); 657362306a36Sopenharmony_ci if (err < 0) 657462306a36Sopenharmony_ci return err; 657562306a36Sopenharmony_ci 657662306a36Sopenharmony_ci pci_set_master(hdspm->pci); 657762306a36Sopenharmony_ci 657862306a36Sopenharmony_ci err = pcim_iomap_regions(pci, 1 << 0, "hdspm"); 657962306a36Sopenharmony_ci if (err < 0) 658062306a36Sopenharmony_ci return err; 658162306a36Sopenharmony_ci 658262306a36Sopenharmony_ci hdspm->port = pci_resource_start(pci, 0); 658362306a36Sopenharmony_ci io_extent = pci_resource_len(pci, 0); 658462306a36Sopenharmony_ci hdspm->iobase = pcim_iomap_table(pci)[0]; 658562306a36Sopenharmony_ci dev_dbg(card->dev, "remapped region (0x%lx) 0x%lx-0x%lx\n", 658662306a36Sopenharmony_ci (unsigned long)hdspm->iobase, hdspm->port, 658762306a36Sopenharmony_ci hdspm->port + io_extent - 1); 658862306a36Sopenharmony_ci 658962306a36Sopenharmony_ci if (devm_request_irq(&pci->dev, pci->irq, snd_hdspm_interrupt, 659062306a36Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, hdspm)) { 659162306a36Sopenharmony_ci dev_err(card->dev, "unable to use IRQ %d\n", pci->irq); 659262306a36Sopenharmony_ci return -EBUSY; 659362306a36Sopenharmony_ci } 659462306a36Sopenharmony_ci 659562306a36Sopenharmony_ci dev_dbg(card->dev, "use IRQ %d\n", pci->irq); 659662306a36Sopenharmony_ci 659762306a36Sopenharmony_ci hdspm->irq = pci->irq; 659862306a36Sopenharmony_ci card->sync_irq = hdspm->irq; 659962306a36Sopenharmony_ci 660062306a36Sopenharmony_ci dev_dbg(card->dev, "kmalloc Mixer memory of %zd Bytes\n", 660162306a36Sopenharmony_ci sizeof(*hdspm->mixer)); 660262306a36Sopenharmony_ci hdspm->mixer = devm_kzalloc(&pci->dev, sizeof(*hdspm->mixer), GFP_KERNEL); 660362306a36Sopenharmony_ci if (!hdspm->mixer) 660462306a36Sopenharmony_ci return -ENOMEM; 660562306a36Sopenharmony_ci 660662306a36Sopenharmony_ci hdspm->port_names_in = NULL; 660762306a36Sopenharmony_ci hdspm->port_names_out = NULL; 660862306a36Sopenharmony_ci 660962306a36Sopenharmony_ci switch (hdspm->io_type) { 661062306a36Sopenharmony_ci case AES32: 661162306a36Sopenharmony_ci hdspm->ss_in_channels = hdspm->ss_out_channels = AES32_CHANNELS; 661262306a36Sopenharmony_ci hdspm->ds_in_channels = hdspm->ds_out_channels = AES32_CHANNELS; 661362306a36Sopenharmony_ci hdspm->qs_in_channels = hdspm->qs_out_channels = AES32_CHANNELS; 661462306a36Sopenharmony_ci 661562306a36Sopenharmony_ci hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 661662306a36Sopenharmony_ci channel_map_aes32; 661762306a36Sopenharmony_ci hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 661862306a36Sopenharmony_ci channel_map_aes32; 661962306a36Sopenharmony_ci hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 662062306a36Sopenharmony_ci channel_map_aes32; 662162306a36Sopenharmony_ci hdspm->port_names_in_ss = hdspm->port_names_out_ss = 662262306a36Sopenharmony_ci texts_ports_aes32; 662362306a36Sopenharmony_ci hdspm->port_names_in_ds = hdspm->port_names_out_ds = 662462306a36Sopenharmony_ci texts_ports_aes32; 662562306a36Sopenharmony_ci hdspm->port_names_in_qs = hdspm->port_names_out_qs = 662662306a36Sopenharmony_ci texts_ports_aes32; 662762306a36Sopenharmony_ci 662862306a36Sopenharmony_ci hdspm->max_channels_out = hdspm->max_channels_in = 662962306a36Sopenharmony_ci AES32_CHANNELS; 663062306a36Sopenharmony_ci hdspm->port_names_in = hdspm->port_names_out = 663162306a36Sopenharmony_ci texts_ports_aes32; 663262306a36Sopenharmony_ci hdspm->channel_map_in = hdspm->channel_map_out = 663362306a36Sopenharmony_ci channel_map_aes32; 663462306a36Sopenharmony_ci 663562306a36Sopenharmony_ci break; 663662306a36Sopenharmony_ci 663762306a36Sopenharmony_ci case MADI: 663862306a36Sopenharmony_ci case MADIface: 663962306a36Sopenharmony_ci hdspm->ss_in_channels = hdspm->ss_out_channels = 664062306a36Sopenharmony_ci MADI_SS_CHANNELS; 664162306a36Sopenharmony_ci hdspm->ds_in_channels = hdspm->ds_out_channels = 664262306a36Sopenharmony_ci MADI_DS_CHANNELS; 664362306a36Sopenharmony_ci hdspm->qs_in_channels = hdspm->qs_out_channels = 664462306a36Sopenharmony_ci MADI_QS_CHANNELS; 664562306a36Sopenharmony_ci 664662306a36Sopenharmony_ci hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 664762306a36Sopenharmony_ci channel_map_unity_ss; 664862306a36Sopenharmony_ci hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 664962306a36Sopenharmony_ci channel_map_unity_ss; 665062306a36Sopenharmony_ci hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 665162306a36Sopenharmony_ci channel_map_unity_ss; 665262306a36Sopenharmony_ci 665362306a36Sopenharmony_ci hdspm->port_names_in_ss = hdspm->port_names_out_ss = 665462306a36Sopenharmony_ci texts_ports_madi; 665562306a36Sopenharmony_ci hdspm->port_names_in_ds = hdspm->port_names_out_ds = 665662306a36Sopenharmony_ci texts_ports_madi; 665762306a36Sopenharmony_ci hdspm->port_names_in_qs = hdspm->port_names_out_qs = 665862306a36Sopenharmony_ci texts_ports_madi; 665962306a36Sopenharmony_ci break; 666062306a36Sopenharmony_ci 666162306a36Sopenharmony_ci case AIO: 666262306a36Sopenharmony_ci hdspm->ss_in_channels = AIO_IN_SS_CHANNELS; 666362306a36Sopenharmony_ci hdspm->ds_in_channels = AIO_IN_DS_CHANNELS; 666462306a36Sopenharmony_ci hdspm->qs_in_channels = AIO_IN_QS_CHANNELS; 666562306a36Sopenharmony_ci hdspm->ss_out_channels = AIO_OUT_SS_CHANNELS; 666662306a36Sopenharmony_ci hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS; 666762306a36Sopenharmony_ci hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS; 666862306a36Sopenharmony_ci 666962306a36Sopenharmony_ci if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { 667062306a36Sopenharmony_ci dev_info(card->dev, "AEB input board found\n"); 667162306a36Sopenharmony_ci hdspm->ss_in_channels += 4; 667262306a36Sopenharmony_ci hdspm->ds_in_channels += 4; 667362306a36Sopenharmony_ci hdspm->qs_in_channels += 4; 667462306a36Sopenharmony_ci } 667562306a36Sopenharmony_ci 667662306a36Sopenharmony_ci if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) { 667762306a36Sopenharmony_ci dev_info(card->dev, "AEB output board found\n"); 667862306a36Sopenharmony_ci hdspm->ss_out_channels += 4; 667962306a36Sopenharmony_ci hdspm->ds_out_channels += 4; 668062306a36Sopenharmony_ci hdspm->qs_out_channels += 4; 668162306a36Sopenharmony_ci } 668262306a36Sopenharmony_ci 668362306a36Sopenharmony_ci hdspm->channel_map_out_ss = channel_map_aio_out_ss; 668462306a36Sopenharmony_ci hdspm->channel_map_out_ds = channel_map_aio_out_ds; 668562306a36Sopenharmony_ci hdspm->channel_map_out_qs = channel_map_aio_out_qs; 668662306a36Sopenharmony_ci 668762306a36Sopenharmony_ci hdspm->channel_map_in_ss = channel_map_aio_in_ss; 668862306a36Sopenharmony_ci hdspm->channel_map_in_ds = channel_map_aio_in_ds; 668962306a36Sopenharmony_ci hdspm->channel_map_in_qs = channel_map_aio_in_qs; 669062306a36Sopenharmony_ci 669162306a36Sopenharmony_ci hdspm->port_names_in_ss = texts_ports_aio_in_ss; 669262306a36Sopenharmony_ci hdspm->port_names_out_ss = texts_ports_aio_out_ss; 669362306a36Sopenharmony_ci hdspm->port_names_in_ds = texts_ports_aio_in_ds; 669462306a36Sopenharmony_ci hdspm->port_names_out_ds = texts_ports_aio_out_ds; 669562306a36Sopenharmony_ci hdspm->port_names_in_qs = texts_ports_aio_in_qs; 669662306a36Sopenharmony_ci hdspm->port_names_out_qs = texts_ports_aio_out_qs; 669762306a36Sopenharmony_ci 669862306a36Sopenharmony_ci break; 669962306a36Sopenharmony_ci 670062306a36Sopenharmony_ci case RayDAT: 670162306a36Sopenharmony_ci hdspm->ss_in_channels = hdspm->ss_out_channels = 670262306a36Sopenharmony_ci RAYDAT_SS_CHANNELS; 670362306a36Sopenharmony_ci hdspm->ds_in_channels = hdspm->ds_out_channels = 670462306a36Sopenharmony_ci RAYDAT_DS_CHANNELS; 670562306a36Sopenharmony_ci hdspm->qs_in_channels = hdspm->qs_out_channels = 670662306a36Sopenharmony_ci RAYDAT_QS_CHANNELS; 670762306a36Sopenharmony_ci 670862306a36Sopenharmony_ci hdspm->max_channels_in = RAYDAT_SS_CHANNELS; 670962306a36Sopenharmony_ci hdspm->max_channels_out = RAYDAT_SS_CHANNELS; 671062306a36Sopenharmony_ci 671162306a36Sopenharmony_ci hdspm->channel_map_in_ss = hdspm->channel_map_out_ss = 671262306a36Sopenharmony_ci channel_map_raydat_ss; 671362306a36Sopenharmony_ci hdspm->channel_map_in_ds = hdspm->channel_map_out_ds = 671462306a36Sopenharmony_ci channel_map_raydat_ds; 671562306a36Sopenharmony_ci hdspm->channel_map_in_qs = hdspm->channel_map_out_qs = 671662306a36Sopenharmony_ci channel_map_raydat_qs; 671762306a36Sopenharmony_ci hdspm->channel_map_in = hdspm->channel_map_out = 671862306a36Sopenharmony_ci channel_map_raydat_ss; 671962306a36Sopenharmony_ci 672062306a36Sopenharmony_ci hdspm->port_names_in_ss = hdspm->port_names_out_ss = 672162306a36Sopenharmony_ci texts_ports_raydat_ss; 672262306a36Sopenharmony_ci hdspm->port_names_in_ds = hdspm->port_names_out_ds = 672362306a36Sopenharmony_ci texts_ports_raydat_ds; 672462306a36Sopenharmony_ci hdspm->port_names_in_qs = hdspm->port_names_out_qs = 672562306a36Sopenharmony_ci texts_ports_raydat_qs; 672662306a36Sopenharmony_ci 672762306a36Sopenharmony_ci 672862306a36Sopenharmony_ci break; 672962306a36Sopenharmony_ci 673062306a36Sopenharmony_ci } 673162306a36Sopenharmony_ci 673262306a36Sopenharmony_ci /* TCO detection */ 673362306a36Sopenharmony_ci switch (hdspm->io_type) { 673462306a36Sopenharmony_ci case AIO: 673562306a36Sopenharmony_ci case RayDAT: 673662306a36Sopenharmony_ci if (hdspm_read(hdspm, HDSPM_statusRegister2) & 673762306a36Sopenharmony_ci HDSPM_s2_tco_detect) { 673862306a36Sopenharmony_ci hdspm->midiPorts++; 673962306a36Sopenharmony_ci hdspm->tco = kzalloc(sizeof(*hdspm->tco), GFP_KERNEL); 674062306a36Sopenharmony_ci if (hdspm->tco) 674162306a36Sopenharmony_ci hdspm_tco_write(hdspm); 674262306a36Sopenharmony_ci 674362306a36Sopenharmony_ci dev_info(card->dev, "AIO/RayDAT TCO module found\n"); 674462306a36Sopenharmony_ci } else { 674562306a36Sopenharmony_ci hdspm->tco = NULL; 674662306a36Sopenharmony_ci } 674762306a36Sopenharmony_ci break; 674862306a36Sopenharmony_ci 674962306a36Sopenharmony_ci case MADI: 675062306a36Sopenharmony_ci case AES32: 675162306a36Sopenharmony_ci if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) { 675262306a36Sopenharmony_ci hdspm->midiPorts++; 675362306a36Sopenharmony_ci hdspm->tco = kzalloc(sizeof(*hdspm->tco), GFP_KERNEL); 675462306a36Sopenharmony_ci if (hdspm->tco) 675562306a36Sopenharmony_ci hdspm_tco_write(hdspm); 675662306a36Sopenharmony_ci 675762306a36Sopenharmony_ci dev_info(card->dev, "MADI/AES TCO module found\n"); 675862306a36Sopenharmony_ci } else { 675962306a36Sopenharmony_ci hdspm->tco = NULL; 676062306a36Sopenharmony_ci } 676162306a36Sopenharmony_ci break; 676262306a36Sopenharmony_ci 676362306a36Sopenharmony_ci default: 676462306a36Sopenharmony_ci hdspm->tco = NULL; 676562306a36Sopenharmony_ci } 676662306a36Sopenharmony_ci 676762306a36Sopenharmony_ci /* texts */ 676862306a36Sopenharmony_ci switch (hdspm->io_type) { 676962306a36Sopenharmony_ci case AES32: 677062306a36Sopenharmony_ci if (hdspm->tco) { 677162306a36Sopenharmony_ci hdspm->texts_autosync = texts_autosync_aes_tco; 677262306a36Sopenharmony_ci hdspm->texts_autosync_items = 677362306a36Sopenharmony_ci ARRAY_SIZE(texts_autosync_aes_tco); 677462306a36Sopenharmony_ci } else { 677562306a36Sopenharmony_ci hdspm->texts_autosync = texts_autosync_aes; 677662306a36Sopenharmony_ci hdspm->texts_autosync_items = 677762306a36Sopenharmony_ci ARRAY_SIZE(texts_autosync_aes); 677862306a36Sopenharmony_ci } 677962306a36Sopenharmony_ci break; 678062306a36Sopenharmony_ci 678162306a36Sopenharmony_ci case MADI: 678262306a36Sopenharmony_ci if (hdspm->tco) { 678362306a36Sopenharmony_ci hdspm->texts_autosync = texts_autosync_madi_tco; 678462306a36Sopenharmony_ci hdspm->texts_autosync_items = 4; 678562306a36Sopenharmony_ci } else { 678662306a36Sopenharmony_ci hdspm->texts_autosync = texts_autosync_madi; 678762306a36Sopenharmony_ci hdspm->texts_autosync_items = 3; 678862306a36Sopenharmony_ci } 678962306a36Sopenharmony_ci break; 679062306a36Sopenharmony_ci 679162306a36Sopenharmony_ci case MADIface: 679262306a36Sopenharmony_ci 679362306a36Sopenharmony_ci break; 679462306a36Sopenharmony_ci 679562306a36Sopenharmony_ci case RayDAT: 679662306a36Sopenharmony_ci if (hdspm->tco) { 679762306a36Sopenharmony_ci hdspm->texts_autosync = texts_autosync_raydat_tco; 679862306a36Sopenharmony_ci hdspm->texts_autosync_items = 9; 679962306a36Sopenharmony_ci } else { 680062306a36Sopenharmony_ci hdspm->texts_autosync = texts_autosync_raydat; 680162306a36Sopenharmony_ci hdspm->texts_autosync_items = 8; 680262306a36Sopenharmony_ci } 680362306a36Sopenharmony_ci break; 680462306a36Sopenharmony_ci 680562306a36Sopenharmony_ci case AIO: 680662306a36Sopenharmony_ci if (hdspm->tco) { 680762306a36Sopenharmony_ci hdspm->texts_autosync = texts_autosync_aio_tco; 680862306a36Sopenharmony_ci hdspm->texts_autosync_items = 6; 680962306a36Sopenharmony_ci } else { 681062306a36Sopenharmony_ci hdspm->texts_autosync = texts_autosync_aio; 681162306a36Sopenharmony_ci hdspm->texts_autosync_items = 5; 681262306a36Sopenharmony_ci } 681362306a36Sopenharmony_ci break; 681462306a36Sopenharmony_ci 681562306a36Sopenharmony_ci } 681662306a36Sopenharmony_ci 681762306a36Sopenharmony_ci if (hdspm->io_type != MADIface) { 681862306a36Sopenharmony_ci hdspm->serial = (hdspm_read(hdspm, 681962306a36Sopenharmony_ci HDSPM_midiStatusIn0)>>8) & 0xFFFFFF; 682062306a36Sopenharmony_ci /* id contains either a user-provided value or the default 682162306a36Sopenharmony_ci * NULL. If it's the default, we're safe to 682262306a36Sopenharmony_ci * fill card->id with the serial number. 682362306a36Sopenharmony_ci * 682462306a36Sopenharmony_ci * If the serial number is 0xFFFFFF, then we're dealing with 682562306a36Sopenharmony_ci * an old PCI revision that comes without a sane number. In 682662306a36Sopenharmony_ci * this case, we don't set card->id to avoid collisions 682762306a36Sopenharmony_ci * when running with multiple cards. 682862306a36Sopenharmony_ci */ 682962306a36Sopenharmony_ci if (!id[hdspm->dev] && hdspm->serial != 0xFFFFFF) { 683062306a36Sopenharmony_ci snprintf(card->id, sizeof(card->id), 683162306a36Sopenharmony_ci "HDSPMx%06x", hdspm->serial); 683262306a36Sopenharmony_ci snd_card_set_id(card, card->id); 683362306a36Sopenharmony_ci } 683462306a36Sopenharmony_ci } 683562306a36Sopenharmony_ci 683662306a36Sopenharmony_ci dev_dbg(card->dev, "create alsa devices.\n"); 683762306a36Sopenharmony_ci err = snd_hdspm_create_alsa_devices(card, hdspm); 683862306a36Sopenharmony_ci if (err < 0) 683962306a36Sopenharmony_ci return err; 684062306a36Sopenharmony_ci 684162306a36Sopenharmony_ci snd_hdspm_initialize_midi_flush(hdspm); 684262306a36Sopenharmony_ci 684362306a36Sopenharmony_ci return 0; 684462306a36Sopenharmony_ci} 684562306a36Sopenharmony_ci 684662306a36Sopenharmony_ci 684762306a36Sopenharmony_cistatic void snd_hdspm_card_free(struct snd_card *card) 684862306a36Sopenharmony_ci{ 684962306a36Sopenharmony_ci struct hdspm *hdspm = card->private_data; 685062306a36Sopenharmony_ci 685162306a36Sopenharmony_ci if (hdspm->port) { 685262306a36Sopenharmony_ci cancel_work_sync(&hdspm->midi_work); 685362306a36Sopenharmony_ci 685462306a36Sopenharmony_ci /* stop th audio, and cancel all interrupts */ 685562306a36Sopenharmony_ci hdspm->control_register &= 685662306a36Sopenharmony_ci ~(HDSPM_Start | HDSPM_AudioInterruptEnable | 685762306a36Sopenharmony_ci HDSPM_Midi0InterruptEnable | HDSPM_Midi1InterruptEnable | 685862306a36Sopenharmony_ci HDSPM_Midi2InterruptEnable | HDSPM_Midi3InterruptEnable); 685962306a36Sopenharmony_ci hdspm_write(hdspm, HDSPM_controlRegister, 686062306a36Sopenharmony_ci hdspm->control_register); 686162306a36Sopenharmony_ci } 686262306a36Sopenharmony_ci} 686362306a36Sopenharmony_ci 686462306a36Sopenharmony_ci 686562306a36Sopenharmony_cistatic int snd_hdspm_probe(struct pci_dev *pci, 686662306a36Sopenharmony_ci const struct pci_device_id *pci_id) 686762306a36Sopenharmony_ci{ 686862306a36Sopenharmony_ci static int dev; 686962306a36Sopenharmony_ci struct hdspm *hdspm; 687062306a36Sopenharmony_ci struct snd_card *card; 687162306a36Sopenharmony_ci int err; 687262306a36Sopenharmony_ci 687362306a36Sopenharmony_ci if (dev >= SNDRV_CARDS) 687462306a36Sopenharmony_ci return -ENODEV; 687562306a36Sopenharmony_ci if (!enable[dev]) { 687662306a36Sopenharmony_ci dev++; 687762306a36Sopenharmony_ci return -ENOENT; 687862306a36Sopenharmony_ci } 687962306a36Sopenharmony_ci 688062306a36Sopenharmony_ci err = snd_devm_card_new(&pci->dev, index[dev], id[dev], 688162306a36Sopenharmony_ci THIS_MODULE, sizeof(*hdspm), &card); 688262306a36Sopenharmony_ci if (err < 0) 688362306a36Sopenharmony_ci return err; 688462306a36Sopenharmony_ci 688562306a36Sopenharmony_ci hdspm = card->private_data; 688662306a36Sopenharmony_ci card->private_free = snd_hdspm_card_free; 688762306a36Sopenharmony_ci hdspm->dev = dev; 688862306a36Sopenharmony_ci hdspm->pci = pci; 688962306a36Sopenharmony_ci 689062306a36Sopenharmony_ci err = snd_hdspm_create(card, hdspm); 689162306a36Sopenharmony_ci if (err < 0) 689262306a36Sopenharmony_ci goto error; 689362306a36Sopenharmony_ci 689462306a36Sopenharmony_ci if (hdspm->io_type != MADIface) { 689562306a36Sopenharmony_ci snprintf(card->shortname, sizeof(card->shortname), "%s_%x", 689662306a36Sopenharmony_ci hdspm->card_name, hdspm->serial); 689762306a36Sopenharmony_ci snprintf(card->longname, sizeof(card->longname), 689862306a36Sopenharmony_ci "%s S/N 0x%x at 0x%lx, irq %d", 689962306a36Sopenharmony_ci hdspm->card_name, hdspm->serial, 690062306a36Sopenharmony_ci hdspm->port, hdspm->irq); 690162306a36Sopenharmony_ci } else { 690262306a36Sopenharmony_ci snprintf(card->shortname, sizeof(card->shortname), "%s", 690362306a36Sopenharmony_ci hdspm->card_name); 690462306a36Sopenharmony_ci snprintf(card->longname, sizeof(card->longname), 690562306a36Sopenharmony_ci "%s at 0x%lx, irq %d", 690662306a36Sopenharmony_ci hdspm->card_name, hdspm->port, hdspm->irq); 690762306a36Sopenharmony_ci } 690862306a36Sopenharmony_ci 690962306a36Sopenharmony_ci err = snd_card_register(card); 691062306a36Sopenharmony_ci if (err < 0) 691162306a36Sopenharmony_ci goto error; 691262306a36Sopenharmony_ci 691362306a36Sopenharmony_ci pci_set_drvdata(pci, card); 691462306a36Sopenharmony_ci 691562306a36Sopenharmony_ci dev++; 691662306a36Sopenharmony_ci return 0; 691762306a36Sopenharmony_ci 691862306a36Sopenharmony_ci error: 691962306a36Sopenharmony_ci snd_card_free(card); 692062306a36Sopenharmony_ci return err; 692162306a36Sopenharmony_ci} 692262306a36Sopenharmony_ci 692362306a36Sopenharmony_cistatic struct pci_driver hdspm_driver = { 692462306a36Sopenharmony_ci .name = KBUILD_MODNAME, 692562306a36Sopenharmony_ci .id_table = snd_hdspm_ids, 692662306a36Sopenharmony_ci .probe = snd_hdspm_probe, 692762306a36Sopenharmony_ci}; 692862306a36Sopenharmony_ci 692962306a36Sopenharmony_cimodule_pci_driver(hdspm_driver); 6930