xref: /openbmc/linux/sound/isa/galaxy/galaxy.c (revision 85515309)
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 
dsp_get_byte(void __iomem * port,u8 * val)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 
dsp_reset(void __iomem * port)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 
dsp_command(void __iomem * port,u8 cmd)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 
dsp_get_version(void __iomem * port,u8 * major,u8 * minor)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 
wss_detect(void __iomem * wss_port)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 
wss_set_config(void __iomem * wss_port,u8 wss_config)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 
snd_galaxy_match(struct device * dev,unsigned int n)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 
galaxy_init(struct snd_galaxy * galaxy,u8 * type)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 
galaxy_set_mode(struct snd_galaxy * galaxy,u8 mode)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 
galaxy_set_config(struct snd_galaxy * galaxy,u32 config)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 
galaxy_config(struct snd_galaxy * galaxy,u32 config)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 
galaxy_wss_config(struct snd_galaxy * galaxy,u8 wss_config)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 
snd_galaxy_free(struct snd_card * card)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 	if (galaxy->config_port)
478 		galaxy_set_config(galaxy, galaxy->config);
479 }
480 
__snd_galaxy_probe(struct device * dev,unsigned int n)481 static int __snd_galaxy_probe(struct device *dev, unsigned int n)
482 {
483 	struct snd_galaxy *galaxy;
484 	struct snd_wss *chip;
485 	struct snd_card *card;
486 	u8 type;
487 	int err;
488 
489 	err = snd_devm_card_new(dev, index[n], id[n], THIS_MODULE,
490 				sizeof(*galaxy), &card);
491 	if (err < 0)
492 		return err;
493 
494 	card->private_free = snd_galaxy_free;
495 	galaxy = card->private_data;
496 
497 	galaxy->res_port = devm_request_region(dev, port[n], 16, DRV_NAME);
498 	if (!galaxy->res_port) {
499 		dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
500 			port[n] + 15);
501 		return -EBUSY;
502 	}
503 	galaxy->port = devm_ioport_map(dev, port[n], 16);
504 	if (!galaxy->port)
505 		return -ENOMEM;
506 
507 	err = galaxy_init(galaxy, &type);
508 	if (err < 0) {
509 		dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
510 		return err;
511 	}
512 	dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
513 
514 	galaxy->res_config_port =
515 		devm_request_region(dev, port[n] + GALAXY_PORT_CONFIG, 16,
516 				    DRV_NAME);
517 	if (!galaxy->res_config_port) {
518 		dev_err(dev, "could not grab ports %#lx-%#lx\n",
519 			port[n] + GALAXY_PORT_CONFIG,
520 			port[n] + GALAXY_PORT_CONFIG + 15);
521 		return -EBUSY;
522 	}
523 	galaxy->config_port =
524 		devm_ioport_map(dev, port[n] + GALAXY_PORT_CONFIG, 16);
525 	if (!galaxy->config_port)
526 		return -ENOMEM;
527 	galaxy_config(galaxy, config[n]);
528 
529 	galaxy->res_wss_port = devm_request_region(dev, wss_port[n], 4, DRV_NAME);
530 	if (!galaxy->res_wss_port)  {
531 		dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
532 			wss_port[n] + 3);
533 		return -EBUSY;
534 	}
535 	galaxy->wss_port = devm_ioport_map(dev, wss_port[n], 4);
536 	if (!galaxy->wss_port)
537 		return -ENOMEM;
538 
539 	err = galaxy_wss_config(galaxy, wss_config[n]);
540 	if (err < 0) {
541 		dev_err(dev, "could not configure WSS\n");
542 		return err;
543 	}
544 
545 	strcpy(card->driver, DRV_NAME);
546 	strcpy(card->shortname, DRV_NAME);
547 	sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
548 		card->shortname, port[n], wss_port[n], irq[n], dma1[n],
549 		dma2[n]);
550 
551 	err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
552 			     dma2[n], WSS_HW_DETECT, 0, &chip);
553 	if (err < 0)
554 		return err;
555 
556 	err = snd_wss_pcm(chip, 0);
557 	if (err < 0)
558 		return err;
559 
560 	err = snd_wss_mixer(chip);
561 	if (err < 0)
562 		return err;
563 
564 	err = snd_wss_timer(chip, 0);
565 	if (err < 0)
566 		return err;
567 
568 	if (mpu_port[n] >= 0) {
569 		err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
570 					  mpu_port[n], 0, mpu_irq[n], NULL);
571 		if (err < 0)
572 			return err;
573 	}
574 
575 	if (fm_port[n] >= 0) {
576 		struct snd_opl3 *opl3;
577 
578 		err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
579 				      OPL3_HW_AUTO, 0, &opl3);
580 		if (err < 0) {
581 			dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
582 			return err;
583 		}
584 		err = snd_opl3_timer_new(opl3, 1, 2);
585 		if (err < 0)
586 			return err;
587 
588 		err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
589 		if (err < 0)
590 			return err;
591 	}
592 
593 	err = snd_card_register(card);
594 	if (err < 0)
595 		return err;
596 
597 	dev_set_drvdata(dev, card);
598 	return 0;
599 }
600 
snd_galaxy_probe(struct device * dev,unsigned int n)601 static int snd_galaxy_probe(struct device *dev, unsigned int n)
602 {
603 	return snd_card_free_on_error(dev, __snd_galaxy_probe(dev, n));
604 }
605 
606 static struct isa_driver snd_galaxy_driver = {
607 	.match		= snd_galaxy_match,
608 	.probe		= snd_galaxy_probe,
609 
610 	.driver		= {
611 		.name	= DEV_NAME
612 	}
613 };
614 
615 module_isa_driver(snd_galaxy_driver, SNDRV_CARDS);
616