cs4236_lib.c (37659B)
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 83static 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 108static 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 115static 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 127static 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 138static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = { 139 .nrats = CLOCKS, 140 .rats = clocks, 141}; 142 143static 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 149static 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 168static 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 186static 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 206static 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 221static 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 */ 259int 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 return -ENODEV; 302 } 303 ver1 = snd_cs4236_ctrl_in(chip, 1); 304 ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION); 305 snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", 306 cport, ver1, ver2); 307 if (ver1 != ver2) { 308 snd_printk(KERN_ERR "CS4236+ chip detected, but " 309 "control port 0x%lx is not valid\n", cport); 310 return -ENODEV; 311 } 312 snd_cs4236_ctrl_out(chip, 0, 0x00); 313 snd_cs4236_ctrl_out(chip, 2, 0xff); 314 snd_cs4236_ctrl_out(chip, 3, 0x00); 315 snd_cs4236_ctrl_out(chip, 4, 0x80); 316 reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | 317 IEC958_AES0_CON_EMPHASIS_NONE; 318 snd_cs4236_ctrl_out(chip, 5, reg); 319 snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2); 320 snd_cs4236_ctrl_out(chip, 7, 0x00); 321 /* 322 * 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 323 * output is working with this setup, other hardware should 324 * have different signal paths and this value should be 325 * selectable in the future 326 */ 327 snd_cs4236_ctrl_out(chip, 8, 0x8c); 328 chip->rate_constraint = snd_cs4236_xrate; 329 chip->set_playback_format = snd_cs4236_playback_format; 330 chip->set_capture_format = snd_cs4236_capture_format; 331#ifdef CONFIG_PM 332 chip->suspend = snd_cs4236_suspend; 333 chip->resume = snd_cs4236_resume; 334#endif 335 336 /* initialize extended registers */ 337 for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++) 338 snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), 339 snd_cs4236_ext_map[reg]); 340 341 /* initialize compatible but more featured registers */ 342 snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40); 343 snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40); 344 snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff); 345 snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff); 346 snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf); 347 snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf); 348 snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff); 349 snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff); 350 snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff); 351 switch (chip->hardware) { 352 case WSS_HW_CS4235: 353 case WSS_HW_CS4239: 354 snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff); 355 snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff); 356 break; 357 } 358 359 *rchip = chip; 360 return 0; 361} 362 363int snd_cs4236_pcm(struct snd_wss *chip, int device) 364{ 365 int err; 366 367 err = snd_wss_pcm(chip, device); 368 if (err < 0) 369 return err; 370 chip->pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX; 371 return 0; 372} 373 374/* 375 * MIXER 376 */ 377 378#define CS4236_SINGLE(xname, xindex, reg, shift, mask, invert) \ 379{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 380 .info = snd_cs4236_info_single, \ 381 .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ 382 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } 383 384#define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ 385{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 386 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 387 .info = snd_cs4236_info_single, \ 388 .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ 389 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ 390 .tlv = { .p = (xtlv) } } 391 392static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 393{ 394 int mask = (kcontrol->private_value >> 16) & 0xff; 395 396 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 397 uinfo->count = 1; 398 uinfo->value.integer.min = 0; 399 uinfo->value.integer.max = mask; 400 return 0; 401} 402 403static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 404{ 405 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 406 unsigned long flags; 407 int reg = kcontrol->private_value & 0xff; 408 int shift = (kcontrol->private_value >> 8) & 0xff; 409 int mask = (kcontrol->private_value >> 16) & 0xff; 410 int invert = (kcontrol->private_value >> 24) & 0xff; 411 412 spin_lock_irqsave(&chip->reg_lock, flags); 413 ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(reg)] >> shift) & mask; 414 spin_unlock_irqrestore(&chip->reg_lock, flags); 415 if (invert) 416 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; 417 return 0; 418} 419 420static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 421{ 422 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 423 unsigned long flags; 424 int reg = kcontrol->private_value & 0xff; 425 int shift = (kcontrol->private_value >> 8) & 0xff; 426 int mask = (kcontrol->private_value >> 16) & 0xff; 427 int invert = (kcontrol->private_value >> 24) & 0xff; 428 int change; 429 unsigned short val; 430 431 val = (ucontrol->value.integer.value[0] & mask); 432 if (invert) 433 val = mask - val; 434 val <<= shift; 435 spin_lock_irqsave(&chip->reg_lock, flags); 436 val = (chip->eimage[CS4236_REG(reg)] & ~(mask << shift)) | val; 437 change = val != chip->eimage[CS4236_REG(reg)]; 438 snd_cs4236_ext_out(chip, reg, val); 439 spin_unlock_irqrestore(&chip->reg_lock, flags); 440 return change; 441} 442 443#define CS4236_SINGLEC(xname, xindex, reg, shift, mask, invert) \ 444{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 445 .info = snd_cs4236_info_single, \ 446 .get = snd_cs4236_get_singlec, .put = snd_cs4236_put_singlec, \ 447 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } 448 449static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 450{ 451 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 452 unsigned long flags; 453 int reg = kcontrol->private_value & 0xff; 454 int shift = (kcontrol->private_value >> 8) & 0xff; 455 int mask = (kcontrol->private_value >> 16) & 0xff; 456 int invert = (kcontrol->private_value >> 24) & 0xff; 457 458 spin_lock_irqsave(&chip->reg_lock, flags); 459 ucontrol->value.integer.value[0] = (chip->cimage[reg] >> shift) & mask; 460 spin_unlock_irqrestore(&chip->reg_lock, flags); 461 if (invert) 462 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; 463 return 0; 464} 465 466static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 467{ 468 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 469 unsigned long flags; 470 int reg = kcontrol->private_value & 0xff; 471 int shift = (kcontrol->private_value >> 8) & 0xff; 472 int mask = (kcontrol->private_value >> 16) & 0xff; 473 int invert = (kcontrol->private_value >> 24) & 0xff; 474 int change; 475 unsigned short val; 476 477 val = (ucontrol->value.integer.value[0] & mask); 478 if (invert) 479 val = mask - val; 480 val <<= shift; 481 spin_lock_irqsave(&chip->reg_lock, flags); 482 val = (chip->cimage[reg] & ~(mask << shift)) | val; 483 change = val != chip->cimage[reg]; 484 snd_cs4236_ctrl_out(chip, reg, val); 485 spin_unlock_irqrestore(&chip->reg_lock, flags); 486 return change; 487} 488 489#define CS4236_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ 490{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 491 .info = snd_cs4236_info_double, \ 492 .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ 493 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } 494 495#define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \ 496 shift_right, mask, invert, xtlv) \ 497{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 498 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 499 .info = snd_cs4236_info_double, \ 500 .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ 501 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ 502 (shift_right << 19) | (mask << 24) | (invert << 22), \ 503 .tlv = { .p = (xtlv) } } 504 505static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 506{ 507 int mask = (kcontrol->private_value >> 24) & 0xff; 508 509 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 510 uinfo->count = 2; 511 uinfo->value.integer.min = 0; 512 uinfo->value.integer.max = mask; 513 return 0; 514} 515 516static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 517{ 518 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 519 unsigned long flags; 520 int left_reg = kcontrol->private_value & 0xff; 521 int right_reg = (kcontrol->private_value >> 8) & 0xff; 522 int shift_left = (kcontrol->private_value >> 16) & 0x07; 523 int shift_right = (kcontrol->private_value >> 19) & 0x07; 524 int mask = (kcontrol->private_value >> 24) & 0xff; 525 int invert = (kcontrol->private_value >> 22) & 1; 526 527 spin_lock_irqsave(&chip->reg_lock, flags); 528 ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(left_reg)] >> shift_left) & mask; 529 ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask; 530 spin_unlock_irqrestore(&chip->reg_lock, flags); 531 if (invert) { 532 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; 533 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; 534 } 535 return 0; 536} 537 538static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 539{ 540 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 541 unsigned long flags; 542 int left_reg = kcontrol->private_value & 0xff; 543 int right_reg = (kcontrol->private_value >> 8) & 0xff; 544 int shift_left = (kcontrol->private_value >> 16) & 0x07; 545 int shift_right = (kcontrol->private_value >> 19) & 0x07; 546 int mask = (kcontrol->private_value >> 24) & 0xff; 547 int invert = (kcontrol->private_value >> 22) & 1; 548 int change; 549 unsigned short val1, val2; 550 551 val1 = ucontrol->value.integer.value[0] & mask; 552 val2 = ucontrol->value.integer.value[1] & mask; 553 if (invert) { 554 val1 = mask - val1; 555 val2 = mask - val2; 556 } 557 val1 <<= shift_left; 558 val2 <<= shift_right; 559 spin_lock_irqsave(&chip->reg_lock, flags); 560 if (left_reg != right_reg) { 561 val1 = (chip->eimage[CS4236_REG(left_reg)] & ~(mask << shift_left)) | val1; 562 val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2; 563 change = val1 != chip->eimage[CS4236_REG(left_reg)] || val2 != chip->eimage[CS4236_REG(right_reg)]; 564 snd_cs4236_ext_out(chip, left_reg, val1); 565 snd_cs4236_ext_out(chip, right_reg, val2); 566 } else { 567 val1 = (chip->eimage[CS4236_REG(left_reg)] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2; 568 change = val1 != chip->eimage[CS4236_REG(left_reg)]; 569 snd_cs4236_ext_out(chip, left_reg, val1); 570 } 571 spin_unlock_irqrestore(&chip->reg_lock, flags); 572 return change; 573} 574 575#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \ 576 shift_right, mask, invert) \ 577{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 578 .info = snd_cs4236_info_double, \ 579 .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ 580 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } 581 582#define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \ 583 shift_right, mask, invert, xtlv) \ 584{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 585 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 586 .info = snd_cs4236_info_double, \ 587 .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ 588 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ 589 (shift_right << 19) | (mask << 24) | (invert << 22), \ 590 .tlv = { .p = (xtlv) } } 591 592static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 593{ 594 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 595 unsigned long flags; 596 int left_reg = kcontrol->private_value & 0xff; 597 int right_reg = (kcontrol->private_value >> 8) & 0xff; 598 int shift_left = (kcontrol->private_value >> 16) & 0x07; 599 int shift_right = (kcontrol->private_value >> 19) & 0x07; 600 int mask = (kcontrol->private_value >> 24) & 0xff; 601 int invert = (kcontrol->private_value >> 22) & 1; 602 603 spin_lock_irqsave(&chip->reg_lock, flags); 604 ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; 605 ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask; 606 spin_unlock_irqrestore(&chip->reg_lock, flags); 607 if (invert) { 608 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; 609 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; 610 } 611 return 0; 612} 613 614static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 615{ 616 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 617 unsigned long flags; 618 int left_reg = kcontrol->private_value & 0xff; 619 int right_reg = (kcontrol->private_value >> 8) & 0xff; 620 int shift_left = (kcontrol->private_value >> 16) & 0x07; 621 int shift_right = (kcontrol->private_value >> 19) & 0x07; 622 int mask = (kcontrol->private_value >> 24) & 0xff; 623 int invert = (kcontrol->private_value >> 22) & 1; 624 int change; 625 unsigned short val1, val2; 626 627 val1 = ucontrol->value.integer.value[0] & mask; 628 val2 = ucontrol->value.integer.value[1] & mask; 629 if (invert) { 630 val1 = mask - val1; 631 val2 = mask - val2; 632 } 633 val1 <<= shift_left; 634 val2 <<= shift_right; 635 spin_lock_irqsave(&chip->reg_lock, flags); 636 val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; 637 val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2; 638 change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)]; 639 snd_wss_out(chip, left_reg, val1); 640 snd_cs4236_ext_out(chip, right_reg, val2); 641 spin_unlock_irqrestore(&chip->reg_lock, flags); 642 return change; 643} 644 645#define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \ 646{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 647 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 648 .info = snd_cs4236_info_double, \ 649 .get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \ 650 .private_value = 71 << 24, \ 651 .tlv = { .p = (xtlv) } } 652 653static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol) 654{ 655 return (vol < 64) ? 63 - vol : 64 + (71 - vol); 656} 657 658static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 659{ 660 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 661 unsigned long flags; 662 663 spin_lock_irqsave(&chip->reg_lock, flags); 664 ucontrol->value.integer.value[0] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & 0x7f); 665 ucontrol->value.integer.value[1] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & 0x7f); 666 spin_unlock_irqrestore(&chip->reg_lock, flags); 667 return 0; 668} 669 670static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 671{ 672 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 673 unsigned long flags; 674 int change; 675 unsigned short val1, val2; 676 677 val1 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[0] & 0x7f); 678 val2 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[1] & 0x7f); 679 spin_lock_irqsave(&chip->reg_lock, flags); 680 val1 = (chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & ~0x7f) | val1; 681 val2 = (chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & ~0x7f) | val2; 682 change = val1 != chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] || val2 != chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)]; 683 snd_cs4236_ext_out(chip, CS4236_LEFT_MASTER, val1); 684 snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val2); 685 spin_unlock_irqrestore(&chip->reg_lock, flags); 686 return change; 687} 688 689#define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \ 690{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 691 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 692 .info = snd_cs4236_info_double, \ 693 .get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \ 694 .private_value = 3 << 24, \ 695 .tlv = { .p = (xtlv) } } 696 697static inline int snd_cs4235_mixer_output_accu_get_volume(int vol) 698{ 699 switch ((vol >> 5) & 3) { 700 case 0: return 1; 701 case 1: return 3; 702 case 2: return 2; 703 case 3: return 0; 704 } 705 return 3; 706} 707 708static inline int snd_cs4235_mixer_output_accu_set_volume(int vol) 709{ 710 switch (vol & 3) { 711 case 0: return 3 << 5; 712 case 1: return 0 << 5; 713 case 2: return 2 << 5; 714 case 3: return 1 << 5; 715 } 716 return 1 << 5; 717} 718 719static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 720{ 721 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 722 unsigned long flags; 723 724 spin_lock_irqsave(&chip->reg_lock, flags); 725 ucontrol->value.integer.value[0] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_LEFT_MASTER]); 726 ucontrol->value.integer.value[1] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_RIGHT_MASTER]); 727 spin_unlock_irqrestore(&chip->reg_lock, flags); 728 return 0; 729} 730 731static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 732{ 733 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 734 unsigned long flags; 735 int change; 736 unsigned short val1, val2; 737 738 val1 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[0]); 739 val2 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[1]); 740 spin_lock_irqsave(&chip->reg_lock, flags); 741 val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1; 742 val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2; 743 change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER]; 744 snd_wss_out(chip, CS4235_LEFT_MASTER, val1); 745 snd_wss_out(chip, CS4235_RIGHT_MASTER, val2); 746 spin_unlock_irqrestore(&chip->reg_lock, flags); 747 return change; 748} 749 750static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0); 751static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); 752static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0); 753static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); 754static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0); 755static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); 756static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0); 757static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); 758 759static const struct snd_kcontrol_new snd_cs4236_controls[] = { 760 761CS4236_DOUBLE("Master Digital Playback Switch", 0, 762 CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), 763CS4236_DOUBLE("Master Digital Capture Switch", 0, 764 CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), 765CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit), 766 767CS4236_DOUBLE_TLV("Capture Boost Volume", 0, 768 CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, 769 db_scale_2bit), 770 771WSS_DOUBLE("PCM Playback Switch", 0, 772 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), 773WSS_DOUBLE_TLV("PCM Playback Volume", 0, 774 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, 775 db_scale_6bit), 776 777CS4236_DOUBLE("DSP Playback Switch", 0, 778 CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), 779CS4236_DOUBLE_TLV("DSP Playback Volume", 0, 780 CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1, 781 db_scale_6bit), 782 783CS4236_DOUBLE("FM Playback Switch", 0, 784 CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), 785CS4236_DOUBLE_TLV("FM Playback Volume", 0, 786 CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1, 787 db_scale_6bit), 788 789CS4236_DOUBLE("Wavetable Playback Switch", 0, 790 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), 791CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0, 792 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1, 793 db_scale_6bit_12db_max), 794 795WSS_DOUBLE("Synth Playback Switch", 0, 796 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), 797WSS_DOUBLE_TLV("Synth Volume", 0, 798 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, 799 db_scale_5bit_12db_max), 800WSS_DOUBLE("Synth Capture Switch", 0, 801 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), 802WSS_DOUBLE("Synth Capture Bypass", 0, 803 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1), 804 805CS4236_DOUBLE("Mic Playback Switch", 0, 806 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), 807CS4236_DOUBLE("Mic Capture Switch", 0, 808 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), 809CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 810 0, 0, 31, 1, db_scale_5bit_22db_max), 811CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0, 812 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0), 813 814WSS_DOUBLE("Line Playback Switch", 0, 815 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), 816WSS_DOUBLE_TLV("Line Volume", 0, 817 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, 818 db_scale_5bit_12db_max), 819WSS_DOUBLE("Line Capture Switch", 0, 820 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), 821WSS_DOUBLE("Line Capture Bypass", 0, 822 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1), 823 824WSS_DOUBLE("CD Playback Switch", 0, 825 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), 826WSS_DOUBLE_TLV("CD Volume", 0, 827 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, 828 db_scale_5bit_12db_max), 829WSS_DOUBLE("CD Capture Switch", 0, 830 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), 831 832CS4236_DOUBLE1("Mono Output Playback Switch", 0, 833 CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), 834CS4236_DOUBLE1("Beep Playback Switch", 0, 835 CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), 836WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1, 837 db_scale_4bit), 838WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), 839 840WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 841 0, 0, 15, 0, db_scale_rec_gain), 842WSS_DOUBLE("Analog Loopback Capture Switch", 0, 843 CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), 844 845WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), 846CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0, 847 CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1, 848 db_scale_6bit), 849}; 850 851static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0); 852static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0); 853 854static const struct snd_kcontrol_new snd_cs4235_controls[] = { 855 856WSS_DOUBLE("Master Playback Switch", 0, 857 CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1), 858WSS_DOUBLE_TLV("Master Playback Volume", 0, 859 CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1, 860 db_scale_5bit_6db_max), 861 862CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max), 863 864WSS_DOUBLE("Synth Playback Switch", 1, 865 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), 866WSS_DOUBLE("Synth Capture Switch", 1, 867 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), 868WSS_DOUBLE_TLV("Synth Volume", 1, 869 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, 870 db_scale_5bit_12db_max), 871 872CS4236_DOUBLE_TLV("Capture Volume", 0, 873 CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, 874 db_scale_2bit), 875 876WSS_DOUBLE("PCM Playback Switch", 0, 877 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), 878WSS_DOUBLE("PCM Capture Switch", 0, 879 CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), 880WSS_DOUBLE_TLV("PCM Volume", 0, 881 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, 882 db_scale_6bit), 883 884CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), 885 886CS4236_DOUBLE("FM Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), 887 888CS4236_DOUBLE("Wavetable Switch", 0, 889 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), 890 891CS4236_DOUBLE("Mic Capture Switch", 0, 892 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), 893CS4236_DOUBLE("Mic Playback Switch", 0, 894 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), 895CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1, 896 db_scale_5bit_22db_max), 897CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0), 898 899WSS_DOUBLE("Line Playback Switch", 0, 900 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), 901WSS_DOUBLE("Line Capture Switch", 0, 902 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), 903WSS_DOUBLE_TLV("Line Volume", 0, 904 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, 905 db_scale_5bit_12db_max), 906 907WSS_DOUBLE("CD Playback Switch", 1, 908 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), 909WSS_DOUBLE("CD Capture Switch", 1, 910 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), 911WSS_DOUBLE_TLV("CD Volume", 1, 912 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, 913 db_scale_5bit_12db_max), 914 915CS4236_DOUBLE1("Beep Playback Switch", 0, 916 CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), 917WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), 918 919WSS_DOUBLE("Analog Loopback Switch", 0, 920 CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), 921}; 922 923#define CS4236_IEC958_ENABLE(xname, xindex) \ 924{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 925 .info = snd_cs4236_info_single, \ 926 .get = snd_cs4236_get_iec958_switch, .put = snd_cs4236_put_iec958_switch, \ 927 .private_value = 1 << 16 } 928 929static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 930{ 931 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 932 unsigned long flags; 933 934 spin_lock_irqsave(&chip->reg_lock, flags); 935 ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0; 936#if 0 937 printk(KERN_DEBUG "get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, " 938 "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n", 939 snd_wss_in(chip, CS4231_ALT_FEATURE_1), 940 snd_cs4236_ctrl_in(chip, 3), 941 snd_cs4236_ctrl_in(chip, 4), 942 snd_cs4236_ctrl_in(chip, 5), 943 snd_cs4236_ctrl_in(chip, 6), 944 snd_cs4236_ctrl_in(chip, 8)); 945#endif 946 spin_unlock_irqrestore(&chip->reg_lock, flags); 947 return 0; 948} 949 950static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 951{ 952 struct snd_wss *chip = snd_kcontrol_chip(kcontrol); 953 unsigned long flags; 954 int change; 955 unsigned short enable, val; 956 957 enable = ucontrol->value.integer.value[0] & 1; 958 959 mutex_lock(&chip->mce_mutex); 960 snd_wss_mce_up(chip); 961 spin_lock_irqsave(&chip->reg_lock, flags); 962 val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1); 963 change = val != chip->image[CS4231_ALT_FEATURE_1]; 964 snd_wss_out(chip, CS4231_ALT_FEATURE_1, val); 965 val = snd_cs4236_ctrl_in(chip, 4) | 0xc0; 966 snd_cs4236_ctrl_out(chip, 4, val); 967 udelay(100); 968 val &= ~0x40; 969 snd_cs4236_ctrl_out(chip, 4, val); 970 spin_unlock_irqrestore(&chip->reg_lock, flags); 971 snd_wss_mce_down(chip); 972 mutex_unlock(&chip->mce_mutex); 973 974#if 0 975 printk(KERN_DEBUG "set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, " 976 "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n", 977 snd_wss_in(chip, CS4231_ALT_FEATURE_1), 978 snd_cs4236_ctrl_in(chip, 3), 979 snd_cs4236_ctrl_in(chip, 4), 980 snd_cs4236_ctrl_in(chip, 5), 981 snd_cs4236_ctrl_in(chip, 6), 982 snd_cs4236_ctrl_in(chip, 8)); 983#endif 984 return change; 985} 986 987static const struct snd_kcontrol_new snd_cs4236_iec958_controls[] = { 988CS4236_IEC958_ENABLE("IEC958 Output Enable", 0), 989CS4236_SINGLEC("IEC958 Output Validity", 0, 4, 4, 1, 0), 990CS4236_SINGLEC("IEC958 Output User", 0, 4, 5, 1, 0), 991CS4236_SINGLEC("IEC958 Output CSBR", 0, 4, 6, 1, 0), 992CS4236_SINGLEC("IEC958 Output Channel Status Low", 0, 5, 1, 127, 0), 993CS4236_SINGLEC("IEC958 Output Channel Status High", 0, 6, 0, 255, 0) 994}; 995 996static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4235[] = { 997CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0), 998CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1) 999}; 1000 1001static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4237[] = { 1002CS4236_SINGLEC("3D Control - Switch", 0, 3, 7, 1, 0), 1003CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1), 1004CS4236_SINGLEC("3D Control - Center", 0, 2, 0, 15, 1), 1005CS4236_SINGLEC("3D Control - Mono", 0, 3, 6, 1, 0), 1006CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0) 1007}; 1008 1009static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4238[] = { 1010CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0), 1011CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1), 1012CS4236_SINGLEC("3D Control - Volume", 0, 2, 0, 15, 1), 1013CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0) 1014}; 1015 1016int snd_cs4236_mixer(struct snd_wss *chip) 1017{ 1018 struct snd_card *card; 1019 unsigned int idx, count; 1020 int err; 1021 const struct snd_kcontrol_new *kcontrol; 1022 1023 if (snd_BUG_ON(!chip || !chip->card)) 1024 return -EINVAL; 1025 card = chip->card; 1026 strcpy(card->mixername, snd_wss_chip_id(chip)); 1027 1028 if (chip->hardware == WSS_HW_CS4235 || 1029 chip->hardware == WSS_HW_CS4239) { 1030 for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) { 1031 err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip)); 1032 if (err < 0) 1033 return err; 1034 } 1035 } else { 1036 for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_controls); idx++) { 1037 err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_controls[idx], chip)); 1038 if (err < 0) 1039 return err; 1040 } 1041 } 1042 switch (chip->hardware) { 1043 case WSS_HW_CS4235: 1044 case WSS_HW_CS4239: 1045 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4235); 1046 kcontrol = snd_cs4236_3d_controls_cs4235; 1047 break; 1048 case WSS_HW_CS4237B: 1049 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4237); 1050 kcontrol = snd_cs4236_3d_controls_cs4237; 1051 break; 1052 case WSS_HW_CS4238B: 1053 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4238); 1054 kcontrol = snd_cs4236_3d_controls_cs4238; 1055 break; 1056 default: 1057 count = 0; 1058 kcontrol = NULL; 1059 } 1060 for (idx = 0; idx < count; idx++, kcontrol++) { 1061 err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip)); 1062 if (err < 0) 1063 return err; 1064 } 1065 if (chip->hardware == WSS_HW_CS4237B || 1066 chip->hardware == WSS_HW_CS4238B) { 1067 for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) { 1068 err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip)); 1069 if (err < 0) 1070 return err; 1071 } 1072 } 1073 return 0; 1074}