1 /* 2 * Driver for Digigram pcxhr compatible soundcards 3 * 4 * mixer interface for stereo cards 5 * 6 * Copyright (c) 2004 by Digigram <alsa@digigram.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23 #include <linux/delay.h> 24 #include <linux/io.h> 25 #include <sound/core.h> 26 #include <sound/control.h> 27 #include <sound/tlv.h> 28 #include <sound/asoundef.h> 29 #include "pcxhr.h" 30 #include "pcxhr_core.h" 31 #include "pcxhr_mix22.h" 32 33 34 /* registers used on the DSP and Xilinx (port 2) : HR stereo cards only */ 35 #define PCXHR_DSP_RESET 0x20 36 #define PCXHR_XLX_CFG 0x24 37 #define PCXHR_XLX_RUER 0x28 38 #define PCXHR_XLX_DATA 0x2C 39 #define PCXHR_XLX_STATUS 0x30 40 #define PCXHR_XLX_LOFREQ 0x34 41 #define PCXHR_XLX_HIFREQ 0x38 42 #define PCXHR_XLX_CSUER 0x3C 43 #define PCXHR_XLX_SELMIC 0x40 44 45 #define PCXHR_DSP 2 46 47 /* byte access only ! */ 48 #define PCXHR_INPB(mgr, x) inb((mgr)->port[PCXHR_DSP] + (x)) 49 #define PCXHR_OUTPB(mgr, x, data) outb((data), (mgr)->port[PCXHR_DSP] + (x)) 50 51 52 /* values for PCHR_DSP_RESET register */ 53 #define PCXHR_DSP_RESET_DSP 0x01 54 #define PCXHR_DSP_RESET_MUTE 0x02 55 #define PCXHR_DSP_RESET_CODEC 0x08 56 #define PCXHR_DSP_RESET_GPO_OFFSET 5 57 #define PCXHR_DSP_RESET_GPO_MASK 0x60 58 59 /* values for PCHR_XLX_CFG register */ 60 #define PCXHR_CFG_SYNCDSP_MASK 0x80 61 #define PCXHR_CFG_DEPENDENCY_MASK 0x60 62 #define PCXHR_CFG_INDEPENDANT_SEL 0x00 63 #define PCXHR_CFG_MASTER_SEL 0x40 64 #define PCXHR_CFG_SLAVE_SEL 0x20 65 #define PCXHR_CFG_DATA_UER1_SEL_MASK 0x10 /* 0 (UER0), 1(UER1) */ 66 #define PCXHR_CFG_DATAIN_SEL_MASK 0x08 /* 0 (ana), 1 (UER) */ 67 #define PCXHR_CFG_SRC_MASK 0x04 /* 0 (Bypass), 1 (SRC Actif) */ 68 #define PCXHR_CFG_CLOCK_UER1_SEL_MASK 0x02 /* 0 (UER0), 1(UER1) */ 69 #define PCXHR_CFG_CLOCKIN_SEL_MASK 0x01 /* 0 (internal), 1 (AES/EBU) */ 70 71 /* values for PCHR_XLX_DATA register */ 72 #define PCXHR_DATA_CODEC 0x80 73 #define AKM_POWER_CONTROL_CMD 0xA007 74 #define AKM_RESET_ON_CMD 0xA100 75 #define AKM_RESET_OFF_CMD 0xA103 76 #define AKM_CLOCK_INF_55K_CMD 0xA240 77 #define AKM_CLOCK_SUP_55K_CMD 0xA24D 78 #define AKM_MUTE_CMD 0xA38D 79 #define AKM_UNMUTE_CMD 0xA30D 80 #define AKM_LEFT_LEVEL_CMD 0xA600 81 #define AKM_RIGHT_LEVEL_CMD 0xA700 82 83 /* values for PCHR_XLX_STATUS register - READ */ 84 #define PCXHR_STAT_SRC_LOCK 0x01 85 #define PCXHR_STAT_LEVEL_IN 0x02 86 #define PCXHR_STAT_GPI_OFFSET 2 87 #define PCXHR_STAT_GPI_MASK 0x0C 88 #define PCXHR_STAT_MIC_CAPS 0x10 89 /* values for PCHR_XLX_STATUS register - WRITE */ 90 #define PCXHR_STAT_FREQ_SYNC_MASK 0x01 91 #define PCXHR_STAT_FREQ_UER1_MASK 0x02 92 #define PCXHR_STAT_FREQ_SAVE_MASK 0x80 93 94 /* values for PCHR_XLX_CSUER register */ 95 #define PCXHR_SUER1_BIT_U_READ_MASK 0x80 96 #define PCXHR_SUER1_BIT_C_READ_MASK 0x40 97 #define PCXHR_SUER1_DATA_PRESENT_MASK 0x20 98 #define PCXHR_SUER1_CLOCK_PRESENT_MASK 0x10 99 #define PCXHR_SUER_BIT_U_READ_MASK 0x08 100 #define PCXHR_SUER_BIT_C_READ_MASK 0x04 101 #define PCXHR_SUER_DATA_PRESENT_MASK 0x02 102 #define PCXHR_SUER_CLOCK_PRESENT_MASK 0x01 103 104 #define PCXHR_SUER_BIT_U_WRITE_MASK 0x02 105 #define PCXHR_SUER_BIT_C_WRITE_MASK 0x01 106 107 /* values for PCXHR_XLX_SELMIC register - WRITE */ 108 #define PCXHR_SELMIC_PREAMPLI_OFFSET 2 109 #define PCXHR_SELMIC_PREAMPLI_MASK 0x0C 110 #define PCXHR_SELMIC_PHANTOM_ALIM 0x80 111 112 113 static const unsigned char g_hr222_p_level[] = { 114 0x00, /* [000] -49.5 dB: AKM[000] = -1.#INF dB (mute) */ 115 0x01, /* [001] -49.0 dB: AKM[001] = -48.131 dB (diff=0.86920 dB) */ 116 0x01, /* [002] -48.5 dB: AKM[001] = -48.131 dB (diff=0.36920 dB) */ 117 0x01, /* [003] -48.0 dB: AKM[001] = -48.131 dB (diff=0.13080 dB) */ 118 0x01, /* [004] -47.5 dB: AKM[001] = -48.131 dB (diff=0.63080 dB) */ 119 0x01, /* [005] -46.5 dB: AKM[001] = -48.131 dB (diff=1.63080 dB) */ 120 0x01, /* [006] -47.0 dB: AKM[001] = -48.131 dB (diff=1.13080 dB) */ 121 0x01, /* [007] -46.0 dB: AKM[001] = -48.131 dB (diff=2.13080 dB) */ 122 0x01, /* [008] -45.5 dB: AKM[001] = -48.131 dB (diff=2.63080 dB) */ 123 0x02, /* [009] -45.0 dB: AKM[002] = -42.110 dB (diff=2.88980 dB) */ 124 0x02, /* [010] -44.5 dB: AKM[002] = -42.110 dB (diff=2.38980 dB) */ 125 0x02, /* [011] -44.0 dB: AKM[002] = -42.110 dB (diff=1.88980 dB) */ 126 0x02, /* [012] -43.5 dB: AKM[002] = -42.110 dB (diff=1.38980 dB) */ 127 0x02, /* [013] -43.0 dB: AKM[002] = -42.110 dB (diff=0.88980 dB) */ 128 0x02, /* [014] -42.5 dB: AKM[002] = -42.110 dB (diff=0.38980 dB) */ 129 0x02, /* [015] -42.0 dB: AKM[002] = -42.110 dB (diff=0.11020 dB) */ 130 0x02, /* [016] -41.5 dB: AKM[002] = -42.110 dB (diff=0.61020 dB) */ 131 0x02, /* [017] -41.0 dB: AKM[002] = -42.110 dB (diff=1.11020 dB) */ 132 0x02, /* [018] -40.5 dB: AKM[002] = -42.110 dB (diff=1.61020 dB) */ 133 0x03, /* [019] -40.0 dB: AKM[003] = -38.588 dB (diff=1.41162 dB) */ 134 0x03, /* [020] -39.5 dB: AKM[003] = -38.588 dB (diff=0.91162 dB) */ 135 0x03, /* [021] -39.0 dB: AKM[003] = -38.588 dB (diff=0.41162 dB) */ 136 0x03, /* [022] -38.5 dB: AKM[003] = -38.588 dB (diff=0.08838 dB) */ 137 0x03, /* [023] -38.0 dB: AKM[003] = -38.588 dB (diff=0.58838 dB) */ 138 0x03, /* [024] -37.5 dB: AKM[003] = -38.588 dB (diff=1.08838 dB) */ 139 0x04, /* [025] -37.0 dB: AKM[004] = -36.090 dB (diff=0.91040 dB) */ 140 0x04, /* [026] -36.5 dB: AKM[004] = -36.090 dB (diff=0.41040 dB) */ 141 0x04, /* [027] -36.0 dB: AKM[004] = -36.090 dB (diff=0.08960 dB) */ 142 0x04, /* [028] -35.5 dB: AKM[004] = -36.090 dB (diff=0.58960 dB) */ 143 0x05, /* [029] -35.0 dB: AKM[005] = -34.151 dB (diff=0.84860 dB) */ 144 0x05, /* [030] -34.5 dB: AKM[005] = -34.151 dB (diff=0.34860 dB) */ 145 0x05, /* [031] -34.0 dB: AKM[005] = -34.151 dB (diff=0.15140 dB) */ 146 0x05, /* [032] -33.5 dB: AKM[005] = -34.151 dB (diff=0.65140 dB) */ 147 0x06, /* [033] -33.0 dB: AKM[006] = -32.568 dB (diff=0.43222 dB) */ 148 0x06, /* [034] -32.5 dB: AKM[006] = -32.568 dB (diff=0.06778 dB) */ 149 0x06, /* [035] -32.0 dB: AKM[006] = -32.568 dB (diff=0.56778 dB) */ 150 0x07, /* [036] -31.5 dB: AKM[007] = -31.229 dB (diff=0.27116 dB) */ 151 0x07, /* [037] -31.0 dB: AKM[007] = -31.229 dB (diff=0.22884 dB) */ 152 0x08, /* [038] -30.5 dB: AKM[008] = -30.069 dB (diff=0.43100 dB) */ 153 0x08, /* [039] -30.0 dB: AKM[008] = -30.069 dB (diff=0.06900 dB) */ 154 0x09, /* [040] -29.5 dB: AKM[009] = -29.046 dB (diff=0.45405 dB) */ 155 0x09, /* [041] -29.0 dB: AKM[009] = -29.046 dB (diff=0.04595 dB) */ 156 0x0a, /* [042] -28.5 dB: AKM[010] = -28.131 dB (diff=0.36920 dB) */ 157 0x0a, /* [043] -28.0 dB: AKM[010] = -28.131 dB (diff=0.13080 dB) */ 158 0x0b, /* [044] -27.5 dB: AKM[011] = -27.303 dB (diff=0.19705 dB) */ 159 0x0b, /* [045] -27.0 dB: AKM[011] = -27.303 dB (diff=0.30295 dB) */ 160 0x0c, /* [046] -26.5 dB: AKM[012] = -26.547 dB (diff=0.04718 dB) */ 161 0x0d, /* [047] -26.0 dB: AKM[013] = -25.852 dB (diff=0.14806 dB) */ 162 0x0e, /* [048] -25.5 dB: AKM[014] = -25.208 dB (diff=0.29176 dB) */ 163 0x0e, /* [049] -25.0 dB: AKM[014] = -25.208 dB (diff=0.20824 dB) */ 164 0x0f, /* [050] -24.5 dB: AKM[015] = -24.609 dB (diff=0.10898 dB) */ 165 0x10, /* [051] -24.0 dB: AKM[016] = -24.048 dB (diff=0.04840 dB) */ 166 0x11, /* [052] -23.5 dB: AKM[017] = -23.522 dB (diff=0.02183 dB) */ 167 0x12, /* [053] -23.0 dB: AKM[018] = -23.025 dB (diff=0.02535 dB) */ 168 0x13, /* [054] -22.5 dB: AKM[019] = -22.556 dB (diff=0.05573 dB) */ 169 0x14, /* [055] -22.0 dB: AKM[020] = -22.110 dB (diff=0.11020 dB) */ 170 0x15, /* [056] -21.5 dB: AKM[021] = -21.686 dB (diff=0.18642 dB) */ 171 0x17, /* [057] -21.0 dB: AKM[023] = -20.896 dB (diff=0.10375 dB) */ 172 0x18, /* [058] -20.5 dB: AKM[024] = -20.527 dB (diff=0.02658 dB) */ 173 0x1a, /* [059] -20.0 dB: AKM[026] = -19.831 dB (diff=0.16866 dB) */ 174 0x1b, /* [060] -19.5 dB: AKM[027] = -19.504 dB (diff=0.00353 dB) */ 175 0x1d, /* [061] -19.0 dB: AKM[029] = -18.883 dB (diff=0.11716 dB) */ 176 0x1e, /* [062] -18.5 dB: AKM[030] = -18.588 dB (diff=0.08838 dB) */ 177 0x20, /* [063] -18.0 dB: AKM[032] = -18.028 dB (diff=0.02780 dB) */ 178 0x22, /* [064] -17.5 dB: AKM[034] = -17.501 dB (diff=0.00123 dB) */ 179 0x24, /* [065] -17.0 dB: AKM[036] = -17.005 dB (diff=0.00475 dB) */ 180 0x26, /* [066] -16.5 dB: AKM[038] = -16.535 dB (diff=0.03513 dB) */ 181 0x28, /* [067] -16.0 dB: AKM[040] = -16.090 dB (diff=0.08960 dB) */ 182 0x2b, /* [068] -15.5 dB: AKM[043] = -15.461 dB (diff=0.03857 dB) */ 183 0x2d, /* [069] -15.0 dB: AKM[045] = -15.067 dB (diff=0.06655 dB) */ 184 0x30, /* [070] -14.5 dB: AKM[048] = -14.506 dB (diff=0.00598 dB) */ 185 0x33, /* [071] -14.0 dB: AKM[051] = -13.979 dB (diff=0.02060 dB) */ 186 0x36, /* [072] -13.5 dB: AKM[054] = -13.483 dB (diff=0.01707 dB) */ 187 0x39, /* [073] -13.0 dB: AKM[057] = -13.013 dB (diff=0.01331 dB) */ 188 0x3c, /* [074] -12.5 dB: AKM[060] = -12.568 dB (diff=0.06778 dB) */ 189 0x40, /* [075] -12.0 dB: AKM[064] = -12.007 dB (diff=0.00720 dB) */ 190 0x44, /* [076] -11.5 dB: AKM[068] = -11.481 dB (diff=0.01937 dB) */ 191 0x48, /* [077] -11.0 dB: AKM[072] = -10.984 dB (diff=0.01585 dB) */ 192 0x4c, /* [078] -10.5 dB: AKM[076] = -10.515 dB (diff=0.01453 dB) */ 193 0x51, /* [079] -10.0 dB: AKM[081] = -9.961 dB (diff=0.03890 dB) */ 194 0x55, /* [080] -9.5 dB: AKM[085] = -9.542 dB (diff=0.04243 dB) */ 195 0x5a, /* [081] -9.0 dB: AKM[090] = -9.046 dB (diff=0.04595 dB) */ 196 0x60, /* [082] -8.5 dB: AKM[096] = -8.485 dB (diff=0.01462 dB) */ 197 0x66, /* [083] -8.0 dB: AKM[102] = -7.959 dB (diff=0.04120 dB) */ 198 0x6c, /* [084] -7.5 dB: AKM[108] = -7.462 dB (diff=0.03767 dB) */ 199 0x72, /* [085] -7.0 dB: AKM[114] = -6.993 dB (diff=0.00729 dB) */ 200 0x79, /* [086] -6.5 dB: AKM[121] = -6.475 dB (diff=0.02490 dB) */ 201 0x80, /* [087] -6.0 dB: AKM[128] = -5.987 dB (diff=0.01340 dB) */ 202 0x87, /* [088] -5.5 dB: AKM[135] = -5.524 dB (diff=0.02413 dB) */ 203 0x8f, /* [089] -5.0 dB: AKM[143] = -5.024 dB (diff=0.02408 dB) */ 204 0x98, /* [090] -4.5 dB: AKM[152] = -4.494 dB (diff=0.00607 dB) */ 205 0xa1, /* [091] -4.0 dB: AKM[161] = -3.994 dB (diff=0.00571 dB) */ 206 0xaa, /* [092] -3.5 dB: AKM[170] = -3.522 dB (diff=0.02183 dB) */ 207 0xb5, /* [093] -3.0 dB: AKM[181] = -2.977 dB (diff=0.02277 dB) */ 208 0xbf, /* [094] -2.5 dB: AKM[191] = -2.510 dB (diff=0.01014 dB) */ 209 0xcb, /* [095] -2.0 dB: AKM[203] = -1.981 dB (diff=0.01912 dB) */ 210 0xd7, /* [096] -1.5 dB: AKM[215] = -1.482 dB (diff=0.01797 dB) */ 211 0xe3, /* [097] -1.0 dB: AKM[227] = -1.010 dB (diff=0.01029 dB) */ 212 0xf1, /* [098] -0.5 dB: AKM[241] = -0.490 dB (diff=0.00954 dB) */ 213 0xff, /* [099] +0.0 dB: AKM[255] = +0.000 dB (diff=0.00000 dB) */ 214 }; 215 216 217 static void hr222_config_akm(struct pcxhr_mgr *mgr, unsigned short data) 218 { 219 unsigned short mask = 0x8000; 220 /* activate access to codec registers */ 221 PCXHR_INPB(mgr, PCXHR_XLX_HIFREQ); 222 223 while (mask) { 224 PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, 225 data & mask ? PCXHR_DATA_CODEC : 0); 226 mask >>= 1; 227 } 228 /* termiate access to codec registers */ 229 PCXHR_INPB(mgr, PCXHR_XLX_RUER); 230 } 231 232 233 static int hr222_set_hw_playback_level(struct pcxhr_mgr *mgr, 234 int idx, int level) 235 { 236 unsigned short cmd; 237 if (idx > 1 || 238 level < 0 || 239 level >= ARRAY_SIZE(g_hr222_p_level)) 240 return -EINVAL; 241 242 if (idx == 0) 243 cmd = AKM_LEFT_LEVEL_CMD; 244 else 245 cmd = AKM_RIGHT_LEVEL_CMD; 246 247 /* conversion from PmBoardCodedLevel to AKM nonlinear programming */ 248 cmd += g_hr222_p_level[level]; 249 250 hr222_config_akm(mgr, cmd); 251 return 0; 252 } 253 254 255 static int hr222_set_hw_capture_level(struct pcxhr_mgr *mgr, 256 int level_l, int level_r, int level_mic) 257 { 258 /* program all input levels at the same time */ 259 unsigned int data; 260 int i; 261 262 if (!mgr->capture_chips) 263 return -EINVAL; /* no PCX22 */ 264 265 data = ((level_mic & 0xff) << 24); /* micro is mono, but apply */ 266 data |= ((level_mic & 0xff) << 16); /* level on both channels */ 267 data |= ((level_r & 0xff) << 8); /* line input right channel */ 268 data |= (level_l & 0xff); /* line input left channel */ 269 270 PCXHR_INPB(mgr, PCXHR_XLX_DATA); /* activate input codec */ 271 /* send 32 bits (4 x 8 bits) */ 272 for (i = 0; i < 32; i++, data <<= 1) { 273 PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, 274 (data & 0x80000000) ? PCXHR_DATA_CODEC : 0); 275 } 276 PCXHR_INPB(mgr, PCXHR_XLX_RUER); /* close input level codec */ 277 return 0; 278 } 279 280 static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level); 281 282 int hr222_sub_init(struct pcxhr_mgr *mgr) 283 { 284 unsigned char reg; 285 286 mgr->board_has_analog = 1; /* analog always available */ 287 mgr->xlx_cfg = PCXHR_CFG_SYNCDSP_MASK; 288 289 reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS); 290 if (reg & PCXHR_STAT_MIC_CAPS) 291 mgr->board_has_mic = 1; /* microphone available */ 292 snd_printdd("MIC input available = %d\n", mgr->board_has_mic); 293 294 /* reset codec */ 295 PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 296 PCXHR_DSP_RESET_DSP); 297 msleep(5); 298 mgr->dsp_reset = PCXHR_DSP_RESET_DSP | 299 PCXHR_DSP_RESET_MUTE | 300 PCXHR_DSP_RESET_CODEC; 301 PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset); 302 /* hr222_write_gpo(mgr, 0); does the same */ 303 msleep(5); 304 305 /* config AKM */ 306 hr222_config_akm(mgr, AKM_POWER_CONTROL_CMD); 307 hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); 308 hr222_config_akm(mgr, AKM_UNMUTE_CMD); 309 hr222_config_akm(mgr, AKM_RESET_OFF_CMD); 310 311 /* init micro boost */ 312 hr222_micro_boost(mgr, 0); 313 314 return 0; 315 } 316 317 318 /* calc PLL register */ 319 /* TODO : there is a very similar fct in pcxhr.c */ 320 static int hr222_pll_freq_register(unsigned int freq, 321 unsigned int *pllreg, 322 unsigned int *realfreq) 323 { 324 unsigned int reg; 325 326 if (freq < 6900 || freq > 219000) 327 return -EINVAL; 328 reg = (28224000 * 2) / freq; 329 reg = (reg - 1) / 2; 330 if (reg < 0x100) 331 *pllreg = reg + 0xC00; 332 else if (reg < 0x200) 333 *pllreg = reg + 0x800; 334 else if (reg < 0x400) 335 *pllreg = reg & 0x1ff; 336 else if (reg < 0x800) { 337 *pllreg = ((reg >> 1) & 0x1ff) + 0x200; 338 reg &= ~1; 339 } else { 340 *pllreg = ((reg >> 2) & 0x1ff) + 0x400; 341 reg &= ~3; 342 } 343 if (realfreq) 344 *realfreq = (28224000 / (reg + 1)); 345 return 0; 346 } 347 348 int hr222_sub_set_clock(struct pcxhr_mgr *mgr, 349 unsigned int rate, 350 int *changed) 351 { 352 unsigned int speed, pllreg = 0; 353 int err; 354 unsigned realfreq = rate; 355 356 switch (mgr->use_clock_type) { 357 case HR22_CLOCK_TYPE_INTERNAL: 358 err = hr222_pll_freq_register(rate, &pllreg, &realfreq); 359 if (err) 360 return err; 361 362 mgr->xlx_cfg &= ~(PCXHR_CFG_CLOCKIN_SEL_MASK | 363 PCXHR_CFG_CLOCK_UER1_SEL_MASK); 364 break; 365 case HR22_CLOCK_TYPE_AES_SYNC: 366 mgr->xlx_cfg |= PCXHR_CFG_CLOCKIN_SEL_MASK; 367 mgr->xlx_cfg &= ~PCXHR_CFG_CLOCK_UER1_SEL_MASK; 368 break; 369 case HR22_CLOCK_TYPE_AES_1: 370 if (!mgr->board_has_aes1) 371 return -EINVAL; 372 373 mgr->xlx_cfg |= (PCXHR_CFG_CLOCKIN_SEL_MASK | 374 PCXHR_CFG_CLOCK_UER1_SEL_MASK); 375 break; 376 default: 377 return -EINVAL; 378 } 379 hr222_config_akm(mgr, AKM_MUTE_CMD); 380 381 if (mgr->use_clock_type == HR22_CLOCK_TYPE_INTERNAL) { 382 PCXHR_OUTPB(mgr, PCXHR_XLX_HIFREQ, pllreg >> 8); 383 PCXHR_OUTPB(mgr, PCXHR_XLX_LOFREQ, pllreg & 0xff); 384 } 385 386 /* set clock source */ 387 PCXHR_OUTPB(mgr, PCXHR_XLX_CFG, mgr->xlx_cfg); 388 389 /* codec speed modes */ 390 speed = rate < 55000 ? 0 : 1; 391 if (mgr->codec_speed != speed) { 392 mgr->codec_speed = speed; 393 if (speed == 0) 394 hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); 395 else 396 hr222_config_akm(mgr, AKM_CLOCK_SUP_55K_CMD); 397 } 398 399 mgr->sample_rate_real = realfreq; 400 mgr->cur_clock_type = mgr->use_clock_type; 401 402 if (changed) 403 *changed = 1; 404 405 hr222_config_akm(mgr, AKM_UNMUTE_CMD); 406 407 snd_printdd("set_clock to %dHz (realfreq=%d pllreg=%x)\n", 408 rate, realfreq, pllreg); 409 return 0; 410 } 411 412 int hr222_get_external_clock(struct pcxhr_mgr *mgr, 413 enum pcxhr_clock_type clock_type, 414 int *sample_rate) 415 { 416 int rate, calc_rate = 0; 417 unsigned int ticks; 418 unsigned char mask, reg; 419 420 if (clock_type == HR22_CLOCK_TYPE_AES_SYNC) { 421 422 mask = (PCXHR_SUER_CLOCK_PRESENT_MASK | 423 PCXHR_SUER_DATA_PRESENT_MASK); 424 reg = PCXHR_STAT_FREQ_SYNC_MASK; 425 426 } else if (clock_type == HR22_CLOCK_TYPE_AES_1 && mgr->board_has_aes1) { 427 428 mask = (PCXHR_SUER1_CLOCK_PRESENT_MASK | 429 PCXHR_SUER1_DATA_PRESENT_MASK); 430 reg = PCXHR_STAT_FREQ_UER1_MASK; 431 432 } else { 433 snd_printdd("get_external_clock : type %d not supported\n", 434 clock_type); 435 return -EINVAL; /* other clocks not supported */ 436 } 437 438 if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) { 439 snd_printdd("get_external_clock(%d) = 0 Hz\n", clock_type); 440 *sample_rate = 0; 441 return 0; /* no external clock locked */ 442 } 443 444 PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* calculate freq */ 445 446 /* save the measured clock frequency */ 447 reg |= PCXHR_STAT_FREQ_SAVE_MASK; 448 449 if (mgr->last_reg_stat != reg) { 450 udelay(500); /* wait min 2 cycles of lowest freq (8000) */ 451 mgr->last_reg_stat = reg; 452 } 453 454 PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* save */ 455 456 /* get the frequency */ 457 ticks = (unsigned int)PCXHR_INPB(mgr, PCXHR_XLX_CFG); 458 ticks = (ticks & 0x03) << 8; 459 ticks |= (unsigned int)PCXHR_INPB(mgr, PCXHR_DSP_RESET); 460 461 if (ticks != 0) 462 calc_rate = 28224000 / ticks; 463 /* rounding */ 464 if (calc_rate > 184200) 465 rate = 192000; 466 else if (calc_rate > 152200) 467 rate = 176400; 468 else if (calc_rate > 112000) 469 rate = 128000; 470 else if (calc_rate > 92100) 471 rate = 96000; 472 else if (calc_rate > 76100) 473 rate = 88200; 474 else if (calc_rate > 56000) 475 rate = 64000; 476 else if (calc_rate > 46050) 477 rate = 48000; 478 else if (calc_rate > 38050) 479 rate = 44100; 480 else if (calc_rate > 28000) 481 rate = 32000; 482 else if (calc_rate > 23025) 483 rate = 24000; 484 else if (calc_rate > 19025) 485 rate = 22050; 486 else if (calc_rate > 14000) 487 rate = 16000; 488 else if (calc_rate > 11512) 489 rate = 12000; 490 else if (calc_rate > 9512) 491 rate = 11025; 492 else if (calc_rate > 7000) 493 rate = 8000; 494 else 495 rate = 0; 496 497 snd_printdd("External clock is at %d Hz (measured %d Hz)\n", 498 rate, calc_rate); 499 *sample_rate = rate; 500 return 0; 501 } 502 503 504 int hr222_read_gpio(struct pcxhr_mgr *mgr, int is_gpi, int *value) 505 { 506 if (is_gpi) { 507 unsigned char reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS); 508 *value = (int)(reg & PCXHR_STAT_GPI_MASK) >> 509 PCXHR_STAT_GPI_OFFSET; 510 } else { 511 *value = (int)(mgr->dsp_reset & PCXHR_DSP_RESET_GPO_MASK) >> 512 PCXHR_DSP_RESET_GPO_OFFSET; 513 } 514 return 0; 515 } 516 517 518 int hr222_write_gpo(struct pcxhr_mgr *mgr, int value) 519 { 520 unsigned char reg = mgr->dsp_reset & ~PCXHR_DSP_RESET_GPO_MASK; 521 522 reg |= (unsigned char)(value << PCXHR_DSP_RESET_GPO_OFFSET) & 523 PCXHR_DSP_RESET_GPO_MASK; 524 525 PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, reg); 526 mgr->dsp_reset = reg; 527 return 0; 528 } 529 530 531 int hr222_update_analog_audio_level(struct snd_pcxhr *chip, 532 int is_capture, int channel) 533 { 534 snd_printdd("hr222_update_analog_audio_level(%s chan=%d)\n", 535 is_capture ? "capture" : "playback", channel); 536 if (is_capture) { 537 int level_l, level_r, level_mic; 538 /* we have to update all levels */ 539 if (chip->analog_capture_active) { 540 level_l = chip->analog_capture_volume[0]; 541 level_r = chip->analog_capture_volume[1]; 542 } else { 543 level_l = HR222_LINE_CAPTURE_LEVEL_MIN; 544 level_r = HR222_LINE_CAPTURE_LEVEL_MIN; 545 } 546 if (chip->mic_active) 547 level_mic = chip->mic_volume; 548 else 549 level_mic = HR222_MICRO_CAPTURE_LEVEL_MIN; 550 return hr222_set_hw_capture_level(chip->mgr, 551 level_l, level_r, level_mic); 552 } else { 553 int vol; 554 if (chip->analog_playback_active[channel]) 555 vol = chip->analog_playback_volume[channel]; 556 else 557 vol = HR222_LINE_PLAYBACK_LEVEL_MIN; 558 return hr222_set_hw_playback_level(chip->mgr, channel, vol); 559 } 560 } 561 562 563 /*texts[5] = {"Line", "Digital", "Digi+SRC", "Mic", "Line+Mic"}*/ 564 #define SOURCE_LINE 0 565 #define SOURCE_DIGITAL 1 566 #define SOURCE_DIGISRC 2 567 #define SOURCE_MIC 3 568 #define SOURCE_LINEMIC 4 569 570 int hr222_set_audio_source(struct snd_pcxhr *chip) 571 { 572 int digital = 0; 573 /* default analog source */ 574 chip->mgr->xlx_cfg &= ~(PCXHR_CFG_SRC_MASK | 575 PCXHR_CFG_DATAIN_SEL_MASK | 576 PCXHR_CFG_DATA_UER1_SEL_MASK); 577 578 if (chip->audio_capture_source == SOURCE_DIGISRC) { 579 chip->mgr->xlx_cfg |= PCXHR_CFG_SRC_MASK; 580 digital = 1; 581 } else { 582 if (chip->audio_capture_source == SOURCE_DIGITAL) 583 digital = 1; 584 } 585 if (digital) { 586 chip->mgr->xlx_cfg |= PCXHR_CFG_DATAIN_SEL_MASK; 587 if (chip->mgr->board_has_aes1) { 588 /* get data from the AES1 plug */ 589 chip->mgr->xlx_cfg |= PCXHR_CFG_DATA_UER1_SEL_MASK; 590 } 591 /* chip->mic_active = 0; */ 592 /* chip->analog_capture_active = 0; */ 593 } else { 594 int update_lvl = 0; 595 chip->analog_capture_active = 0; 596 chip->mic_active = 0; 597 if (chip->audio_capture_source == SOURCE_LINE || 598 chip->audio_capture_source == SOURCE_LINEMIC) { 599 if (chip->analog_capture_active == 0) 600 update_lvl = 1; 601 chip->analog_capture_active = 1; 602 } 603 if (chip->audio_capture_source == SOURCE_MIC || 604 chip->audio_capture_source == SOURCE_LINEMIC) { 605 if (chip->mic_active == 0) 606 update_lvl = 1; 607 chip->mic_active = 1; 608 } 609 if (update_lvl) { 610 /* capture: update all 3 mutes/unmutes with one call */ 611 hr222_update_analog_audio_level(chip, 1, 0); 612 } 613 } 614 /* set the source infos (max 3 bits modified) */ 615 PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CFG, chip->mgr->xlx_cfg); 616 return 0; 617 } 618 619 620 int hr222_iec958_capture_byte(struct snd_pcxhr *chip, 621 int aes_idx, unsigned char *aes_bits) 622 { 623 unsigned char idx = (unsigned char)(aes_idx * 8); 624 unsigned char temp = 0; 625 unsigned char mask = chip->mgr->board_has_aes1 ? 626 PCXHR_SUER1_BIT_C_READ_MASK : PCXHR_SUER_BIT_C_READ_MASK; 627 int i; 628 for (i = 0; i < 8; i++) { 629 PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx++); /* idx < 192 */ 630 temp <<= 1; 631 if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask) 632 temp |= 1; 633 } 634 snd_printdd("read iec958 AES %d byte %d = 0x%x\n", 635 chip->chip_idx, aes_idx, temp); 636 *aes_bits = temp; 637 return 0; 638 } 639 640 641 int hr222_iec958_update_byte(struct snd_pcxhr *chip, 642 int aes_idx, unsigned char aes_bits) 643 { 644 int i; 645 unsigned char new_bits = aes_bits; 646 unsigned char old_bits = chip->aes_bits[aes_idx]; 647 unsigned char idx = (unsigned char)(aes_idx * 8); 648 for (i = 0; i < 8; i++) { 649 if ((old_bits & 0x01) != (new_bits & 0x01)) { 650 /* idx < 192 */ 651 PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx); 652 /* write C and U bit */ 653 PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CSUER, new_bits&0x01 ? 654 PCXHR_SUER_BIT_C_WRITE_MASK : 0); 655 } 656 idx++; 657 old_bits >>= 1; 658 new_bits >>= 1; 659 } 660 chip->aes_bits[aes_idx] = aes_bits; 661 return 0; 662 } 663 664 static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level) 665 { 666 unsigned char boost_mask; 667 boost_mask = (unsigned char) (level << PCXHR_SELMIC_PREAMPLI_OFFSET); 668 if (boost_mask & (~PCXHR_SELMIC_PREAMPLI_MASK)) 669 return; /* only values form 0 to 3 accepted */ 670 671 mgr->xlx_selmic &= ~PCXHR_SELMIC_PREAMPLI_MASK; 672 mgr->xlx_selmic |= boost_mask; 673 674 PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); 675 676 snd_printdd("hr222_micro_boost : set %x\n", boost_mask); 677 } 678 679 static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power) 680 { 681 if (power) 682 mgr->xlx_selmic |= PCXHR_SELMIC_PHANTOM_ALIM; 683 else 684 mgr->xlx_selmic &= ~PCXHR_SELMIC_PHANTOM_ALIM; 685 686 PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); 687 688 snd_printdd("hr222_phantom_power : set %d\n", power); 689 } 690 691 692 /* mic level */ 693 static const DECLARE_TLV_DB_SCALE(db_scale_mic_hr222, -9850, 50, 650); 694 695 static int hr222_mic_vol_info(struct snd_kcontrol *kcontrol, 696 struct snd_ctl_elem_info *uinfo) 697 { 698 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 699 uinfo->count = 1; 700 uinfo->value.integer.min = HR222_MICRO_CAPTURE_LEVEL_MIN; /* -98 dB */ 701 /* gains from 9 dB to 31.5 dB not recommended; use micboost instead */ 702 uinfo->value.integer.max = HR222_MICRO_CAPTURE_LEVEL_MAX; /* +7 dB */ 703 return 0; 704 } 705 706 static int hr222_mic_vol_get(struct snd_kcontrol *kcontrol, 707 struct snd_ctl_elem_value *ucontrol) 708 { 709 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 710 mutex_lock(&chip->mgr->mixer_mutex); 711 ucontrol->value.integer.value[0] = chip->mic_volume; 712 mutex_unlock(&chip->mgr->mixer_mutex); 713 return 0; 714 } 715 716 static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol, 717 struct snd_ctl_elem_value *ucontrol) 718 { 719 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 720 int changed = 0; 721 mutex_lock(&chip->mgr->mixer_mutex); 722 if (chip->mic_volume != ucontrol->value.integer.value[0]) { 723 changed = 1; 724 chip->mic_volume = ucontrol->value.integer.value[0]; 725 hr222_update_analog_audio_level(chip, 1, 0); 726 } 727 mutex_unlock(&chip->mgr->mixer_mutex); 728 return changed; 729 } 730 731 static struct snd_kcontrol_new hr222_control_mic_level = { 732 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 733 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 734 SNDRV_CTL_ELEM_ACCESS_TLV_READ), 735 .name = "Mic Capture Volume", 736 .info = hr222_mic_vol_info, 737 .get = hr222_mic_vol_get, 738 .put = hr222_mic_vol_put, 739 .tlv = { .p = db_scale_mic_hr222 }, 740 }; 741 742 743 /* mic boost level */ 744 static const DECLARE_TLV_DB_SCALE(db_scale_micboost_hr222, 0, 1800, 5400); 745 746 static int hr222_mic_boost_info(struct snd_kcontrol *kcontrol, 747 struct snd_ctl_elem_info *uinfo) 748 { 749 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 750 uinfo->count = 1; 751 uinfo->value.integer.min = 0; /* 0 dB */ 752 uinfo->value.integer.max = 3; /* 54 dB */ 753 return 0; 754 } 755 756 static int hr222_mic_boost_get(struct snd_kcontrol *kcontrol, 757 struct snd_ctl_elem_value *ucontrol) 758 { 759 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 760 mutex_lock(&chip->mgr->mixer_mutex); 761 ucontrol->value.integer.value[0] = chip->mic_boost; 762 mutex_unlock(&chip->mgr->mixer_mutex); 763 return 0; 764 } 765 766 static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol, 767 struct snd_ctl_elem_value *ucontrol) 768 { 769 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 770 int changed = 0; 771 mutex_lock(&chip->mgr->mixer_mutex); 772 if (chip->mic_boost != ucontrol->value.integer.value[0]) { 773 changed = 1; 774 chip->mic_boost = ucontrol->value.integer.value[0]; 775 hr222_micro_boost(chip->mgr, chip->mic_boost); 776 } 777 mutex_unlock(&chip->mgr->mixer_mutex); 778 return changed; 779 } 780 781 static struct snd_kcontrol_new hr222_control_mic_boost = { 782 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 783 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 784 SNDRV_CTL_ELEM_ACCESS_TLV_READ), 785 .name = "MicBoost Capture Volume", 786 .info = hr222_mic_boost_info, 787 .get = hr222_mic_boost_get, 788 .put = hr222_mic_boost_put, 789 .tlv = { .p = db_scale_micboost_hr222 }, 790 }; 791 792 793 /******************* Phantom power switch *******************/ 794 #define hr222_phantom_power_info snd_ctl_boolean_mono_info 795 796 static int hr222_phantom_power_get(struct snd_kcontrol *kcontrol, 797 struct snd_ctl_elem_value *ucontrol) 798 { 799 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 800 mutex_lock(&chip->mgr->mixer_mutex); 801 ucontrol->value.integer.value[0] = chip->phantom_power; 802 mutex_unlock(&chip->mgr->mixer_mutex); 803 return 0; 804 } 805 806 static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol, 807 struct snd_ctl_elem_value *ucontrol) 808 { 809 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); 810 int power, changed = 0; 811 812 mutex_lock(&chip->mgr->mixer_mutex); 813 power = !!ucontrol->value.integer.value[0]; 814 if (chip->phantom_power != power) { 815 hr222_phantom_power(chip->mgr, power); 816 chip->phantom_power = power; 817 changed = 1; 818 } 819 mutex_unlock(&chip->mgr->mixer_mutex); 820 return changed; 821 } 822 823 static struct snd_kcontrol_new hr222_phantom_power_switch = { 824 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 825 .name = "Phantom Power Switch", 826 .info = hr222_phantom_power_info, 827 .get = hr222_phantom_power_get, 828 .put = hr222_phantom_power_put, 829 }; 830 831 832 int hr222_add_mic_controls(struct snd_pcxhr *chip) 833 { 834 int err; 835 if (!chip->mgr->board_has_mic) 836 return 0; 837 838 /* controls */ 839 err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_level, 840 chip)); 841 if (err < 0) 842 return err; 843 844 err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_boost, 845 chip)); 846 if (err < 0) 847 return err; 848 849 err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_phantom_power_switch, 850 chip)); 851 return err; 852 } 853