1 /* 2 * Aztech AZT1605/AZT2316 Driver 3 * Copyright (C) 2007,2010 Rene Herman 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 #include <linux/kernel.h> 21 #include <linux/module.h> 22 #include <linux/isa.h> 23 #include <linux/delay.h> 24 #include <linux/io.h> 25 #include <asm/processor.h> 26 #include <sound/core.h> 27 #include <sound/initval.h> 28 #include <sound/wss.h> 29 #include <sound/mpu401.h> 30 #include <sound/opl3.h> 31 32 MODULE_DESCRIPTION(CRD_NAME); 33 MODULE_AUTHOR("Rene Herman"); 34 MODULE_LICENSE("GPL"); 35 36 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 37 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 38 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; 39 40 module_param_array(index, int, NULL, 0444); 41 MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard."); 42 module_param_array(id, charp, NULL, 0444); 43 MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard."); 44 module_param_array(enable, bool, NULL, 0444); 45 MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); 46 47 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 48 static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 49 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 50 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 51 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; 52 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; 53 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; 54 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; 55 56 module_param_hw_array(port, long, ioport, NULL, 0444); 57 MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); 58 module_param_hw_array(wss_port, long, ioport, NULL, 0444); 59 MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver."); 60 module_param_hw_array(mpu_port, long, ioport, NULL, 0444); 61 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver."); 62 module_param_hw_array(fm_port, long, ioport, NULL, 0444); 63 MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver."); 64 module_param_hw_array(irq, int, irq, NULL, 0444); 65 MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver."); 66 module_param_hw_array(mpu_irq, int, irq, NULL, 0444); 67 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver."); 68 module_param_hw_array(dma1, int, dma, NULL, 0444); 69 MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver."); 70 module_param_hw_array(dma2, int, dma, NULL, 0444); 71 MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver."); 72 73 /* 74 * Generic SB DSP support routines 75 */ 76 77 #define DSP_PORT_RESET 0x6 78 #define DSP_PORT_READ 0xa 79 #define DSP_PORT_COMMAND 0xc 80 #define DSP_PORT_STATUS 0xc 81 #define DSP_PORT_DATA_AVAIL 0xe 82 83 #define DSP_SIGNATURE 0xaa 84 85 #define DSP_COMMAND_GET_VERSION 0xe1 86 87 static int dsp_get_byte(void __iomem *port, u8 *val) 88 { 89 int loops = 1000; 90 91 while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) { 92 if (!loops--) 93 return -EIO; 94 cpu_relax(); 95 } 96 *val = ioread8(port + DSP_PORT_READ); 97 return 0; 98 } 99 100 static int dsp_reset(void __iomem *port) 101 { 102 u8 val; 103 104 iowrite8(1, port + DSP_PORT_RESET); 105 udelay(10); 106 iowrite8(0, port + DSP_PORT_RESET); 107 108 if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE) 109 return -ENODEV; 110 111 return 0; 112 } 113 114 static int dsp_command(void __iomem *port, u8 cmd) 115 { 116 int loops = 1000; 117 118 while (ioread8(port + DSP_PORT_STATUS) & 0x80) { 119 if (!loops--) 120 return -EIO; 121 cpu_relax(); 122 } 123 iowrite8(cmd, port + DSP_PORT_COMMAND); 124 return 0; 125 } 126 127 static int dsp_get_version(void __iomem *port, u8 *major, u8 *minor) 128 { 129 int err; 130 131 err = dsp_command(port, DSP_COMMAND_GET_VERSION); 132 if (err < 0) 133 return err; 134 135 err = dsp_get_byte(port, major); 136 if (err < 0) 137 return err; 138 139 err = dsp_get_byte(port, minor); 140 if (err < 0) 141 return err; 142 143 return 0; 144 } 145 146 /* 147 * Generic WSS support routines 148 */ 149 150 #define WSS_CONFIG_DMA_0 (1 << 0) 151 #define WSS_CONFIG_DMA_1 (2 << 0) 152 #define WSS_CONFIG_DMA_3 (3 << 0) 153 #define WSS_CONFIG_DUPLEX (1 << 2) 154 #define WSS_CONFIG_IRQ_7 (1 << 3) 155 #define WSS_CONFIG_IRQ_9 (2 << 3) 156 #define WSS_CONFIG_IRQ_10 (3 << 3) 157 #define WSS_CONFIG_IRQ_11 (4 << 3) 158 159 #define WSS_PORT_CONFIG 0 160 #define WSS_PORT_SIGNATURE 3 161 162 #define WSS_SIGNATURE 4 163 164 static int wss_detect(void __iomem *wss_port) 165 { 166 if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE) 167 return -ENODEV; 168 169 return 0; 170 } 171 172 static void wss_set_config(void __iomem *wss_port, u8 wss_config) 173 { 174 iowrite8(wss_config, wss_port + WSS_PORT_CONFIG); 175 } 176 177 /* 178 * Aztech Sound Galaxy specifics 179 */ 180 181 #define GALAXY_PORT_CONFIG 1024 182 #define CONFIG_PORT_SET 4 183 184 #define DSP_COMMAND_GALAXY_8 8 185 #define GALAXY_COMMAND_GET_TYPE 5 186 187 #define DSP_COMMAND_GALAXY_9 9 188 #define GALAXY_COMMAND_WSSMODE 0 189 #define GALAXY_COMMAND_SB8MODE 1 190 191 #define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE 192 #define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE 193 194 struct snd_galaxy { 195 void __iomem *port; 196 void __iomem *config_port; 197 void __iomem *wss_port; 198 u32 config; 199 struct resource *res_port; 200 struct resource *res_config_port; 201 struct resource *res_wss_port; 202 }; 203 204 static u32 config[SNDRV_CARDS]; 205 static u8 wss_config[SNDRV_CARDS]; 206 207 static int snd_galaxy_match(struct device *dev, unsigned int n) 208 { 209 if (!enable[n]) 210 return 0; 211 212 switch (port[n]) { 213 case SNDRV_AUTO_PORT: 214 dev_err(dev, "please specify port\n"); 215 return 0; 216 case 0x220: 217 config[n] |= GALAXY_CONFIG_SBA_220; 218 break; 219 case 0x240: 220 config[n] |= GALAXY_CONFIG_SBA_240; 221 break; 222 case 0x260: 223 config[n] |= GALAXY_CONFIG_SBA_260; 224 break; 225 case 0x280: 226 config[n] |= GALAXY_CONFIG_SBA_280; 227 break; 228 default: 229 dev_err(dev, "invalid port %#lx\n", port[n]); 230 return 0; 231 } 232 233 switch (wss_port[n]) { 234 case SNDRV_AUTO_PORT: 235 dev_err(dev, "please specify wss_port\n"); 236 return 0; 237 case 0x530: 238 config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530; 239 break; 240 case 0x604: 241 config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604; 242 break; 243 case 0xe80: 244 config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80; 245 break; 246 case 0xf40: 247 config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40; 248 break; 249 default: 250 dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]); 251 return 0; 252 } 253 254 switch (irq[n]) { 255 case SNDRV_AUTO_IRQ: 256 dev_err(dev, "please specify irq\n"); 257 return 0; 258 case 7: 259 wss_config[n] |= WSS_CONFIG_IRQ_7; 260 break; 261 case 2: 262 irq[n] = 9; 263 /* Fall through */ 264 case 9: 265 wss_config[n] |= WSS_CONFIG_IRQ_9; 266 break; 267 case 10: 268 wss_config[n] |= WSS_CONFIG_IRQ_10; 269 break; 270 case 11: 271 wss_config[n] |= WSS_CONFIG_IRQ_11; 272 break; 273 default: 274 dev_err(dev, "invalid IRQ %d\n", irq[n]); 275 return 0; 276 } 277 278 switch (dma1[n]) { 279 case SNDRV_AUTO_DMA: 280 dev_err(dev, "please specify dma1\n"); 281 return 0; 282 case 0: 283 wss_config[n] |= WSS_CONFIG_DMA_0; 284 break; 285 case 1: 286 wss_config[n] |= WSS_CONFIG_DMA_1; 287 break; 288 case 3: 289 wss_config[n] |= WSS_CONFIG_DMA_3; 290 break; 291 default: 292 dev_err(dev, "invalid playback DMA %d\n", dma1[n]); 293 return 0; 294 } 295 296 if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) { 297 dma2[n] = -1; 298 goto mpu; 299 } 300 301 wss_config[n] |= WSS_CONFIG_DUPLEX; 302 switch (dma2[n]) { 303 case 0: 304 break; 305 case 1: 306 if (dma1[n] == 0) 307 break; 308 /* Fall through */ 309 default: 310 dev_err(dev, "invalid capture DMA %d\n", dma2[n]); 311 return 0; 312 } 313 314 mpu: 315 switch (mpu_port[n]) { 316 case SNDRV_AUTO_PORT: 317 dev_warn(dev, "mpu_port not specified; not using MPU-401\n"); 318 mpu_port[n] = -1; 319 goto fm; 320 case 0x300: 321 config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300; 322 break; 323 case 0x330: 324 config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330; 325 break; 326 default: 327 dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]); 328 return 0; 329 } 330 331 switch (mpu_irq[n]) { 332 case SNDRV_AUTO_IRQ: 333 dev_warn(dev, "mpu_irq not specified: using polling mode\n"); 334 mpu_irq[n] = -1; 335 break; 336 case 2: 337 mpu_irq[n] = 9; 338 /* Fall through */ 339 case 9: 340 config[n] |= GALAXY_CONFIG_MPUIRQ_2; 341 break; 342 #ifdef AZT1605 343 case 3: 344 config[n] |= GALAXY_CONFIG_MPUIRQ_3; 345 break; 346 #endif 347 case 5: 348 config[n] |= GALAXY_CONFIG_MPUIRQ_5; 349 break; 350 case 7: 351 config[n] |= GALAXY_CONFIG_MPUIRQ_7; 352 break; 353 #ifdef AZT2316 354 case 10: 355 config[n] |= GALAXY_CONFIG_MPUIRQ_10; 356 break; 357 #endif 358 default: 359 dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]); 360 return 0; 361 } 362 363 if (mpu_irq[n] == irq[n]) { 364 dev_err(dev, "cannot share IRQ between WSS and MPU-401\n"); 365 return 0; 366 } 367 368 fm: 369 switch (fm_port[n]) { 370 case SNDRV_AUTO_PORT: 371 dev_warn(dev, "fm_port not specified: not using OPL3\n"); 372 fm_port[n] = -1; 373 break; 374 case 0x388: 375 break; 376 default: 377 dev_err(dev, "illegal FM port %#lx\n", fm_port[n]); 378 return 0; 379 } 380 381 config[n] |= GALAXY_CONFIG_GAME_ENABLE; 382 return 1; 383 } 384 385 static int galaxy_init(struct snd_galaxy *galaxy, u8 *type) 386 { 387 u8 major; 388 u8 minor; 389 int err; 390 391 err = dsp_reset(galaxy->port); 392 if (err < 0) 393 return err; 394 395 err = dsp_get_version(galaxy->port, &major, &minor); 396 if (err < 0) 397 return err; 398 399 if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR) 400 return -ENODEV; 401 402 err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8); 403 if (err < 0) 404 return err; 405 406 err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE); 407 if (err < 0) 408 return err; 409 410 err = dsp_get_byte(galaxy->port, type); 411 if (err < 0) 412 return err; 413 414 return 0; 415 } 416 417 static int galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode) 418 { 419 int err; 420 421 err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9); 422 if (err < 0) 423 return err; 424 425 err = dsp_command(galaxy->port, mode); 426 if (err < 0) 427 return err; 428 429 #ifdef AZT1605 430 /* 431 * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again 432 */ 433 err = dsp_reset(galaxy->port); 434 if (err < 0) 435 return err; 436 #endif 437 438 return 0; 439 } 440 441 static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config) 442 { 443 u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET); 444 int i; 445 446 iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET); 447 for (i = 0; i < GALAXY_CONFIG_SIZE; i++) { 448 iowrite8(config, galaxy->config_port + i); 449 config >>= 8; 450 } 451 iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET); 452 msleep(10); 453 } 454 455 static void galaxy_config(struct snd_galaxy *galaxy, u32 config) 456 { 457 int i; 458 459 for (i = GALAXY_CONFIG_SIZE; i; i--) { 460 u8 tmp = ioread8(galaxy->config_port + i - 1); 461 galaxy->config = (galaxy->config << 8) | tmp; 462 } 463 config |= galaxy->config & GALAXY_CONFIG_MASK; 464 galaxy_set_config(galaxy, config); 465 } 466 467 static int galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config) 468 { 469 int err; 470 471 err = wss_detect(galaxy->wss_port); 472 if (err < 0) 473 return err; 474 475 wss_set_config(galaxy->wss_port, wss_config); 476 477 err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS); 478 if (err < 0) 479 return err; 480 481 return 0; 482 } 483 484 static void snd_galaxy_free(struct snd_card *card) 485 { 486 struct snd_galaxy *galaxy = card->private_data; 487 488 if (galaxy->wss_port) { 489 wss_set_config(galaxy->wss_port, 0); 490 ioport_unmap(galaxy->wss_port); 491 release_and_free_resource(galaxy->res_wss_port); 492 } 493 if (galaxy->config_port) { 494 galaxy_set_config(galaxy, galaxy->config); 495 ioport_unmap(galaxy->config_port); 496 release_and_free_resource(galaxy->res_config_port); 497 } 498 if (galaxy->port) { 499 ioport_unmap(galaxy->port); 500 release_and_free_resource(galaxy->res_port); 501 } 502 } 503 504 static int snd_galaxy_probe(struct device *dev, unsigned int n) 505 { 506 struct snd_galaxy *galaxy; 507 struct snd_wss *chip; 508 struct snd_card *card; 509 u8 type; 510 int err; 511 512 err = snd_card_new(dev, index[n], id[n], THIS_MODULE, 513 sizeof(*galaxy), &card); 514 if (err < 0) 515 return err; 516 517 card->private_free = snd_galaxy_free; 518 galaxy = card->private_data; 519 520 galaxy->res_port = request_region(port[n], 16, DRV_NAME); 521 if (!galaxy->res_port) { 522 dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n], 523 port[n] + 15); 524 err = -EBUSY; 525 goto error; 526 } 527 galaxy->port = ioport_map(port[n], 16); 528 529 err = galaxy_init(galaxy, &type); 530 if (err < 0) { 531 dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]); 532 goto error; 533 } 534 dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]); 535 536 galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG, 537 16, DRV_NAME); 538 if (!galaxy->res_config_port) { 539 dev_err(dev, "could not grab ports %#lx-%#lx\n", 540 port[n] + GALAXY_PORT_CONFIG, 541 port[n] + GALAXY_PORT_CONFIG + 15); 542 err = -EBUSY; 543 goto error; 544 } 545 galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16); 546 547 galaxy_config(galaxy, config[n]); 548 549 galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME); 550 if (!galaxy->res_wss_port) { 551 dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n], 552 wss_port[n] + 3); 553 err = -EBUSY; 554 goto error; 555 } 556 galaxy->wss_port = ioport_map(wss_port[n], 4); 557 558 err = galaxy_wss_config(galaxy, wss_config[n]); 559 if (err < 0) { 560 dev_err(dev, "could not configure WSS\n"); 561 goto error; 562 } 563 564 strcpy(card->driver, DRV_NAME); 565 strcpy(card->shortname, DRV_NAME); 566 sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d", 567 card->shortname, port[n], wss_port[n], irq[n], dma1[n], 568 dma2[n]); 569 570 err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n], 571 dma2[n], WSS_HW_DETECT, 0, &chip); 572 if (err < 0) 573 goto error; 574 575 err = snd_wss_pcm(chip, 0); 576 if (err < 0) 577 goto error; 578 579 err = snd_wss_mixer(chip); 580 if (err < 0) 581 goto error; 582 583 err = snd_wss_timer(chip, 0); 584 if (err < 0) 585 goto error; 586 587 if (mpu_port[n] >= 0) { 588 err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, 589 mpu_port[n], 0, mpu_irq[n], NULL); 590 if (err < 0) 591 goto error; 592 } 593 594 if (fm_port[n] >= 0) { 595 struct snd_opl3 *opl3; 596 597 err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2, 598 OPL3_HW_AUTO, 0, &opl3); 599 if (err < 0) { 600 dev_err(dev, "no OPL device at %#lx\n", fm_port[n]); 601 goto error; 602 } 603 err = snd_opl3_timer_new(opl3, 1, 2); 604 if (err < 0) 605 goto error; 606 607 err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); 608 if (err < 0) 609 goto error; 610 } 611 612 err = snd_card_register(card); 613 if (err < 0) 614 goto error; 615 616 dev_set_drvdata(dev, card); 617 return 0; 618 619 error: 620 snd_card_free(card); 621 return err; 622 } 623 624 static int snd_galaxy_remove(struct device *dev, unsigned int n) 625 { 626 snd_card_free(dev_get_drvdata(dev)); 627 return 0; 628 } 629 630 static struct isa_driver snd_galaxy_driver = { 631 .match = snd_galaxy_match, 632 .probe = snd_galaxy_probe, 633 .remove = snd_galaxy_remove, 634 635 .driver = { 636 .name = DEV_NAME 637 } 638 }; 639 640 module_isa_driver(snd_galaxy_driver, SNDRV_CARDS); 641