162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for Digigram pcxhr compatible soundcards 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * mixer interface for stereo cards 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2004 by Digigram <alsa@digigram.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/pci.h> 1362306a36Sopenharmony_ci#include <sound/core.h> 1462306a36Sopenharmony_ci#include <sound/control.h> 1562306a36Sopenharmony_ci#include <sound/tlv.h> 1662306a36Sopenharmony_ci#include <sound/asoundef.h> 1762306a36Sopenharmony_ci#include "pcxhr.h" 1862306a36Sopenharmony_ci#include "pcxhr_core.h" 1962306a36Sopenharmony_ci#include "pcxhr_mix22.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* registers used on the DSP and Xilinx (port 2) : HR stereo cards only */ 2362306a36Sopenharmony_ci#define PCXHR_DSP_RESET 0x20 2462306a36Sopenharmony_ci#define PCXHR_XLX_CFG 0x24 2562306a36Sopenharmony_ci#define PCXHR_XLX_RUER 0x28 2662306a36Sopenharmony_ci#define PCXHR_XLX_DATA 0x2C 2762306a36Sopenharmony_ci#define PCXHR_XLX_STATUS 0x30 2862306a36Sopenharmony_ci#define PCXHR_XLX_LOFREQ 0x34 2962306a36Sopenharmony_ci#define PCXHR_XLX_HIFREQ 0x38 3062306a36Sopenharmony_ci#define PCXHR_XLX_CSUER 0x3C 3162306a36Sopenharmony_ci#define PCXHR_XLX_SELMIC 0x40 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define PCXHR_DSP 2 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* byte access only ! */ 3662306a36Sopenharmony_ci#define PCXHR_INPB(mgr, x) inb((mgr)->port[PCXHR_DSP] + (x)) 3762306a36Sopenharmony_ci#define PCXHR_OUTPB(mgr, x, data) outb((data), (mgr)->port[PCXHR_DSP] + (x)) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* values for PCHR_DSP_RESET register */ 4162306a36Sopenharmony_ci#define PCXHR_DSP_RESET_DSP 0x01 4262306a36Sopenharmony_ci#define PCXHR_DSP_RESET_MUTE 0x02 4362306a36Sopenharmony_ci#define PCXHR_DSP_RESET_CODEC 0x08 4462306a36Sopenharmony_ci#define PCXHR_DSP_RESET_SMPTE 0x10 4562306a36Sopenharmony_ci#define PCXHR_DSP_RESET_GPO_OFFSET 5 4662306a36Sopenharmony_ci#define PCXHR_DSP_RESET_GPO_MASK 0x60 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* values for PCHR_XLX_CFG register */ 4962306a36Sopenharmony_ci#define PCXHR_CFG_SYNCDSP_MASK 0x80 5062306a36Sopenharmony_ci#define PCXHR_CFG_DEPENDENCY_MASK 0x60 5162306a36Sopenharmony_ci#define PCXHR_CFG_INDEPENDANT_SEL 0x00 5262306a36Sopenharmony_ci#define PCXHR_CFG_MASTER_SEL 0x40 5362306a36Sopenharmony_ci#define PCXHR_CFG_SLAVE_SEL 0x20 5462306a36Sopenharmony_ci#define PCXHR_CFG_DATA_UER1_SEL_MASK 0x10 /* 0 (UER0), 1(UER1) */ 5562306a36Sopenharmony_ci#define PCXHR_CFG_DATAIN_SEL_MASK 0x08 /* 0 (ana), 1 (UER) */ 5662306a36Sopenharmony_ci#define PCXHR_CFG_SRC_MASK 0x04 /* 0 (Bypass), 1 (SRC Actif) */ 5762306a36Sopenharmony_ci#define PCXHR_CFG_CLOCK_UER1_SEL_MASK 0x02 /* 0 (UER0), 1(UER1) */ 5862306a36Sopenharmony_ci#define PCXHR_CFG_CLOCKIN_SEL_MASK 0x01 /* 0 (internal), 1 (AES/EBU) */ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* values for PCHR_XLX_DATA register */ 6162306a36Sopenharmony_ci#define PCXHR_DATA_CODEC 0x80 6262306a36Sopenharmony_ci#define AKM_POWER_CONTROL_CMD 0xA007 6362306a36Sopenharmony_ci#define AKM_RESET_ON_CMD 0xA100 6462306a36Sopenharmony_ci#define AKM_RESET_OFF_CMD 0xA103 6562306a36Sopenharmony_ci#define AKM_CLOCK_INF_55K_CMD 0xA240 6662306a36Sopenharmony_ci#define AKM_CLOCK_SUP_55K_CMD 0xA24D 6762306a36Sopenharmony_ci#define AKM_MUTE_CMD 0xA38D 6862306a36Sopenharmony_ci#define AKM_UNMUTE_CMD 0xA30D 6962306a36Sopenharmony_ci#define AKM_LEFT_LEVEL_CMD 0xA600 7062306a36Sopenharmony_ci#define AKM_RIGHT_LEVEL_CMD 0xA700 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* values for PCHR_XLX_STATUS register - READ */ 7362306a36Sopenharmony_ci#define PCXHR_STAT_SRC_LOCK 0x01 7462306a36Sopenharmony_ci#define PCXHR_STAT_LEVEL_IN 0x02 7562306a36Sopenharmony_ci#define PCXHR_STAT_GPI_OFFSET 2 7662306a36Sopenharmony_ci#define PCXHR_STAT_GPI_MASK 0x0C 7762306a36Sopenharmony_ci#define PCXHR_STAT_MIC_CAPS 0x10 7862306a36Sopenharmony_ci/* values for PCHR_XLX_STATUS register - WRITE */ 7962306a36Sopenharmony_ci#define PCXHR_STAT_FREQ_SYNC_MASK 0x01 8062306a36Sopenharmony_ci#define PCXHR_STAT_FREQ_UER1_MASK 0x02 8162306a36Sopenharmony_ci#define PCXHR_STAT_FREQ_SAVE_MASK 0x80 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* values for PCHR_XLX_CSUER register */ 8462306a36Sopenharmony_ci#define PCXHR_SUER1_BIT_U_READ_MASK 0x80 8562306a36Sopenharmony_ci#define PCXHR_SUER1_BIT_C_READ_MASK 0x40 8662306a36Sopenharmony_ci#define PCXHR_SUER1_DATA_PRESENT_MASK 0x20 8762306a36Sopenharmony_ci#define PCXHR_SUER1_CLOCK_PRESENT_MASK 0x10 8862306a36Sopenharmony_ci#define PCXHR_SUER_BIT_U_READ_MASK 0x08 8962306a36Sopenharmony_ci#define PCXHR_SUER_BIT_C_READ_MASK 0x04 9062306a36Sopenharmony_ci#define PCXHR_SUER_DATA_PRESENT_MASK 0x02 9162306a36Sopenharmony_ci#define PCXHR_SUER_CLOCK_PRESENT_MASK 0x01 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define PCXHR_SUER_BIT_U_WRITE_MASK 0x02 9462306a36Sopenharmony_ci#define PCXHR_SUER_BIT_C_WRITE_MASK 0x01 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* values for PCXHR_XLX_SELMIC register - WRITE */ 9762306a36Sopenharmony_ci#define PCXHR_SELMIC_PREAMPLI_OFFSET 2 9862306a36Sopenharmony_ci#define PCXHR_SELMIC_PREAMPLI_MASK 0x0C 9962306a36Sopenharmony_ci#define PCXHR_SELMIC_PHANTOM_ALIM 0x80 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic const unsigned char g_hr222_p_level[] = { 10362306a36Sopenharmony_ci 0x00, /* [000] -49.5 dB: AKM[000] = -1.#INF dB (mute) */ 10462306a36Sopenharmony_ci 0x01, /* [001] -49.0 dB: AKM[001] = -48.131 dB (diff=0.86920 dB) */ 10562306a36Sopenharmony_ci 0x01, /* [002] -48.5 dB: AKM[001] = -48.131 dB (diff=0.36920 dB) */ 10662306a36Sopenharmony_ci 0x01, /* [003] -48.0 dB: AKM[001] = -48.131 dB (diff=0.13080 dB) */ 10762306a36Sopenharmony_ci 0x01, /* [004] -47.5 dB: AKM[001] = -48.131 dB (diff=0.63080 dB) */ 10862306a36Sopenharmony_ci 0x01, /* [005] -46.5 dB: AKM[001] = -48.131 dB (diff=1.63080 dB) */ 10962306a36Sopenharmony_ci 0x01, /* [006] -47.0 dB: AKM[001] = -48.131 dB (diff=1.13080 dB) */ 11062306a36Sopenharmony_ci 0x01, /* [007] -46.0 dB: AKM[001] = -48.131 dB (diff=2.13080 dB) */ 11162306a36Sopenharmony_ci 0x01, /* [008] -45.5 dB: AKM[001] = -48.131 dB (diff=2.63080 dB) */ 11262306a36Sopenharmony_ci 0x02, /* [009] -45.0 dB: AKM[002] = -42.110 dB (diff=2.88980 dB) */ 11362306a36Sopenharmony_ci 0x02, /* [010] -44.5 dB: AKM[002] = -42.110 dB (diff=2.38980 dB) */ 11462306a36Sopenharmony_ci 0x02, /* [011] -44.0 dB: AKM[002] = -42.110 dB (diff=1.88980 dB) */ 11562306a36Sopenharmony_ci 0x02, /* [012] -43.5 dB: AKM[002] = -42.110 dB (diff=1.38980 dB) */ 11662306a36Sopenharmony_ci 0x02, /* [013] -43.0 dB: AKM[002] = -42.110 dB (diff=0.88980 dB) */ 11762306a36Sopenharmony_ci 0x02, /* [014] -42.5 dB: AKM[002] = -42.110 dB (diff=0.38980 dB) */ 11862306a36Sopenharmony_ci 0x02, /* [015] -42.0 dB: AKM[002] = -42.110 dB (diff=0.11020 dB) */ 11962306a36Sopenharmony_ci 0x02, /* [016] -41.5 dB: AKM[002] = -42.110 dB (diff=0.61020 dB) */ 12062306a36Sopenharmony_ci 0x02, /* [017] -41.0 dB: AKM[002] = -42.110 dB (diff=1.11020 dB) */ 12162306a36Sopenharmony_ci 0x02, /* [018] -40.5 dB: AKM[002] = -42.110 dB (diff=1.61020 dB) */ 12262306a36Sopenharmony_ci 0x03, /* [019] -40.0 dB: AKM[003] = -38.588 dB (diff=1.41162 dB) */ 12362306a36Sopenharmony_ci 0x03, /* [020] -39.5 dB: AKM[003] = -38.588 dB (diff=0.91162 dB) */ 12462306a36Sopenharmony_ci 0x03, /* [021] -39.0 dB: AKM[003] = -38.588 dB (diff=0.41162 dB) */ 12562306a36Sopenharmony_ci 0x03, /* [022] -38.5 dB: AKM[003] = -38.588 dB (diff=0.08838 dB) */ 12662306a36Sopenharmony_ci 0x03, /* [023] -38.0 dB: AKM[003] = -38.588 dB (diff=0.58838 dB) */ 12762306a36Sopenharmony_ci 0x03, /* [024] -37.5 dB: AKM[003] = -38.588 dB (diff=1.08838 dB) */ 12862306a36Sopenharmony_ci 0x04, /* [025] -37.0 dB: AKM[004] = -36.090 dB (diff=0.91040 dB) */ 12962306a36Sopenharmony_ci 0x04, /* [026] -36.5 dB: AKM[004] = -36.090 dB (diff=0.41040 dB) */ 13062306a36Sopenharmony_ci 0x04, /* [027] -36.0 dB: AKM[004] = -36.090 dB (diff=0.08960 dB) */ 13162306a36Sopenharmony_ci 0x04, /* [028] -35.5 dB: AKM[004] = -36.090 dB (diff=0.58960 dB) */ 13262306a36Sopenharmony_ci 0x05, /* [029] -35.0 dB: AKM[005] = -34.151 dB (diff=0.84860 dB) */ 13362306a36Sopenharmony_ci 0x05, /* [030] -34.5 dB: AKM[005] = -34.151 dB (diff=0.34860 dB) */ 13462306a36Sopenharmony_ci 0x05, /* [031] -34.0 dB: AKM[005] = -34.151 dB (diff=0.15140 dB) */ 13562306a36Sopenharmony_ci 0x05, /* [032] -33.5 dB: AKM[005] = -34.151 dB (diff=0.65140 dB) */ 13662306a36Sopenharmony_ci 0x06, /* [033] -33.0 dB: AKM[006] = -32.568 dB (diff=0.43222 dB) */ 13762306a36Sopenharmony_ci 0x06, /* [034] -32.5 dB: AKM[006] = -32.568 dB (diff=0.06778 dB) */ 13862306a36Sopenharmony_ci 0x06, /* [035] -32.0 dB: AKM[006] = -32.568 dB (diff=0.56778 dB) */ 13962306a36Sopenharmony_ci 0x07, /* [036] -31.5 dB: AKM[007] = -31.229 dB (diff=0.27116 dB) */ 14062306a36Sopenharmony_ci 0x07, /* [037] -31.0 dB: AKM[007] = -31.229 dB (diff=0.22884 dB) */ 14162306a36Sopenharmony_ci 0x08, /* [038] -30.5 dB: AKM[008] = -30.069 dB (diff=0.43100 dB) */ 14262306a36Sopenharmony_ci 0x08, /* [039] -30.0 dB: AKM[008] = -30.069 dB (diff=0.06900 dB) */ 14362306a36Sopenharmony_ci 0x09, /* [040] -29.5 dB: AKM[009] = -29.046 dB (diff=0.45405 dB) */ 14462306a36Sopenharmony_ci 0x09, /* [041] -29.0 dB: AKM[009] = -29.046 dB (diff=0.04595 dB) */ 14562306a36Sopenharmony_ci 0x0a, /* [042] -28.5 dB: AKM[010] = -28.131 dB (diff=0.36920 dB) */ 14662306a36Sopenharmony_ci 0x0a, /* [043] -28.0 dB: AKM[010] = -28.131 dB (diff=0.13080 dB) */ 14762306a36Sopenharmony_ci 0x0b, /* [044] -27.5 dB: AKM[011] = -27.303 dB (diff=0.19705 dB) */ 14862306a36Sopenharmony_ci 0x0b, /* [045] -27.0 dB: AKM[011] = -27.303 dB (diff=0.30295 dB) */ 14962306a36Sopenharmony_ci 0x0c, /* [046] -26.5 dB: AKM[012] = -26.547 dB (diff=0.04718 dB) */ 15062306a36Sopenharmony_ci 0x0d, /* [047] -26.0 dB: AKM[013] = -25.852 dB (diff=0.14806 dB) */ 15162306a36Sopenharmony_ci 0x0e, /* [048] -25.5 dB: AKM[014] = -25.208 dB (diff=0.29176 dB) */ 15262306a36Sopenharmony_ci 0x0e, /* [049] -25.0 dB: AKM[014] = -25.208 dB (diff=0.20824 dB) */ 15362306a36Sopenharmony_ci 0x0f, /* [050] -24.5 dB: AKM[015] = -24.609 dB (diff=0.10898 dB) */ 15462306a36Sopenharmony_ci 0x10, /* [051] -24.0 dB: AKM[016] = -24.048 dB (diff=0.04840 dB) */ 15562306a36Sopenharmony_ci 0x11, /* [052] -23.5 dB: AKM[017] = -23.522 dB (diff=0.02183 dB) */ 15662306a36Sopenharmony_ci 0x12, /* [053] -23.0 dB: AKM[018] = -23.025 dB (diff=0.02535 dB) */ 15762306a36Sopenharmony_ci 0x13, /* [054] -22.5 dB: AKM[019] = -22.556 dB (diff=0.05573 dB) */ 15862306a36Sopenharmony_ci 0x14, /* [055] -22.0 dB: AKM[020] = -22.110 dB (diff=0.11020 dB) */ 15962306a36Sopenharmony_ci 0x15, /* [056] -21.5 dB: AKM[021] = -21.686 dB (diff=0.18642 dB) */ 16062306a36Sopenharmony_ci 0x17, /* [057] -21.0 dB: AKM[023] = -20.896 dB (diff=0.10375 dB) */ 16162306a36Sopenharmony_ci 0x18, /* [058] -20.5 dB: AKM[024] = -20.527 dB (diff=0.02658 dB) */ 16262306a36Sopenharmony_ci 0x1a, /* [059] -20.0 dB: AKM[026] = -19.831 dB (diff=0.16866 dB) */ 16362306a36Sopenharmony_ci 0x1b, /* [060] -19.5 dB: AKM[027] = -19.504 dB (diff=0.00353 dB) */ 16462306a36Sopenharmony_ci 0x1d, /* [061] -19.0 dB: AKM[029] = -18.883 dB (diff=0.11716 dB) */ 16562306a36Sopenharmony_ci 0x1e, /* [062] -18.5 dB: AKM[030] = -18.588 dB (diff=0.08838 dB) */ 16662306a36Sopenharmony_ci 0x20, /* [063] -18.0 dB: AKM[032] = -18.028 dB (diff=0.02780 dB) */ 16762306a36Sopenharmony_ci 0x22, /* [064] -17.5 dB: AKM[034] = -17.501 dB (diff=0.00123 dB) */ 16862306a36Sopenharmony_ci 0x24, /* [065] -17.0 dB: AKM[036] = -17.005 dB (diff=0.00475 dB) */ 16962306a36Sopenharmony_ci 0x26, /* [066] -16.5 dB: AKM[038] = -16.535 dB (diff=0.03513 dB) */ 17062306a36Sopenharmony_ci 0x28, /* [067] -16.0 dB: AKM[040] = -16.090 dB (diff=0.08960 dB) */ 17162306a36Sopenharmony_ci 0x2b, /* [068] -15.5 dB: AKM[043] = -15.461 dB (diff=0.03857 dB) */ 17262306a36Sopenharmony_ci 0x2d, /* [069] -15.0 dB: AKM[045] = -15.067 dB (diff=0.06655 dB) */ 17362306a36Sopenharmony_ci 0x30, /* [070] -14.5 dB: AKM[048] = -14.506 dB (diff=0.00598 dB) */ 17462306a36Sopenharmony_ci 0x33, /* [071] -14.0 dB: AKM[051] = -13.979 dB (diff=0.02060 dB) */ 17562306a36Sopenharmony_ci 0x36, /* [072] -13.5 dB: AKM[054] = -13.483 dB (diff=0.01707 dB) */ 17662306a36Sopenharmony_ci 0x39, /* [073] -13.0 dB: AKM[057] = -13.013 dB (diff=0.01331 dB) */ 17762306a36Sopenharmony_ci 0x3c, /* [074] -12.5 dB: AKM[060] = -12.568 dB (diff=0.06778 dB) */ 17862306a36Sopenharmony_ci 0x40, /* [075] -12.0 dB: AKM[064] = -12.007 dB (diff=0.00720 dB) */ 17962306a36Sopenharmony_ci 0x44, /* [076] -11.5 dB: AKM[068] = -11.481 dB (diff=0.01937 dB) */ 18062306a36Sopenharmony_ci 0x48, /* [077] -11.0 dB: AKM[072] = -10.984 dB (diff=0.01585 dB) */ 18162306a36Sopenharmony_ci 0x4c, /* [078] -10.5 dB: AKM[076] = -10.515 dB (diff=0.01453 dB) */ 18262306a36Sopenharmony_ci 0x51, /* [079] -10.0 dB: AKM[081] = -9.961 dB (diff=0.03890 dB) */ 18362306a36Sopenharmony_ci 0x55, /* [080] -9.5 dB: AKM[085] = -9.542 dB (diff=0.04243 dB) */ 18462306a36Sopenharmony_ci 0x5a, /* [081] -9.0 dB: AKM[090] = -9.046 dB (diff=0.04595 dB) */ 18562306a36Sopenharmony_ci 0x60, /* [082] -8.5 dB: AKM[096] = -8.485 dB (diff=0.01462 dB) */ 18662306a36Sopenharmony_ci 0x66, /* [083] -8.0 dB: AKM[102] = -7.959 dB (diff=0.04120 dB) */ 18762306a36Sopenharmony_ci 0x6c, /* [084] -7.5 dB: AKM[108] = -7.462 dB (diff=0.03767 dB) */ 18862306a36Sopenharmony_ci 0x72, /* [085] -7.0 dB: AKM[114] = -6.993 dB (diff=0.00729 dB) */ 18962306a36Sopenharmony_ci 0x79, /* [086] -6.5 dB: AKM[121] = -6.475 dB (diff=0.02490 dB) */ 19062306a36Sopenharmony_ci 0x80, /* [087] -6.0 dB: AKM[128] = -5.987 dB (diff=0.01340 dB) */ 19162306a36Sopenharmony_ci 0x87, /* [088] -5.5 dB: AKM[135] = -5.524 dB (diff=0.02413 dB) */ 19262306a36Sopenharmony_ci 0x8f, /* [089] -5.0 dB: AKM[143] = -5.024 dB (diff=0.02408 dB) */ 19362306a36Sopenharmony_ci 0x98, /* [090] -4.5 dB: AKM[152] = -4.494 dB (diff=0.00607 dB) */ 19462306a36Sopenharmony_ci 0xa1, /* [091] -4.0 dB: AKM[161] = -3.994 dB (diff=0.00571 dB) */ 19562306a36Sopenharmony_ci 0xaa, /* [092] -3.5 dB: AKM[170] = -3.522 dB (diff=0.02183 dB) */ 19662306a36Sopenharmony_ci 0xb5, /* [093] -3.0 dB: AKM[181] = -2.977 dB (diff=0.02277 dB) */ 19762306a36Sopenharmony_ci 0xbf, /* [094] -2.5 dB: AKM[191] = -2.510 dB (diff=0.01014 dB) */ 19862306a36Sopenharmony_ci 0xcb, /* [095] -2.0 dB: AKM[203] = -1.981 dB (diff=0.01912 dB) */ 19962306a36Sopenharmony_ci 0xd7, /* [096] -1.5 dB: AKM[215] = -1.482 dB (diff=0.01797 dB) */ 20062306a36Sopenharmony_ci 0xe3, /* [097] -1.0 dB: AKM[227] = -1.010 dB (diff=0.01029 dB) */ 20162306a36Sopenharmony_ci 0xf1, /* [098] -0.5 dB: AKM[241] = -0.490 dB (diff=0.00954 dB) */ 20262306a36Sopenharmony_ci 0xff, /* [099] +0.0 dB: AKM[255] = +0.000 dB (diff=0.00000 dB) */ 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic void hr222_config_akm(struct pcxhr_mgr *mgr, unsigned short data) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci unsigned short mask = 0x8000; 20962306a36Sopenharmony_ci /* activate access to codec registers */ 21062306a36Sopenharmony_ci PCXHR_INPB(mgr, PCXHR_XLX_HIFREQ); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci while (mask) { 21362306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, 21462306a36Sopenharmony_ci data & mask ? PCXHR_DATA_CODEC : 0); 21562306a36Sopenharmony_ci mask >>= 1; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci /* termiate access to codec registers */ 21862306a36Sopenharmony_ci PCXHR_INPB(mgr, PCXHR_XLX_RUER); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic int hr222_set_hw_playback_level(struct pcxhr_mgr *mgr, 22362306a36Sopenharmony_ci int idx, int level) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci unsigned short cmd; 22662306a36Sopenharmony_ci if (idx > 1 || 22762306a36Sopenharmony_ci level < 0 || 22862306a36Sopenharmony_ci level >= ARRAY_SIZE(g_hr222_p_level)) 22962306a36Sopenharmony_ci return -EINVAL; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (idx == 0) 23262306a36Sopenharmony_ci cmd = AKM_LEFT_LEVEL_CMD; 23362306a36Sopenharmony_ci else 23462306a36Sopenharmony_ci cmd = AKM_RIGHT_LEVEL_CMD; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* conversion from PmBoardCodedLevel to AKM nonlinear programming */ 23762306a36Sopenharmony_ci cmd += g_hr222_p_level[level]; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci hr222_config_akm(mgr, cmd); 24062306a36Sopenharmony_ci return 0; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int hr222_set_hw_capture_level(struct pcxhr_mgr *mgr, 24562306a36Sopenharmony_ci int level_l, int level_r, int level_mic) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci /* program all input levels at the same time */ 24862306a36Sopenharmony_ci unsigned int data; 24962306a36Sopenharmony_ci int i; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (!mgr->capture_chips) 25262306a36Sopenharmony_ci return -EINVAL; /* no PCX22 */ 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci data = ((level_mic & 0xff) << 24); /* micro is mono, but apply */ 25562306a36Sopenharmony_ci data |= ((level_mic & 0xff) << 16); /* level on both channels */ 25662306a36Sopenharmony_ci data |= ((level_r & 0xff) << 8); /* line input right channel */ 25762306a36Sopenharmony_ci data |= (level_l & 0xff); /* line input left channel */ 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci PCXHR_INPB(mgr, PCXHR_XLX_DATA); /* activate input codec */ 26062306a36Sopenharmony_ci /* send 32 bits (4 x 8 bits) */ 26162306a36Sopenharmony_ci for (i = 0; i < 32; i++, data <<= 1) { 26262306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, 26362306a36Sopenharmony_ci (data & 0x80000000) ? PCXHR_DATA_CODEC : 0); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci PCXHR_INPB(mgr, PCXHR_XLX_RUER); /* close input level codec */ 26662306a36Sopenharmony_ci return 0; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic void hr222_micro_boost(struct pcxhr_mgr *mgr, int level); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ciint hr222_sub_init(struct pcxhr_mgr *mgr) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci unsigned char reg; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci mgr->board_has_analog = 1; /* analog always available */ 27662306a36Sopenharmony_ci mgr->xlx_cfg = PCXHR_CFG_SYNCDSP_MASK; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS); 27962306a36Sopenharmony_ci if (reg & PCXHR_STAT_MIC_CAPS) 28062306a36Sopenharmony_ci mgr->board_has_mic = 1; /* microphone available */ 28162306a36Sopenharmony_ci dev_dbg(&mgr->pci->dev, 28262306a36Sopenharmony_ci "MIC input available = %d\n", mgr->board_has_mic); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* reset codec */ 28562306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 28662306a36Sopenharmony_ci PCXHR_DSP_RESET_DSP); 28762306a36Sopenharmony_ci msleep(5); 28862306a36Sopenharmony_ci mgr->dsp_reset = PCXHR_DSP_RESET_DSP | 28962306a36Sopenharmony_ci PCXHR_DSP_RESET_MUTE | 29062306a36Sopenharmony_ci PCXHR_DSP_RESET_CODEC; 29162306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset); 29262306a36Sopenharmony_ci /* hr222_write_gpo(mgr, 0); does the same */ 29362306a36Sopenharmony_ci msleep(5); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* config AKM */ 29662306a36Sopenharmony_ci hr222_config_akm(mgr, AKM_POWER_CONTROL_CMD); 29762306a36Sopenharmony_ci hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); 29862306a36Sopenharmony_ci hr222_config_akm(mgr, AKM_UNMUTE_CMD); 29962306a36Sopenharmony_ci hr222_config_akm(mgr, AKM_RESET_OFF_CMD); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* init micro boost */ 30262306a36Sopenharmony_ci hr222_micro_boost(mgr, 0); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/* calc PLL register */ 30962306a36Sopenharmony_ci/* TODO : there is a very similar fct in pcxhr.c */ 31062306a36Sopenharmony_cistatic int hr222_pll_freq_register(unsigned int freq, 31162306a36Sopenharmony_ci unsigned int *pllreg, 31262306a36Sopenharmony_ci unsigned int *realfreq) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci unsigned int reg; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (freq < 6900 || freq > 219000) 31762306a36Sopenharmony_ci return -EINVAL; 31862306a36Sopenharmony_ci reg = (28224000 * 2) / freq; 31962306a36Sopenharmony_ci reg = (reg - 1) / 2; 32062306a36Sopenharmony_ci if (reg < 0x100) 32162306a36Sopenharmony_ci *pllreg = reg + 0xC00; 32262306a36Sopenharmony_ci else if (reg < 0x200) 32362306a36Sopenharmony_ci *pllreg = reg + 0x800; 32462306a36Sopenharmony_ci else if (reg < 0x400) 32562306a36Sopenharmony_ci *pllreg = reg & 0x1ff; 32662306a36Sopenharmony_ci else if (reg < 0x800) { 32762306a36Sopenharmony_ci *pllreg = ((reg >> 1) & 0x1ff) + 0x200; 32862306a36Sopenharmony_ci reg &= ~1; 32962306a36Sopenharmony_ci } else { 33062306a36Sopenharmony_ci *pllreg = ((reg >> 2) & 0x1ff) + 0x400; 33162306a36Sopenharmony_ci reg &= ~3; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci if (realfreq) 33462306a36Sopenharmony_ci *realfreq = (28224000 / (reg + 1)); 33562306a36Sopenharmony_ci return 0; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ciint hr222_sub_set_clock(struct pcxhr_mgr *mgr, 33962306a36Sopenharmony_ci unsigned int rate, 34062306a36Sopenharmony_ci int *changed) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci unsigned int speed, pllreg = 0; 34362306a36Sopenharmony_ci int err; 34462306a36Sopenharmony_ci unsigned realfreq = rate; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci switch (mgr->use_clock_type) { 34762306a36Sopenharmony_ci case HR22_CLOCK_TYPE_INTERNAL: 34862306a36Sopenharmony_ci err = hr222_pll_freq_register(rate, &pllreg, &realfreq); 34962306a36Sopenharmony_ci if (err) 35062306a36Sopenharmony_ci return err; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci mgr->xlx_cfg &= ~(PCXHR_CFG_CLOCKIN_SEL_MASK | 35362306a36Sopenharmony_ci PCXHR_CFG_CLOCK_UER1_SEL_MASK); 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci case HR22_CLOCK_TYPE_AES_SYNC: 35662306a36Sopenharmony_ci mgr->xlx_cfg |= PCXHR_CFG_CLOCKIN_SEL_MASK; 35762306a36Sopenharmony_ci mgr->xlx_cfg &= ~PCXHR_CFG_CLOCK_UER1_SEL_MASK; 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci case HR22_CLOCK_TYPE_AES_1: 36062306a36Sopenharmony_ci if (!mgr->board_has_aes1) 36162306a36Sopenharmony_ci return -EINVAL; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci mgr->xlx_cfg |= (PCXHR_CFG_CLOCKIN_SEL_MASK | 36462306a36Sopenharmony_ci PCXHR_CFG_CLOCK_UER1_SEL_MASK); 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci default: 36762306a36Sopenharmony_ci return -EINVAL; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci hr222_config_akm(mgr, AKM_MUTE_CMD); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (mgr->use_clock_type == HR22_CLOCK_TYPE_INTERNAL) { 37262306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_XLX_HIFREQ, pllreg >> 8); 37362306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_XLX_LOFREQ, pllreg & 0xff); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* set clock source */ 37762306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_XLX_CFG, mgr->xlx_cfg); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* codec speed modes */ 38062306a36Sopenharmony_ci speed = rate < 55000 ? 0 : 1; 38162306a36Sopenharmony_ci if (mgr->codec_speed != speed) { 38262306a36Sopenharmony_ci mgr->codec_speed = speed; 38362306a36Sopenharmony_ci if (speed == 0) 38462306a36Sopenharmony_ci hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); 38562306a36Sopenharmony_ci else 38662306a36Sopenharmony_ci hr222_config_akm(mgr, AKM_CLOCK_SUP_55K_CMD); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci mgr->sample_rate_real = realfreq; 39062306a36Sopenharmony_ci mgr->cur_clock_type = mgr->use_clock_type; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (changed) 39362306a36Sopenharmony_ci *changed = 1; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci hr222_config_akm(mgr, AKM_UNMUTE_CMD); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci dev_dbg(&mgr->pci->dev, "set_clock to %dHz (realfreq=%d pllreg=%x)\n", 39862306a36Sopenharmony_ci rate, realfreq, pllreg); 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ciint hr222_get_external_clock(struct pcxhr_mgr *mgr, 40362306a36Sopenharmony_ci enum pcxhr_clock_type clock_type, 40462306a36Sopenharmony_ci int *sample_rate) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci int rate, calc_rate = 0; 40762306a36Sopenharmony_ci unsigned int ticks; 40862306a36Sopenharmony_ci unsigned char mask, reg; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (clock_type == HR22_CLOCK_TYPE_AES_SYNC) { 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci mask = (PCXHR_SUER_CLOCK_PRESENT_MASK | 41362306a36Sopenharmony_ci PCXHR_SUER_DATA_PRESENT_MASK); 41462306a36Sopenharmony_ci reg = PCXHR_STAT_FREQ_SYNC_MASK; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci } else if (clock_type == HR22_CLOCK_TYPE_AES_1 && mgr->board_has_aes1) { 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci mask = (PCXHR_SUER1_CLOCK_PRESENT_MASK | 41962306a36Sopenharmony_ci PCXHR_SUER1_DATA_PRESENT_MASK); 42062306a36Sopenharmony_ci reg = PCXHR_STAT_FREQ_UER1_MASK; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci } else { 42362306a36Sopenharmony_ci dev_dbg(&mgr->pci->dev, 42462306a36Sopenharmony_ci "get_external_clock : type %d not supported\n", 42562306a36Sopenharmony_ci clock_type); 42662306a36Sopenharmony_ci return -EINVAL; /* other clocks not supported */ 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) { 43062306a36Sopenharmony_ci dev_dbg(&mgr->pci->dev, 43162306a36Sopenharmony_ci "get_external_clock(%d) = 0 Hz\n", clock_type); 43262306a36Sopenharmony_ci *sample_rate = 0; 43362306a36Sopenharmony_ci return 0; /* no external clock locked */ 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* calculate freq */ 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* save the measured clock frequency */ 43962306a36Sopenharmony_ci reg |= PCXHR_STAT_FREQ_SAVE_MASK; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (mgr->last_reg_stat != reg) { 44262306a36Sopenharmony_ci udelay(500); /* wait min 2 cycles of lowest freq (8000) */ 44362306a36Sopenharmony_ci mgr->last_reg_stat = reg; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* save */ 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* get the frequency */ 44962306a36Sopenharmony_ci ticks = (unsigned int)PCXHR_INPB(mgr, PCXHR_XLX_CFG); 45062306a36Sopenharmony_ci ticks = (ticks & 0x03) << 8; 45162306a36Sopenharmony_ci ticks |= (unsigned int)PCXHR_INPB(mgr, PCXHR_DSP_RESET); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (ticks != 0) 45462306a36Sopenharmony_ci calc_rate = 28224000 / ticks; 45562306a36Sopenharmony_ci /* rounding */ 45662306a36Sopenharmony_ci if (calc_rate > 184200) 45762306a36Sopenharmony_ci rate = 192000; 45862306a36Sopenharmony_ci else if (calc_rate > 152200) 45962306a36Sopenharmony_ci rate = 176400; 46062306a36Sopenharmony_ci else if (calc_rate > 112000) 46162306a36Sopenharmony_ci rate = 128000; 46262306a36Sopenharmony_ci else if (calc_rate > 92100) 46362306a36Sopenharmony_ci rate = 96000; 46462306a36Sopenharmony_ci else if (calc_rate > 76100) 46562306a36Sopenharmony_ci rate = 88200; 46662306a36Sopenharmony_ci else if (calc_rate > 56000) 46762306a36Sopenharmony_ci rate = 64000; 46862306a36Sopenharmony_ci else if (calc_rate > 46050) 46962306a36Sopenharmony_ci rate = 48000; 47062306a36Sopenharmony_ci else if (calc_rate > 38050) 47162306a36Sopenharmony_ci rate = 44100; 47262306a36Sopenharmony_ci else if (calc_rate > 28000) 47362306a36Sopenharmony_ci rate = 32000; 47462306a36Sopenharmony_ci else if (calc_rate > 23025) 47562306a36Sopenharmony_ci rate = 24000; 47662306a36Sopenharmony_ci else if (calc_rate > 19025) 47762306a36Sopenharmony_ci rate = 22050; 47862306a36Sopenharmony_ci else if (calc_rate > 14000) 47962306a36Sopenharmony_ci rate = 16000; 48062306a36Sopenharmony_ci else if (calc_rate > 11512) 48162306a36Sopenharmony_ci rate = 12000; 48262306a36Sopenharmony_ci else if (calc_rate > 9512) 48362306a36Sopenharmony_ci rate = 11025; 48462306a36Sopenharmony_ci else if (calc_rate > 7000) 48562306a36Sopenharmony_ci rate = 8000; 48662306a36Sopenharmony_ci else 48762306a36Sopenharmony_ci rate = 0; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci dev_dbg(&mgr->pci->dev, "External clock is at %d Hz (measured %d Hz)\n", 49062306a36Sopenharmony_ci rate, calc_rate); 49162306a36Sopenharmony_ci *sample_rate = rate; 49262306a36Sopenharmony_ci return 0; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ciint hr222_read_gpio(struct pcxhr_mgr *mgr, int is_gpi, int *value) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci if (is_gpi) { 49962306a36Sopenharmony_ci unsigned char reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS); 50062306a36Sopenharmony_ci *value = (int)(reg & PCXHR_STAT_GPI_MASK) >> 50162306a36Sopenharmony_ci PCXHR_STAT_GPI_OFFSET; 50262306a36Sopenharmony_ci } else { 50362306a36Sopenharmony_ci *value = (int)(mgr->dsp_reset & PCXHR_DSP_RESET_GPO_MASK) >> 50462306a36Sopenharmony_ci PCXHR_DSP_RESET_GPO_OFFSET; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ciint hr222_write_gpo(struct pcxhr_mgr *mgr, int value) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci unsigned char reg = mgr->dsp_reset & ~PCXHR_DSP_RESET_GPO_MASK; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci reg |= (unsigned char)(value << PCXHR_DSP_RESET_GPO_OFFSET) & 51562306a36Sopenharmony_ci PCXHR_DSP_RESET_GPO_MASK; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, reg); 51862306a36Sopenharmony_ci mgr->dsp_reset = reg; 51962306a36Sopenharmony_ci return 0; 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ciint hr222_manage_timecode(struct pcxhr_mgr *mgr, int enable) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci if (enable) 52562306a36Sopenharmony_ci mgr->dsp_reset |= PCXHR_DSP_RESET_SMPTE; 52662306a36Sopenharmony_ci else 52762306a36Sopenharmony_ci mgr->dsp_reset &= ~PCXHR_DSP_RESET_SMPTE; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset); 53062306a36Sopenharmony_ci return 0; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ciint hr222_update_analog_audio_level(struct snd_pcxhr *chip, 53462306a36Sopenharmony_ci int is_capture, int channel) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci dev_dbg(chip->card->dev, 53762306a36Sopenharmony_ci "hr222_update_analog_audio_level(%s chan=%d)\n", 53862306a36Sopenharmony_ci is_capture ? "capture" : "playback", channel); 53962306a36Sopenharmony_ci if (is_capture) { 54062306a36Sopenharmony_ci int level_l, level_r, level_mic; 54162306a36Sopenharmony_ci /* we have to update all levels */ 54262306a36Sopenharmony_ci if (chip->analog_capture_active) { 54362306a36Sopenharmony_ci level_l = chip->analog_capture_volume[0]; 54462306a36Sopenharmony_ci level_r = chip->analog_capture_volume[1]; 54562306a36Sopenharmony_ci } else { 54662306a36Sopenharmony_ci level_l = HR222_LINE_CAPTURE_LEVEL_MIN; 54762306a36Sopenharmony_ci level_r = HR222_LINE_CAPTURE_LEVEL_MIN; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci if (chip->mic_active) 55062306a36Sopenharmony_ci level_mic = chip->mic_volume; 55162306a36Sopenharmony_ci else 55262306a36Sopenharmony_ci level_mic = HR222_MICRO_CAPTURE_LEVEL_MIN; 55362306a36Sopenharmony_ci return hr222_set_hw_capture_level(chip->mgr, 55462306a36Sopenharmony_ci level_l, level_r, level_mic); 55562306a36Sopenharmony_ci } else { 55662306a36Sopenharmony_ci int vol; 55762306a36Sopenharmony_ci if (chip->analog_playback_active[channel]) 55862306a36Sopenharmony_ci vol = chip->analog_playback_volume[channel]; 55962306a36Sopenharmony_ci else 56062306a36Sopenharmony_ci vol = HR222_LINE_PLAYBACK_LEVEL_MIN; 56162306a36Sopenharmony_ci return hr222_set_hw_playback_level(chip->mgr, channel, vol); 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci/*texts[5] = {"Line", "Digital", "Digi+SRC", "Mic", "Line+Mic"}*/ 56762306a36Sopenharmony_ci#define SOURCE_LINE 0 56862306a36Sopenharmony_ci#define SOURCE_DIGITAL 1 56962306a36Sopenharmony_ci#define SOURCE_DIGISRC 2 57062306a36Sopenharmony_ci#define SOURCE_MIC 3 57162306a36Sopenharmony_ci#define SOURCE_LINEMIC 4 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ciint hr222_set_audio_source(struct snd_pcxhr *chip) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci int digital = 0; 57662306a36Sopenharmony_ci /* default analog source */ 57762306a36Sopenharmony_ci chip->mgr->xlx_cfg &= ~(PCXHR_CFG_SRC_MASK | 57862306a36Sopenharmony_ci PCXHR_CFG_DATAIN_SEL_MASK | 57962306a36Sopenharmony_ci PCXHR_CFG_DATA_UER1_SEL_MASK); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (chip->audio_capture_source == SOURCE_DIGISRC) { 58262306a36Sopenharmony_ci chip->mgr->xlx_cfg |= PCXHR_CFG_SRC_MASK; 58362306a36Sopenharmony_ci digital = 1; 58462306a36Sopenharmony_ci } else { 58562306a36Sopenharmony_ci if (chip->audio_capture_source == SOURCE_DIGITAL) 58662306a36Sopenharmony_ci digital = 1; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci if (digital) { 58962306a36Sopenharmony_ci chip->mgr->xlx_cfg |= PCXHR_CFG_DATAIN_SEL_MASK; 59062306a36Sopenharmony_ci if (chip->mgr->board_has_aes1) { 59162306a36Sopenharmony_ci /* get data from the AES1 plug */ 59262306a36Sopenharmony_ci chip->mgr->xlx_cfg |= PCXHR_CFG_DATA_UER1_SEL_MASK; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci /* chip->mic_active = 0; */ 59562306a36Sopenharmony_ci /* chip->analog_capture_active = 0; */ 59662306a36Sopenharmony_ci } else { 59762306a36Sopenharmony_ci int update_lvl = 0; 59862306a36Sopenharmony_ci chip->analog_capture_active = 0; 59962306a36Sopenharmony_ci chip->mic_active = 0; 60062306a36Sopenharmony_ci if (chip->audio_capture_source == SOURCE_LINE || 60162306a36Sopenharmony_ci chip->audio_capture_source == SOURCE_LINEMIC) { 60262306a36Sopenharmony_ci if (chip->analog_capture_active == 0) 60362306a36Sopenharmony_ci update_lvl = 1; 60462306a36Sopenharmony_ci chip->analog_capture_active = 1; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci if (chip->audio_capture_source == SOURCE_MIC || 60762306a36Sopenharmony_ci chip->audio_capture_source == SOURCE_LINEMIC) { 60862306a36Sopenharmony_ci if (chip->mic_active == 0) 60962306a36Sopenharmony_ci update_lvl = 1; 61062306a36Sopenharmony_ci chip->mic_active = 1; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci if (update_lvl) { 61362306a36Sopenharmony_ci /* capture: update all 3 mutes/unmutes with one call */ 61462306a36Sopenharmony_ci hr222_update_analog_audio_level(chip, 1, 0); 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci /* set the source infos (max 3 bits modified) */ 61862306a36Sopenharmony_ci PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CFG, chip->mgr->xlx_cfg); 61962306a36Sopenharmony_ci return 0; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ciint hr222_iec958_capture_byte(struct snd_pcxhr *chip, 62462306a36Sopenharmony_ci int aes_idx, unsigned char *aes_bits) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci unsigned char idx = (unsigned char)(aes_idx * 8); 62762306a36Sopenharmony_ci unsigned char temp = 0; 62862306a36Sopenharmony_ci unsigned char mask = chip->mgr->board_has_aes1 ? 62962306a36Sopenharmony_ci PCXHR_SUER1_BIT_C_READ_MASK : PCXHR_SUER_BIT_C_READ_MASK; 63062306a36Sopenharmony_ci int i; 63162306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 63262306a36Sopenharmony_ci PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx++); /* idx < 192 */ 63362306a36Sopenharmony_ci temp <<= 1; 63462306a36Sopenharmony_ci if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask) 63562306a36Sopenharmony_ci temp |= 1; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci dev_dbg(chip->card->dev, "read iec958 AES %d byte %d = 0x%x\n", 63862306a36Sopenharmony_ci chip->chip_idx, aes_idx, temp); 63962306a36Sopenharmony_ci *aes_bits = temp; 64062306a36Sopenharmony_ci return 0; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ciint hr222_iec958_update_byte(struct snd_pcxhr *chip, 64562306a36Sopenharmony_ci int aes_idx, unsigned char aes_bits) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci int i; 64862306a36Sopenharmony_ci unsigned char new_bits = aes_bits; 64962306a36Sopenharmony_ci unsigned char old_bits = chip->aes_bits[aes_idx]; 65062306a36Sopenharmony_ci unsigned char idx = (unsigned char)(aes_idx * 8); 65162306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 65262306a36Sopenharmony_ci if ((old_bits & 0x01) != (new_bits & 0x01)) { 65362306a36Sopenharmony_ci /* idx < 192 */ 65462306a36Sopenharmony_ci PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx); 65562306a36Sopenharmony_ci /* write C and U bit */ 65662306a36Sopenharmony_ci PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CSUER, new_bits&0x01 ? 65762306a36Sopenharmony_ci PCXHR_SUER_BIT_C_WRITE_MASK : 0); 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci idx++; 66062306a36Sopenharmony_ci old_bits >>= 1; 66162306a36Sopenharmony_ci new_bits >>= 1; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci chip->aes_bits[aes_idx] = aes_bits; 66462306a36Sopenharmony_ci return 0; 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic void hr222_micro_boost(struct pcxhr_mgr *mgr, int level) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci unsigned char boost_mask; 67062306a36Sopenharmony_ci boost_mask = (unsigned char) (level << PCXHR_SELMIC_PREAMPLI_OFFSET); 67162306a36Sopenharmony_ci if (boost_mask & (~PCXHR_SELMIC_PREAMPLI_MASK)) 67262306a36Sopenharmony_ci return; /* only values form 0 to 3 accepted */ 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci mgr->xlx_selmic &= ~PCXHR_SELMIC_PREAMPLI_MASK; 67562306a36Sopenharmony_ci mgr->xlx_selmic |= boost_mask; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci dev_dbg(&mgr->pci->dev, "hr222_micro_boost : set %x\n", boost_mask); 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic void hr222_phantom_power(struct pcxhr_mgr *mgr, int power) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci if (power) 68562306a36Sopenharmony_ci mgr->xlx_selmic |= PCXHR_SELMIC_PHANTOM_ALIM; 68662306a36Sopenharmony_ci else 68762306a36Sopenharmony_ci mgr->xlx_selmic &= ~PCXHR_SELMIC_PHANTOM_ALIM; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci dev_dbg(&mgr->pci->dev, "hr222_phantom_power : set %d\n", power); 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci/* mic level */ 69662306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_mic_hr222, -9850, 50, 650); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic int hr222_mic_vol_info(struct snd_kcontrol *kcontrol, 69962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 70262306a36Sopenharmony_ci uinfo->count = 1; 70362306a36Sopenharmony_ci uinfo->value.integer.min = HR222_MICRO_CAPTURE_LEVEL_MIN; /* -98 dB */ 70462306a36Sopenharmony_ci /* gains from 9 dB to 31.5 dB not recommended; use micboost instead */ 70562306a36Sopenharmony_ci uinfo->value.integer.max = HR222_MICRO_CAPTURE_LEVEL_MAX; /* +7 dB */ 70662306a36Sopenharmony_ci return 0; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic int hr222_mic_vol_get(struct snd_kcontrol *kcontrol, 71062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 71362306a36Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 71462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = chip->mic_volume; 71562306a36Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 71662306a36Sopenharmony_ci return 0; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic int hr222_mic_vol_put(struct snd_kcontrol *kcontrol, 72062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 72362306a36Sopenharmony_ci int changed = 0; 72462306a36Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 72562306a36Sopenharmony_ci if (chip->mic_volume != ucontrol->value.integer.value[0]) { 72662306a36Sopenharmony_ci changed = 1; 72762306a36Sopenharmony_ci chip->mic_volume = ucontrol->value.integer.value[0]; 72862306a36Sopenharmony_ci hr222_update_analog_audio_level(chip, 1, 0); 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 73162306a36Sopenharmony_ci return changed; 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic const struct snd_kcontrol_new hr222_control_mic_level = { 73562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 73662306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 73762306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 73862306a36Sopenharmony_ci .name = "Mic Capture Volume", 73962306a36Sopenharmony_ci .info = hr222_mic_vol_info, 74062306a36Sopenharmony_ci .get = hr222_mic_vol_get, 74162306a36Sopenharmony_ci .put = hr222_mic_vol_put, 74262306a36Sopenharmony_ci .tlv = { .p = db_scale_mic_hr222 }, 74362306a36Sopenharmony_ci}; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci/* mic boost level */ 74762306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_micboost_hr222, 0, 1800, 5400); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic int hr222_mic_boost_info(struct snd_kcontrol *kcontrol, 75062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 75362306a36Sopenharmony_ci uinfo->count = 1; 75462306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* 0 dB */ 75562306a36Sopenharmony_ci uinfo->value.integer.max = 3; /* 54 dB */ 75662306a36Sopenharmony_ci return 0; 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic int hr222_mic_boost_get(struct snd_kcontrol *kcontrol, 76062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 76362306a36Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 76462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = chip->mic_boost; 76562306a36Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 76662306a36Sopenharmony_ci return 0; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic int hr222_mic_boost_put(struct snd_kcontrol *kcontrol, 77062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 77362306a36Sopenharmony_ci int changed = 0; 77462306a36Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 77562306a36Sopenharmony_ci if (chip->mic_boost != ucontrol->value.integer.value[0]) { 77662306a36Sopenharmony_ci changed = 1; 77762306a36Sopenharmony_ci chip->mic_boost = ucontrol->value.integer.value[0]; 77862306a36Sopenharmony_ci hr222_micro_boost(chip->mgr, chip->mic_boost); 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 78162306a36Sopenharmony_ci return changed; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic const struct snd_kcontrol_new hr222_control_mic_boost = { 78562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 78662306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 78762306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 78862306a36Sopenharmony_ci .name = "MicBoost Capture Volume", 78962306a36Sopenharmony_ci .info = hr222_mic_boost_info, 79062306a36Sopenharmony_ci .get = hr222_mic_boost_get, 79162306a36Sopenharmony_ci .put = hr222_mic_boost_put, 79262306a36Sopenharmony_ci .tlv = { .p = db_scale_micboost_hr222 }, 79362306a36Sopenharmony_ci}; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci/******************* Phantom power switch *******************/ 79762306a36Sopenharmony_ci#define hr222_phantom_power_info snd_ctl_boolean_mono_info 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic int hr222_phantom_power_get(struct snd_kcontrol *kcontrol, 80062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 80362306a36Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 80462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = chip->phantom_power; 80562306a36Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 80662306a36Sopenharmony_ci return 0; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic int hr222_phantom_power_put(struct snd_kcontrol *kcontrol, 81062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 81362306a36Sopenharmony_ci int power, changed = 0; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci mutex_lock(&chip->mgr->mixer_mutex); 81662306a36Sopenharmony_ci power = !!ucontrol->value.integer.value[0]; 81762306a36Sopenharmony_ci if (chip->phantom_power != power) { 81862306a36Sopenharmony_ci hr222_phantom_power(chip->mgr, power); 81962306a36Sopenharmony_ci chip->phantom_power = power; 82062306a36Sopenharmony_ci changed = 1; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci mutex_unlock(&chip->mgr->mixer_mutex); 82362306a36Sopenharmony_ci return changed; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic const struct snd_kcontrol_new hr222_phantom_power_switch = { 82762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 82862306a36Sopenharmony_ci .name = "Phantom Power Switch", 82962306a36Sopenharmony_ci .info = hr222_phantom_power_info, 83062306a36Sopenharmony_ci .get = hr222_phantom_power_get, 83162306a36Sopenharmony_ci .put = hr222_phantom_power_put, 83262306a36Sopenharmony_ci}; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ciint hr222_add_mic_controls(struct snd_pcxhr *chip) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci int err; 83862306a36Sopenharmony_ci if (!chip->mgr->board_has_mic) 83962306a36Sopenharmony_ci return 0; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* controls */ 84262306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_level, 84362306a36Sopenharmony_ci chip)); 84462306a36Sopenharmony_ci if (err < 0) 84562306a36Sopenharmony_ci return err; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_boost, 84862306a36Sopenharmony_ci chip)); 84962306a36Sopenharmony_ci if (err < 0) 85062306a36Sopenharmony_ci return err; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_phantom_power_switch, 85362306a36Sopenharmony_ci chip)); 85462306a36Sopenharmony_ci return err; 85562306a36Sopenharmony_ci} 856