1 /* 2 * ALSA driver for ICEnsemble VT1724 (Envy24HT) 3 * 4 * Lowlevel functions for Ego Sys Waveterminal 192M 5 * 6 * Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com> 7 * Some functions are taken from the Prodigy192 driver 8 * source 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 * 24 */ 25 26 27 28 #include <sound/driver.h> 29 #include <asm/io.h> 30 #include <linux/delay.h> 31 #include <linux/interrupt.h> 32 #include <linux/init.h> 33 #include <linux/slab.h> 34 #include <sound/core.h> 35 36 #include "ice1712.h" 37 #include "envy24ht.h" 38 #include "wtm.h" 39 #include "stac946x.h" 40 41 42 /* 43 * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus 44 */ 45 static inline void stac9460_put(struct snd_ice1712 *ice, int reg, 46 unsigned char val) 47 { 48 snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val); 49 } 50 51 static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) 52 { 53 return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg); 54 } 55 56 /* 57 * 2*ADC 2*DAC no2 ringbuffer r/w on i2c bus 58 */ 59 static inline void stac9460_2_put(struct snd_ice1712 *ice, int reg, 60 unsigned char val) 61 { 62 snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val); 63 } 64 65 static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg) 66 { 67 return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg); 68 } 69 70 71 /* 72 * DAC mute control 73 */ 74 static int stac9460_dac_mute_info(struct snd_kcontrol *kcontrol, 75 struct snd_ctl_elem_info *uinfo) 76 { 77 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 78 uinfo->count = 1; 79 uinfo->value.integer.min = 0; 80 return 0; 81 } 82 83 static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, 84 struct snd_ctl_elem_value *ucontrol) 85 { 86 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 87 unsigned char val; 88 int idx, id; 89 90 if (kcontrol->private_value) { 91 idx = STAC946X_MASTER_VOLUME; 92 id = 0; 93 } else { 94 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 95 idx = id + STAC946X_LF_VOLUME; 96 } 97 if (id < 6) 98 val = stac9460_get(ice, idx); 99 else 100 val = stac9460_2_get(ice,idx - 6); 101 ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; 102 return 0; 103 } 104 105 static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, 106 struct snd_ctl_elem_value *ucontrol) 107 { 108 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 109 unsigned char new, old; 110 int id, idx; 111 int change; 112 113 if (kcontrol->private_value) { 114 idx = STAC946X_MASTER_VOLUME; 115 old = stac9460_get(ice, idx); 116 new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | 117 (old & ~0x80); 118 change = (new != old); 119 if (change) { 120 stac9460_put(ice, idx, new); 121 stac9460_2_put(ice, idx, new); 122 } 123 } else { 124 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 125 idx = id + STAC946X_LF_VOLUME; 126 if (id < 6) 127 old = stac9460_get(ice, idx); 128 else 129 old = stac9460_2_get(ice, idx - 6); 130 new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | 131 (old & ~0x80); 132 change = (new != old); 133 if (change) { 134 if (id < 6) 135 stac9460_put(ice, idx, new); 136 else 137 stac9460_2_put(ice, idx - 6, new); 138 } 139 } 140 return change; 141 } 142 143 /* 144 * DAC volume attenuation mixer control 145 */ 146 static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol, 147 struct snd_ctl_elem_info *uinfo) 148 { 149 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 150 uinfo->count = 1; 151 uinfo->value.integer.min = 0; /* mute */ 152 uinfo->value.integer.max = 0x7f; /* 0dB */ 153 return 0; 154 } 155 156 static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol, 157 struct snd_ctl_elem_value *ucontrol) 158 { 159 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 160 int idx, id; 161 unsigned char vol; 162 163 if (kcontrol->private_value) { 164 idx = STAC946X_MASTER_VOLUME; 165 id = 0; 166 } else { 167 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 168 idx = id + STAC946X_LF_VOLUME; 169 } 170 if (id < 6) 171 vol = stac9460_get(ice, idx) & 0x7f; 172 else 173 vol = stac9460_2_get(ice, idx - 6) & 0x7f; 174 ucontrol->value.integer.value[0] = 0x7f - vol; 175 return 0; 176 } 177 178 static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, 179 struct snd_ctl_elem_value *ucontrol) 180 { 181 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 182 int idx, id; 183 unsigned char tmp, ovol, nvol; 184 int change; 185 186 if (kcontrol->private_value) { 187 idx = STAC946X_MASTER_VOLUME; 188 nvol = ucontrol->value.integer.value[0]; 189 tmp = stac9460_get(ice, idx); 190 ovol = 0x7f - (tmp & 0x7f); 191 change = (ovol != nvol); 192 if (change) { 193 stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); 194 stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); 195 } 196 } else { 197 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 198 idx = id + STAC946X_LF_VOLUME; 199 nvol = ucontrol->value.integer.value[0]; 200 if (id < 6) 201 tmp = stac9460_get(ice, idx); 202 else 203 tmp = stac9460_2_get(ice, idx - 6); 204 ovol = 0x7f - (tmp & 0x7f); 205 change = (ovol != nvol); 206 if (change) { 207 if (id < 6) 208 stac9460_put(ice, idx, (0x7f - nvol) | 209 (tmp & 0x80)); 210 else 211 stac9460_2_put(ice, idx-6, (0x7f - nvol) | 212 (tmp & 0x80)); 213 } 214 } 215 return change; 216 } 217 218 /* 219 * ADC mute control 220 */ 221 static int stac9460_adc_mute_info(struct snd_kcontrol *kcontrol, 222 struct snd_ctl_elem_info *uinfo) 223 { 224 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 225 uinfo->count = 2; 226 uinfo->value.integer.min = 0; 227 uinfo->value.integer.max = 1; 228 return 0; 229 } 230 231 static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, 232 struct snd_ctl_elem_value *ucontrol) 233 { 234 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 235 unsigned char val; 236 int i, id; 237 238 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 239 if (id == 0) { 240 for (i = 0; i < 2; ++i) { 241 val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i); 242 ucontrol->value.integer.value[i] = ~val>>7 & 0x1; 243 } 244 } else { 245 for (i = 0; i < 2; ++i) { 246 val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i); 247 ucontrol->value.integer.value[i] = ~val>>7 & 0x1; 248 } 249 } 250 return 0; 251 } 252 253 static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol, 254 struct snd_ctl_elem_value *ucontrol) 255 { 256 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 257 unsigned char new, old; 258 int i, reg, id; 259 int change; 260 261 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 262 if (id == 0) { 263 for (i = 0; i < 2; ++i) { 264 reg = STAC946X_MIC_L_VOLUME + i; 265 old = stac9460_get(ice, reg); 266 new = (~ucontrol->value.integer.value[i]<<7&0x80) | 267 (old&~0x80); 268 change = (new != old); 269 if (change) 270 stac9460_put(ice, reg, new); 271 } 272 } else { 273 for (i = 0; i < 2; ++i) { 274 reg = STAC946X_MIC_L_VOLUME + i; 275 old = stac9460_2_get(ice, reg); 276 new = (~ucontrol->value.integer.value[i]<<7&0x80) | 277 (old&~0x80); 278 change = (new != old); 279 if (change) 280 stac9460_2_put(ice, reg, new); 281 } 282 } 283 return change; 284 } 285 286 /* 287 *ADC gain mixer control 288 */ 289 static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol, 290 struct snd_ctl_elem_info *uinfo) 291 { 292 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 293 uinfo->count = 2; 294 uinfo->value.integer.min = 0; /* 0dB */ 295 uinfo->value.integer.max = 0x0f; /* 22.5dB */ 296 return 0; 297 } 298 299 static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol, 300 struct snd_ctl_elem_value *ucontrol) 301 { 302 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 303 int i, reg, id; 304 unsigned char vol; 305 306 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 307 if (id == 0) { 308 for (i = 0; i < 2; ++i) { 309 reg = STAC946X_MIC_L_VOLUME + i; 310 vol = stac9460_get(ice, reg) & 0x0f; 311 ucontrol->value.integer.value[i] = 0x0f - vol; 312 } 313 } else { 314 for (i = 0; i < 2; ++i) { 315 reg = STAC946X_MIC_L_VOLUME + i; 316 vol = stac9460_2_get(ice, reg) & 0x0f; 317 ucontrol->value.integer.value[i] = 0x0f - vol; 318 } 319 } 320 return 0; 321 } 322 323 static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, 324 struct snd_ctl_elem_value *ucontrol) 325 { 326 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 327 int i, reg, id; 328 unsigned char ovol, nvol; 329 int change; 330 331 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 332 if (id == 0) { 333 for (i = 0; i < 2; ++i) { 334 reg = STAC946X_MIC_L_VOLUME + i; 335 nvol = ucontrol->value.integer.value[i]; 336 ovol = 0x0f - stac9460_get(ice, reg); 337 change = ((ovol & 0x0f) != nvol); 338 if (change) 339 stac9460_put(ice, reg, (0x0f - nvol) | 340 (ovol & ~0x0f)); 341 } 342 } else { 343 for (i = 0; i < 2; ++i) { 344 reg = STAC946X_MIC_L_VOLUME + i; 345 nvol = ucontrol->value.integer.value[i]; 346 ovol = 0x0f - stac9460_2_get(ice, reg); 347 change = ((ovol & 0x0f) != nvol); 348 if (change) 349 stac9460_2_put(ice, reg, (0x0f - nvol) | 350 (ovol & ~0x0f)); 351 } 352 } 353 return change; 354 } 355 356 /* 357 * MIC / LINE switch fonction 358 */ 359 360 static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, 361 struct snd_ctl_elem_info *uinfo) 362 { 363 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 364 uinfo->count = 1; 365 uinfo->value.integer.min = 0; 366 uinfo->value.integer.max = 1; 367 return 0; 368 } 369 370 static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, 371 struct snd_ctl_elem_value *ucontrol) 372 { 373 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 374 unsigned char val; 375 int id; 376 377 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 378 if (id == 0) 379 val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 380 else 381 val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); 382 ucontrol->value.integer.value[0] = ~val>>7 & 0x1; 383 return 0; 384 } 385 386 static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, 387 struct snd_ctl_elem_value *ucontrol) 388 { 389 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 390 unsigned char new, old; 391 int change, id; 392 393 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 394 if (id == 0) 395 old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 396 else 397 old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); 398 new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80); 399 change = (new != old); 400 if (change) { 401 if (id == 0) 402 stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); 403 else 404 stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new); 405 } 406 return change; 407 } 408 409 /* 410 * Control tabs 411 */ 412 static struct snd_kcontrol_new stac9640_controls[] __devinitdata = { 413 { 414 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 415 .name = "Master Playback Switch", 416 .info = stac9460_dac_mute_info, 417 .get = stac9460_dac_mute_get, 418 .put = stac9460_dac_mute_put, 419 .private_value = 1 420 }, 421 { 422 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 423 .name = "Master Playback Volume", 424 .info = stac9460_dac_vol_info, 425 .get = stac9460_dac_vol_get, 426 .put = stac9460_dac_vol_put, 427 .private_value = 1, 428 }, 429 { 430 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 431 .name = "MIC/Line switch", 432 .count = 2, 433 .info = stac9460_mic_sw_info, 434 .get = stac9460_mic_sw_get, 435 .put = stac9460_mic_sw_put, 436 437 }, 438 { 439 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 440 .name = "DAC Switch", 441 .count = 8, 442 .info = stac9460_dac_mute_info, 443 .get = stac9460_dac_mute_get, 444 .put = stac9460_dac_mute_put, 445 }, 446 { 447 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 448 .name = "DAC Volume", 449 .count = 8, 450 .info = stac9460_dac_vol_info, 451 .get = stac9460_dac_vol_get, 452 .put = stac9460_dac_vol_put, 453 }, 454 { 455 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 456 .name = "ADC Switch", 457 .count = 2, 458 .info = stac9460_adc_mute_info, 459 .get = stac9460_adc_mute_get, 460 .put = stac9460_adc_mute_put, 461 }, 462 { 463 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 464 .name = "ADC Volume", 465 .count = 2, 466 .info = stac9460_adc_vol_info, 467 .get = stac9460_adc_vol_get, 468 .put = stac9460_adc_vol_put, 469 470 } 471 }; 472 473 474 475 /*INIT*/ 476 static int __devinit wtm_add_controls(struct snd_ice1712 *ice) 477 { 478 unsigned int i; 479 int err; 480 481 for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) { 482 err = snd_ctl_add(ice->card, 483 snd_ctl_new1(&stac9640_controls[i], ice)); 484 if (err < 0) 485 return err; 486 } 487 return 0; 488 } 489 490 static int __devinit wtm_init(struct snd_ice1712 *ice) 491 { 492 static unsigned short stac_inits_prodigy[] = { 493 STAC946X_RESET, 0, 494 (unsigned short)-1 495 }; 496 unsigned short *p; 497 498 /*WTM 192M*/ 499 ice->num_total_dacs = 8; 500 ice->num_total_adcs = 4; 501 ice->force_rdma1 = 1; 502 503 /*initialize codec*/ 504 p = stac_inits_prodigy; 505 for (; *p != (unsigned short)-1; p += 2) { 506 stac9460_put(ice, p[0], p[1]); 507 stac9460_2_put(ice, p[0], p[1]); 508 } 509 return 0; 510 } 511 512 513 static unsigned char wtm_eeprom[] __devinitdata = { 514 0x47, /*SYSCONF: clock 192KHz, 4ADC, 8DAC */ 515 0x80, /* ACLINK : I2S */ 516 0xf8, /* I2S: vol; 96k, 24bit, 192k */ 517 0xc1 /*SPDIF: out-en, spidf ext out*/, 518 0x9f, /* GPIO_DIR */ 519 0xff, /* GPIO_DIR1 */ 520 0x7f, /* GPIO_DIR2 */ 521 0x9f, /* GPIO_MASK */ 522 0xff, /* GPIO_MASK1 */ 523 0x7f, /* GPIO_MASK2 */ 524 0x16, /* GPIO_STATE */ 525 0x80, /* GPIO_STATE1 */ 526 0x00, /* GPIO_STATE2 */ 527 }; 528 529 530 /*entry point*/ 531 struct snd_ice1712_card_info snd_vt1724_wtm_cards[] __devinitdata = { 532 { 533 .subvendor = VT1724_SUBDEVICE_WTM, 534 .name = "ESI Waveterminal 192M", 535 .model = "WT192M", 536 .chip_init = wtm_init, 537 .build_controls = wtm_add_controls, 538 .eeprom_size = sizeof(wtm_eeprom), 539 .eeprom_data = wtm_eeprom, 540 }, 541 {} /*terminator*/ 542 }; 543