1 /* 2 * ALSA driver for ICEnsemble VT1724 (Envy24HT) 3 * 4 * Lowlevel functions for AudioTrak Prodigy 192 cards 5 * 6 * Copyright (c) 2003 Takashi Iwai <tiwai@suse.de> 7 * Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca> 8 * Copyright (c) 2004 Kouichi ONO <co2b@ceres.dti.ne.jp> 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 #include <sound/driver.h> 27 #include <asm/io.h> 28 #include <linux/delay.h> 29 #include <linux/interrupt.h> 30 #include <linux/init.h> 31 #include <linux/slab.h> 32 #include <sound/core.h> 33 34 #include "ice1712.h" 35 #include "envy24ht.h" 36 #include "prodigy192.h" 37 #include "stac946x.h" 38 39 static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) 40 { 41 snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val); 42 } 43 44 static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) 45 { 46 return snd_vt1724_read_i2c(ice, PRODIGY192_STAC9460_ADDR, reg); 47 } 48 49 /* 50 * DAC mute control 51 */ 52 static int stac9460_dac_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 53 { 54 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 55 uinfo->count = 1; 56 uinfo->value.integer.min = 0; 57 uinfo->value.integer.max = 1; 58 return 0; 59 } 60 61 static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 62 { 63 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 64 unsigned char val; 65 int idx; 66 67 if (kcontrol->private_value) 68 idx = STAC946X_MASTER_VOLUME; 69 else 70 idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 71 val = stac9460_get(ice, idx); 72 ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; 73 return 0; 74 } 75 76 static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 77 { 78 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 79 unsigned char new, old; 80 int idx; 81 int change; 82 83 if (kcontrol->private_value) 84 idx = STAC946X_MASTER_VOLUME; 85 else 86 idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 87 old = stac9460_get(ice, idx); 88 new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80); 89 change = (new != old); 90 if (change) 91 stac9460_put(ice, idx, new); 92 93 return change; 94 } 95 96 /* 97 * DAC volume attenuation mixer control 98 */ 99 static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 100 { 101 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 102 uinfo->count = 1; 103 uinfo->value.integer.min = 0; /* mute */ 104 uinfo->value.integer.max = 0x7f; /* 0dB */ 105 return 0; 106 } 107 108 static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 109 { 110 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 111 int idx; 112 unsigned char vol; 113 114 if (kcontrol->private_value) 115 idx = STAC946X_MASTER_VOLUME; 116 else 117 idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 118 vol = stac9460_get(ice, idx) & 0x7f; 119 ucontrol->value.integer.value[0] = 0x7f - vol; 120 121 return 0; 122 } 123 124 static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 125 { 126 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 127 int idx; 128 unsigned char tmp, ovol, nvol; 129 int change; 130 131 if (kcontrol->private_value) 132 idx = STAC946X_MASTER_VOLUME; 133 else 134 idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 135 nvol = ucontrol->value.integer.value[0]; 136 tmp = stac9460_get(ice, idx); 137 ovol = 0x7f - (tmp & 0x7f); 138 change = (ovol != nvol); 139 if (change) { 140 stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); 141 } 142 return change; 143 } 144 145 /* 146 * ADC mute control 147 */ 148 static int stac9460_adc_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 149 { 150 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 151 uinfo->count = 2; 152 uinfo->value.integer.min = 0; 153 uinfo->value.integer.max = 1; 154 return 0; 155 } 156 157 static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 158 { 159 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 160 unsigned char val; 161 int i; 162 163 for (i = 0; i < 2; ++i) { 164 val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i); 165 ucontrol->value.integer.value[i] = ~val>>7 & 0x1; 166 } 167 168 return 0; 169 } 170 171 static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 172 { 173 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 174 unsigned char new, old; 175 int i, reg; 176 int change; 177 178 for (i = 0; i < 2; ++i) { 179 reg = STAC946X_MIC_L_VOLUME + i; 180 old = stac9460_get(ice, reg); 181 new = (~ucontrol->value.integer.value[i]<<7&0x80) | (old&~0x80); 182 change = (new != old); 183 if (change) 184 stac9460_put(ice, reg, new); 185 } 186 187 return change; 188 } 189 190 /* 191 * ADC gain mixer control 192 */ 193 static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 194 { 195 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 196 uinfo->count = 2; 197 uinfo->value.integer.min = 0; /* 0dB */ 198 uinfo->value.integer.max = 0x0f; /* 22.5dB */ 199 return 0; 200 } 201 202 static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 203 { 204 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 205 int i, reg; 206 unsigned char vol; 207 208 for (i = 0; i < 2; ++i) { 209 reg = STAC946X_MIC_L_VOLUME + i; 210 vol = stac9460_get(ice, reg) & 0x0f; 211 ucontrol->value.integer.value[i] = 0x0f - vol; 212 } 213 214 return 0; 215 } 216 217 static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 218 { 219 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 220 int i, reg; 221 unsigned char ovol, nvol; 222 int change; 223 224 for (i = 0; i < 2; ++i) { 225 reg = STAC946X_MIC_L_VOLUME + i; 226 nvol = ucontrol->value.integer.value[i]; 227 ovol = 0x0f - stac9460_get(ice, reg); 228 change = ((ovol & 0x0f) != nvol); 229 if (change) 230 stac9460_put(ice, reg, (0x0f - nvol) | (ovol & ~0x0f)); 231 } 232 233 return change; 234 } 235 236 #if 0 237 /* 238 * Headphone Amplifier 239 */ 240 static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable) 241 { 242 unsigned int tmp, tmp2; 243 244 tmp2 = tmp = snd_ice1712_gpio_read(ice); 245 if (enable) 246 tmp |= AUREON_HP_SEL; 247 else 248 tmp &= ~ AUREON_HP_SEL; 249 if (tmp != tmp2) { 250 snd_ice1712_gpio_write(ice, tmp); 251 return 1; 252 } 253 return 0; 254 } 255 256 static int aureon_get_headphone_amp(struct snd_ice1712 *ice) 257 { 258 unsigned int tmp = snd_ice1712_gpio_read(ice); 259 260 return ( tmp & AUREON_HP_SEL )!= 0; 261 } 262 263 static int aureon_bool_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) 264 { 265 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 266 uinfo->count = 1; 267 uinfo->value.integer.min = 0; 268 uinfo->value.integer.max = 1; 269 return 0; 270 } 271 272 static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 273 { 274 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 275 276 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice); 277 return 0; 278 } 279 280 281 static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 282 { 283 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 284 285 return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]); 286 } 287 288 /* 289 * Deemphasis 290 */ 291 static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 292 { 293 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 294 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf; 295 return 0; 296 } 297 298 static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 299 { 300 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 301 int temp, temp2; 302 temp2 = temp = wm_get(ice, WM_DAC_CTRL2); 303 if (ucontrol->value.integer.value[0]) 304 temp |= 0xf; 305 else 306 temp &= ~0xf; 307 if (temp != temp2) { 308 wm_put(ice, WM_DAC_CTRL2, temp); 309 return 1; 310 } 311 return 0; 312 } 313 314 /* 315 * ADC Oversampling 316 */ 317 static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) 318 { 319 static char *texts[2] = { "128x", "64x" }; 320 321 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 322 uinfo->count = 1; 323 uinfo->value.enumerated.items = 2; 324 325 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 326 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 327 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 328 329 return 0; 330 } 331 332 static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 333 { 334 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 335 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8; 336 return 0; 337 } 338 339 static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 340 { 341 int temp, temp2; 342 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 343 344 temp2 = temp = wm_get(ice, WM_MASTER); 345 346 if (ucontrol->value.enumerated.item[0]) 347 temp |= 0x8; 348 else 349 temp &= ~0x8; 350 351 if (temp != temp2) { 352 wm_put(ice, WM_MASTER, temp); 353 return 1; 354 } 355 return 0; 356 } 357 #endif 358 359 /* 360 * mixers 361 */ 362 363 static struct snd_kcontrol_new stac_controls[] __devinitdata = { 364 { 365 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 366 .name = "Master Playback Switch", 367 .info = stac9460_dac_mute_info, 368 .get = stac9460_dac_mute_get, 369 .put = stac9460_dac_mute_put, 370 .private_value = 1, 371 }, 372 { 373 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 374 .name = "Master Playback Volume", 375 .info = stac9460_dac_vol_info, 376 .get = stac9460_dac_vol_get, 377 .put = stac9460_dac_vol_put, 378 .private_value = 1, 379 }, 380 { 381 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 382 .name = "DAC Switch", 383 .count = 6, 384 .info = stac9460_dac_mute_info, 385 .get = stac9460_dac_mute_get, 386 .put = stac9460_dac_mute_put, 387 }, 388 { 389 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 390 .name = "DAC Volume", 391 .count = 6, 392 .info = stac9460_dac_vol_info, 393 .get = stac9460_dac_vol_get, 394 .put = stac9460_dac_vol_put, 395 }, 396 { 397 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 398 .name = "ADC Switch", 399 .count = 1, 400 .info = stac9460_adc_mute_info, 401 .get = stac9460_adc_mute_get, 402 .put = stac9460_adc_mute_put, 403 404 }, 405 { 406 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 407 .name = "ADC Volume", 408 .count = 1, 409 .info = stac9460_adc_vol_info, 410 .get = stac9460_adc_vol_get, 411 .put = stac9460_adc_vol_put, 412 }, 413 #if 0 414 { 415 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 416 .name = "Capture Route", 417 .info = wm_adc_mux_info, 418 .get = wm_adc_mux_get, 419 .put = wm_adc_mux_put, 420 }, 421 { 422 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 423 .name = "Headphone Amplifier Switch", 424 .info = aureon_bool_info, 425 .get = aureon_hpamp_get, 426 .put = aureon_hpamp_put 427 }, 428 { 429 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 430 .name = "DAC Deemphasis Switch", 431 .info = aureon_bool_info, 432 .get = aureon_deemp_get, 433 .put = aureon_deemp_put 434 }, 435 { 436 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 437 .name = "ADC Oversampling", 438 .info = aureon_oversampling_info, 439 .get = aureon_oversampling_get, 440 .put = aureon_oversampling_put 441 }, 442 #endif 443 }; 444 445 static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) 446 { 447 unsigned int i; 448 int err; 449 450 for (i = 0; i < ARRAY_SIZE(stac_controls); i++) { 451 err = snd_ctl_add(ice->card, snd_ctl_new1(&stac_controls[i], ice)); 452 if (err < 0) 453 return err; 454 } 455 return 0; 456 } 457 458 459 /* 460 * initialize the chip 461 */ 462 static int __devinit prodigy192_init(struct snd_ice1712 *ice) 463 { 464 static unsigned short stac_inits_prodigy[] = { 465 STAC946X_RESET, 0, 466 /* STAC946X_MASTER_VOLUME, 0, 467 STAC946X_LF_VOLUME, 0, 468 STAC946X_RF_VOLUME, 0, 469 STAC946X_LR_VOLUME, 0, 470 STAC946X_RR_VOLUME, 0, 471 STAC946X_CENTER_VOLUME, 0, 472 STAC946X_LFE_VOLUME, 0,*/ 473 (unsigned short)-1 474 }; 475 unsigned short *p; 476 477 /* prodigy 192 */ 478 ice->num_total_dacs = 6; 479 ice->num_total_adcs = 2; 480 481 /* initialize codec */ 482 p = stac_inits_prodigy; 483 for (; *p != (unsigned short)-1; p += 2) 484 stac9460_put(ice, p[0], p[1]); 485 486 return 0; 487 } 488 489 490 /* 491 * Aureon boards don't provide the EEPROM data except for the vendor IDs. 492 * hence the driver needs to sets up it properly. 493 */ 494 495 static unsigned char prodigy71_eeprom[] __devinitdata = { 496 0x2b, /* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */ 497 0x80, /* ACLINK: I2S */ 498 0xf8, /* I2S: vol, 96k, 24bit, 192k */ 499 0xc3, /* SPDIF: out-en, out-int, spdif-in */ 500 0xff, /* GPIO_DIR */ 501 0xff, /* GPIO_DIR1 */ 502 0xbf, /* GPIO_DIR2 */ 503 0x00, /* GPIO_MASK */ 504 0x00, /* GPIO_MASK1 */ 505 0x00, /* GPIO_MASK2 */ 506 0x00, /* GPIO_STATE */ 507 0x00, /* GPIO_STATE1 */ 508 0x00, /* GPIO_STATE2 */ 509 }; 510 511 512 /* entry point */ 513 struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = { 514 { 515 .subvendor = VT1724_SUBDEVICE_PRODIGY192VE, 516 .name = "Audiotrak Prodigy 192", 517 .model = "prodigy192", 518 .chip_init = prodigy192_init, 519 .build_controls = prodigy192_add_controls, 520 .eeprom_size = sizeof(prodigy71_eeprom), 521 .eeprom_data = prodigy71_eeprom, 522 }, 523 { } /* terminator */ 524 }; 525