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