1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4 * Routines for control of CS4235/4236B/4237B/4238B/4239 chips 5 * 6 * Note: 7 * ----- 8 * 9 * Bugs: 10 * ----- 11 */ 12 13 /* 14 * Indirect control registers (CS4236B+) 15 * 16 * C0 17 * D8: WSS reset (all chips) 18 * 19 * C1 (all chips except CS4236) 20 * D7-D5: version 21 * D4-D0: chip id 22 * 11101 - CS4235 23 * 01011 - CS4236B 24 * 01000 - CS4237B 25 * 01001 - CS4238B 26 * 11110 - CS4239 27 * 28 * C2 29 * D7-D4: 3D Space (CS4235,CS4237B,CS4238B,CS4239) 30 * D3-D0: 3D Center (CS4237B); 3D Volume (CS4238B) 31 * 32 * C3 33 * D7: 3D Enable (CS4237B) 34 * D6: 3D Mono Enable (CS4237B) 35 * D5: 3D Serial Output (CS4237B,CS4238B) 36 * D4: 3D Enable (CS4235,CS4238B,CS4239) 37 * 38 * C4 39 * D7: consumer serial port enable (CS4237B,CS4238B) 40 * D6: channels status block reset (CS4237B,CS4238B) 41 * D5: user bit in sub-frame of digital audio data (CS4237B,CS4238B) 42 * D4: validity bit in sub-frame of digital audio data (CS4237B,CS4238B) 43 * 44 * C5 lower channel status (digital serial data description) (CS4237B,CS4238B) 45 * D7-D6: first two bits of category code 46 * D5: lock 47 * D4-D3: pre-emphasis (0 = none, 1 = 50/15us) 48 * D2: copy/copyright (0 = copy inhibited) 49 * D1: 0 = digital audio / 1 = non-digital audio 50 * 51 * C6 upper channel status (digital serial data description) (CS4237B,CS4238B) 52 * D7-D6: sample frequency (0 = 44.1kHz) 53 * D5: generation status (0 = no indication, 1 = original/commercially precaptureed data) 54 * D4-D0: category code (upper bits) 55 * 56 * C7 reserved (must write 0) 57 * 58 * C8 wavetable control 59 * D7: volume control interrupt enable (CS4235,CS4239) 60 * D6: hardware volume control format (CS4235,CS4239) 61 * D3: wavetable serial port enable (all chips) 62 * D2: DSP serial port switch (all chips) 63 * D1: disable MCLK (all chips) 64 * D0: force BRESET low (all chips) 65 * 66 */ 67 68 #include <linux/io.h> 69 #include <linux/delay.h> 70 #include <linux/init.h> 71 #include <linux/time.h> 72 #include <linux/wait.h> 73 #include <sound/core.h> 74 #include <sound/wss.h> 75 #include <sound/asoundef.h> 76 #include <sound/initval.h> 77 #include <sound/tlv.h> 78 79 /* 80 * 81 */ 82 83 static const unsigned char snd_cs4236_ext_map[18] = { 84 /* CS4236_LEFT_LINE */ 0xff, 85 /* CS4236_RIGHT_LINE */ 0xff, 86 /* CS4236_LEFT_MIC */ 0xdf, 87 /* CS4236_RIGHT_MIC */ 0xdf, 88 /* CS4236_LEFT_MIX_CTRL */ 0xe0 | 0x18, 89 /* CS4236_RIGHT_MIX_CTRL */ 0xe0, 90 /* CS4236_LEFT_FM */ 0xbf, 91 /* CS4236_RIGHT_FM */ 0xbf, 92 /* CS4236_LEFT_DSP */ 0xbf, 93 /* CS4236_RIGHT_DSP */ 0xbf, 94 /* CS4236_RIGHT_LOOPBACK */ 0xbf, 95 /* CS4236_DAC_MUTE */ 0xe0, 96 /* CS4236_ADC_RATE */ 0x01, /* 48kHz */ 97 /* CS4236_DAC_RATE */ 0x01, /* 48kHz */ 98 /* CS4236_LEFT_MASTER */ 0xbf, 99 /* CS4236_RIGHT_MASTER */ 0xbf, 100 /* CS4236_LEFT_WAVE */ 0xbf, 101 /* CS4236_RIGHT_WAVE */ 0xbf 102 }; 103 104 /* 105 * 106 */ 107 108 static void snd_cs4236_ctrl_out(struct snd_wss *chip, 109 unsigned char reg, unsigned char val) 110 { 111 outb(reg, chip->cport + 3); 112 outb(chip->cimage[reg] = val, chip->cport + 4); 113 } 114 115 static unsigned char snd_cs4236_ctrl_in(struct snd_wss *chip, unsigned char reg) 116 { 117 outb(reg, chip->cport + 3); 118 return inb(chip->cport + 4); 119 } 120 121 /* 122 * PCM 123 */ 124 125 #define CLOCKS 8 126 127 static const struct snd_ratnum clocks[CLOCKS] = { 128 { .num = 16934400, .den_min = 353, .den_max = 353, .den_step = 1 }, 129 { .num = 16934400, .den_min = 529, .den_max = 529, .den_step = 1 }, 130 { .num = 16934400, .den_min = 617, .den_max = 617, .den_step = 1 }, 131 { .num = 16934400, .den_min = 1058, .den_max = 1058, .den_step = 1 }, 132 { .num = 16934400, .den_min = 1764, .den_max = 1764, .den_step = 1 }, 133 { .num = 16934400, .den_min = 2117, .den_max = 2117, .den_step = 1 }, 134 { .num = 16934400, .den_min = 2558, .den_max = 2558, .den_step = 1 }, 135 { .num = 16934400/16, .den_min = 21, .den_max = 192, .den_step = 1 } 136 }; 137 138 static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = { 139 .nrats = CLOCKS, 140 .rats = clocks, 141 }; 142 143 static int snd_cs4236_xrate(struct snd_pcm_runtime *runtime) 144 { 145 return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 146 &hw_constraints_clocks); 147 } 148 149 static unsigned char divisor_to_rate_register(unsigned int divisor) 150 { 151 switch (divisor) { 152 case 353: return 1; 153 case 529: return 2; 154 case 617: return 3; 155 case 1058: return 4; 156 case 1764: return 5; 157 case 2117: return 6; 158 case 2558: return 7; 159 default: 160 if (divisor < 21 || divisor > 192) { 161 snd_BUG(); 162 return 192; 163 } 164 return divisor; 165 } 166 } 167 168 static void snd_cs4236_playback_format(struct snd_wss *chip, 169 struct snd_pcm_hw_params *params, 170 unsigned char pdfr) 171 { 172 unsigned long flags; 173 unsigned char rate = divisor_to_rate_register(params->rate_den); 174 175 spin_lock_irqsave(&chip->reg_lock, flags); 176 /* set fast playback format change and clean playback FIFO */ 177 snd_wss_out(chip, CS4231_ALT_FEATURE_1, 178 chip->image[CS4231_ALT_FEATURE_1] | 0x10); 179 snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0); 180 snd_wss_out(chip, CS4231_ALT_FEATURE_1, 181 chip->image[CS4231_ALT_FEATURE_1] & ~0x10); 182 snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate); 183 spin_unlock_irqrestore(&chip->reg_lock, flags); 184 } 185 186 static void snd_cs4236_capture_format(struct snd_wss *chip, 187 struct snd_pcm_hw_params *params, 188 unsigned char cdfr) 189 { 190 unsigned long flags; 191 unsigned char rate = divisor_to_rate_register(params->rate_den); 192 193 spin_lock_irqsave(&chip->reg_lock, flags); 194 /* set fast capture format change and clean capture FIFO */ 195 snd_wss_out(chip, CS4231_ALT_FEATURE_1, 196 chip->image[CS4231_ALT_FEATURE_1] | 0x20); 197 snd_wss_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0); 198 snd_wss_out(chip, CS4231_ALT_FEATURE_1, 199 chip->image[CS4231_ALT_FEATURE_1] & ~0x20); 200 snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate); 201 spin_unlock_irqrestore(&chip->reg_lock, flags); 202 } 203 204 #ifdef CONFIG_PM 205 206 static void snd_cs4236_suspend(struct snd_wss *chip) 207 { 208 int reg; 209 unsigned long flags; 210 211 spin_lock_irqsave(&chip->reg_lock, flags); 212 for (reg = 0; reg < 32; reg++) 213 chip->image[reg] = snd_wss_in(chip, reg); 214 for (reg = 0; reg < 18; reg++) 215 chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg)); 216 for (reg = 2; reg < 9; reg++) 217 chip->cimage[reg] = snd_cs4236_ctrl_in(chip, reg); 218 spin_unlock_irqrestore(&chip->reg_lock, flags); 219 } 220 221 static void snd_cs4236_resume(struct snd_wss *chip) 222 { 223 int reg; 224 unsigned long flags; 225 226 snd_wss_mce_up(chip); 227 spin_lock_irqsave(&chip->reg_lock, flags); 228 for (reg = 0; reg < 32; reg++) { 229 switch (reg) { 230 case CS4236_EXT_REG: 231 case CS4231_VERSION: 232 case 27: /* why? CS4235 - master left */ 233 case 29: /* why? CS4235 - master right */ 234 break; 235 default: 236 snd_wss_out(chip, reg, chip->image[reg]); 237 break; 238 } 239 } 240 for (reg = 0; reg < 18; reg++) 241 snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), chip->eimage[reg]); 242 for (reg = 2; reg < 9; reg++) { 243 switch (reg) { 244 case 7: 245 break; 246 default: 247 snd_cs4236_ctrl_out(chip, reg, chip->cimage[reg]); 248 } 249 } 250 spin_unlock_irqrestore(&chip->reg_lock, flags); 251 snd_wss_mce_down(chip); 252 } 253 254 #endif /* CONFIG_PM */ 255 /* 256 * This function does no fail if the chip is not CS4236B or compatible. 257 * It just an equivalent to the snd_wss_create() then. 258 */ 259 int snd_cs4236_create(struct snd_card *card, 260 unsigned long port, 261 unsigned long cport, 262 int irq, int dma1, int dma2, 263 unsigned short hardware, 264 unsigned short hwshare, 265 struct snd_wss **rchip) 266 { 267 struct snd_wss *chip; 268 unsigned char ver1, ver2; 269 unsigned int reg; 270 int err; 271 272 *rchip = NULL; 273 if (hardware == WSS_HW_DETECT) 274 hardware = WSS_HW_DETECT3; 275 276 err = snd_wss_create(card, port, cport, 277 irq, dma1, dma2, hardware, hwshare, &chip); 278 if (err < 0) 279 return err; 280 281 if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) { 282 snd_printd("chip is not CS4236+, hardware=0x%x\n", 283 chip->hardware); 284 *rchip = chip; 285 return 0; 286 } 287 #if 0 288 { 289 int idx; 290 for (idx = 0; idx < 8; idx++) 291 snd_printk(KERN_DEBUG "CD%i = 0x%x\n", 292 idx, inb(chip->cport + idx)); 293 for (idx = 0; idx < 9; idx++) 294 snd_printk(KERN_DEBUG "C%i = 0x%x\n", 295 idx, snd_cs4236_ctrl_in(chip, idx)); 296 } 297 #endif 298 if (cport < 0x100 || cport == SNDRV_AUTO_PORT) { 299 snd_printk(KERN_ERR "please, specify control port " 300 "for CS4236+ chips\n"); 301 snd_device_free(card, chip); 302 return -ENODEV; 303 } 304 ver1 = snd_cs4236_ctrl_in(chip, 1); 305 ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION); 306 snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", 307 cport, ver1, ver2); 308 if (ver1 != ver2) { 309 snd_printk(KERN_ERR "CS4236+ chip detected, but " 310 "control port 0x%lx is not valid\n", cport); 311 snd_device_free(card, chip); 312 return -ENODEV; 313 } 314 snd_cs4236_ctrl_out(chip, 0, 0x00); 315 snd_cs4236_ctrl_out(chip, 2, 0xff); 316 snd_cs4236_ctrl_out(chip, 3, 0x00); 317 snd_cs4236_ctrl_out(chip, 4, 0x80); 318 reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | 319 IEC958_AES0_CON_EMPHASIS_NONE; 320 snd_cs4236_ctrl_out(chip, 5, reg); 321 snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2); 322 snd_cs4236_ctrl_out(chip, 7, 0x00); 323 /* 324 * 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 325 * output is working with this setup, other hardware should 326 * have different signal paths and this value should be 327 * selectable in the future 328 */ 329 snd_cs4236_ctrl_out(chip, 8, 0x8c); 330 chip->rate_constraint = snd_cs4236_xrate; 331 chip->set_playback_format = snd_cs4236_playback_format; 332 chip->set_capture_format = snd_cs4236_capture_format; 333 #ifdef CONFIG_PM 334 chip->suspend = snd_cs4236_suspend; 335 chip->resume = snd_cs4236_resume; 336 #endif 337 338 /* initialize extended registers */ 339 for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++) 340 snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), 341 snd_cs4236_ext_map[reg]); 342 343 /* initialize compatible but more featured registers */ 344 snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40); 345 snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40); 346 snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff); 347 snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff); 348 snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf); 349 snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf); 350 snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff); 351 snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff); 352 snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff); 353 switch (chip->hardware) { 354 case WSS_HW_CS4235: 355 case WSS_HW_CS4239: 356 snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff); 357 snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff); 358 break; 359 } 360 361 *rchip = chip; 362 return 0; 363 } 364 365 int snd_cs4236_pcm(struct snd_wss *chip, int device) 366 { 367 int err; 368 369 err = snd_wss_pcm(chip, device); 370 if (err < 0) 371 return err; 372 chip->pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX; 373 return 0; 374 } 375 376 /* 377 * MIXER 378 */ 379 380 #define CS4236_SINGLE(xname, xindex, reg, shift, mask, invert) \ 381 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 382 .info = snd_cs4236_info_single, \ 383 .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ 384 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } 385 386 #define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ 387 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 388 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 389 .info = snd_cs4236_info_single, \ 390 .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ 391 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ 392 .tlv = { .p = (xtlv) } } 393 394 static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 395 { 396 int mask = (kcontrol->private_value >> 16) & 0xff; 397 398 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 399 uinfo->count = 1; 400 uinfo->value.integer.min = 0; 401 uinfo->value.integer.max = mask; 402 return 0; 403 } 404 405 static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 406 { 407 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 408 unsigned long flags; 409 int reg = kcontrol->private_value & 0xff; 410 int shift = (kcontrol->private_value >> 8) & 0xff; 411 int mask = (kcontrol->private_value >> 16) & 0xff; 412 int invert = (kcontrol->private_value >> 24) & 0xff; 413 414 spin_lock_irqsave(&chip->reg_lock, flags); 415 ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(reg)] >> shift) & mask; 416 spin_unlock_irqrestore(&chip->reg_lock, flags); 417 if (invert) 418 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; 419 return 0; 420 } 421 422 static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 423 { 424 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 425 unsigned long flags; 426 int reg = kcontrol->private_value & 0xff; 427 int shift = (kcontrol->private_value >> 8) & 0xff; 428 int mask = (kcontrol->private_value >> 16) & 0xff; 429 int invert = (kcontrol->private_value >> 24) & 0xff; 430 int change; 431 unsigned short val; 432 433 val = (ucontrol->value.integer.value[0] & mask); 434 if (invert) 435 val = mask - val; 436 val <<= shift; 437 spin_lock_irqsave(&chip->reg_lock, flags); 438 val = (chip->eimage[CS4236_REG(reg)] & ~(mask << shift)) | val; 439 change = val != chip->eimage[CS4236_REG(reg)]; 440 snd_cs4236_ext_out(chip, reg, val); 441 spin_unlock_irqrestore(&chip->reg_lock, flags); 442 return change; 443 } 444 445 #define CS4236_SINGLEC(xname, xindex, reg, shift, mask, invert) \ 446 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 447 .info = snd_cs4236_info_single, \ 448 .get = snd_cs4236_get_singlec, .put = snd_cs4236_put_singlec, \ 449 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } 450 451 static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 452 { 453 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 454 unsigned long flags; 455 int reg = kcontrol->private_value & 0xff; 456 int shift = (kcontrol->private_value >> 8) & 0xff; 457 int mask = (kcontrol->private_value >> 16) & 0xff; 458 int invert = (kcontrol->private_value >> 24) & 0xff; 459 460 spin_lock_irqsave(&chip->reg_lock, flags); 461 ucontrol->value.integer.value[0] = (chip->cimage[reg] >> shift) & mask; 462 spin_unlock_irqrestore(&chip->reg_lock, flags); 463 if (invert) 464 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; 465 return 0; 466 } 467 468 static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 469 { 470 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 471 unsigned long flags; 472 int reg = kcontrol->private_value & 0xff; 473 int shift = (kcontrol->private_value >> 8) & 0xff; 474 int mask = (kcontrol->private_value >> 16) & 0xff; 475 int invert = (kcontrol->private_value >> 24) & 0xff; 476 int change; 477 unsigned short val; 478 479 val = (ucontrol->value.integer.value[0] & mask); 480 if (invert) 481 val = mask - val; 482 val <<= shift; 483 spin_lock_irqsave(&chip->reg_lock, flags); 484 val = (chip->cimage[reg] & ~(mask << shift)) | val; 485 change = val != chip->cimage[reg]; 486 snd_cs4236_ctrl_out(chip, reg, val); 487 spin_unlock_irqrestore(&chip->reg_lock, flags); 488 return change; 489 } 490 491 #define CS4236_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ 492 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 493 .info = snd_cs4236_info_double, \ 494 .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ 495 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } 496 497 #define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \ 498 shift_right, mask, invert, xtlv) \ 499 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 500 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 501 .info = snd_cs4236_info_double, \ 502 .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ 503 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ 504 (shift_right << 19) | (mask << 24) | (invert << 22), \ 505 .tlv = { .p = (xtlv) } } 506 507 static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 508 { 509 int mask = (kcontrol->private_value >> 24) & 0xff; 510 511 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 512 uinfo->count = 2; 513 uinfo->value.integer.min = 0; 514 uinfo->value.integer.max = mask; 515 return 0; 516 } 517 518 static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 519 { 520 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 521 unsigned long flags; 522 int left_reg = kcontrol->private_value & 0xff; 523 int right_reg = (kcontrol->private_value >> 8) & 0xff; 524 int shift_left = (kcontrol->private_value >> 16) & 0x07; 525 int shift_right = (kcontrol->private_value >> 19) & 0x07; 526 int mask = (kcontrol->private_value >> 24) & 0xff; 527 int invert = (kcontrol->private_value >> 22) & 1; 528 529 spin_lock_irqsave(&chip->reg_lock, flags); 530 ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(left_reg)] >> shift_left) & mask; 531 ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask; 532 spin_unlock_irqrestore(&chip->reg_lock, flags); 533 if (invert) { 534 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; 535 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; 536 } 537 return 0; 538 } 539 540 static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 541 { 542 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 543 unsigned long flags; 544 int left_reg = kcontrol->private_value & 0xff; 545 int right_reg = (kcontrol->private_value >> 8) & 0xff; 546 int shift_left = (kcontrol->private_value >> 16) & 0x07; 547 int shift_right = (kcontrol->private_value >> 19) & 0x07; 548 int mask = (kcontrol->private_value >> 24) & 0xff; 549 int invert = (kcontrol->private_value >> 22) & 1; 550 int change; 551 unsigned short val1, val2; 552 553 val1 = ucontrol->value.integer.value[0] & mask; 554 val2 = ucontrol->value.integer.value[1] & mask; 555 if (invert) { 556 val1 = mask - val1; 557 val2 = mask - val2; 558 } 559 val1 <<= shift_left; 560 val2 <<= shift_right; 561 spin_lock_irqsave(&chip->reg_lock, flags); 562 if (left_reg != right_reg) { 563 val1 = (chip->eimage[CS4236_REG(left_reg)] & ~(mask << shift_left)) | val1; 564 val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2; 565 change = val1 != chip->eimage[CS4236_REG(left_reg)] || val2 != chip->eimage[CS4236_REG(right_reg)]; 566 snd_cs4236_ext_out(chip, left_reg, val1); 567 snd_cs4236_ext_out(chip, right_reg, val2); 568 } else { 569 val1 = (chip->eimage[CS4236_REG(left_reg)] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2; 570 change = val1 != chip->eimage[CS4236_REG(left_reg)]; 571 snd_cs4236_ext_out(chip, left_reg, val1); 572 } 573 spin_unlock_irqrestore(&chip->reg_lock, flags); 574 return change; 575 } 576 577 #define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \ 578 shift_right, mask, invert) \ 579 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 580 .info = snd_cs4236_info_double, \ 581 .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ 582 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } 583 584 #define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \ 585 shift_right, mask, invert, xtlv) \ 586 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 587 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 588 .info = snd_cs4236_info_double, \ 589 .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ 590 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ 591 (shift_right << 19) | (mask << 24) | (invert << 22), \ 592 .tlv = { .p = (xtlv) } } 593 594 static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 595 { 596 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 597 unsigned long flags; 598 int left_reg = kcontrol->private_value & 0xff; 599 int right_reg = (kcontrol->private_value >> 8) & 0xff; 600 int shift_left = (kcontrol->private_value >> 16) & 0x07; 601 int shift_right = (kcontrol->private_value >> 19) & 0x07; 602 int mask = (kcontrol->private_value >> 24) & 0xff; 603 int invert = (kcontrol->private_value >> 22) & 1; 604 605 spin_lock_irqsave(&chip->reg_lock, flags); 606 ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; 607 ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask; 608 spin_unlock_irqrestore(&chip->reg_lock, flags); 609 if (invert) { 610 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; 611 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; 612 } 613 return 0; 614 } 615 616 static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 617 { 618 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 619 unsigned long flags; 620 int left_reg = kcontrol->private_value & 0xff; 621 int right_reg = (kcontrol->private_value >> 8) & 0xff; 622 int shift_left = (kcontrol->private_value >> 16) & 0x07; 623 int shift_right = (kcontrol->private_value >> 19) & 0x07; 624 int mask = (kcontrol->private_value >> 24) & 0xff; 625 int invert = (kcontrol->private_value >> 22) & 1; 626 int change; 627 unsigned short val1, val2; 628 629 val1 = ucontrol->value.integer.value[0] & mask; 630 val2 = ucontrol->value.integer.value[1] & mask; 631 if (invert) { 632 val1 = mask - val1; 633 val2 = mask - val2; 634 } 635 val1 <<= shift_left; 636 val2 <<= shift_right; 637 spin_lock_irqsave(&chip->reg_lock, flags); 638 val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; 639 val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2; 640 change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)]; 641 snd_wss_out(chip, left_reg, val1); 642 snd_cs4236_ext_out(chip, right_reg, val2); 643 spin_unlock_irqrestore(&chip->reg_lock, flags); 644 return change; 645 } 646 647 #define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \ 648 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 649 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 650 .info = snd_cs4236_info_double, \ 651 .get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \ 652 .private_value = 71 << 24, \ 653 .tlv = { .p = (xtlv) } } 654 655 static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol) 656 { 657 return (vol < 64) ? 63 - vol : 64 + (71 - vol); 658 } 659 660 static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 661 { 662 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 663 unsigned long flags; 664 665 spin_lock_irqsave(&chip->reg_lock, flags); 666 ucontrol->value.integer.value[0] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & 0x7f); 667 ucontrol->value.integer.value[1] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & 0x7f); 668 spin_unlock_irqrestore(&chip->reg_lock, flags); 669 return 0; 670 } 671 672 static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 673 { 674 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 675 unsigned long flags; 676 int change; 677 unsigned short val1, val2; 678 679 val1 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[0] & 0x7f); 680 val2 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[1] & 0x7f); 681 spin_lock_irqsave(&chip->reg_lock, flags); 682 val1 = (chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & ~0x7f) | val1; 683 val2 = (chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & ~0x7f) | val2; 684 change = val1 != chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] || val2 != chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)]; 685 snd_cs4236_ext_out(chip, CS4236_LEFT_MASTER, val1); 686 snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val2); 687 spin_unlock_irqrestore(&chip->reg_lock, flags); 688 return change; 689 } 690 691 #define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \ 692 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 693 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 694 .info = snd_cs4236_info_double, \ 695 .get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \ 696 .private_value = 3 << 24, \ 697 .tlv = { .p = (xtlv) } } 698 699 static inline int snd_cs4235_mixer_output_accu_get_volume(int vol) 700 { 701 switch ((vol >> 5) & 3) { 702 case 0: return 1; 703 case 1: return 3; 704 case 2: return 2; 705 case 3: return 0; 706 } 707 return 3; 708 } 709 710 static inline int snd_cs4235_mixer_output_accu_set_volume(int vol) 711 { 712 switch (vol & 3) { 713 case 0: return 3 << 5; 714 case 1: return 0 << 5; 715 case 2: return 2 << 5; 716 case 3: return 1 << 5; 717 } 718 return 1 << 5; 719 } 720 721 static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 722 { 723 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 724 unsigned long flags; 725 726 spin_lock_irqsave(&chip->reg_lock, flags); 727 ucontrol->value.integer.value[0] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_LEFT_MASTER]); 728 ucontrol->value.integer.value[1] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_RIGHT_MASTER]); 729 spin_unlock_irqrestore(&chip->reg_lock, flags); 730 return 0; 731 } 732 733 static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 734 { 735 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 736 unsigned long flags; 737 int change; 738 unsigned short val1, val2; 739 740 val1 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[0]); 741 val2 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[1]); 742 spin_lock_irqsave(&chip->reg_lock, flags); 743 val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1; 744 val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2; 745 change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER]; 746 snd_wss_out(chip, CS4235_LEFT_MASTER, val1); 747 snd_wss_out(chip, CS4235_RIGHT_MASTER, val2); 748 spin_unlock_irqrestore(&chip->reg_lock, flags); 749 return change; 750 } 751 752 static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0); 753 static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); 754 static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0); 755 static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); 756 static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0); 757 static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); 758 static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0); 759 static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); 760 761 static const struct snd_kcontrol_new snd_cs4236_controls[] = { 762 763 CS4236_DOUBLE("Master Digital Playback Switch", 0, 764 CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), 765 CS4236_DOUBLE("Master Digital Capture Switch", 0, 766 CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), 767 CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit), 768 769 CS4236_DOUBLE_TLV("Capture Boost Volume", 0, 770 CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, 771 db_scale_2bit), 772 773 WSS_DOUBLE("PCM Playback Switch", 0, 774 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), 775 WSS_DOUBLE_TLV("PCM Playback Volume", 0, 776 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, 777 db_scale_6bit), 778 779 CS4236_DOUBLE("DSP Playback Switch", 0, 780 CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), 781 CS4236_DOUBLE_TLV("DSP Playback Volume", 0, 782 CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1, 783 db_scale_6bit), 784 785 CS4236_DOUBLE("FM Playback Switch", 0, 786 CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), 787 CS4236_DOUBLE_TLV("FM Playback Volume", 0, 788 CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1, 789 db_scale_6bit), 790 791 CS4236_DOUBLE("Wavetable Playback Switch", 0, 792 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), 793 CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0, 794 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1, 795 db_scale_6bit_12db_max), 796 797 WSS_DOUBLE("Synth Playback Switch", 0, 798 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), 799 WSS_DOUBLE_TLV("Synth Volume", 0, 800 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, 801 db_scale_5bit_12db_max), 802 WSS_DOUBLE("Synth Capture Switch", 0, 803 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), 804 WSS_DOUBLE("Synth Capture Bypass", 0, 805 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1), 806 807 CS4236_DOUBLE("Mic Playback Switch", 0, 808 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), 809 CS4236_DOUBLE("Mic Capture Switch", 0, 810 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), 811 CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 812 0, 0, 31, 1, db_scale_5bit_22db_max), 813 CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0, 814 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0), 815 816 WSS_DOUBLE("Line Playback Switch", 0, 817 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), 818 WSS_DOUBLE_TLV("Line Volume", 0, 819 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, 820 db_scale_5bit_12db_max), 821 WSS_DOUBLE("Line Capture Switch", 0, 822 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), 823 WSS_DOUBLE("Line Capture Bypass", 0, 824 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1), 825 826 WSS_DOUBLE("CD Playback Switch", 0, 827 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), 828 WSS_DOUBLE_TLV("CD Volume", 0, 829 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, 830 db_scale_5bit_12db_max), 831 WSS_DOUBLE("CD Capture Switch", 0, 832 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), 833 834 CS4236_DOUBLE1("Mono Output Playback Switch", 0, 835 CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), 836 CS4236_DOUBLE1("Beep Playback Switch", 0, 837 CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), 838 WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1, 839 db_scale_4bit), 840 WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), 841 842 WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 843 0, 0, 15, 0, db_scale_rec_gain), 844 WSS_DOUBLE("Analog Loopback Capture Switch", 0, 845 CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), 846 847 WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), 848 CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0, 849 CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1, 850 db_scale_6bit), 851 }; 852 853 static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0); 854 static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0); 855 856 static const struct snd_kcontrol_new snd_cs4235_controls[] = { 857 858 WSS_DOUBLE("Master Playback Switch", 0, 859 CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1), 860 WSS_DOUBLE_TLV("Master Playback Volume", 0, 861 CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1, 862 db_scale_5bit_6db_max), 863 864 CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max), 865 866 WSS_DOUBLE("Synth Playback Switch", 1, 867 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), 868 WSS_DOUBLE("Synth Capture Switch", 1, 869 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), 870 WSS_DOUBLE_TLV("Synth Volume", 1, 871 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, 872 db_scale_5bit_12db_max), 873 874 CS4236_DOUBLE_TLV("Capture Volume", 0, 875 CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, 876 db_scale_2bit), 877 878 WSS_DOUBLE("PCM Playback Switch", 0, 879 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), 880 WSS_DOUBLE("PCM Capture Switch", 0, 881 CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), 882 WSS_DOUBLE_TLV("PCM Volume", 0, 883 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, 884 db_scale_6bit), 885 886 CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), 887 888 CS4236_DOUBLE("FM Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), 889 890 CS4236_DOUBLE("Wavetable Switch", 0, 891 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), 892 893 CS4236_DOUBLE("Mic Capture Switch", 0, 894 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), 895 CS4236_DOUBLE("Mic Playback Switch", 0, 896 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), 897 CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1, 898 db_scale_5bit_22db_max), 899 CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0), 900 901 WSS_DOUBLE("Line Playback Switch", 0, 902 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), 903 WSS_DOUBLE("Line Capture Switch", 0, 904 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), 905 WSS_DOUBLE_TLV("Line Volume", 0, 906 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, 907 db_scale_5bit_12db_max), 908 909 WSS_DOUBLE("CD Playback Switch", 1, 910 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), 911 WSS_DOUBLE("CD Capture Switch", 1, 912 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), 913 WSS_DOUBLE_TLV("CD Volume", 1, 914 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, 915 db_scale_5bit_12db_max), 916 917 CS4236_DOUBLE1("Beep Playback Switch", 0, 918 CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), 919 WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), 920 921 WSS_DOUBLE("Analog Loopback Switch", 0, 922 CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), 923 }; 924 925 #define CS4236_IEC958_ENABLE(xname, xindex) \ 926 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 927 .info = snd_cs4236_info_single, \ 928 .get = snd_cs4236_get_iec958_switch, .put = snd_cs4236_put_iec958_switch, \ 929 .private_value = 1 << 16 } 930 931 static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 932 { 933 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 934 unsigned long flags; 935 936 spin_lock_irqsave(&chip->reg_lock, flags); 937 ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0; 938 #if 0 939 printk(KERN_DEBUG "get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, " 940 "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n", 941 snd_wss_in(chip, CS4231_ALT_FEATURE_1), 942 snd_cs4236_ctrl_in(chip, 3), 943 snd_cs4236_ctrl_in(chip, 4), 944 snd_cs4236_ctrl_in(chip, 5), 945 snd_cs4236_ctrl_in(chip, 6), 946 snd_cs4236_ctrl_in(chip, 8)); 947 #endif 948 spin_unlock_irqrestore(&chip->reg_lock, flags); 949 return 0; 950 } 951 952 static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 953 { 954 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 955 unsigned long flags; 956 int change; 957 unsigned short enable, val; 958 959 enable = ucontrol->value.integer.value[0] & 1; 960 961 mutex_lock(&chip->mce_mutex); 962 snd_wss_mce_up(chip); 963 spin_lock_irqsave(&chip->reg_lock, flags); 964 val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1); 965 change = val != chip->image[CS4231_ALT_FEATURE_1]; 966 snd_wss_out(chip, CS4231_ALT_FEATURE_1, val); 967 val = snd_cs4236_ctrl_in(chip, 4) | 0xc0; 968 snd_cs4236_ctrl_out(chip, 4, val); 969 udelay(100); 970 val &= ~0x40; 971 snd_cs4236_ctrl_out(chip, 4, val); 972 spin_unlock_irqrestore(&chip->reg_lock, flags); 973 snd_wss_mce_down(chip); 974 mutex_unlock(&chip->mce_mutex); 975 976 #if 0 977 printk(KERN_DEBUG "set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, " 978 "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n", 979 snd_wss_in(chip, CS4231_ALT_FEATURE_1), 980 snd_cs4236_ctrl_in(chip, 3), 981 snd_cs4236_ctrl_in(chip, 4), 982 snd_cs4236_ctrl_in(chip, 5), 983 snd_cs4236_ctrl_in(chip, 6), 984 snd_cs4236_ctrl_in(chip, 8)); 985 #endif 986 return change; 987 } 988 989 static const struct snd_kcontrol_new snd_cs4236_iec958_controls[] = { 990 CS4236_IEC958_ENABLE("IEC958 Output Enable", 0), 991 CS4236_SINGLEC("IEC958 Output Validity", 0, 4, 4, 1, 0), 992 CS4236_SINGLEC("IEC958 Output User", 0, 4, 5, 1, 0), 993 CS4236_SINGLEC("IEC958 Output CSBR", 0, 4, 6, 1, 0), 994 CS4236_SINGLEC("IEC958 Output Channel Status Low", 0, 5, 1, 127, 0), 995 CS4236_SINGLEC("IEC958 Output Channel Status High", 0, 6, 0, 255, 0) 996 }; 997 998 static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4235[] = { 999 CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0), 1000 CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1) 1001 }; 1002 1003 static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4237[] = { 1004 CS4236_SINGLEC("3D Control - Switch", 0, 3, 7, 1, 0), 1005 CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1), 1006 CS4236_SINGLEC("3D Control - Center", 0, 2, 0, 15, 1), 1007 CS4236_SINGLEC("3D Control - Mono", 0, 3, 6, 1, 0), 1008 CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0) 1009 }; 1010 1011 static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4238[] = { 1012 CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0), 1013 CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1), 1014 CS4236_SINGLEC("3D Control - Volume", 0, 2, 0, 15, 1), 1015 CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0) 1016 }; 1017 1018 int snd_cs4236_mixer(struct snd_wss *chip) 1019 { 1020 struct snd_card *card; 1021 unsigned int idx, count; 1022 int err; 1023 const struct snd_kcontrol_new *kcontrol; 1024 1025 if (snd_BUG_ON(!chip || !chip->card)) 1026 return -EINVAL; 1027 card = chip->card; 1028 strcpy(card->mixername, snd_wss_chip_id(chip)); 1029 1030 if (chip->hardware == WSS_HW_CS4235 || 1031 chip->hardware == WSS_HW_CS4239) { 1032 for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) { 1033 err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip)); 1034 if (err < 0) 1035 return err; 1036 } 1037 } else { 1038 for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_controls); idx++) { 1039 err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_controls[idx], chip)); 1040 if (err < 0) 1041 return err; 1042 } 1043 } 1044 switch (chip->hardware) { 1045 case WSS_HW_CS4235: 1046 case WSS_HW_CS4239: 1047 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4235); 1048 kcontrol = snd_cs4236_3d_controls_cs4235; 1049 break; 1050 case WSS_HW_CS4237B: 1051 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4237); 1052 kcontrol = snd_cs4236_3d_controls_cs4237; 1053 break; 1054 case WSS_HW_CS4238B: 1055 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4238); 1056 kcontrol = snd_cs4236_3d_controls_cs4238; 1057 break; 1058 default: 1059 count = 0; 1060 kcontrol = NULL; 1061 } 1062 for (idx = 0; idx < count; idx++, kcontrol++) { 1063 err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip)); 1064 if (err < 0) 1065 return err; 1066 } 1067 if (chip->hardware == WSS_HW_CS4237B || 1068 chip->hardware == WSS_HW_CS4238B) { 1069 for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) { 1070 err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip)); 1071 if (err < 0) 1072 return err; 1073 } 1074 } 1075 return 0; 1076 } 1077