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