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