Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Driver for Digigram pcxhr compatible soundcards
0004  *
0005  * mixer interface for stereo cards
0006  *
0007  * Copyright (c) 2004 by Digigram <alsa@digigram.com>
0008  */
0009 
0010 #include <linux/delay.h>
0011 #include <linux/io.h>
0012 #include <linux/pci.h>
0013 #include <sound/core.h>
0014 #include <sound/control.h>
0015 #include <sound/tlv.h>
0016 #include <sound/asoundef.h>
0017 #include "pcxhr.h"
0018 #include "pcxhr_core.h"
0019 #include "pcxhr_mix22.h"
0020 
0021 
0022 /* registers used on the DSP and Xilinx (port 2) : HR stereo cards only */
0023 #define PCXHR_DSP_RESET     0x20
0024 #define PCXHR_XLX_CFG       0x24
0025 #define PCXHR_XLX_RUER      0x28
0026 #define PCXHR_XLX_DATA      0x2C
0027 #define PCXHR_XLX_STATUS    0x30
0028 #define PCXHR_XLX_LOFREQ    0x34
0029 #define PCXHR_XLX_HIFREQ    0x38
0030 #define PCXHR_XLX_CSUER     0x3C
0031 #define PCXHR_XLX_SELMIC    0x40
0032 
0033 #define PCXHR_DSP 2
0034 
0035 /* byte access only ! */
0036 #define PCXHR_INPB(mgr, x)  inb((mgr)->port[PCXHR_DSP] + (x))
0037 #define PCXHR_OUTPB(mgr, x, data) outb((data), (mgr)->port[PCXHR_DSP] + (x))
0038 
0039 
0040 /* values for PCHR_DSP_RESET register */
0041 #define PCXHR_DSP_RESET_DSP 0x01
0042 #define PCXHR_DSP_RESET_MUTE    0x02
0043 #define PCXHR_DSP_RESET_CODEC   0x08
0044 #define PCXHR_DSP_RESET_SMPTE   0x10
0045 #define PCXHR_DSP_RESET_GPO_OFFSET  5
0046 #define PCXHR_DSP_RESET_GPO_MASK    0x60
0047 
0048 /* values for PCHR_XLX_CFG register */
0049 #define PCXHR_CFG_SYNCDSP_MASK      0x80
0050 #define PCXHR_CFG_DEPENDENCY_MASK   0x60
0051 #define PCXHR_CFG_INDEPENDANT_SEL   0x00
0052 #define PCXHR_CFG_MASTER_SEL        0x40
0053 #define PCXHR_CFG_SLAVE_SEL     0x20
0054 #define PCXHR_CFG_DATA_UER1_SEL_MASK    0x10    /* 0 (UER0), 1(UER1) */
0055 #define PCXHR_CFG_DATAIN_SEL_MASK   0x08    /* 0 (ana), 1 (UER) */
0056 #define PCXHR_CFG_SRC_MASK      0x04    /* 0 (Bypass), 1 (SRC Actif) */
0057 #define PCXHR_CFG_CLOCK_UER1_SEL_MASK   0x02    /* 0 (UER0), 1(UER1) */
0058 #define PCXHR_CFG_CLOCKIN_SEL_MASK  0x01    /* 0 (internal), 1 (AES/EBU) */
0059 
0060 /* values for PCHR_XLX_DATA register */
0061 #define PCXHR_DATA_CODEC    0x80
0062 #define AKM_POWER_CONTROL_CMD   0xA007
0063 #define AKM_RESET_ON_CMD    0xA100
0064 #define AKM_RESET_OFF_CMD   0xA103
0065 #define AKM_CLOCK_INF_55K_CMD   0xA240
0066 #define AKM_CLOCK_SUP_55K_CMD   0xA24D
0067 #define AKM_MUTE_CMD        0xA38D
0068 #define AKM_UNMUTE_CMD      0xA30D
0069 #define AKM_LEFT_LEVEL_CMD  0xA600
0070 #define AKM_RIGHT_LEVEL_CMD 0xA700
0071 
0072 /* values for PCHR_XLX_STATUS register - READ */
0073 #define PCXHR_STAT_SRC_LOCK     0x01
0074 #define PCXHR_STAT_LEVEL_IN     0x02
0075 #define PCXHR_STAT_GPI_OFFSET       2
0076 #define PCXHR_STAT_GPI_MASK     0x0C
0077 #define PCXHR_STAT_MIC_CAPS     0x10
0078 /* values for PCHR_XLX_STATUS register - WRITE */
0079 #define PCXHR_STAT_FREQ_SYNC_MASK   0x01
0080 #define PCXHR_STAT_FREQ_UER1_MASK   0x02
0081 #define PCXHR_STAT_FREQ_SAVE_MASK   0x80
0082 
0083 /* values for PCHR_XLX_CSUER register */
0084 #define PCXHR_SUER1_BIT_U_READ_MASK 0x80
0085 #define PCXHR_SUER1_BIT_C_READ_MASK 0x40
0086 #define PCXHR_SUER1_DATA_PRESENT_MASK   0x20
0087 #define PCXHR_SUER1_CLOCK_PRESENT_MASK  0x10
0088 #define PCXHR_SUER_BIT_U_READ_MASK  0x08
0089 #define PCXHR_SUER_BIT_C_READ_MASK  0x04
0090 #define PCXHR_SUER_DATA_PRESENT_MASK    0x02
0091 #define PCXHR_SUER_CLOCK_PRESENT_MASK   0x01
0092 
0093 #define PCXHR_SUER_BIT_U_WRITE_MASK 0x02
0094 #define PCXHR_SUER_BIT_C_WRITE_MASK 0x01
0095 
0096 /* values for PCXHR_XLX_SELMIC register - WRITE */
0097 #define PCXHR_SELMIC_PREAMPLI_OFFSET    2
0098 #define PCXHR_SELMIC_PREAMPLI_MASK  0x0C
0099 #define PCXHR_SELMIC_PHANTOM_ALIM   0x80
0100 
0101 
0102 static const unsigned char g_hr222_p_level[] = {
0103     0x00,   /* [000] -49.5 dB:  AKM[000] = -1.#INF dB   (mute) */
0104     0x01,   /* [001] -49.0 dB:  AKM[001] = -48.131 dB   (diff=0.86920 dB) */
0105     0x01,   /* [002] -48.5 dB:  AKM[001] = -48.131 dB   (diff=0.36920 dB) */
0106     0x01,   /* [003] -48.0 dB:  AKM[001] = -48.131 dB   (diff=0.13080 dB) */
0107     0x01,   /* [004] -47.5 dB:  AKM[001] = -48.131 dB   (diff=0.63080 dB) */
0108     0x01,   /* [005] -46.5 dB:  AKM[001] = -48.131 dB   (diff=1.63080 dB) */
0109     0x01,   /* [006] -47.0 dB:  AKM[001] = -48.131 dB   (diff=1.13080 dB) */
0110     0x01,   /* [007] -46.0 dB:  AKM[001] = -48.131 dB   (diff=2.13080 dB) */
0111     0x01,   /* [008] -45.5 dB:  AKM[001] = -48.131 dB   (diff=2.63080 dB) */
0112     0x02,   /* [009] -45.0 dB:  AKM[002] = -42.110 dB   (diff=2.88980 dB) */
0113     0x02,   /* [010] -44.5 dB:  AKM[002] = -42.110 dB   (diff=2.38980 dB) */
0114     0x02,   /* [011] -44.0 dB:  AKM[002] = -42.110 dB   (diff=1.88980 dB) */
0115     0x02,   /* [012] -43.5 dB:  AKM[002] = -42.110 dB   (diff=1.38980 dB) */
0116     0x02,   /* [013] -43.0 dB:  AKM[002] = -42.110 dB   (diff=0.88980 dB) */
0117     0x02,   /* [014] -42.5 dB:  AKM[002] = -42.110 dB   (diff=0.38980 dB) */
0118     0x02,   /* [015] -42.0 dB:  AKM[002] = -42.110 dB   (diff=0.11020 dB) */
0119     0x02,   /* [016] -41.5 dB:  AKM[002] = -42.110 dB   (diff=0.61020 dB) */
0120     0x02,   /* [017] -41.0 dB:  AKM[002] = -42.110 dB   (diff=1.11020 dB) */
0121     0x02,   /* [018] -40.5 dB:  AKM[002] = -42.110 dB   (diff=1.61020 dB) */
0122     0x03,   /* [019] -40.0 dB:  AKM[003] = -38.588 dB   (diff=1.41162 dB) */
0123     0x03,   /* [020] -39.5 dB:  AKM[003] = -38.588 dB   (diff=0.91162 dB) */
0124     0x03,   /* [021] -39.0 dB:  AKM[003] = -38.588 dB   (diff=0.41162 dB) */
0125     0x03,   /* [022] -38.5 dB:  AKM[003] = -38.588 dB   (diff=0.08838 dB) */
0126     0x03,   /* [023] -38.0 dB:  AKM[003] = -38.588 dB   (diff=0.58838 dB) */
0127     0x03,   /* [024] -37.5 dB:  AKM[003] = -38.588 dB   (diff=1.08838 dB) */
0128     0x04,   /* [025] -37.0 dB:  AKM[004] = -36.090 dB   (diff=0.91040 dB) */
0129     0x04,   /* [026] -36.5 dB:  AKM[004] = -36.090 dB   (diff=0.41040 dB) */
0130     0x04,   /* [027] -36.0 dB:  AKM[004] = -36.090 dB   (diff=0.08960 dB) */
0131     0x04,   /* [028] -35.5 dB:  AKM[004] = -36.090 dB   (diff=0.58960 dB) */
0132     0x05,   /* [029] -35.0 dB:  AKM[005] = -34.151 dB   (diff=0.84860 dB) */
0133     0x05,   /* [030] -34.5 dB:  AKM[005] = -34.151 dB   (diff=0.34860 dB) */
0134     0x05,   /* [031] -34.0 dB:  AKM[005] = -34.151 dB   (diff=0.15140 dB) */
0135     0x05,   /* [032] -33.5 dB:  AKM[005] = -34.151 dB   (diff=0.65140 dB) */
0136     0x06,   /* [033] -33.0 dB:  AKM[006] = -32.568 dB   (diff=0.43222 dB) */
0137     0x06,   /* [034] -32.5 dB:  AKM[006] = -32.568 dB   (diff=0.06778 dB) */
0138     0x06,   /* [035] -32.0 dB:  AKM[006] = -32.568 dB   (diff=0.56778 dB) */
0139     0x07,   /* [036] -31.5 dB:  AKM[007] = -31.229 dB   (diff=0.27116 dB) */
0140     0x07,   /* [037] -31.0 dB:  AKM[007] = -31.229 dB   (diff=0.22884 dB) */
0141     0x08,   /* [038] -30.5 dB:  AKM[008] = -30.069 dB   (diff=0.43100 dB) */
0142     0x08,   /* [039] -30.0 dB:  AKM[008] = -30.069 dB   (diff=0.06900 dB) */
0143     0x09,   /* [040] -29.5 dB:  AKM[009] = -29.046 dB   (diff=0.45405 dB) */
0144     0x09,   /* [041] -29.0 dB:  AKM[009] = -29.046 dB   (diff=0.04595 dB) */
0145     0x0a,   /* [042] -28.5 dB:  AKM[010] = -28.131 dB   (diff=0.36920 dB) */
0146     0x0a,   /* [043] -28.0 dB:  AKM[010] = -28.131 dB   (diff=0.13080 dB) */
0147     0x0b,   /* [044] -27.5 dB:  AKM[011] = -27.303 dB   (diff=0.19705 dB) */
0148     0x0b,   /* [045] -27.0 dB:  AKM[011] = -27.303 dB   (diff=0.30295 dB) */
0149     0x0c,   /* [046] -26.5 dB:  AKM[012] = -26.547 dB   (diff=0.04718 dB) */
0150     0x0d,   /* [047] -26.0 dB:  AKM[013] = -25.852 dB   (diff=0.14806 dB) */
0151     0x0e,   /* [048] -25.5 dB:  AKM[014] = -25.208 dB   (diff=0.29176 dB) */
0152     0x0e,   /* [049] -25.0 dB:  AKM[014] = -25.208 dB   (diff=0.20824 dB) */
0153     0x0f,   /* [050] -24.5 dB:  AKM[015] = -24.609 dB   (diff=0.10898 dB) */
0154     0x10,   /* [051] -24.0 dB:  AKM[016] = -24.048 dB   (diff=0.04840 dB) */
0155     0x11,   /* [052] -23.5 dB:  AKM[017] = -23.522 dB   (diff=0.02183 dB) */
0156     0x12,   /* [053] -23.0 dB:  AKM[018] = -23.025 dB   (diff=0.02535 dB) */
0157     0x13,   /* [054] -22.5 dB:  AKM[019] = -22.556 dB   (diff=0.05573 dB) */
0158     0x14,   /* [055] -22.0 dB:  AKM[020] = -22.110 dB   (diff=0.11020 dB) */
0159     0x15,   /* [056] -21.5 dB:  AKM[021] = -21.686 dB   (diff=0.18642 dB) */
0160     0x17,   /* [057] -21.0 dB:  AKM[023] = -20.896 dB   (diff=0.10375 dB) */
0161     0x18,   /* [058] -20.5 dB:  AKM[024] = -20.527 dB   (diff=0.02658 dB) */
0162     0x1a,   /* [059] -20.0 dB:  AKM[026] = -19.831 dB   (diff=0.16866 dB) */
0163     0x1b,   /* [060] -19.5 dB:  AKM[027] = -19.504 dB   (diff=0.00353 dB) */
0164     0x1d,   /* [061] -19.0 dB:  AKM[029] = -18.883 dB   (diff=0.11716 dB) */
0165     0x1e,   /* [062] -18.5 dB:  AKM[030] = -18.588 dB   (diff=0.08838 dB) */
0166     0x20,   /* [063] -18.0 dB:  AKM[032] = -18.028 dB   (diff=0.02780 dB) */
0167     0x22,   /* [064] -17.5 dB:  AKM[034] = -17.501 dB   (diff=0.00123 dB) */
0168     0x24,   /* [065] -17.0 dB:  AKM[036] = -17.005 dB   (diff=0.00475 dB) */
0169     0x26,   /* [066] -16.5 dB:  AKM[038] = -16.535 dB   (diff=0.03513 dB) */
0170     0x28,   /* [067] -16.0 dB:  AKM[040] = -16.090 dB   (diff=0.08960 dB) */
0171     0x2b,   /* [068] -15.5 dB:  AKM[043] = -15.461 dB   (diff=0.03857 dB) */
0172     0x2d,   /* [069] -15.0 dB:  AKM[045] = -15.067 dB   (diff=0.06655 dB) */
0173     0x30,   /* [070] -14.5 dB:  AKM[048] = -14.506 dB   (diff=0.00598 dB) */
0174     0x33,   /* [071] -14.0 dB:  AKM[051] = -13.979 dB   (diff=0.02060 dB) */
0175     0x36,   /* [072] -13.5 dB:  AKM[054] = -13.483 dB   (diff=0.01707 dB) */
0176     0x39,   /* [073] -13.0 dB:  AKM[057] = -13.013 dB   (diff=0.01331 dB) */
0177     0x3c,   /* [074] -12.5 dB:  AKM[060] = -12.568 dB   (diff=0.06778 dB) */
0178     0x40,   /* [075] -12.0 dB:  AKM[064] = -12.007 dB   (diff=0.00720 dB) */
0179     0x44,   /* [076] -11.5 dB:  AKM[068] = -11.481 dB   (diff=0.01937 dB) */
0180     0x48,   /* [077] -11.0 dB:  AKM[072] = -10.984 dB   (diff=0.01585 dB) */
0181     0x4c,   /* [078] -10.5 dB:  AKM[076] = -10.515 dB   (diff=0.01453 dB) */
0182     0x51,   /* [079] -10.0 dB:  AKM[081] = -9.961 dB    (diff=0.03890 dB) */
0183     0x55,   /* [080] -9.5 dB:   AKM[085] = -9.542 dB    (diff=0.04243 dB) */
0184     0x5a,   /* [081] -9.0 dB:   AKM[090] = -9.046 dB    (diff=0.04595 dB) */
0185     0x60,   /* [082] -8.5 dB:   AKM[096] = -8.485 dB    (diff=0.01462 dB) */
0186     0x66,   /* [083] -8.0 dB:   AKM[102] = -7.959 dB    (diff=0.04120 dB) */
0187     0x6c,   /* [084] -7.5 dB:   AKM[108] = -7.462 dB    (diff=0.03767 dB) */
0188     0x72,   /* [085] -7.0 dB:   AKM[114] = -6.993 dB    (diff=0.00729 dB) */
0189     0x79,   /* [086] -6.5 dB:   AKM[121] = -6.475 dB    (diff=0.02490 dB) */
0190     0x80,   /* [087] -6.0 dB:   AKM[128] = -5.987 dB    (diff=0.01340 dB) */
0191     0x87,   /* [088] -5.5 dB:   AKM[135] = -5.524 dB    (diff=0.02413 dB) */
0192     0x8f,   /* [089] -5.0 dB:   AKM[143] = -5.024 dB    (diff=0.02408 dB) */
0193     0x98,   /* [090] -4.5 dB:   AKM[152] = -4.494 dB    (diff=0.00607 dB) */
0194     0xa1,   /* [091] -4.0 dB:   AKM[161] = -3.994 dB    (diff=0.00571 dB) */
0195     0xaa,   /* [092] -3.5 dB:   AKM[170] = -3.522 dB    (diff=0.02183 dB) */
0196     0xb5,   /* [093] -3.0 dB:   AKM[181] = -2.977 dB    (diff=0.02277 dB) */
0197     0xbf,   /* [094] -2.5 dB:   AKM[191] = -2.510 dB    (diff=0.01014 dB) */
0198     0xcb,   /* [095] -2.0 dB:   AKM[203] = -1.981 dB    (diff=0.01912 dB) */
0199     0xd7,   /* [096] -1.5 dB:   AKM[215] = -1.482 dB    (diff=0.01797 dB) */
0200     0xe3,   /* [097] -1.0 dB:   AKM[227] = -1.010 dB    (diff=0.01029 dB) */
0201     0xf1,   /* [098] -0.5 dB:   AKM[241] = -0.490 dB    (diff=0.00954 dB) */
0202     0xff,   /* [099] +0.0 dB:   AKM[255] = +0.000 dB    (diff=0.00000 dB) */
0203 };
0204 
0205 
0206 static void hr222_config_akm(struct pcxhr_mgr *mgr, unsigned short data)
0207 {
0208     unsigned short mask = 0x8000;
0209     /* activate access to codec registers */
0210     PCXHR_INPB(mgr, PCXHR_XLX_HIFREQ);
0211 
0212     while (mask) {
0213         PCXHR_OUTPB(mgr, PCXHR_XLX_DATA,
0214                 data & mask ? PCXHR_DATA_CODEC : 0);
0215         mask >>= 1;
0216     }
0217     /* termiate access to codec registers */
0218     PCXHR_INPB(mgr, PCXHR_XLX_RUER);
0219 }
0220 
0221 
0222 static int hr222_set_hw_playback_level(struct pcxhr_mgr *mgr,
0223                        int idx, int level)
0224 {
0225     unsigned short cmd;
0226     if (idx > 1 ||
0227         level < 0 ||
0228         level >= ARRAY_SIZE(g_hr222_p_level))
0229         return -EINVAL;
0230 
0231     if (idx == 0)
0232         cmd = AKM_LEFT_LEVEL_CMD;
0233     else
0234         cmd = AKM_RIGHT_LEVEL_CMD;
0235 
0236     /* conversion from PmBoardCodedLevel to AKM nonlinear programming */
0237     cmd += g_hr222_p_level[level];
0238 
0239     hr222_config_akm(mgr, cmd);
0240     return 0;
0241 }
0242 
0243 
0244 static int hr222_set_hw_capture_level(struct pcxhr_mgr *mgr,
0245                       int level_l, int level_r, int level_mic)
0246 {
0247     /* program all input levels at the same time */
0248     unsigned int data;
0249     int i;
0250 
0251     if (!mgr->capture_chips)
0252         return -EINVAL; /* no PCX22 */
0253 
0254     data  = ((level_mic & 0xff) << 24); /* micro is mono, but apply */
0255     data |= ((level_mic & 0xff) << 16); /* level on both channels */
0256     data |= ((level_r & 0xff) << 8);    /* line input right channel */
0257     data |= (level_l & 0xff);       /* line input left channel */
0258 
0259     PCXHR_INPB(mgr, PCXHR_XLX_DATA);    /* activate input codec */
0260     /* send 32 bits (4 x 8 bits) */
0261     for (i = 0; i < 32; i++, data <<= 1) {
0262         PCXHR_OUTPB(mgr, PCXHR_XLX_DATA,
0263                 (data & 0x80000000) ? PCXHR_DATA_CODEC : 0);
0264     }
0265     PCXHR_INPB(mgr, PCXHR_XLX_RUER);    /* close input level codec */
0266     return 0;
0267 }
0268 
0269 static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level);
0270 
0271 int hr222_sub_init(struct pcxhr_mgr *mgr)
0272 {
0273     unsigned char reg;
0274 
0275     mgr->board_has_analog = 1;  /* analog always available */
0276     mgr->xlx_cfg = PCXHR_CFG_SYNCDSP_MASK;
0277 
0278     reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS);
0279     if (reg & PCXHR_STAT_MIC_CAPS)
0280         mgr->board_has_mic = 1; /* microphone available */
0281     dev_dbg(&mgr->pci->dev,
0282         "MIC input available = %d\n", mgr->board_has_mic);
0283 
0284     /* reset codec */
0285     PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
0286             PCXHR_DSP_RESET_DSP);
0287     msleep(5);
0288     mgr->dsp_reset = PCXHR_DSP_RESET_DSP  |
0289              PCXHR_DSP_RESET_MUTE |
0290              PCXHR_DSP_RESET_CODEC;
0291     PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset);
0292     /* hr222_write_gpo(mgr, 0); does the same */
0293     msleep(5);
0294 
0295     /* config AKM */
0296     hr222_config_akm(mgr, AKM_POWER_CONTROL_CMD);
0297     hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD);
0298     hr222_config_akm(mgr, AKM_UNMUTE_CMD);
0299     hr222_config_akm(mgr, AKM_RESET_OFF_CMD);
0300 
0301     /* init micro boost */
0302     hr222_micro_boost(mgr, 0);
0303 
0304     return 0;
0305 }
0306 
0307 
0308 /* calc PLL register */
0309 /* TODO : there is a very similar fct in pcxhr.c */
0310 static int hr222_pll_freq_register(unsigned int freq,
0311                    unsigned int *pllreg,
0312                    unsigned int *realfreq)
0313 {
0314     unsigned int reg;
0315 
0316     if (freq < 6900 || freq > 219000)
0317         return -EINVAL;
0318     reg = (28224000 * 2) / freq;
0319     reg = (reg - 1) / 2;
0320     if (reg < 0x100)
0321         *pllreg = reg + 0xC00;
0322     else if (reg < 0x200)
0323         *pllreg = reg + 0x800;
0324     else if (reg < 0x400)
0325         *pllreg = reg & 0x1ff;
0326     else if (reg < 0x800) {
0327         *pllreg = ((reg >> 1) & 0x1ff) + 0x200;
0328         reg &= ~1;
0329     } else {
0330         *pllreg = ((reg >> 2) & 0x1ff) + 0x400;
0331         reg &= ~3;
0332     }
0333     if (realfreq)
0334         *realfreq = (28224000 / (reg + 1));
0335     return 0;
0336 }
0337 
0338 int hr222_sub_set_clock(struct pcxhr_mgr *mgr,
0339             unsigned int rate,
0340             int *changed)
0341 {
0342     unsigned int speed, pllreg = 0;
0343     int err;
0344     unsigned realfreq = rate;
0345 
0346     switch (mgr->use_clock_type) {
0347     case HR22_CLOCK_TYPE_INTERNAL:
0348         err = hr222_pll_freq_register(rate, &pllreg, &realfreq);
0349         if (err)
0350             return err;
0351 
0352         mgr->xlx_cfg &= ~(PCXHR_CFG_CLOCKIN_SEL_MASK |
0353                   PCXHR_CFG_CLOCK_UER1_SEL_MASK);
0354         break;
0355     case HR22_CLOCK_TYPE_AES_SYNC:
0356         mgr->xlx_cfg |= PCXHR_CFG_CLOCKIN_SEL_MASK;
0357         mgr->xlx_cfg &= ~PCXHR_CFG_CLOCK_UER1_SEL_MASK;
0358         break;
0359     case HR22_CLOCK_TYPE_AES_1:
0360         if (!mgr->board_has_aes1)
0361             return -EINVAL;
0362 
0363         mgr->xlx_cfg |= (PCXHR_CFG_CLOCKIN_SEL_MASK |
0364                  PCXHR_CFG_CLOCK_UER1_SEL_MASK);
0365         break;
0366     default:
0367         return -EINVAL;
0368     }
0369     hr222_config_akm(mgr, AKM_MUTE_CMD);
0370 
0371     if (mgr->use_clock_type == HR22_CLOCK_TYPE_INTERNAL) {
0372         PCXHR_OUTPB(mgr, PCXHR_XLX_HIFREQ, pllreg >> 8);
0373         PCXHR_OUTPB(mgr, PCXHR_XLX_LOFREQ, pllreg & 0xff);
0374     }
0375 
0376     /* set clock source */
0377     PCXHR_OUTPB(mgr, PCXHR_XLX_CFG, mgr->xlx_cfg);
0378 
0379     /* codec speed modes */
0380     speed = rate < 55000 ? 0 : 1;
0381     if (mgr->codec_speed != speed) {
0382         mgr->codec_speed = speed;
0383         if (speed == 0)
0384             hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD);
0385         else
0386             hr222_config_akm(mgr, AKM_CLOCK_SUP_55K_CMD);
0387     }
0388 
0389     mgr->sample_rate_real = realfreq;
0390     mgr->cur_clock_type = mgr->use_clock_type;
0391 
0392     if (changed)
0393         *changed = 1;
0394 
0395     hr222_config_akm(mgr, AKM_UNMUTE_CMD);
0396 
0397     dev_dbg(&mgr->pci->dev, "set_clock to %dHz (realfreq=%d pllreg=%x)\n",
0398             rate, realfreq, pllreg);
0399     return 0;
0400 }
0401 
0402 int hr222_get_external_clock(struct pcxhr_mgr *mgr,
0403                  enum pcxhr_clock_type clock_type,
0404                  int *sample_rate)
0405 {
0406     int rate, calc_rate = 0;
0407     unsigned int ticks;
0408     unsigned char mask, reg;
0409 
0410     if (clock_type == HR22_CLOCK_TYPE_AES_SYNC) {
0411 
0412         mask = (PCXHR_SUER_CLOCK_PRESENT_MASK |
0413             PCXHR_SUER_DATA_PRESENT_MASK);
0414         reg = PCXHR_STAT_FREQ_SYNC_MASK;
0415 
0416     } else if (clock_type == HR22_CLOCK_TYPE_AES_1 && mgr->board_has_aes1) {
0417 
0418         mask = (PCXHR_SUER1_CLOCK_PRESENT_MASK |
0419             PCXHR_SUER1_DATA_PRESENT_MASK);
0420         reg = PCXHR_STAT_FREQ_UER1_MASK;
0421 
0422     } else {
0423         dev_dbg(&mgr->pci->dev,
0424             "get_external_clock : type %d not supported\n",
0425                 clock_type);
0426         return -EINVAL; /* other clocks not supported */
0427     }
0428 
0429     if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) {
0430         dev_dbg(&mgr->pci->dev,
0431             "get_external_clock(%d) = 0 Hz\n", clock_type);
0432         *sample_rate = 0;
0433         return 0; /* no external clock locked */
0434     }
0435 
0436     PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* calculate freq */
0437 
0438     /* save the measured clock frequency */
0439     reg |= PCXHR_STAT_FREQ_SAVE_MASK;
0440 
0441     if (mgr->last_reg_stat != reg) {
0442         udelay(500);    /* wait min 2 cycles of lowest freq (8000) */
0443         mgr->last_reg_stat = reg;
0444     }
0445 
0446     PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* save */
0447 
0448     /* get the frequency */
0449     ticks = (unsigned int)PCXHR_INPB(mgr, PCXHR_XLX_CFG);
0450     ticks = (ticks & 0x03) << 8;
0451     ticks |= (unsigned int)PCXHR_INPB(mgr, PCXHR_DSP_RESET);
0452 
0453     if (ticks != 0)
0454         calc_rate = 28224000 / ticks;
0455     /* rounding */
0456     if (calc_rate > 184200)
0457         rate = 192000;
0458     else if (calc_rate > 152200)
0459         rate = 176400;
0460     else if (calc_rate > 112000)
0461         rate = 128000;
0462     else if (calc_rate > 92100)
0463         rate = 96000;
0464     else if (calc_rate > 76100)
0465         rate = 88200;
0466     else if (calc_rate > 56000)
0467         rate = 64000;
0468     else if (calc_rate > 46050)
0469         rate = 48000;
0470     else if (calc_rate > 38050)
0471         rate = 44100;
0472     else if (calc_rate > 28000)
0473         rate = 32000;
0474     else if (calc_rate > 23025)
0475         rate = 24000;
0476     else if (calc_rate > 19025)
0477         rate = 22050;
0478     else if (calc_rate > 14000)
0479         rate = 16000;
0480     else if (calc_rate > 11512)
0481         rate = 12000;
0482     else if (calc_rate > 9512)
0483         rate = 11025;
0484     else if (calc_rate > 7000)
0485         rate = 8000;
0486     else
0487         rate = 0;
0488 
0489     dev_dbg(&mgr->pci->dev, "External clock is at %d Hz (measured %d Hz)\n",
0490             rate, calc_rate);
0491     *sample_rate = rate;
0492     return 0;
0493 }
0494 
0495 
0496 int hr222_read_gpio(struct pcxhr_mgr *mgr, int is_gpi, int *value)
0497 {
0498     if (is_gpi) {
0499         unsigned char reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS);
0500         *value = (int)(reg & PCXHR_STAT_GPI_MASK) >>
0501                   PCXHR_STAT_GPI_OFFSET;
0502     } else {
0503         *value = (int)(mgr->dsp_reset & PCXHR_DSP_RESET_GPO_MASK) >>
0504              PCXHR_DSP_RESET_GPO_OFFSET;
0505     }
0506     return 0;
0507 }
0508 
0509 
0510 int hr222_write_gpo(struct pcxhr_mgr *mgr, int value)
0511 {
0512     unsigned char reg = mgr->dsp_reset & ~PCXHR_DSP_RESET_GPO_MASK;
0513 
0514     reg |= (unsigned char)(value << PCXHR_DSP_RESET_GPO_OFFSET) &
0515            PCXHR_DSP_RESET_GPO_MASK;
0516 
0517     PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, reg);
0518     mgr->dsp_reset = reg;
0519     return 0;
0520 }
0521 
0522 int hr222_manage_timecode(struct pcxhr_mgr *mgr, int enable)
0523 {
0524     if (enable)
0525         mgr->dsp_reset |= PCXHR_DSP_RESET_SMPTE;
0526     else
0527         mgr->dsp_reset &= ~PCXHR_DSP_RESET_SMPTE;
0528 
0529     PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset);
0530     return 0;
0531 }
0532 
0533 int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
0534                     int is_capture, int channel)
0535 {
0536     dev_dbg(chip->card->dev,
0537         "hr222_update_analog_audio_level(%s chan=%d)\n",
0538             is_capture ? "capture" : "playback", channel);
0539     if (is_capture) {
0540         int level_l, level_r, level_mic;
0541         /* we have to update all levels */
0542         if (chip->analog_capture_active) {
0543             level_l = chip->analog_capture_volume[0];
0544             level_r = chip->analog_capture_volume[1];
0545         } else {
0546             level_l = HR222_LINE_CAPTURE_LEVEL_MIN;
0547             level_r = HR222_LINE_CAPTURE_LEVEL_MIN;
0548         }
0549         if (chip->mic_active)
0550             level_mic = chip->mic_volume;
0551         else
0552             level_mic = HR222_MICRO_CAPTURE_LEVEL_MIN;
0553         return hr222_set_hw_capture_level(chip->mgr,
0554                          level_l, level_r, level_mic);
0555     } else {
0556         int vol;
0557         if (chip->analog_playback_active[channel])
0558             vol = chip->analog_playback_volume[channel];
0559         else
0560             vol = HR222_LINE_PLAYBACK_LEVEL_MIN;
0561         return hr222_set_hw_playback_level(chip->mgr, channel, vol);
0562     }
0563 }
0564 
0565 
0566 /*texts[5] = {"Line", "Digital", "Digi+SRC", "Mic", "Line+Mic"}*/
0567 #define SOURCE_LINE 0
0568 #define SOURCE_DIGITAL  1
0569 #define SOURCE_DIGISRC  2
0570 #define SOURCE_MIC  3
0571 #define SOURCE_LINEMIC  4
0572 
0573 int hr222_set_audio_source(struct snd_pcxhr *chip)
0574 {
0575     int digital = 0;
0576     /* default analog source */
0577     chip->mgr->xlx_cfg &= ~(PCXHR_CFG_SRC_MASK |
0578                 PCXHR_CFG_DATAIN_SEL_MASK |
0579                 PCXHR_CFG_DATA_UER1_SEL_MASK);
0580 
0581     if (chip->audio_capture_source == SOURCE_DIGISRC) {
0582         chip->mgr->xlx_cfg |= PCXHR_CFG_SRC_MASK;
0583         digital = 1;
0584     } else {
0585         if (chip->audio_capture_source == SOURCE_DIGITAL)
0586             digital = 1;
0587     }
0588     if (digital) {
0589         chip->mgr->xlx_cfg |=  PCXHR_CFG_DATAIN_SEL_MASK;
0590         if (chip->mgr->board_has_aes1) {
0591             /* get data from the AES1 plug */
0592             chip->mgr->xlx_cfg |= PCXHR_CFG_DATA_UER1_SEL_MASK;
0593         }
0594         /* chip->mic_active = 0; */
0595         /* chip->analog_capture_active = 0; */
0596     } else {
0597         int update_lvl = 0;
0598         chip->analog_capture_active = 0;
0599         chip->mic_active = 0;
0600         if (chip->audio_capture_source == SOURCE_LINE ||
0601             chip->audio_capture_source == SOURCE_LINEMIC) {
0602             if (chip->analog_capture_active == 0)
0603                 update_lvl = 1;
0604             chip->analog_capture_active = 1;
0605         }
0606         if (chip->audio_capture_source == SOURCE_MIC ||
0607             chip->audio_capture_source == SOURCE_LINEMIC) {
0608             if (chip->mic_active == 0)
0609                 update_lvl = 1;
0610             chip->mic_active = 1;
0611         }
0612         if (update_lvl) {
0613             /* capture: update all 3 mutes/unmutes with one call */
0614             hr222_update_analog_audio_level(chip, 1, 0);
0615         }
0616     }
0617     /* set the source infos (max 3 bits modified) */
0618     PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CFG, chip->mgr->xlx_cfg);
0619     return 0;
0620 }
0621 
0622 
0623 int hr222_iec958_capture_byte(struct snd_pcxhr *chip,
0624                  int aes_idx, unsigned char *aes_bits)
0625 {
0626     unsigned char idx = (unsigned char)(aes_idx * 8);
0627     unsigned char temp = 0;
0628     unsigned char mask = chip->mgr->board_has_aes1 ?
0629         PCXHR_SUER1_BIT_C_READ_MASK : PCXHR_SUER_BIT_C_READ_MASK;
0630     int i;
0631     for (i = 0; i < 8; i++) {
0632         PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx++); /* idx < 192 */
0633         temp <<= 1;
0634         if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask)
0635             temp |= 1;
0636     }
0637     dev_dbg(chip->card->dev, "read iec958 AES %d byte %d = 0x%x\n",
0638             chip->chip_idx, aes_idx, temp);
0639     *aes_bits = temp;
0640     return 0;
0641 }
0642 
0643 
0644 int hr222_iec958_update_byte(struct snd_pcxhr *chip,
0645                  int aes_idx, unsigned char aes_bits)
0646 {
0647     int i;
0648     unsigned char new_bits = aes_bits;
0649     unsigned char old_bits = chip->aes_bits[aes_idx];
0650     unsigned char idx = (unsigned char)(aes_idx * 8);
0651     for (i = 0; i < 8; i++) {
0652         if ((old_bits & 0x01) != (new_bits & 0x01)) {
0653             /* idx < 192 */
0654             PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx);
0655             /* write C and U bit */
0656             PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CSUER, new_bits&0x01 ?
0657                     PCXHR_SUER_BIT_C_WRITE_MASK : 0);
0658         }
0659         idx++;
0660         old_bits >>= 1;
0661         new_bits >>= 1;
0662     }
0663     chip->aes_bits[aes_idx] = aes_bits;
0664     return 0;
0665 }
0666 
0667 static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level)
0668 {
0669     unsigned char boost_mask;
0670     boost_mask = (unsigned char) (level << PCXHR_SELMIC_PREAMPLI_OFFSET);
0671     if (boost_mask & (~PCXHR_SELMIC_PREAMPLI_MASK))
0672         return; /* only values form 0 to 3 accepted */
0673 
0674     mgr->xlx_selmic &= ~PCXHR_SELMIC_PREAMPLI_MASK;
0675     mgr->xlx_selmic |= boost_mask;
0676 
0677     PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
0678 
0679     dev_dbg(&mgr->pci->dev, "hr222_micro_boost : set %x\n", boost_mask);
0680 }
0681 
0682 static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power)
0683 {
0684     if (power)
0685         mgr->xlx_selmic |= PCXHR_SELMIC_PHANTOM_ALIM;
0686     else
0687         mgr->xlx_selmic &= ~PCXHR_SELMIC_PHANTOM_ALIM;
0688 
0689     PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
0690 
0691     dev_dbg(&mgr->pci->dev, "hr222_phantom_power : set %d\n", power);
0692 }
0693 
0694 
0695 /* mic level */
0696 static const DECLARE_TLV_DB_SCALE(db_scale_mic_hr222, -9850, 50, 650);
0697 
0698 static int hr222_mic_vol_info(struct snd_kcontrol *kcontrol,
0699                   struct snd_ctl_elem_info *uinfo)
0700 {
0701     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0702     uinfo->count = 1;
0703     uinfo->value.integer.min = HR222_MICRO_CAPTURE_LEVEL_MIN; /* -98 dB */
0704     /* gains from 9 dB to 31.5 dB not recommended; use micboost instead */
0705     uinfo->value.integer.max = HR222_MICRO_CAPTURE_LEVEL_MAX; /*  +7 dB */
0706     return 0;
0707 }
0708 
0709 static int hr222_mic_vol_get(struct snd_kcontrol *kcontrol,
0710                  struct snd_ctl_elem_value *ucontrol)
0711 {
0712     struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
0713     mutex_lock(&chip->mgr->mixer_mutex);
0714     ucontrol->value.integer.value[0] = chip->mic_volume;
0715     mutex_unlock(&chip->mgr->mixer_mutex);
0716     return 0;
0717 }
0718 
0719 static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol,
0720                  struct snd_ctl_elem_value *ucontrol)
0721 {
0722     struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
0723     int changed = 0;
0724     mutex_lock(&chip->mgr->mixer_mutex);
0725     if (chip->mic_volume != ucontrol->value.integer.value[0]) {
0726         changed = 1;
0727         chip->mic_volume = ucontrol->value.integer.value[0];
0728         hr222_update_analog_audio_level(chip, 1, 0);
0729     }
0730     mutex_unlock(&chip->mgr->mixer_mutex);
0731     return changed;
0732 }
0733 
0734 static const struct snd_kcontrol_new hr222_control_mic_level = {
0735     .iface =    SNDRV_CTL_ELEM_IFACE_MIXER,
0736     .access =   (SNDRV_CTL_ELEM_ACCESS_READWRITE |
0737              SNDRV_CTL_ELEM_ACCESS_TLV_READ),
0738     .name =     "Mic Capture Volume",
0739     .info =     hr222_mic_vol_info,
0740     .get =      hr222_mic_vol_get,
0741     .put =      hr222_mic_vol_put,
0742     .tlv = { .p = db_scale_mic_hr222 },
0743 };
0744 
0745 
0746 /* mic boost level */
0747 static const DECLARE_TLV_DB_SCALE(db_scale_micboost_hr222, 0, 1800, 5400);
0748 
0749 static int hr222_mic_boost_info(struct snd_kcontrol *kcontrol,
0750                 struct snd_ctl_elem_info *uinfo)
0751 {
0752     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0753     uinfo->count = 1;
0754     uinfo->value.integer.min = 0;   /*  0 dB */
0755     uinfo->value.integer.max = 3;   /* 54 dB */
0756     return 0;
0757 }
0758 
0759 static int hr222_mic_boost_get(struct snd_kcontrol *kcontrol,
0760                    struct snd_ctl_elem_value *ucontrol)
0761 {
0762     struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
0763     mutex_lock(&chip->mgr->mixer_mutex);
0764     ucontrol->value.integer.value[0] = chip->mic_boost;
0765     mutex_unlock(&chip->mgr->mixer_mutex);
0766     return 0;
0767 }
0768 
0769 static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol,
0770                    struct snd_ctl_elem_value *ucontrol)
0771 {
0772     struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
0773     int changed = 0;
0774     mutex_lock(&chip->mgr->mixer_mutex);
0775     if (chip->mic_boost != ucontrol->value.integer.value[0]) {
0776         changed = 1;
0777         chip->mic_boost = ucontrol->value.integer.value[0];
0778         hr222_micro_boost(chip->mgr, chip->mic_boost);
0779     }
0780     mutex_unlock(&chip->mgr->mixer_mutex);
0781     return changed;
0782 }
0783 
0784 static const struct snd_kcontrol_new hr222_control_mic_boost = {
0785     .iface =    SNDRV_CTL_ELEM_IFACE_MIXER,
0786     .access =   (SNDRV_CTL_ELEM_ACCESS_READWRITE |
0787              SNDRV_CTL_ELEM_ACCESS_TLV_READ),
0788     .name =     "MicBoost Capture Volume",
0789     .info =     hr222_mic_boost_info,
0790     .get =      hr222_mic_boost_get,
0791     .put =      hr222_mic_boost_put,
0792     .tlv = { .p = db_scale_micboost_hr222 },
0793 };
0794 
0795 
0796 /******************* Phantom power switch *******************/
0797 #define hr222_phantom_power_info    snd_ctl_boolean_mono_info
0798 
0799 static int hr222_phantom_power_get(struct snd_kcontrol *kcontrol,
0800                    struct snd_ctl_elem_value *ucontrol)
0801 {
0802     struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
0803     mutex_lock(&chip->mgr->mixer_mutex);
0804     ucontrol->value.integer.value[0] = chip->phantom_power;
0805     mutex_unlock(&chip->mgr->mixer_mutex);
0806     return 0;
0807 }
0808 
0809 static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol,
0810                    struct snd_ctl_elem_value *ucontrol)
0811 {
0812     struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
0813     int power, changed = 0;
0814 
0815     mutex_lock(&chip->mgr->mixer_mutex);
0816     power = !!ucontrol->value.integer.value[0];
0817     if (chip->phantom_power != power) {
0818         hr222_phantom_power(chip->mgr, power);
0819         chip->phantom_power = power;
0820         changed = 1;
0821     }
0822     mutex_unlock(&chip->mgr->mixer_mutex);
0823     return changed;
0824 }
0825 
0826 static const struct snd_kcontrol_new hr222_phantom_power_switch = {
0827     .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0828     .name = "Phantom Power Switch",
0829     .info = hr222_phantom_power_info,
0830     .get = hr222_phantom_power_get,
0831     .put = hr222_phantom_power_put,
0832 };
0833 
0834 
0835 int hr222_add_mic_controls(struct snd_pcxhr *chip)
0836 {
0837     int err;
0838     if (!chip->mgr->board_has_mic)
0839         return 0;
0840 
0841     /* controls */
0842     err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_level,
0843                            chip));
0844     if (err < 0)
0845         return err;
0846 
0847     err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_boost,
0848                            chip));
0849     if (err < 0)
0850         return err;
0851 
0852     err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_phantom_power_switch,
0853                            chip));
0854     return err;
0855 }